diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 4db5c67..a24aac9 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -18,5 +18,7 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: 'npm' - - run: npm ${{ vars.NPM_CI_FLAGS }} ci - - run: npm run -- test -p e2e + - run: npm config set registry ${{ vars.NPM_CI_REGISTRY }} + if: ${{ vars.NPM_CI_REGISTRY }} + - run: npm ci + - run: npm run -- test -t 120000 -p e2e diff --git a/build/publish.js b/build/publish.js index 159daf1..7231bcc 100644 --- a/build/publish.js +++ b/build/publish.js @@ -7,6 +7,7 @@ const {join} = require('path'); const { processCode, + run, spawnWith, } = require('@flecks/core/src/server'); const Arborist = require('@npmcli/arborist'); @@ -25,18 +26,6 @@ const localVersions = {}; const packCache = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'publish'); const {workspaces} = require(join(FLECKS_CORE_ROOT, 'package.json')); -const run = (cmd) => ( - new Promise((resolve) => { - exec(cmd, (error, stdout) => { - if (error) { - resolve(undefined) - return; - } - resolve(stdout.trim()); - }); - }) -); - // Get integrity sums for creator dependencies. const packPkg = async (pkg) => { await processCode(spawnWith( diff --git a/package.json b/package.json index 7f90a77..532c851 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "dox": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus", "lint": "node build/tasks npm run lint", "publish": "node build/publish --provenance", - "test": "node build/tasks npm run -- test -t 300000" + "test": "node build/tasks npm run -- test" }, "workspaces": [ "packages/*" diff --git a/packages/core/build/testing.js b/packages/core/build/testing.js index 12afdae..78cc972 100644 --- a/packages/core/build/testing.js +++ b/packages/core/build/testing.js @@ -13,7 +13,6 @@ export function id() { export async function createWorkspace() { const workspace = join(tmpdir(), '@flecks', 'core', 'testing', await id()); - await rimraf(workspace); await mkdir(workspace, {recursive: true}); // sheeeeesh process.prependListener('message', async (message) => { @@ -23,3 +22,10 @@ export async function createWorkspace() { }); return workspace; } + +export function heavySetup(fn) { + return function heavySetup() { + this.timeout(0); + return fn(); + }; +} diff --git a/packages/core/src/server/process.js b/packages/core/src/server/process.js index acf8035..fa38149 100644 --- a/packages/core/src/server/process.js +++ b/packages/core/src/server/process.js @@ -1,4 +1,4 @@ -const {fork, spawn} = require('child_process'); +const {exec, fork, spawn} = require('child_process'); const { access, constants: {X_OK}, @@ -41,6 +41,22 @@ exports.processCode = (child) => new Promise((resolve, reject) => { }); }); +exports.run = (cmd, {suppressError = true} = {}) => ( + new Promise((resolve) => { + exec(cmd, (error, stdout) => { + if (error) { + if (!suppressError) { + // eslint-disable-next-line no-console + console.error(error); + } + resolve(undefined); + return; + } + resolve(stdout.trim()); + }); + }) +); + const children = []; exports.spawnWith = (cmd, opts = {}) => { diff --git a/packages/create-app/test/e2e/npm.js b/packages/create-app/test/e2e/npm.js index f283889..385c0d3 100644 --- a/packages/create-app/test/e2e/npm.js +++ b/packages/create-app/test/e2e/npm.js @@ -13,7 +13,10 @@ it('generates a working application with npm', async () => { const child = spawnWith( [join(FLECKS_CORE_ROOT, 'build', 'cli.js'), 'test-application'], { - env: {FLECKS_CORE_ROOT: workspace}, + env: { + FLECKS_CORE_ROOT: workspace, + PATCH_PACKAGE_INTEGRATION_TEST: 1, + }, stdio: 'ignore', }, ); diff --git a/packages/server/test/server/build-dev.js b/packages/server/test/server/build-dev.js index 9955ff1..5db5365 100644 --- a/packages/server/test/server/build-dev.js +++ b/packages/server/test/server/build-dev.js @@ -1,14 +1,16 @@ import {access} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {createApplication, build} from './build/build'; -it('builds for development', async () => { +let artifact; + +before(heavySetup(async () => { const path = await createApplication(); await build(path, {args: ['-d']}); - let artifact; try { await access(join(path, 'dist', 'server', 'index.js')); artifact = true; @@ -19,6 +21,9 @@ it('builds for development', async () => { console.error(error); artifact = false; } +})); + +it('builds for development', async () => { expect(artifact) .to.be.true; }); diff --git a/packages/server/test/server/build-production.js b/packages/server/test/server/build-production.js index 89e0fae..a8812ab 100644 --- a/packages/server/test/server/build-production.js +++ b/packages/server/test/server/build-production.js @@ -1,21 +1,28 @@ import {access} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {createApplication, build} from './build/build'; -it('builds for production', async () => { +let artifact; + +before(heavySetup(async () => { const path = await createApplication(); await build(path); - let artifact; try { await access(join(path, 'dist', 'server', 'index.js')); artifact = true; } catch (error) { + // intermittent failure... + console.error(error); // eslint-disable-line no-console artifact = false; } +})); + +it('builds for production', async () => { expect(artifact) .to.be.true; }); diff --git a/packages/server/test/server/config-fail.js b/packages/server/test/server/config-fail.js index 784da41..fc5881e 100644 --- a/packages/server/test/server/config-fail.js +++ b/packages/server/test/server/config-fail.js @@ -1,13 +1,17 @@ import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('updates config', async () => { - const path = await createApplication(); +let path; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); const {socketPath, socketServer} = await socketListener(); build( path, @@ -21,7 +25,10 @@ it('updates config', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +it('updates config', async () => { expect((await socket.send({type: 'config.get', payload: 'comm.foo'})).payload) .to.equal('bar'); await writeFile( diff --git a/packages/server/test/server/config-restart.js b/packages/server/test/server/config-restart.js index d712b5d..ac9cded 100644 --- a/packages/server/test/server/config-restart.js +++ b/packages/server/test/server/config-restart.js @@ -1,14 +1,20 @@ import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {buildChild, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('restarts when config keys change', async () => { - const path = await createApplication(); - const {socketPath, socketServer} = await socketListener(); +let path; +let listener; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); + listener = await socketListener(); + const {socketPath, socketServer} = listener; await buildChild( path, { @@ -21,7 +27,11 @@ it('restarts when config keys change', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +async function restart() { + this.timeout(0); let restarted; const whatHappened = Promise.race([ socket.waitForHmr() @@ -50,10 +60,15 @@ it('restarts when config keys change', async () => { expect(restarted) .to.be.true; let config; - await socketServer.waitForSocket() + const before = Date.now(); + await listener.socketServer.waitForSocket() .then(async (socket) => { ({payload: config} = await socket.send({type: 'config.get', payload: '@flecks/repl/server'})); }); + // Had to rebuild... + this.timeout(2000 + (Date.now() - before)); expect(config) .to.not.be.undefined; -}); +} + +it('restarts when config keys change', restart); diff --git a/packages/server/test/server/config-update.js b/packages/server/test/server/config-update.js index 05537d6..e3d70cf 100644 --- a/packages/server/test/server/config-update.js +++ b/packages/server/test/server/config-update.js @@ -1,13 +1,17 @@ import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('updates config', async () => { - const path = await createApplication(); +let path; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); const {socketPath, socketServer} = await socketListener(); build( path, @@ -21,7 +25,10 @@ it('updates config', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +it('updates config', async () => { expect((await socket.send({type: 'config.get', payload: '@flecks/core.id'})).payload) .to.equal('flecks'); await writeFile( diff --git a/packages/server/test/server/runtime-config-bootstrap.js b/packages/server/test/server/runtime-config-bootstrap.js index 5dccf60..171f0af 100644 --- a/packages/server/test/server/runtime-config-bootstrap.js +++ b/packages/server/test/server/runtime-config-bootstrap.js @@ -1,12 +1,15 @@ import {mkdir, writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('propagates bootstrap config', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await mkdir(join(path, 'server-only', 'build'), {recursive: true}); await writeFile(join(path, 'server-only', 'package.json'), '{}'); const config = ` @@ -29,6 +32,9 @@ it('propagates bootstrap config', async () => { `, ); await build(path, {args: ['-d']}); +})); + +it('propagates bootstrap config', async () => { const {results: [{payload: foo}, {payload: blah}]} = await serverActions(path, [ {type: 'config.get', payload: 'server-only.foo'}, {type: 'config.get', payload: 'server-only.blah'}, diff --git a/packages/server/test/server/runtime-config-override.js b/packages/server/test/server/runtime-config-override.js index 908bd17..bb582c4 100644 --- a/packages/server/test/server/runtime-config-override.js +++ b/packages/server/test/server/runtime-config-override.js @@ -1,12 +1,15 @@ import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('propagates bootstrap config', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await writeFile( join(path, 'build', 'flecks.yml'), ` @@ -17,6 +20,9 @@ it('propagates bootstrap config', async () => { `, ); await build(path, {args: ['-d']}); +})); + +it('propagates bootstrap config', async () => { const {results: [{payload: id}, {payload: foo}]} = await serverActions(path, [ {type: 'config.get', payload: '@flecks/core.id'}, {type: 'config.get', payload: 'comm.foo'}, diff --git a/packages/server/test/server/runtime-config-runtime.js b/packages/server/test/server/runtime-config-runtime.js index a9f80e8..f6f6ee9 100644 --- a/packages/server/test/server/runtime-config-runtime.js +++ b/packages/server/test/server/runtime-config-runtime.js @@ -1,10 +1,16 @@ +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('propagates runtime config', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await build(path, {args: ['-d']}); +})); + +it('propagates runtime config', async () => { const {results: [{payload: foo}]} = await serverActions(path, [ {type: 'config.get', payload: 'comm.foo'}, {type: 'exit'}, diff --git a/packages/server/test/server/runtime-connect.js b/packages/server/test/server/runtime-connect.js index d2fe59d..9dea1c4 100644 --- a/packages/server/test/server/runtime-connect.js +++ b/packages/server/test/server/runtime-connect.js @@ -1,10 +1,16 @@ +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('connects', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await build(path, {args: ['-d']}); +})); + +it('connects', async () => { const {code} = await serverActions(path, [ {type: 'exit', payload: 42}, ]); diff --git a/packages/server/test/server/source-restart.js b/packages/server/test/server/source-restart.js index 94173d3..8a14e53 100644 --- a/packages/server/test/server/source-restart.js +++ b/packages/server/test/server/source-restart.js @@ -1,13 +1,17 @@ import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {buildChild, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('restarts when root sources change', async () => { - const path = await createApplication(); +let path; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); const {socketPath, socketServer} = await socketListener(); await buildChild( path, @@ -21,7 +25,10 @@ it('restarts when root sources change', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +it('restarts when root sources change', async () => { let restarted; const whatHappened = Promise.race([ socket.waitForHmr()