test: simplify

This commit is contained in:
cha0s 2024-02-14 20:16:31 -06:00
parent 1cf5f328f5
commit b5b53b8f22
91 changed files with 259 additions and 266 deletions

View File

@ -38,7 +38,7 @@ jobs:
strategy:
max-parallel: ${{ vars.CI_PARALLEL || 256 }}
matrix:
test-platforms: ['-p default -p server', '-p e2e']
test-platforms: ['', '-s e2e']
node-version: [16.x, 18.x, 20.x]
steps:
- uses: actions/checkout@v4

View File

@ -8,13 +8,13 @@
},
"scripts": {
"build": "FORCE_COLOR=1 node build/tasks npm run -- build",
"ci": "act -W .github/workflows/ci.yml --matrix node-version:20.x",
"dox": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus npx docusaurus",
"dox:build": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus npx docusaurus build && cd .. && rm -rf gh-pages/* && mv website/build/* gh-pages && rm -rf website/build",
"gh-pages": "cd gh-pages && git add . && git commit -m $(git -C ../website rev-parse HEAD) && git push origin gh-pages",
"lint": "FORCE_COLOR=1 node build/tasks npm run -- lint",
"publish": "node build/publish --provenance",
"test": "FORCE_COLOR=1 MOCHA_COLORS=1 node build/tasks npm run -- test",
"verify": "act -j test --matrix node-version:20.x"
"test": "FORCE_COLOR=1 MOCHA_COLORS=1 node build/tasks npm run -- test"
},
"workspaces": [
"packages/*"

View File

@ -22,7 +22,7 @@ module.exports = async (flecks) => ({
'build/flecks.hooks.js',
// Internal.
...!FLECKS_BUILD_TESTING_LINT
? ['test/server/lint/fail.js']
? ['test/lint/fail.js']
: [],
],
overrides: [

View File

@ -12,7 +12,7 @@ const configFn = require('./common.webpack.config');
const {
FLECKS_CORE_ROOT = process.cwd(),
FLECKS_CORE_TEST_PLATFORMS,
FLECKS_CORE_TEST_SUBDIRECTORIES,
} = process.env;
const tests = join(FLECKS_CORE_ROOT, 'test');
@ -22,14 +22,13 @@ module.exports = async (env, argv, flecks) => {
config.output.chunkFormat = false;
config.output.path = join(FLECKS_CORE_ROOT, 'dist', 'test');
const testPaths = [];
const platforms = FLECKS_CORE_TEST_PLATFORMS
? JSON.parse(FLECKS_CORE_TEST_PLATFORMS)
: [...new Set(['default', ...flecks.platforms])];
if (platforms.includes('default')) {
testPaths.push(...await glob(join(tests, '*.js')));
}
const subdirectories = JSON.parse(FLECKS_CORE_TEST_SUBDIRECTORIES);
testPaths.push(
...(await Promise.all(platforms.map((platform) => glob(join(tests, platform, '*.js')))))
...(await Promise.all(
subdirectories
.filter((subdirectory) => 'default' !== subdirectory)
.map((subdirectory) => glob(join(tests, subdirectory, '*.js'))),
))
.flat(),
);
if (testPaths.length > 0) {

View File

@ -9,7 +9,7 @@ const {
const Build = __non_webpack_require__(join(FLECKS_CORE_ROOT, 'build', 'build'));
const loadConfig = __non_webpack_require__(join(FLECKS_CORE_ROOT, 'build', 'load-config'));
const buildRoot = join(FLECKS_CORE_ROOT, 'test', 'server', 'build', 'root');
const buildRoot = join(FLECKS_CORE_ROOT, 'test', 'root');
it('defaults config', async () => {
expect(await loadConfig(FLECKS_CORE_ROOT))

View File

@ -4,7 +4,7 @@ import {expect} from 'chai';
it('can lint', async () => {
expect(
await processCode(await spawnWith(
['npx', 'eslint', '--config', 'build/eslint.config.js', 'test/server/lint/fine.js'],
['npx', 'eslint', '--config', 'build/eslint.config.js', 'test/lint/fine.js'],
{
env: {
FLECKS_BUILD_ESLINT_NO_CACHE: true,
@ -19,7 +19,7 @@ it('can lint', async () => {
it('can fail to lint', async () => {
expect(
await processCode(await spawnWith(
['npx', 'eslint', '--config', 'build/eslint.config.js', 'test/server/lint/fail.js'],
['npx', 'eslint', '--config', 'build/eslint.config.js', 'test/lint/fail.js'],
{
env: {
FLECKS_BUILD_ESLINT_NO_CACHE: true,
@ -35,12 +35,12 @@ it('can fail to lint', async () => {
it('can override lint', async () => {
expect(
await processCode(await spawnWith(
['npx', 'eslint', '--config', 'build/eslint.config.js', 'test/server/lint/fine.js'],
['npx', 'eslint', '--config', 'build/eslint.config.js', 'test/lint/fine.js'],
{
env: {
FLECKS_BUILD_ESLINT_NO_CACHE: true,
FLECKS_BUILD_TESTING_LINT: true,
FLECKS_CORE_ROOT: 'test/server/lint/root',
FLECKS_CORE_ROOT: 'test/lint/root',
},
stdio: 'ignore',
},

View File

@ -11,7 +11,7 @@ const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
const root = join(FLECKS_CORE_ROOT, 'test', 'server', 'explicate');
const root = join(FLECKS_CORE_ROOT, 'test', 'explicate');
function createExplication(paths, platforms) {
const resolver = new Resolver({

View File

@ -10,15 +10,15 @@ const {
it('can resolve', async () => {
const resolver = new Resolver();
expect(await resolver.resolve('./test/server/resolve'))
.to.equal(join(FLECKS_CORE_ROOT, 'test', 'server', 'resolve.js'));
expect(await resolver.resolve('./test/resolve'))
.to.equal(join(FLECKS_CORE_ROOT, 'test', 'resolve.js'));
});
it('can create aliases at runtime', async () => {
const resolver = new Resolver();
expect(await resolver.resolve('./test/server/foobar'))
expect(await resolver.resolve('./test/foobar'))
.to.be.undefined;
resolver.addAlias('./test/server/foobar', './test/server/resolve');
expect(await resolver.resolve('./test/server/foobar'))
resolver.addAlias('./test/foobar', './test/resolve');
expect(await resolver.resolve('./test/foobar'))
.to.not.be.undefined;
});

View File

@ -5,13 +5,13 @@ import {readFile} from 'fs/promises';
it('can add paths to YML', async () => {
await writeFile(
'test/server/yml/build/flecks.yml',
'test/yml/build/flecks.yml',
`
bar: {}
foo: {}
`,
);
await addPathsToYml(['a', 'two'], 'test/server/yml');
expect(Object.keys(await loadYml(await readFile('test/server/yml/build/flecks.yml'))))
await addPathsToYml(['a', 'two'], 'test/yml');
expect(Object.keys(await loadYml(await readFile('test/yml/build/flecks.yml'))))
.to.deep.equal(['a', 'bar', 'foo', 'two']);
});

View File

@ -10,7 +10,7 @@ const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
const root = join(FLECKS_CORE_ROOT, 'test', 'server', 'resolve');
const root = join(FLECKS_CORE_ROOT, 'test', 'resolve');
it('can resolve inexact', async () => {
const clear = resolve({

View File

@ -5,8 +5,8 @@ it('automatically gathers models', async () => {
const flecks = await Flecks.from({
flecks: {
'@flecks/core': await import('@flecks/core'),
'@flecks/db': await import('../../src'),
'@flecks/db/server': await import('../../src/server'),
'@flecks/db': await import('@flecks/db'),
'@flecks/db/server': await import('@flecks/db/server'),
'@test/thing': await import('./thing'),
},
});

View File

@ -84,6 +84,6 @@ it('parses todos', async () => {
});
it('parses a root', async () => {
expect(await parseFleckRoot('@test/server', './test/server/root'))
expect(await parseFleckRoot('@test/server', './test/root'))
.to.deep.equal(verifiedRoot);
});

View File

@ -23,7 +23,8 @@ module.exports = (program, flecks) => {
],
options: [
program.createOption('-d, --no-production', 'dev build'),
program.createOption('-p, --platform [platforms...]', 'platforms to test'),
program.createOption('-s, --subdirectory [subdirectories...]', 'subdirectories to test')
.default(['.']),
program.createOption('-t, --timeout <ms>', 'timeout').default(2000),
program.createOption('-v, --verbose', 'verbose output'),
program.createOption('-w, --watch', 'watch for changes'),
@ -35,7 +36,7 @@ module.exports = (program, flecks) => {
].join('\n'),
action: async (only, opts) => {
const {
platform: platforms,
subdirectory: subdirectories,
production,
timeout,
watch,
@ -43,9 +44,7 @@ module.exports = (program, flecks) => {
const {build} = coreCommands(program, flecks);
// Check for work.
const [env, argv] = [{}, {mode: production ? 'production' : 'development'}];
if (platforms) {
process.env.FLECKS_CORE_TEST_PLATFORMS = JSON.stringify(platforms);
}
process.env.FLECKS_CORE_TEST_SUBDIRECTORIES = JSON.stringify(subdirectories);
const filename = await flecks.resolveBuildConfig('test.webpack.config.js', '@flecks/build');
const config = {test: await require(filename)(env, argv, flecks)};
await flecks.configureBuilds(config, env, argv);
@ -59,7 +58,6 @@ module.exports = (program, flecks) => {
'test',
{
env: {
FLECKS_CORE_TEST_PLATFORMS: platforms && JSON.stringify(platforms),
FORCE_COLOR: 'dumb' !== TERM,
},
production,

View File

@ -4,7 +4,8 @@ import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {expect} from 'chai';
import {createApplication, build} from './build/build';
import {build} from './helpers/build';
import {createApplication} from './helpers/create-application';
let artifact;

View File

@ -4,7 +4,8 @@ import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {expect} from 'chai';
import {createApplication, build} from './build/build';
import {build} from './helpers/build';
import {createApplication} from './helpers/create-application';
let artifact;

View File

@ -3,7 +3,7 @@ import {join} from 'path';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('allows updates to fail', withServer(async ({server, socket}) => {
expect((await socket.send({type: 'config.get', payload: 'comm.foo'})).payload)

View File

@ -3,7 +3,7 @@ import {join} from 'path';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('restarts when config keys change', withServer(async ({server, socket}) => {
let restarted;

View File

@ -3,7 +3,7 @@ import {join} from 'path';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('updates config', withServer(async ({server, socket}) => {
expect((await socket.send({type: 'config.get', payload: '@flecks/core.id'})).payload)

View File

@ -0,0 +1,29 @@
import {join} from 'path';
import {
binaryPath,
processCode,
spawnWith,
} from '@flecks/core/server';
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
export async function build(path, {args = [], opts = {}} = {}) {
return processCode(spawnWith(
[await binaryPath('flecks', '@flecks/build'), 'build', ...args],
{
stdio: 'ignore',
...opts,
env: {
FLECKS_ENV__flecks_server__stats: '{"preset": "none"}',
FLECKS_ENV__flecks_server__start: 0,
FLECKS_CORE_ROOT: path,
NODE_ENV: 'test',
NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'),
...opts.env,
},
},
));
}

View File

@ -0,0 +1,16 @@
import {cp} from 'fs/promises';
import {join} from 'path';
import {createWorkspace} from '@flecks/core/build/testing';
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
export const templateDefaultPath = join(FLECKS_CORE_ROOT, 'test', 'template');
export async function createApplication(template = templateDefaultPath) {
const workspace = await createWorkspace();
await cp(template, workspace, {recursive: true});
return workspace;
}

View File

View File

@ -4,6 +4,17 @@ import {tmpdir} from 'os';
import {dirname, join} from 'path';
import {id} from '@flecks/core/build/testing';
import {
binaryPath,
pipesink,
spawnWith,
} from '@flecks/core/server';
import {createApplication} from './create-application';
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
class SocketWrapper {
@ -47,7 +58,21 @@ class SocketWrapper {
}
export async function socketListener() {
class TestingServer {
constructor(path, child, socketServer) {
this.path = path;
this.child = child;
this.socketServer = socketServer;
}
async waitForSocket(options) {
return this.socketServer.waitForSocket(options);
}
}
async function socketListener() {
const path = join(tmpdir(), 'flecks', 'ci', await id());
await mkdir(dirname(path), {recursive: true});
const server = createServer();
@ -83,3 +108,66 @@ export async function socketListener() {
});
return {socketServer: server, socketPath: path};
}
export async function startServer({
args = ['-h'],
beforeBuild,
failOnErrorCode = true,
opts = {},
path: request,
task,
} = {}) {
let previousTimeout;
const start = Date.now();
if (task) {
previousTimeout = task.timeout();
task.timeout(0);
}
const {socketPath, socketServer} = await socketListener();
const path = request || await createApplication();
if (beforeBuild) {
await beforeBuild({path, task});
}
const server = spawnWith(
[await binaryPath('flecks', '@flecks/build'), 'build', ...args],
{
stdio: 'pipe',
...opts,
env: {
FLECKS_ENV__flecks_server__stats: '{"preset": "none"}',
FLECKS_ENV__flecks_server__start: true,
FLECKS_CORE_ROOT: path,
FLECKS_SERVER_TEST_SOCKET: socketPath,
NODE_ENV: 'test',
NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'),
...opts.env,
},
},
);
server.on('exit', async () => {
socketServer.close();
});
if (failOnErrorCode) {
const stderr = pipesink(server.stderr);
server.on('exit', async (code) => {
if (!server.done && 0 !== code) {
const buffer = await stderr;
if (!process.stderr.write(buffer)) {
await new Promise((resolve, reject) => {
process.stderr.on('error', reject);
process.stderr.on('drain', resolve);
});
}
// eslint-disable-next-line no-console
console.error('\nserver process exited unexpectedly\n');
process.exit(code);
}
});
}
task?.timeout(previousTimeout + (Date.now() - start));
return new TestingServer(
path,
server,
socketServer,
);
}

View File

@ -0,0 +1,35 @@
import {startServer} from './start-server';
export function withServer(task, options) {
return async function withServer() {
const server = await startServer({...options, task: this});
const socket = await server.waitForSocket({task: this});
server.actions = async (actions) => {
const results = [];
await actions.reduce(
(p, action) => (
p.then(() => (
socket.send(action)
.then((result) => {
results.push(result);
})
))
),
Promise.resolve(),
);
return results;
};
let taskError;
try {
await task({server, socket});
}
catch (error) {
taskError = error;
}
server.child.done = true;
server.child.kill();
if (taskError) {
throw taskError;
}
};
}

View File

@ -4,7 +4,7 @@ import {join} from 'path';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('propagates bootstrap config', withServer(
async ({server}) => {

View File

@ -3,7 +3,7 @@ import {join} from 'path';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('propagates override config', withServer(
async ({server}) => {

View File

@ -1,6 +1,6 @@
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('propagates runtime config', withServer(async ({server}) => {
const [{payload: foo}] = await server.actions([

View File

@ -1,7 +1,7 @@
import {processCode} from '@flecks/core/src/server';
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('connects', withServer(
async ({server}) => {

View File

@ -1,153 +0,0 @@
import {cp} from 'fs/promises';
import {join} from 'path';
import {createWorkspace} from '@flecks/core/build/testing';
import {
binaryPath,
pipesink,
processCode,
spawnWith,
} from '@flecks/core/server';
import {socketListener} from './listen';
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
export const template = join(FLECKS_CORE_ROOT, 'test', 'server', 'template');
export async function createApplication() {
const workspace = await createWorkspace();
await cp(template, workspace, {recursive: true});
return workspace;
}
class TestingServer {
constructor(path, child, socketServer) {
this.path = path;
this.child = child;
this.socketServer = socketServer;
}
async waitForSocket(options) {
return this.socketServer.waitForSocket(options);
}
}
export async function startServer({
args = ['-h'],
beforeBuild,
failOnErrorCode = true,
opts = {},
path: request,
task,
} = {}) {
let previousTimeout;
const start = Date.now();
if (task) {
previousTimeout = task.timeout();
task.timeout(0);
}
const {socketPath, socketServer} = await socketListener();
const path = request || await createApplication();
if (beforeBuild) {
await beforeBuild({path, task});
}
const server = spawnWith(
[await binaryPath('flecks', '@flecks/build'), 'build', ...args],
{
stdio: 'pipe',
...opts,
env: {
FLECKS_ENV__flecks_server__stats: '{"preset": "none"}',
FLECKS_ENV__flecks_server__start: true,
FLECKS_CORE_ROOT: path,
FLECKS_SERVER_TEST_SOCKET: socketPath,
NODE_ENV: 'test',
NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'),
...opts.env,
},
},
);
server.on('exit', async () => {
socketServer.close();
});
if (failOnErrorCode) {
const stderr = pipesink(server.stderr);
server.on('exit', async (code) => {
if (!server.done && 0 !== code) {
const buffer = await stderr;
if (!process.stderr.write(buffer)) {
await new Promise((resolve, reject) => {
process.stderr.on('error', reject);
process.stderr.on('drain', resolve);
});
}
// eslint-disable-next-line no-console
console.error('\nserver process exited unexpectedly\n');
process.exit(code);
}
});
}
task?.timeout(previousTimeout + (Date.now() - start));
return new TestingServer(
path,
server,
socketServer,
);
}
export function withServer(task, options) {
return async function withServer() {
const server = await startServer({...options, task: this});
const socket = await server.waitForSocket({task: this});
server.actions = async (actions) => {
const results = [];
await actions.reduce(
(p, action) => (
p.then(() => (
socket.send(action)
.then((result) => {
results.push(result);
})
))
),
Promise.resolve(),
);
return results;
};
let taskError;
try {
await task({server, socket});
}
catch (error) {
taskError = error;
}
server.child.done = true;
server.child.kill();
if (taskError) {
throw taskError;
}
};
}
export async function build(path, {args = [], opts = {}} = {}) {
return processCode(spawnWith(
[await binaryPath('flecks', '@flecks/build'), 'build', ...args],
{
stdio: 'ignore',
...opts,
env: {
FLECKS_ENV__flecks_server__stats: '{"preset": "none"}',
FLECKS_ENV__flecks_server__start: 0,
FLECKS_CORE_ROOT: path,
NODE_ENV: 'test',
NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'),
...opts.env,
},
},
));
}

View File

@ -3,7 +3,7 @@ import {join} from 'path';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai';
import {withServer} from './build/build';
import {withServer} from './helpers/with-server';
it('restarts when root sources change', withServer(async ({server, socket}) => {
let restarted;

View File

@ -5,7 +5,7 @@ it('automatically gathers packets', async () => {
const flecks = await Flecks.from({
flecks: {
'@flecks/core': await import('@flecks/core'),
'@flecks/socket': await import('../../src'),
'@flecks/socket': await import('@flecks/socket'),
'@test/thing': await import('./thing'),
},
});

View File

@ -1,4 +1,4 @@
import Packet from '../../../src/packet/packet';
import Packet from '@flecks/socket/packet/packet';
export const hooks = {
'@flecks/socket.packets': () => ({

View File

@ -1,24 +1,15 @@
const {stat, unlink} = require('fs/promises');
const {
basename,
dirname,
extname,
join,
relative,
} = require('path');
const {join} = require('path');
const Build = require('@flecks/build/build/build');
const {regexFromExtensions} = require('@flecks/build/src/server');
const {binaryPath, glob, spawnWith} = require('@flecks/core/src/server');
const {binaryPath, spawnWith} = require('@flecks/core/src/server');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {
FLECKS_CORE_ROOT = process.cwd(),
FLECKS_CORE_TEST_PLATFORMS,
} = process.env;
const tests = join(FLECKS_CORE_ROOT, 'test');
exports.hooks = {
'@flecks/build.config': async (target, config, env, argv, flecks) => {
const isProduction = 'production' === argv.mode;
@ -37,20 +28,6 @@ exports.hooks = {
case 'test': {
finalLoader = {loader: MiniCssExtractPlugin.loader};
config.plugins.push(new MiniCssExtractPlugin({filename: 'assets/[name].css'}));
if (
FLECKS_CORE_TEST_PLATFORMS
? JSON.parse(FLECKS_CORE_TEST_PLATFORMS).includes('client')
: true
) {
(await glob(join(tests, 'client', '*.js')))
.forEach((path) => {
const entry = relative(tests, path);
config.entry[join(dirname(entry), basename(entry, extname(entry)))] = [
'source-map-support/register',
path,
];
});
}
break;
}
case 'web': {

View File

@ -0,0 +1,38 @@
import puppeteer from 'puppeteer';
export async function connectBrowser(url, options = {}) {
let previousTimeout;
const start = Date.now();
if (options.task) {
previousTimeout = options.task.timeout();
options.task.timeout(0);
}
const {timeout = 30000} = options;
const browser = await puppeteer.launch({
// For CI.
args: ['--no-sandbox'],
});
const page = await browser.newPage();
let response;
const handle = setTimeout(() => {
throw new Error(`timed out trying to connect browser to '${url}'!`);
}, timeout);
/* eslint-disable no-await-in-loop */
while (!response) {
try {
response = await page.goto(url, {...options, timeout: timeout - (Date.now() - start)});
if (response) {
break;
}
}
catch {
await new Promise((resolve) => {
setTimeout(resolve, 250);
});
}
}
/* eslint-enable no-await-in-loop */
clearTimeout(handle);
options.task?.timeout(previousTimeout + (Date.now() - start));
return {browser, page, response};
}

