diff --git a/src/worker/collect.ts b/src/worker/collect.ts index bcfb999..bf4f3ae 100644 --- a/src/worker/collect.ts +++ b/src/worker/collect.ts @@ -90,6 +90,12 @@ export function astParseFile(filepath: string, code: string) { return getName(callee.tag) } if (callee.type === 'MemberExpression') { + if ( + callee.object?.type === 'Identifier' + && ['it', 'test', 'describe', 'suite'].includes(callee.object.name) + ) { + return callee.object?.name + } // direct call as `__vite_ssr_exports_0__.test()` if (callee.object?.name?.startsWith('__vite_ssr_')) { return getName(callee.property) diff --git a/test-e2e/discovery.test.ts b/test-e2e/discovery.test.ts new file mode 100644 index 0000000..bbabdee --- /dev/null +++ b/test-e2e/discovery.test.ts @@ -0,0 +1,63 @@ +import { resolve } from 'node:path' +import type { RunnerTestCase, RunnerTestSuite } from 'vitest' +import { describe, expect, it } from 'vitest' +import { createVitest } from 'vitest/node' +import { astCollectTests } from '../src/worker/collect' + +describe('can discover tests', () => { + it.for([ + 'todo-import-suite.ts', + 'todo-globals-suite.ts', + ])('can discover todo tests inside a suite in %s', async (fixture) => { + const vitest = await createVitest('test', { config: false }) + const file = await astCollectTests( + vitest.getCoreWorkspaceProject(), + resolve(`test-e2e/fixtures/collect/${fixture}`), + 'web', + ) + expect(file.filepath).toBe(resolve(`test-e2e/fixtures/collect/${fixture}`)) + expect(file.name).toBe(`test-e2e/fixtures/collect/${fixture}`) + + expect(file.tasks).toHaveLength(1) + const suite = file.tasks[0] as RunnerTestSuite + expect(suite.name).toBe('TicketDetailBottomBar') + expect(suite.mode).toBe('run') + expect(suite.location).toMatchObject({ + line: 3, + column: 0, + }) + expect(suite.tasks).toHaveLength(2) + + const [testTask, suiteTask] = suite.tasks as [RunnerTestCase, RunnerTestSuite] + expect(testTask.name).toBe('emits %s event when button is clicked') + expect((testTask as any).dynamic).toBe(true) + expect(testTask.mode).toBe('run') + expect(testTask.location).toMatchObject({ + line: 4, + column: 31, // TODO: should it be 5 instead? + }) + + expect(suiteTask.name).toBe('Drafts') + expect(suiteTask.mode).toBe('skip') + expect(suiteTask.location).toMatchObject({ + line: 10, + column: 2, + }) + expect(suiteTask.tasks).toHaveLength(2) + + const [todo1, todo2] = suiteTask.tasks as RunnerTestCase[] + expect(todo1.name).toBe('should not display draft information if ticket has no draft') + expect(todo1.mode).toBe('todo') + expect(todo1.location).toMatchObject({ + line: 11, + column: 4, + }) + + expect(todo2.name).toBe('should display draft information if ticket has a draft') + expect(todo2.mode).toBe('todo') + expect(todo2.location).toMatchObject({ + line: 12, + column: 4, + }) + }) +}) diff --git a/test-e2e/fixtures/collect/todo-globals-suite.ts b/test-e2e/fixtures/collect/todo-globals-suite.ts new file mode 100644 index 0000000..c7b73e9 --- /dev/null +++ b/test-e2e/fixtures/collect/todo-globals-suite.ts @@ -0,0 +1,14 @@ +// @ts-nocheck + +describe('TicketDetailBottomBar', () => { + it.each(['submit', 'discard'])( + 'emits %s event when button is clicked', + async (eventName) => { + }, + ) + + describe('Drafts', () => { + it.todo('should not display draft information if ticket has no draft') + it.todo('should display draft information if ticket has a draft') + }) +}) diff --git a/test-e2e/fixtures/collect/todo-import-suite.ts b/test-e2e/fixtures/collect/todo-import-suite.ts new file mode 100644 index 0000000..6c54fd4 --- /dev/null +++ b/test-e2e/fixtures/collect/todo-import-suite.ts @@ -0,0 +1,14 @@ +import { describe, it } from 'vitest' + +describe('TicketDetailBottomBar', () => { + it.each(['submit', 'discard'])( + 'emits %s event when button is clicked', + async (eventName) => { + }, + ) + + describe('Drafts', () => { + it.todo('should not display draft information if ticket has no draft') + it.todo('should display draft information if ticket has a draft') + }) +})