From bba0b16dc1cc73a101da55dd0b7861403ac62d5e Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 15 Sep 2023 14:44:12 +0200 Subject: [PATCH 1/4] fix(vitest): rerun tests if a file loaded with query changes --- packages/vitest/src/node/core.ts | 46 +++++++++++--------------- packages/vitest/src/node/workspace.ts | 7 ++++ test/watch/fixtures/42.txt | 1 + test/watch/fixtures/txt-import.test.ts | 8 +++++ test/watch/test/file-watching.test.ts | 15 ++++++++- 5 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 test/watch/fixtures/42.txt create mode 100644 test/watch/fixtures/txt-import.test.ts diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index dd3baec355e8..62b68133b9af 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -586,7 +586,7 @@ export class Vitest { public getModuleProjects(id: string) { return this.projects.filter((project) => { - return project.getModuleById(id) + return project.getModulesByFilepath(id).size // TODO: reevaluate || project.browser?.moduleGraph.getModulesByFile(id)?.size }) } @@ -596,9 +596,11 @@ export class Vitest { const updateLastChanged = (id: string) => { const projects = this.getModuleProjects(id) projects.forEach(({ server, browser }) => { - const mod = server.moduleGraph.getModuleById(id) || browser?.moduleGraph.getModuleById(id) - if (mod) + const mods = server.moduleGraph.getModulesByFile(id) + mods?.forEach((mod) => { server.moduleGraph.invalidateModule(mod) + browser?.moduleGraph.invalidateModule(mod) + }) }) } @@ -675,22 +677,10 @@ export class Vitest { const files: string[] = [] for (const project of projects) { - const { server, browser } = project - const mod = server.moduleGraph.getModuleById(id) || browser?.moduleGraph.getModuleById(id) - if (!mod) { - // files with `?v=` query from the browser - const mods = browser?.moduleGraph.getModulesByFile(id) - if (!mods?.size) - return [] - let rerun = false - mods.forEach((m) => { - if (m.id && this.handleFileChanged(m.id)) - rerun = true - }) - if (rerun) - files.push(id) + const { server } = project + const mods = project.getModulesByFilepath(id) + if (!mods.size) continue - } // remove queries from id id = normalizeRequestId(id, server.config.base) @@ -705,14 +695,18 @@ export class Vitest { } let rerun = false - mod.importers.forEach((i) => { - if (!i.id) - return - - const heedsRerun = this.handleFileChanged(i.id) - if (heedsRerun) - rerun = true - }) + for (const mod of mods) { + if (!mod.id) + continue + mod.importers.forEach((i) => { + if (!i.id) + return + + const heedsRerun = this.handleFileChanged(i.id) + if (heedsRerun) + rerun = true + }) + } if (rerun) files.push(id) diff --git a/packages/vitest/src/node/workspace.ts b/packages/vitest/src/node/workspace.ts index 02a3ce48d4e4..96638ab67fe3 100644 --- a/packages/vitest/src/node/workspace.ts +++ b/packages/vitest/src/node/workspace.ts @@ -77,6 +77,13 @@ export class WorkspaceProject { return this.ctx.getCoreWorkspaceProject() === this } + // it's possible that file path was imported with different queries (?raw, ?url, etc) + getModulesByFilepath(file: string) { + const set = this.server.moduleGraph.getModulesByFile(file) + || this.browser?.moduleGraph.getModulesByFile(file) + return set || new Set() + } + getModuleById(id: string) { return this.server.moduleGraph.getModuleById(id) || this.browser?.moduleGraph.getModuleById(id) diff --git a/test/watch/fixtures/42.txt b/test/watch/fixtures/42.txt new file mode 100644 index 000000000000..d81cc0710eb6 --- /dev/null +++ b/test/watch/fixtures/42.txt @@ -0,0 +1 @@ +42 diff --git a/test/watch/fixtures/txt-import.test.ts b/test/watch/fixtures/txt-import.test.ts new file mode 100644 index 000000000000..2b089d43ed89 --- /dev/null +++ b/test/watch/fixtures/txt-import.test.ts @@ -0,0 +1,8 @@ +import { expect, it } from 'vitest' + +// @ts-expect-error not typed txt +import answer from './42.txt?raw' + +it('should be 42', () => { + expect(answer).toContain('42') +}) diff --git a/test/watch/test/file-watching.test.ts b/test/watch/test/file-watching.test.ts index c79754985307..681d073d03fa 100644 --- a/test/watch/test/file-watching.test.ts +++ b/test/watch/test/file-watching.test.ts @@ -50,6 +50,18 @@ test('editing source file triggers re-run', async () => { await vitest.waitForStdout('1 passed') }) +test('editing file that was imported with a query reruns suite', async () => { + const vitest = await runVitestCli(...cliArgs) + + testUtils.editFile( + testUtils.resolvePath(import.meta.url, '../fixtures/42.txt'), + file => `${file}\n`, + ) + + await vitest.waitForStdout('RERUN ../42.txt') + await vitest.waitForStdout('1 passed') +}) + test('editing force rerun trigger reruns all tests', async () => { const vitest = await runVitestCli(...cliArgs) @@ -140,7 +152,8 @@ test('editing source file generates new test report to file system', async () => expect(existsSync(report)).toBe(true) }) -describe('browser', () => { +// TODO: don't skip +describe.skip('browser', () => { test.runIf((process.platform !== 'win32'))('editing source file triggers re-run', async () => { const vitest = await runVitestCli(...cliArgs, '--browser.enabled', '--browser.headless', '--browser.name=chrome') From b407e9dfe2589c69a9283954668ddc0f4c9cd9e7 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 15 Sep 2023 14:46:16 +0200 Subject: [PATCH 2/4] chore: cleanup --- test/watch/test/file-watching.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/watch/test/file-watching.test.ts b/test/watch/test/file-watching.test.ts index 681d073d03fa..6533a78ad1d8 100644 --- a/test/watch/test/file-watching.test.ts +++ b/test/watch/test/file-watching.test.ts @@ -152,8 +152,7 @@ test('editing source file generates new test report to file system', async () => expect(existsSync(report)).toBe(true) }) -// TODO: don't skip -describe.skip('browser', () => { +describe('browser', () => { test.runIf((process.platform !== 'win32'))('editing source file triggers re-run', async () => { const vitest = await runVitestCli(...cliArgs, '--browser.enabled', '--browser.headless', '--browser.name=chrome') From a45363737c58c72dc18ad788210fa30229d1d63d Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 15 Sep 2023 15:01:33 +0200 Subject: [PATCH 3/4] chore: move test into example test --- test/watch/fixtures/example.test.ts | 7 +++++++ test/watch/fixtures/txt-import.test.ts | 8 -------- 2 files changed, 7 insertions(+), 8 deletions(-) delete mode 100644 test/watch/fixtures/txt-import.test.ts diff --git a/test/watch/fixtures/example.test.ts b/test/watch/fixtures/example.test.ts index 4fd8bd10912c..8ca564f5fb2e 100644 --- a/test/watch/fixtures/example.test.ts +++ b/test/watch/fixtures/example.test.ts @@ -2,6 +2,13 @@ import { expect, test } from 'vitest' import { getHelloWorld } from './example' +// @ts-expect-error not typed txt +import answer from './42.txt?raw' + +test('answer is 42', () => { + expect(answer).toContain('42') +}) + test('getHello', async () => { expect(getHelloWorld()).toBe('Hello world') }) diff --git a/test/watch/fixtures/txt-import.test.ts b/test/watch/fixtures/txt-import.test.ts deleted file mode 100644 index 2b089d43ed89..000000000000 --- a/test/watch/fixtures/txt-import.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { expect, it } from 'vitest' - -// @ts-expect-error not typed txt -import answer from './42.txt?raw' - -it('should be 42', () => { - expect(answer).toContain('42') -}) From fdb1e46fd95d18df824eaae805379899947901d5 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 18 Sep 2023 12:33:33 +0200 Subject: [PATCH 4/4] fix: correctly invalidate browser modules when watcher triggers --- packages/vitest/src/node/core.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 62b68133b9af..3b34455b8080 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -596,11 +596,13 @@ export class Vitest { const updateLastChanged = (id: string) => { const projects = this.getModuleProjects(id) projects.forEach(({ server, browser }) => { - const mods = server.moduleGraph.getModulesByFile(id) - mods?.forEach((mod) => { - server.moduleGraph.invalidateModule(mod) - browser?.moduleGraph.invalidateModule(mod) - }) + const serverMods = server.moduleGraph.getModulesByFile(id) + serverMods?.forEach(mod => server.moduleGraph.invalidateModule(mod)) + + if (browser) { + const browserMods = browser.moduleGraph.getModulesByFile(id) + browserMods?.forEach(mod => browser.moduleGraph.invalidateModule(mod)) + } }) }