test: major improvements
This commit is contained in:
parent
393e8d684d
commit
2289f27b97
2418
package-lock.json
generated
2418
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,7 @@
|
|||
"dox:serve": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus build --no-minify --out-dir ../dox-tmp && node_modules/.bin/docusaurus serve --dir ../dox-tmp",
|
||||
"dox": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus",
|
||||
"lint": "node build/tasks lint",
|
||||
"test": "node build/tasks test"
|
||||
"test": "node build/tasks -- test -t 60000"
|
||||
},
|
||||
"devDependencies": {
|
||||
"husky": "^9.0.7",
|
||||
|
|
|
@ -52,16 +52,7 @@ module.exports = class Build extends Flecks {
|
|||
}) {
|
||||
const cleanConfig = JSON.parse(JSON.stringify(originalConfig));
|
||||
// Dealias the config keys.
|
||||
const dealiasedConfig = Object.fromEntries(
|
||||
Object.entries(cleanConfig)
|
||||
.map(([maybeAliasedPath, config]) => {
|
||||
const index = maybeAliasedPath.indexOf(':');
|
||||
return [
|
||||
-1 === index ? maybeAliasedPath : maybeAliasedPath.slice(0, index),
|
||||
config,
|
||||
];
|
||||
}),
|
||||
);
|
||||
const dealiasedConfig = this.dealiasedConfig(cleanConfig);
|
||||
const resolver = new Resolver({root});
|
||||
const {paths, roots} = await explicate({
|
||||
paths: Object.keys(originalConfig),
|
||||
|
|
|
@ -22,7 +22,7 @@ const {
|
|||
spawnWith,
|
||||
} = require('@flecks/core/src/server');
|
||||
const {glob} = require('glob');
|
||||
const rimraf = require('rimraf');
|
||||
const {rimraf} = require('rimraf');
|
||||
|
||||
const addPathsToYml = require('./add-paths-to-yml');
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ module.exports = async function explicate(
|
|||
let realResolvedCandidate = await realpath(resolvedCandidate);
|
||||
const isSymlink = resolvedCandidate !== realResolvedCandidate;
|
||||
if (isSymlink) {
|
||||
if (realResolvedCandidate.endsWith('/dist')) {
|
||||
realResolvedCandidate = realResolvedCandidate.slice(0, -5);
|
||||
if (realResolvedCandidate.endsWith('/dist/fleck')) {
|
||||
realResolvedCandidate = realResolvedCandidate.slice(0, -11);
|
||||
}
|
||||
}
|
||||
// Aliased? Include submodules.
|
||||
|
|
|
@ -37,6 +37,7 @@ const resolveValidModulePath = (source) => (path) => {
|
|||
module.exports = async (env, argv, flecks) => {
|
||||
const config = await configFn(env, argv, flecks);
|
||||
config.externals = await externals();
|
||||
config.output.path = join(FLECKS_CORE_ROOT, 'dist', 'fleck');
|
||||
config.plugins.push(
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
const {join} = require('path');
|
||||
const {
|
||||
basename,
|
||||
dirname,
|
||||
extname,
|
||||
join,
|
||||
relative,
|
||||
} = require('path');
|
||||
|
||||
const {glob} = require('glob');
|
||||
|
||||
|
@ -13,7 +19,7 @@ const tests = join(FLECKS_CORE_ROOT, 'test');
|
|||
module.exports = async (env, argv, flecks) => {
|
||||
const config = await configFn(env, argv, flecks);
|
||||
config.output.chunkFormat = false;
|
||||
config.output.clean = false;
|
||||
config.output.path = join(FLECKS_CORE_ROOT, 'dist', 'test');
|
||||
// Test entry.
|
||||
const testPaths = await glob(join(tests, '*.js'));
|
||||
const {platforms} = flecks;
|
||||
|
@ -22,7 +28,13 @@ module.exports = async (env, argv, flecks) => {
|
|||
.flat(),
|
||||
);
|
||||
if (testPaths.length > 0) {
|
||||
config.entry.test = ['source-map-support/register', ...testPaths];
|
||||
testPaths.forEach((path) => {
|
||||
const entry = relative(tests, path);
|
||||
config.entry[join(dirname(entry), basename(entry, extname(entry)))] = [
|
||||
'source-map-support/register',
|
||||
path,
|
||||
];
|
||||
});
|
||||
}
|
||||
return config;
|
||||
};
|
||||
|
|
|
@ -97,7 +97,7 @@ exports.executable = () => (
|
|||
compiler.hooks.afterEmit.tapPromise(
|
||||
'Executable',
|
||||
async () => (
|
||||
chmod(join(FLECKS_CORE_ROOT, 'dist', 'build', 'cli.js'), 0o755)
|
||||
chmod(join(FLECKS_CORE_ROOT, 'dist', 'fleck', 'build', 'cli.js'), 0o755)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
"clean": "rm -rf dist node_modules yarn.lock",
|
||||
"lint": "eslint --config ./build/eslint.config.js .",
|
||||
"postversion": "npm run build",
|
||||
"test": "webpack --config ./build/build.test.webpack.config.js --mode production && mocha --colors ./dist/test.js --timeout 10000",
|
||||
"test:watch": "webpack watch --config ./build/build.test.webpack.config.js --mode development & mocha --parallel --watch --watch-files ./dist/test.js --colors ./dist/test.js --timeout 10000"
|
||||
"test": "webpack --config ./build/build.test.webpack.config.js --mode production && mocha --colors --parallel ./dist/test/*.js ./dist/test/server/*.js",
|
||||
"test:watch": "webpack watch --config ./build/build.test.webpack.config.js --mode development & mocha --colors --parallel --watch --watch-files ./dist/test/*.js ./dist/test/server/*.js"
|
||||
},
|
||||
"bin": {
|
||||
"flecks": "./build/cli.js"
|
||||
|
@ -51,7 +51,7 @@
|
|||
"graceful-fs": "^4.2.11",
|
||||
"js-yaml": "4.1.0",
|
||||
"mocha": "^10.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rimraf": "^5.0.5",
|
||||
"source-map-loader": "4.0.1",
|
||||
"source-map-support": "0.5.19",
|
||||
"webpack": "^5.89.0",
|
||||
|
|
|
@ -5,6 +5,7 @@ const {dump: dumpYml, load: loadYml} = require('js-yaml');
|
|||
module.exports = {
|
||||
dumpYml,
|
||||
loadYml,
|
||||
rimraf: require('rimraf').rimraf,
|
||||
webpack: require('webpack'),
|
||||
...require('../build/webpack'),
|
||||
};
|
||||
|
|
|
@ -45,12 +45,10 @@ it('configures from environment', async () => {
|
|||
});
|
||||
|
||||
it('dealiases config', async () => {
|
||||
expect(await Build.buildRuntime({
|
||||
originalConfig: {'two:./two': {foo: 2}},
|
||||
platforms: [],
|
||||
root: buildRoot,
|
||||
}))
|
||||
.to.nested.include({
|
||||
'runtime.config.two.foo': 2,
|
||||
expect(await Build.dealiasedConfig({'two:./two': {foo: 2}}))
|
||||
.to.deep.equal({
|
||||
two: {
|
||||
foo: 2,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {readFile, writeFile} from 'fs/promises';
|
||||
import {load as loadYml} from 'js-yaml';
|
||||
import addPathsToYml from '@flecks/build/build/add-paths-to-yml';
|
||||
import {expect} from 'chai';
|
||||
import {readFile, writeFile} from 'fs/promises';
|
||||
import {load as loadYml} from 'js-yaml';
|
||||
|
||||
it('can add paths to YML', async () => {
|
||||
await writeFile(
|
||||
|
|
|
@ -134,6 +134,25 @@ class Flecks {
|
|||
return join(parts.join('-'), basename(path, extname(path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dealias a configuration object.
|
||||
*
|
||||
* @param {Object} config Configuration.
|
||||
* @returns {Object}
|
||||
*/
|
||||
static dealiasedConfig(config) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(config)
|
||||
.map(([maybeAliasedPath, config]) => {
|
||||
const index = maybeAliasedPath.indexOf(':');
|
||||
return [
|
||||
-1 === index ? maybeAliasedPath : maybeAliasedPath.slice(0, index),
|
||||
config,
|
||||
];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a decorator from a require context.
|
||||
*
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
"clean": "rm -rf dist node_modules yarn.lock",
|
||||
"lint": "eslint --config ./build/core.eslint.config.js .",
|
||||
"postversion": "npm run build",
|
||||
"test": "webpack --config ./build/test.webpack.config.js --mode production && mocha --colors ./dist/test.js",
|
||||
"test:watch": "webpack watch --config ./build/test.webpack.config.js --mode development & mocha --parallel --watch --watch-files ./dist/test.js --colors ./dist/test.js"
|
||||
"test": "webpack --config ./build/test.webpack.config.js --mode production && mocha --colors --parallel ./dist/test/*.js ./dist/test/server/*.js",
|
||||
"test:watch": "webpack watch --config ./build/test.webpack.config.js --mode development & mocha --colors --parallel --watch --watch-files ./dist/test/*.js ./dist/test/server/*.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -54,7 +54,7 @@
|
|||
"eslint-webpack-plugin": "^3.2.0",
|
||||
"globals": "^13.23.0",
|
||||
"mocha": "^10.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rimraf": "^5.0.5",
|
||||
"source-map-loader": "4.0.1",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
|
|
|
@ -11,7 +11,7 @@ exports.generateDockerFile = async (flecks) => {
|
|||
'ENV DEBUG=*',
|
||||
'ENV NODE_ENV=production',
|
||||
'',
|
||||
'CMD ["node", "./dist/server/index.js"]',
|
||||
'CMD ["node", "dist/server"]',
|
||||
'',
|
||||
'VOLUME /var/www/node_modules',
|
||||
'',
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const {stat, unlink} = require('fs/promises');
|
||||
const {join} = require('path');
|
||||
const {access} = require('fs/promises');
|
||||
const {join, relative} = require('path');
|
||||
|
||||
const {commands: coreCommands} = require('@flecks/build/build/commands');
|
||||
const {rimraf} = require('@flecks/build/src/server');
|
||||
const {D} = require('@flecks/core/src');
|
||||
const {glob} = require('@flecks/core/src/server');
|
||||
const Mocha = require('mocha');
|
||||
|
@ -18,6 +19,7 @@ module.exports = (program, flecks) => {
|
|||
commands.test = {
|
||||
options: [
|
||||
program.createOption('-d, --no-production', 'dev build'),
|
||||
program.createOption('-t, --timeout <ms>', 'timeout').default(2000),
|
||||
program.createOption('-w, --watch', 'watch for changes'),
|
||||
program.createOption('-v, --verbose', 'verbose output'),
|
||||
],
|
||||
|
@ -28,22 +30,19 @@ module.exports = (program, flecks) => {
|
|||
].join('\n'),
|
||||
action: async (opts) => {
|
||||
const {
|
||||
timeout,
|
||||
watch,
|
||||
} = opts;
|
||||
const {build} = coreCommands(program, flecks);
|
||||
const testPaths = await glob(join(FLECKS_CORE_ROOT, 'test/**/*.js'));
|
||||
if (0 === testPaths.length) {
|
||||
const tests = await glob(join(FLECKS_CORE_ROOT, 'test', '*.js'));
|
||||
const serverTests = await glob(join(FLECKS_CORE_ROOT, 'test', 'server', '*.js'));
|
||||
if (0 === tests.length + serverTests.length) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('No tests found.');
|
||||
return undefined;
|
||||
}
|
||||
// Remove the previous test.
|
||||
const testLocation = join(FLECKS_CORE_ROOT, 'dist', 'test.js');
|
||||
try {
|
||||
await unlink(testLocation);
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
catch (error) {}
|
||||
await rimraf(join(FLECKS_CORE_ROOT, 'dist', 'test'));
|
||||
// Kick off building the test and wait for the file to exist.
|
||||
await build.action('test', opts);
|
||||
debug('Testing...', opts);
|
||||
|
@ -51,7 +50,7 @@ module.exports = (program, flecks) => {
|
|||
while (true) {
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await stat(testLocation);
|
||||
await access(join(FLECKS_CORE_ROOT, 'dist', 'test'));
|
||||
break;
|
||||
}
|
||||
catch (error) {
|
||||
|
@ -69,13 +68,25 @@ module.exports = (program, flecks) => {
|
|||
},
|
||||
flecks.stubs,
|
||||
);
|
||||
const mocha = new Mocha({parallel: true});
|
||||
const mocha = new Mocha({parallel: true, timeout});
|
||||
mocha.ui('bdd');
|
||||
const files = []
|
||||
.concat(tests, serverTests)
|
||||
.map((path) => join('dist', relative(FLECKS_CORE_ROOT, path)));
|
||||
if (watch) {
|
||||
watchParallelRun(mocha, {watchFiles: [testLocation]}, {file: [testLocation], spec: []});
|
||||
watchParallelRun(
|
||||
mocha,
|
||||
{
|
||||
watchFiles: files,
|
||||
},
|
||||
{
|
||||
file: files,
|
||||
spec: [],
|
||||
},
|
||||
);
|
||||
return new Promise(() => {});
|
||||
}
|
||||
mocha.files = [testLocation];
|
||||
mocha.files = files;
|
||||
return new Promise((r, e) => {
|
||||
mocha.run((code) => {
|
||||
if (!code) {
|
||||
|
|
19
packages/server/build/fleck.webpack.config.js
Normal file
19
packages/server/build/fleck.webpack.config.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
const {copy} = require('@flecks/build/src/server');
|
||||
const configFn = require('@flecks/fleck/build/fleck.webpack.config');
|
||||
|
||||
module.exports = async (env, argv, flecks) => {
|
||||
const config = await configFn(env, argv, flecks);
|
||||
delete config.entry.entry;
|
||||
config.plugins.push(
|
||||
copy({
|
||||
patterns: [
|
||||
{
|
||||
from: 'src/entry.js',
|
||||
to: 'entry.js',
|
||||
info: { minimized: true },
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
return config;
|
||||
};
|
|
@ -4,6 +4,8 @@ const D = require('@flecks/core/build/debug');
|
|||
|
||||
const debug = D('@flecks/server/build/runtime');
|
||||
|
||||
const {version} = require('../package.json');
|
||||
|
||||
module.exports = async (config, env, argv, flecks) => {
|
||||
const runtimePath = await flecks.resolver.resolve('@flecks/server/runtime');
|
||||
// Inject flecks configuration.
|
||||
|
@ -38,6 +40,7 @@ module.exports = async (config, env, argv, flecks) => {
|
|||
' )',
|
||||
')',
|
||||
].join('\n'),
|
||||
version: JSON.stringify(version),
|
||||
...await flecks.invokeAsync('@flecks/server.runtime'),
|
||||
};
|
||||
const runtimeString = `{${
|
||||
|
@ -100,7 +103,7 @@ module.exports = async (config, env, argv, flecks) => {
|
|||
flecks.stubs.forEach((stub) => {
|
||||
config.resolve.alias[stub] = false;
|
||||
});
|
||||
await flecks.runtimeCompiler('server', config);
|
||||
await flecks.runtimeCompiler('server', config, env, argv);
|
||||
// Rewrite to signals for HMR.
|
||||
if ('production' !== argv.mode) {
|
||||
allowlist.push(/^webpack\/hot\/signal/);
|
||||
|
|
|
@ -58,6 +58,7 @@ module.exports = async (env, argv, flecks) => {
|
|||
NODE_PRESERVE_SYMLINKS: flecks.roots.some(([path, request]) => path !== request) ? 1 : 0,
|
||||
},
|
||||
exec: 'index.js',
|
||||
killOnExit: !!hot,
|
||||
// Bail hard on unhandled rejections and report.
|
||||
nodeArgs: [...nodeArgs, '--unhandled-rejections=strict', '--trace-uncaught'],
|
||||
// HMR.
|
||||
|
|
|
@ -21,13 +21,17 @@ class StartServerPlugin {
|
|||
apply(compiler) {
|
||||
const {options: {exec, signal}, pluginName} = this;
|
||||
const logger = compiler.getInfrastructureLogger(pluginName);
|
||||
compiler.hooks.afterEmit.tapAsync(pluginName, (compilation, callback) => {
|
||||
compiler.hooks.afterEmit.tapPromise(pluginName, async (compilation) => {
|
||||
if (this.worker && this.worker.isConnected()) {
|
||||
if (signal) {
|
||||
process.kill(this.worker.process.pid, true === signal ? 'SIGUSR2' : signal);
|
||||
this.worker.kill(true === signal ? 'SIGUSR2' : signal);
|
||||
return undefined;
|
||||
}
|
||||
callback();
|
||||
return;
|
||||
const promise = new Promise((resolve) => {
|
||||
this.worker.on('disconnect', resolve);
|
||||
});
|
||||
this.worker.disconnect();
|
||||
await promise;
|
||||
}
|
||||
let entryPoint;
|
||||
if (!exec) {
|
||||
|
@ -42,7 +46,7 @@ class StartServerPlugin {
|
|||
else {
|
||||
entryPoint = exec(compilation);
|
||||
}
|
||||
this.startServer(join(compiler.options.output.path, entryPoint), callback);
|
||||
return this.startServer(join(compiler.options.output.path, entryPoint));
|
||||
});
|
||||
compiler.hooks.shouldEmit.tap(pluginName, (compilation) => {
|
||||
const entryPoints = Object.keys(compilation.assets);
|
||||
|
@ -66,7 +70,7 @@ class StartServerPlugin {
|
|||
return parseInt(port, 10);
|
||||
}
|
||||
|
||||
startServer(exec, callback) {
|
||||
async startServer(exec) {
|
||||
const {
|
||||
args,
|
||||
env,
|
||||
|
@ -81,13 +85,16 @@ class StartServerPlugin {
|
|||
args,
|
||||
...(inspectPort && {inspectPort}),
|
||||
});
|
||||
cluster.on('online', () => callback());
|
||||
this.worker = cluster.fork(env);
|
||||
if (killOnExit) {
|
||||
this.worker.on('exit', () => {
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
this.worker.on('error', reject);
|
||||
this.worker.on('online', resolve);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,11 +4,10 @@ import {join} from 'path';
|
|||
|
||||
import {D, Flecks} from '@flecks/core';
|
||||
|
||||
const {version} = require('../package.json');
|
||||
|
||||
(async () => {
|
||||
const runtime = await __non_webpack_require__('@flecks/server/runtime');
|
||||
const {loadFlecks} = runtime;
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const runtime = await import('@flecks/server/runtime');
|
||||
const {loadFlecks, version} = runtime;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`flecks server v${version}`);
|
||||
try {
|
||||
|
@ -27,6 +26,7 @@ const {version} = require('../package.json');
|
|||
debug('up!');
|
||||
}
|
||||
catch (error) {
|
||||
debug(error);
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
}
|
||||
})();
|
||||
|
|
21
packages/server/test/server/build-dev.js
Normal file
21
packages/server/test/server/build-dev.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import {access} from 'fs/promises';
|
||||
import {join} from 'path';
|
||||
|
||||
import {expect} from 'chai';
|
||||
|
||||
import {createApplicationAt, build} from './build/build';
|
||||
|
||||
it('builds for development', async () => {
|
||||
const path = await createApplicationAt('development');
|
||||
await build(path, {args: ['-d']});
|
||||
let artifact;
|
||||
try {
|
||||
await access(join(path, 'dist', 'server', 'index.js'));
|
||||
artifact = true;
|
||||
}
|
||||
catch (error) {
|
||||
artifact = false;
|
||||
}
|
||||
expect(artifact)
|
||||
.to.be.true;
|
||||
});
|
21
packages/server/test/server/build-production.js
Normal file
21
packages/server/test/server/build-production.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import {access} from 'fs/promises';
|
||||
import {join} from 'path';
|
||||
|
||||
import {expect} from 'chai';
|
||||
|
||||
import {createApplicationAt, build} from './build/build';
|
||||
|
||||
it('builds for production', async () => {
|
||||
const path = await createApplicationAt('production');
|
||||
await build(path);
|
||||
let artifact;
|
||||
try {
|
||||
await access(join(path, 'dist', 'server', 'index.js'));
|
||||
artifact = true;
|
||||
}
|
||||
catch (error) {
|
||||
artifact = false;
|
||||
}
|
||||
expect(artifact)
|
||||
.to.be.true;
|
||||
});
|
69
packages/server/test/server/build/build.js
Normal file
69
packages/server/test/server/build/build.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
import {cp, mkdir} from 'fs/promises';
|
||||
import {join} from 'path';
|
||||
|
||||
import {rimraf} from '@flecks/build/server';
|
||||
import {processCode, spawnWith} from '@flecks/core/server';
|
||||
|
||||
import {listen} from './listen';
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
export const applications = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'server');
|
||||
export const template = join(FLECKS_CORE_ROOT, 'test', 'server', 'template');
|
||||
|
||||
export async function createApplicationAt(path) {
|
||||
await rimraf(join(applications, path));
|
||||
await mkdir(join(applications, path), {recursive: true});
|
||||
const qualified = join(applications, path, process.pid.toString());
|
||||
await cp(template, qualified, {recursive: true});
|
||||
return qualified;
|
||||
}
|
||||
|
||||
export function build(path, {args = [], opts = {}} = {}) {
|
||||
return processCode(spawnWith(
|
||||
['npx', 'flecks', 'build', ...args],
|
||||
{
|
||||
...opts,
|
||||
env: {
|
||||
FLECKS_ENV__flecks_server__stats: '{"all": false}',
|
||||
FLECKS_ENV__flecks_server__start: 0,
|
||||
FLECKS_CORE_ROOT: path,
|
||||
...opts.env,
|
||||
},
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
export async function serverActions(path, actions) {
|
||||
const {connected, listening, path: socketPath} = await listen();
|
||||
await listening;
|
||||
const server = spawnWith(
|
||||
['node', join(path, 'dist', 'server')],
|
||||
{
|
||||
env: {
|
||||
FLECKS_SERVER_TEST_SOCKET: socketPath,
|
||||
},
|
||||
},
|
||||
);
|
||||
const [code, results] = await Promise.all([
|
||||
processCode(server),
|
||||
connected.then(async (socket) => {
|
||||
const results = [];
|
||||
await actions.reduce(
|
||||
(p, action) => (
|
||||
p.then(() => (
|
||||
socket.send(action)
|
||||
.then((result) => {
|
||||
results.push(result);
|
||||
})
|
||||
))
|
||||
),
|
||||
Promise.resolve(),
|
||||
);
|
||||
return results;
|
||||
}),
|
||||
]);
|
||||
return {code, results};
|
||||
}
|
7
packages/server/test/server/build/id.js
Normal file
7
packages/server/test/server/build/id.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import {randomBytes} from 'crypto';
|
||||
|
||||
export default function id() {
|
||||
return new Promise((resolve, reject) => {
|
||||
randomBytes(16, (error, bytes) => (error ? reject(error) : resolve(bytes.toString('hex'))));
|
||||
});
|
||||
}
|
56
packages/server/test/server/build/listen.js
Normal file
56
packages/server/test/server/build/listen.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
import {mkdir} from 'fs/promises';
|
||||
import {createServer} from 'net';
|
||||
import {tmpdir} from 'os';
|
||||
import {dirname, join} from 'path';
|
||||
|
||||
import id from './id';
|
||||
|
||||
class SocketWrapper {
|
||||
|
||||
constructor(socket) {
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
async send(action) {
|
||||
const unique = await id();
|
||||
return new Promise((resolve, reject) => {
|
||||
const onData = (data) => {
|
||||
const action = JSON.parse(data.toString());
|
||||
if (unique === action.meta.id) {
|
||||
this.socket.off('error', reject);
|
||||
this.socket.off('data', onData);
|
||||
resolve(action);
|
||||
}
|
||||
};
|
||||
this.socket.on('close', () => {
|
||||
this.socket.off('error', reject);
|
||||
this.socket.off('data', onData);
|
||||
resolve();
|
||||
});
|
||||
this.socket.on('error', reject);
|
||||
this.socket.on('data', onData);
|
||||
this.socket.write(JSON.stringify({...action, meta: {...action.meta, id: unique}}));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export async function listen() {
|
||||
const path = join(tmpdir(), 'flecks', 'ci', await id());
|
||||
await mkdir(dirname(path), {recursive: true});
|
||||
const server = createServer();
|
||||
server.listen(path);
|
||||
return {
|
||||
connected: new Promise((resolve, reject) => {
|
||||
server.on('error', reject);
|
||||
server.on('connection', (socket) => {
|
||||
resolve(new SocketWrapper(socket));
|
||||
});
|
||||
}),
|
||||
listening: new Promise((resolve, reject) => {
|
||||
server.on('error', reject);
|
||||
server.on('listening', resolve);
|
||||
}),
|
||||
path,
|
||||
};
|
||||
}
|
14
packages/server/test/server/runtime-config-bootstrap.js
Normal file
14
packages/server/test/server/runtime-config-bootstrap.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
import {build, createApplicationAt, serverActions} from './build/build';
|
||||
|
||||
it('propagates bootstrap config', async () => {
|
||||
const path = await createApplicationAt('runtime-config-bootstrap');
|
||||
await build(path, {args: ['-d']});
|
||||
const {results: [{payload: id}]} = await serverActions(path, [
|
||||
{type: 'config.get', payload: '@flecks/core.id'},
|
||||
{type: 'exit'},
|
||||
]);
|
||||
expect(id)
|
||||
.to.equal('flecks');
|
||||
});
|
29
packages/server/test/server/runtime-config-override.js
Normal file
29
packages/server/test/server/runtime-config-override.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import {writeFile} from 'fs/promises';
|
||||
import {join} from 'path';
|
||||
|
||||
import {expect} from 'chai';
|
||||
|
||||
import {build, createApplicationAt, serverActions} from './build/build';
|
||||
|
||||
it('propagates bootstrap config', async () => {
|
||||
const path = await createApplicationAt('runtime-config-override');
|
||||
await writeFile(
|
||||
join(path, 'build', 'flecks.yml'),
|
||||
`
|
||||
'@flecks/build': {}
|
||||
'@flecks/core': {id: 'testing'}
|
||||
'@flecks/server': {}
|
||||
'comm:./comm': {foo: 'baz'}
|
||||
`,
|
||||
);
|
||||
await build(path, {args: ['-d']});
|
||||
const {results: [{payload: id}, {payload: foo}]} = await serverActions(path, [
|
||||
{type: 'config.get', payload: '@flecks/core.id'},
|
||||
{type: 'config.get', payload: 'comm.foo'},
|
||||
{type: 'exit'},
|
||||
]);
|
||||
expect(id)
|
||||
.to.equal('testing');
|
||||
expect(foo)
|
||||
.to.equal('baz');
|
||||
});
|
14
packages/server/test/server/runtime-config-runtime.js
Normal file
14
packages/server/test/server/runtime-config-runtime.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
import {build, createApplicationAt, serverActions} from './build/build';
|
||||
|
||||
it('propagates runtime config', async () => {
|
||||
const path = await createApplicationAt('runtime-config-runtime');
|
||||
await build(path, {args: ['-d']});
|
||||
const {results: [{payload: foo}]} = await serverActions(path, [
|
||||
{type: 'config.get', payload: 'comm.foo'},
|
||||
{type: 'exit'},
|
||||
]);
|
||||
expect(foo)
|
||||
.to.equal('bar');
|
||||
});
|
13
packages/server/test/server/runtime-connect.js
Normal file
13
packages/server/test/server/runtime-connect.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
import {build, createApplicationAt, serverActions} from './build/build';
|
||||
|
||||
it('connects', async () => {
|
||||
const path = await createApplicationAt('runtime-connect');
|
||||
await build(path, {args: ['-d']});
|
||||
const {code} = await serverActions(path, [
|
||||
{type: 'exit', payload: 42},
|
||||
]);
|
||||
expect(code)
|
||||
.to.equal(42);
|
||||
});
|
4
packages/server/test/server/template/build/flecks.yml
Normal file
4
packages/server/test/server/template/build/flecks.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
'@flecks/build': {}
|
||||
'@flecks/core': {}
|
||||
'@flecks/server': {}
|
||||
'comm:./comm': {}
|
1
packages/server/test/server/template/comm/package.json
Normal file
1
packages/server/test/server/template/comm/package.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
5
packages/server/test/server/template/comm/src/index.js
Normal file
5
packages/server/test/server/template/comm/src/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export const hooks = {
|
||||
'@flecks/core.config': () => ({
|
||||
foo: 'bar',
|
||||
}),
|
||||
};
|
29
packages/server/test/server/template/comm/src/server.js
Normal file
29
packages/server/test/server/template/comm/src/server.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import {createConnection} from 'net';
|
||||
|
||||
const {
|
||||
FLECKS_SERVER_TEST_SOCKET,
|
||||
} = process.env;
|
||||
|
||||
export const hooks = {
|
||||
'@flecks/server.up': async (flecks) => {
|
||||
const socket = createConnection({path: FLECKS_SERVER_TEST_SOCKET});
|
||||
socket.on('connect', () => {
|
||||
socket.on('data', (data) => {
|
||||
const {meta, payload, type} = JSON.parse(data);
|
||||
switch (type) {
|
||||
case 'config.get':
|
||||
socket.write(JSON.stringify({
|
||||
meta,
|
||||
payload: flecks.get(payload),
|
||||
}));
|
||||
break;
|
||||
case 'exit':
|
||||
socket.end();
|
||||
process.exit(payload);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
1
packages/server/test/server/template/package.json
Normal file
1
packages/server/test/server/template/package.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -94,7 +94,7 @@ module.exports = async (config, env, argv, flecks) => {
|
|||
buildFlecks.stubs.forEach((stub) => {
|
||||
config.resolve.alias[stub] = false;
|
||||
});
|
||||
await buildFlecks.runtimeCompiler('web', config);
|
||||
await buildFlecks.runtimeCompiler('web', config, env, argv);
|
||||
// Styles.
|
||||
config.entry.index.push(...styles);
|
||||
// Tests.
|
||||
|
|
Loading…
Reference in New Issue
Block a user