Skip to content

Commit

Permalink
feat(types): better local test context support (#1805)
Browse files Browse the repository at this point in the history
* feat(types): better local test context support

* feat(types): fix beforeEach and afterEach

* test: add unit test for local context
  • Loading branch information
Tanimodori committed Aug 6, 2022
1 parent 18e0bec commit 426503c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
4 changes: 2 additions & 2 deletions packages/vitest/src/runtime/hooks.ts
Expand Up @@ -5,5 +5,5 @@ import { getCurrentSuite } from './suite'
// suite hooks
export const beforeAll = (fn: SuiteHooks['beforeAll'][0], timeout?: number) => getCurrentSuite().on('beforeAll', withTimeout(fn, timeout ?? getDefaultHookTimeout(), true))
export const afterAll = (fn: SuiteHooks['afterAll'][0], timeout?: number) => getCurrentSuite().on('afterAll', withTimeout(fn, timeout ?? getDefaultHookTimeout(), true))
export const beforeEach = (fn: SuiteHooks['beforeEach'][0], timeout?: number) => getCurrentSuite().on('beforeEach', withTimeout(fn, timeout ?? getDefaultHookTimeout(), true))
export const afterEach = (fn: SuiteHooks['afterEach'][0], timeout?: number) => getCurrentSuite().on('afterEach', withTimeout(fn, timeout ?? getDefaultHookTimeout(), true))
export const beforeEach = <ExtraContext = {}>(fn: SuiteHooks<ExtraContext>['beforeEach'][0], timeout?: number) => getCurrentSuite<ExtraContext>().on('beforeEach', withTimeout(fn, timeout ?? getDefaultHookTimeout(), true))
export const afterEach = <ExtraContext = {}>(fn: SuiteHooks<ExtraContext>['afterEach'][0], timeout?: number) => getCurrentSuite<ExtraContext>().on('afterEach', withTimeout(fn, timeout ?? getDefaultHookTimeout(), true))
4 changes: 2 additions & 2 deletions packages/vitest/src/runtime/suite.ts
Expand Up @@ -50,8 +50,8 @@ export function clearCollectorContext() {
collectorContext.currentSuite = defaultSuite
}

export function getCurrentSuite() {
return collectorContext.currentSuite || defaultSuite
export function getCurrentSuite<ExtraContext = {}>() {
return (collectorContext.currentSuite || defaultSuite) as SuiteCollector<ExtraContext>
}

export function createSuiteHooks() {
Expand Down
24 changes: 15 additions & 9 deletions packages/vitest/src/types/tasks.ts
Expand Up @@ -126,7 +126,10 @@ type ChainableTestAPI<ExtraContext = {}> = ChainableFunction<
'concurrent' | 'only' | 'skip' | 'todo' | 'fails',
[name: string, fn?: TestFunction<ExtraContext>, timeout?: number],
void,
{ each: TestEachFunction }
{
each: TestEachFunction
<T extends ExtraContext>(name: string, fn?: TestFunction<T>, timeout?: number): void
}
>

export type TestAPI<ExtraContext = {}> = ChainableTestAPI<ExtraContext> & {
Expand All @@ -137,12 +140,15 @@ export type TestAPI<ExtraContext = {}> = ChainableTestAPI<ExtraContext> & {

type ChainableSuiteAPI<ExtraContext = {}> = ChainableFunction<
'concurrent' | 'only' | 'skip' | 'todo' | 'shuffle',
[name: string, factory?: SuiteFactory],
[name: string, factory?: SuiteFactory<ExtraContext>],
SuiteCollector<ExtraContext>,
{ each: TestEachFunction }
{
each: TestEachFunction
<T extends ExtraContext>(name: string, factory?: SuiteFactory<T>): SuiteCollector<T>
}
>

export type SuiteAPI<ExtraContext = {}> = ChainableSuiteAPI & {
export type SuiteAPI<ExtraContext = {}> = ChainableSuiteAPI<ExtraContext> & {
each: SuiteEachFunction
skipIf(condition: any): ChainableSuiteAPI<ExtraContext>
runIf(condition: any): ChainableSuiteAPI<ExtraContext>
Expand All @@ -152,11 +158,11 @@ export type HookListener<T extends any[], Return = void> = (...args: T) => Await

export type HookCleanupCallback = (() => Awaitable<unknown>) | void

export interface SuiteHooks {
export interface SuiteHooks<ExtraContext = {}> {
beforeAll: HookListener<[Suite | File], HookCleanupCallback>[]
afterAll: HookListener<[Suite | File]>[]
beforeEach: HookListener<[TestContext, Suite], HookCleanupCallback>[]
afterEach: HookListener<[TestContext, Suite]>[]
beforeEach: HookListener<[TestContext & ExtraContext, Suite], HookCleanupCallback>[]
afterEach: HookListener<[TestContext & ExtraContext, Suite]>[]
}

export interface SuiteCollector<ExtraContext = {}> {
Expand All @@ -167,10 +173,10 @@ export interface SuiteCollector<ExtraContext = {}> {
tasks: (Suite | Test | SuiteCollector<ExtraContext>)[]
collect: (file?: File) => Promise<Suite>
clear: () => void
on: <T extends keyof SuiteHooks>(name: T, ...fn: SuiteHooks[T]) => void
on: <T extends keyof SuiteHooks<ExtraContext>>(name: T, ...fn: SuiteHooks<ExtraContext>[T]) => void
}

export type SuiteFactory = (test: (name: string, fn: TestFunction) => void) => Awaitable<void>
export type SuiteFactory<ExtraContext = {}> = (test: (name: string, fn: TestFunction<ExtraContext>) => void) => Awaitable<void>

export interface RuntimeContext {
tasks: (SuiteCollector | Test)[]
Expand Down
31 changes: 31 additions & 0 deletions test/core/test/local-context.test.ts
@@ -0,0 +1,31 @@
import { beforeEach, describe, expect, it } from 'vitest'

describe('local test context works with explicit type', () => {
interface LocalTestContext {
foo: string
}
beforeEach<LocalTestContext>((context) => {
context.foo = 'foo'
})
it<LocalTestContext>('works with explicit type', (context) => {
expect(context.foo).toBe('foo')
})
it.todo.skip<LocalTestContext>('is chainable with explicit type', (context) => {
expect(context.foo).toBe('foo')
})
})

describe('local test context works with implicit type', () => {
interface LocalTestContext {
bar: string
}
beforeEach((context: LocalTestContext) => {
context.bar = 'bar'
})
it('works with implicit type', (context: LocalTestContext) => {
expect(context.bar).toBe('bar')
})
it.only('is chainable with implicit type', (context: LocalTestContext) => {
expect(context.bar).toBe('bar')
})
})

0 comments on commit 426503c

Please sign in to comment.