diff --git a/src/dev_server.ts b/src/dev_server.ts index e9948cd3..3a727702 100644 --- a/src/dev_server.ts +++ b/src/dev_server.ts @@ -600,8 +600,8 @@ export class DevServer { * by regenerating indexes and handling server restarts as needed. */ #registerServerRestartHooks() { - this.#hooks.add('fileAdded', (relativePath, absolutePath) => { - this.#regenerateIndex(absolutePath, 'add') + this.#hooks.add('fileAdded', async (relativePath, absolutePath) => { + await this.#regenerateIndex(absolutePath, 'add') this.#handleFileChange(relativePath, absolutePath, 'add') }) this.#hooks.add('fileChanged', (relativePath, absolutePath, info) => { @@ -614,8 +614,8 @@ export class DevServer { } this.#handleFileChange(relativePath, absolutePath, 'update', info) }) - this.#hooks.add('fileRemoved', (relativePath, absolutePath) => { - this.#regenerateIndex(absolutePath, 'delete') + this.#hooks.add('fileRemoved', async (relativePath, absolutePath) => { + await this.#regenerateIndex(absolutePath, 'delete') this.#handleFileChange(relativePath, absolutePath, 'delete') }) } diff --git a/src/test_runner.ts b/src/test_runner.ts index bc731ee6..0e0de374 100644 --- a/src/test_runner.ts +++ b/src/test_runner.ts @@ -349,16 +349,16 @@ export class TestRunner { * triggering appropriate test runs based on the changed files. */ #registerServerRestartHooks() { - this.#hooks.add('fileAdded', (relativePath, absolutePath) => { - this.#regenerateIndex(absolutePath, 'add') + this.#hooks.add('fileAdded', async (relativePath, absolutePath) => { + await this.#regenerateIndex(absolutePath, 'add') this.#handleFileChange(relativePath, absolutePath, 'add') }) - this.#hooks.add('fileChanged', (relativePath, absolutePath) => { - this.#regenerateIndex(absolutePath, 'add') + this.#hooks.add('fileChanged', async (relativePath, absolutePath) => { + await this.#regenerateIndex(absolutePath, 'add') this.#handleFileChange(relativePath, absolutePath, 'update') }) - this.#hooks.add('fileRemoved', (relativePath, absolutePath) => { - this.#regenerateIndex(absolutePath, 'delete') + this.#hooks.add('fileRemoved', async (relativePath, absolutePath) => { + await this.#regenerateIndex(absolutePath, 'delete') this.#handleFileChange(relativePath, absolutePath, 'delete') }) } diff --git a/tests/dev_server.spec.ts b/tests/dev_server.spec.ts index 4f1e7cd6..0dafb356 100644 --- a/tests/dev_server.spec.ts +++ b/tests/dev_server.spec.ts @@ -257,6 +257,85 @@ test.group('DevServer', () => { ]) }).timeout(8 * 1000) + test('wait for index regeneration before restarting the server', async ({ + fs, + assert, + cleanup, + }) => { + const indexUpdate = Promise.withResolvers() + const indexUpdateStarted = Promise.withResolvers() + const serverRestarted = Promise.withResolvers() + const watcherReady = Promise.withResolvers() + let serverStarts = 0 + + await fs.createJson('tsconfig.json', { include: ['**/*'], exclude: [] }) + await fs.create( + 'bin/server.ts', + ` + process.send({ isAdonisJS: true, environment: 'web', port: process.env.PORT, host: 'localhost' }) + setInterval(() => {}, 5000) + ` + ) + await fs.create('.env', 'PORT=3360') + + const devServer = new DevServer(fs.baseUrl, { + nodeArgs: [], + scriptArgs: [], + hooks: { + init: [ + { + run(_, __, indexGenerator) { + const addFile = indexGenerator.addFile.bind(indexGenerator) + indexGenerator.addFile = async (filePath) => { + indexUpdateStarted.resolve() + await indexUpdate.promise + await addFile(filePath) + } + }, + }, + ], + devServerStarting: [ + { + run() { + serverStarts++ + }, + }, + ], + devServerStarted: [ + { + run() { + if (serverStarts === 2) { + serverRestarted.resolve() + } + }, + }, + ], + }, + }) + + devServer.ui = cliui() + devServer.ui.switchMode('raw') + const logInfo = devServer.ui.logger.info.bind(devServer.ui.logger) + devServer.ui.logger.info = (...args: Parameters) => { + if (args[0] === 'watching file system for changes...') { + watcherReady.resolve() + } + logInfo(...args) + } + + await devServer.startAndWatch() + cleanup(() => devServer.close()) + await watcherReady.promise + + await fs.create('app/controllers/users_controller.ts', 'export default class {}') + await indexUpdateStarted.promise + + assert.equal(serverStarts, 1) + + indexUpdate.resolve() + await serverRestarted.promise + }) + test('restart server if hot-hook:full-reload message is received', async ({ assert, fs }) => { await fs.createJson('tsconfig.json', { include: ['**/*'], exclude: [] }) await fs.create( diff --git a/tests/test_runner.spec.ts b/tests/test_runner.spec.ts new file mode 100644 index 00000000..ee9e2706 --- /dev/null +++ b/tests/test_runner.spec.ts @@ -0,0 +1,84 @@ +/* + * @adonisjs/assembler + * + * (c) AdonisJS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { test } from '@japa/runner' +import { cliui } from '@poppinss/cliui' + +import { TestRunner } from '../index.ts' + +test.group('TestRunner', () => { + test('wait for index regeneration before re-running tests', async ({ fs, assert, cleanup }) => { + const indexUpdate = Promise.withResolvers() + const indexUpdateStarted = Promise.withResolvers() + const testsFinished = Promise.withResolvers() + const watcherReady = Promise.withResolvers() + let testRuns = 0 + + await fs.createJson('tsconfig.json', { include: ['**/*'], exclude: [] }) + await fs.create('bin/test.ts', '') + + const testRunner = new TestRunner(fs.baseUrl, { + filters: {}, + nodeArgs: [], + scriptArgs: [], + hooks: { + init: [ + { + run(_, __, indexGenerator) { + const addFile = indexGenerator.addFile.bind(indexGenerator) + indexGenerator.addFile = async (filePath) => { + indexUpdateStarted.resolve() + await indexUpdate.promise + await addFile(filePath) + } + }, + }, + ], + testsStarting: [ + { + run() { + testRuns++ + }, + }, + ], + testsFinished: [ + { + run() { + if (testRuns === 2) { + testsFinished.resolve() + } + }, + }, + ], + }, + }) + + testRunner.ui = cliui() + testRunner.ui.switchMode('raw') + const logInfo = testRunner.ui.logger.info.bind(testRunner.ui.logger) + testRunner.ui.logger.info = (...args: Parameters) => { + if (args[0] === 'watching file system for changes...') { + watcherReady.resolve() + } + logInfo(...args) + } + + await testRunner.runAndWatch() + cleanup(() => testRunner.close()) + await watcherReady.promise + + await fs.create('app/controllers/users_controller.ts', 'export default class {}') + await indexUpdateStarted.promise + + assert.equal(testRuns, 1) + + indexUpdate.resolve() + await testsFinished.promise + }) +})