View File

@ -1,42 +1,6 @@
import {startServer} from '@flecks/server/test/server/build/build';
import puppeteer from 'puppeteer';
import {startServer} from '@flecks/server/test/helpers/start-server';
export async function connectBrowser(url, options = {}) {
let previousTimeout;
const start = Date.now();
if (options.task) {
previousTimeout = options.task.timeout();
options.task.timeout(0);
}
const {timeout = 30000} = options;
const browser = await puppeteer.launch({
// For CI.
args: ['--no-sandbox'],
});
const page = await browser.newPage();
let response;
const handle = setTimeout(() => {
throw new Error(`timed out trying to connect browser to '${url}'!`);
}, timeout);
/* eslint-disable no-await-in-loop */
while (!response) {
try {
response = await page.goto(url, {...options, timeout: timeout - (Date.now() - start)});
if (response) {
break;
}
}
catch {
await new Promise((resolve) => {
setTimeout(resolve, 250);
});
}
}
/* eslint-enable no-await-in-loop */
clearTimeout(handle);
options.task?.timeout(previousTimeout + (Date.now() - start));
return {browser, page, response};
}
import {connectBrowser} from './connect-browser';
export function withWeb(task, options) {
return async function withWeb() {

View File

@ -1,6 +1,6 @@
import {expect} from 'chai';
import {withWeb} from '../helpers/with-web';
import {withWeb} from './helpers/with-web';
let report;