diff --git a/package.json b/package.json index 362704392..1e6608e2f 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^13.1.3", + "@types/lodash": "^4.14.178", "@types/node": "^17.0.12", "bumpp": "^7.1.1", "c8": "^7.11.0", diff --git a/packages/ui/client/auto-imports.d.ts b/packages/ui/client/auto-imports.d.ts index 4e379fb30..83ff08948 100644 --- a/packages/ui/client/auto-imports.d.ts +++ b/packages/ui/client/auto-imports.d.ts @@ -170,6 +170,7 @@ declare global { const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] const useStorage: typeof import('@vueuse/core')['useStorage'] const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] + const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] const useSwipe: typeof import('@vueuse/core')['useSwipe'] const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] diff --git a/packages/vitest/LICENSE.md b/packages/vitest/LICENSE.md index 31a75fb5e..0e235c7b6 100644 --- a/packages/vitest/LICENSE.md +++ b/packages/vitest/LICENSE.md @@ -1231,6 +1231,35 @@ Repository: unjs/mlly --------------------------------------- +## mockdate +License: MIT +By: Bob Lauer +Repository: https://github.com/boblauer/MockDate.git + +> The MIT License (MIT) +> +> Copyright (c) 2014 Bob Lauer +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. + +--------------------------------------- + ## natural-compare License: MIT By: Lauri Rooden diff --git a/packages/vitest/rollup.config.js b/packages/vitest/rollup.config.js index f7d5c7c78..83916cd42 100644 --- a/packages/vitest/rollup.config.js +++ b/packages/vitest/rollup.config.js @@ -29,6 +29,7 @@ const external = [ ...Object.keys(pkg.dependencies), ...Object.keys(pkg.peerDependencies), 'worker_threads', + 'inspector', ] export default ({ watch }) => [ diff --git a/packages/vitest/src/index.ts b/packages/vitest/src/index.ts index 9127e21fb..0c0e68d1d 100644 --- a/packages/vitest/src/index.ts +++ b/packages/vitest/src/index.ts @@ -42,7 +42,6 @@ type Promisify = { declare global { namespace Vi { - interface ExpectStatic extends Chai.ExpectStatic, AsymmetricMatchersContaining { (actual: T, message?: string): Vi.Assertion @@ -115,15 +114,17 @@ declare global { nthReturnedWith(nthCall: number, value: E): void } - type VitestifyAssertion = { + // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error + // @ts-ignore build namspace conflict + type VitestAssertion = { [K in keyof A]: A[K] extends Chai.Assertion ? Assertion : A[K] extends (...args: any[]) => any ? A[K] // not converting function since they may contain overload - : VitestifyAssertion + : VitestAssertion } - interface Assertion extends VitestifyAssertion, JestAssertion { + interface Assertion extends VitestAssertion, JestAssertion { resolves: Promisify> rejects: Promisify> } diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 977d03e13..f211a97eb 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -1,19 +1,30 @@ -import type { File, RunMode, Suite, SuiteCollector, SuiteHooks, Test, TestCollector, TestFactory, TestFunction } from '../types' -import { noop } from '../utils' +import { format } from 'util' +import type { File, RunMode, Suite, SuiteAPI, SuiteCollector, SuiteFactory, SuiteHooks, Test, TestAPI, TestFunction } from '../types' +import { isObject, noop, toArray } from '../utils' import { createChainable } from './chain' import { collectTask, context, normalizeTest, runWithSuite } from './context' import { getHooks, setFn, setHooks } from './map' // apis export const suite = createSuite() -export const test: TestCollector = createChainable( - ['concurrent', 'skip', 'only', 'todo', 'fails'], +export const test = createTest( function(name: string, fn?: TestFunction, timeout?: number) { // @ts-expect-error untyped internal prop getCurrentSuite().test.fn.call(this, name, fn, timeout) }, ) +function formatTitle(template: string, items: any[]) { + const count = template.split('%').length - 1 + let formatted = format(template, ...items.slice(0, count)) + if (isObject(items[0])) { + formatted = formatted.replace(/\$([$\w_]+)/g, (_, key) => { + return items[0][key] + }) + } + return formatted +} + // alias export const describe = suite export const it = test @@ -40,7 +51,7 @@ export function createSuiteHooks() { } } -function createSuiteCollector(name: string, factory: TestFactory = () => { }, mode: RunMode, concurrent?: boolean) { +function createSuiteCollector(name: string, factory: SuiteFactory = () => { }, mode: RunMode, concurrent?: boolean) { const tasks: (Test | Suite | SuiteCollector)[] = [] const factoryQueue: (Test | Suite | SuiteCollector)[] = [] @@ -48,26 +59,23 @@ function createSuiteCollector(name: string, factory: TestFactory = () => { }, mo initSuite() - const test = createChainable( - ['concurrent', 'skip', 'only', 'todo', 'fails'], - function(name: string, fn?: TestFunction, timeout?: number) { - const mode = this.only ? 'only' : this.skip ? 'skip' : this.todo ? 'todo' : 'run' + const test = createTest(function(name: string, fn?: TestFunction, timeout?: number) { + const mode = this.only ? 'only' : this.skip ? 'skip' : this.todo ? 'todo' : 'run' - const test: Test = { - id: '', - type: 'test', - name, - mode, - suite: undefined!, - fails: this.fails, - } - if (this.concurrent || concurrent) - test.concurrent = true - - setFn(test, normalizeTest(fn || noop, timeout)) - tasks.push(test) - }, - ) + const test: Test = { + id: '', + type: 'test', + name, + mode, + suite: undefined!, + fails: this.fails, + } + if (this.concurrent || concurrent) + test.concurrent = true + + setFn(test, normalizeTest(fn || noop, timeout)) + tasks.push(test) + }) const collector: SuiteCollector = { type: 'collector', @@ -129,11 +137,40 @@ function createSuiteCollector(name: string, factory: TestFactory = () => { }, mo } function createSuite() { - return createChainable( + const suite = createChainable( ['concurrent', 'skip', 'only', 'todo'], - function(name: string, factory?: TestFactory) { + function(name: string, factory?: SuiteFactory) { const mode = this.only ? 'only' : this.skip ? 'skip' : this.todo ? 'todo' : 'run' return createSuiteCollector(name, factory, mode, this.concurrent) }, - ) + ) as SuiteAPI + + suite.each = (cases: T[]) => { + return (name: string, fn: (...args: T extends any[] ? T : [T]) => void) => { + cases.forEach((i) => { + const items = toArray(i) as any + suite(formatTitle(name, items), () => fn(...items)) + }) + } + } + + return suite as SuiteAPI +} + +function createTest(fn: ((this: Record<'concurrent'| 'skip'| 'only'| 'todo'| 'fails', boolean | undefined>, title: string, fn?: TestFunction, timeout?: number) => void)) { + const test = createChainable( + ['concurrent', 'skip', 'only', 'todo', 'fails'], + fn, + ) as TestAPI + + test.each = (cases: T[]) => { + return (name: string, fn: (...args: T extends any[] ? T : [T]) => void) => { + cases.forEach((i) => { + const items = toArray(i) as any + test(formatTitle(name, items), () => fn(...items)) + }) + } + } + + return test as TestAPI } diff --git a/packages/vitest/src/types/tasks.ts b/packages/vitest/src/types/tasks.ts index 0f7ebf6e7..0f58de67d 100644 --- a/packages/vitest/src/types/tasks.ts +++ b/packages/vitest/src/types/tasks.ts @@ -44,12 +44,19 @@ export type Task = Test | Suite | File export type DoneCallback = (error?: any) => void export type TestFunction = (done: DoneCallback) => Awaitable +export type EachFunction = (cases: T[]) => (name: string, fn: (...args: T extends any[] ? T : [T]) => void) => void -export type TestCollector = ChainableFunction< +export type TestAPI = ChainableFunction< 'concurrent' | 'only' | 'skip' | 'todo' | 'fails', [name: string, fn?: TestFunction, timeout?: number], void -> +> & { each: EachFunction } + +export type SuiteAPI = ChainableFunction< +'concurrent' | 'only' | 'skip' | 'todo', +[name: string, factory?: SuiteFactory], +SuiteCollector +> & { each: EachFunction } export type HookListener = (...args: T) => Awaitable @@ -64,14 +71,14 @@ export interface SuiteCollector { readonly name: string readonly mode: RunMode type: 'collector' - test: TestCollector + test: TestAPI tasks: (Suite | Test | SuiteCollector)[] collect: (file?: File) => Promise clear: () => void on: (name: T, ...fn: SuiteHooks[T]) => void } -export type TestFactory = (test: (name: string, fn: TestFunction) => void) => Awaitable +export type SuiteFactory = (test: (name: string, fn: TestFunction) => void) => Awaitable export interface RuntimeContext { tasks: (SuiteCollector | Test)[] diff --git a/packages/ws-client/rollup.config.js b/packages/ws-client/rollup.config.js index b0ca29a2a..f682c2599 100644 --- a/packages/ws-client/rollup.config.js +++ b/packages/ws-client/rollup.config.js @@ -14,6 +14,7 @@ const external = [ 'birpc', 'worker_threads', 'vitest', + 'inspector', ] export default () => [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe0fed0fb..2a7323e82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,7 @@ importers: '@rollup/plugin-commonjs': ^21.0.1 '@rollup/plugin-json': ^4.1.0 '@rollup/plugin-node-resolve': ^13.1.3 + '@types/lodash': ^4.14.178 '@types/node': ^17.0.12 bumpp: ^7.1.1 c8: ^7.11.0 @@ -40,6 +41,7 @@ importers: '@rollup/plugin-commonjs': 21.0.1_rollup@2.66.1 '@rollup/plugin-json': 4.1.0_rollup@2.66.1 '@rollup/plugin-node-resolve': 13.1.3_rollup@2.66.1 + '@types/lodash': 4.14.178 '@types/node': 17.0.12 bumpp: 7.1.1 c8: 7.11.0 @@ -5651,6 +5653,10 @@ packages: resolution: {integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4=} dev: true + /@types/lodash/4.14.178: + resolution: {integrity: sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==} + dev: true + /@types/mdast/3.0.10: resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} dependencies: diff --git a/test/core/test/each.test.ts b/test/core/test/each.test.ts new file mode 100644 index 000000000..cb61dd1d8 --- /dev/null +++ b/test/core/test/each.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, test } from 'vitest' + +test.each([ + [1, 1, 2], + [1, 2, 3], + [2, 1, 3], +])('add(%i, %i) -> %i', (a, b, expected) => { + expect(a + b).toBe(expected) +}) + +describe.each([ + [1, 1, 2], + [1, 2, 3], + [2, 1, 3], +])('describe add(%i, %i)', (a, b, expected) => { + test(`returns ${expected}`, () => { + expect(a + b).toBe(expected) + }) + + test(`returned value not be greater than ${expected}`, () => { + expect(a + b).not.toBeGreaterThan(expected) + }) + + test(`returned value not be less than ${expected}`, () => { + expect(a + b).not.toBeLessThan(expected) + }) +}) + +describe.each([ + { a: 1, b: 1, expected: 2 }, + { a: 1, b: 2, expected: 3 }, + { a: 2, b: 1, expected: 3 }, +])('describe object add($a, $b)', ({ a, b, expected }) => { + test(`returns ${expected}`, () => { + expect(a + b).toBe(expected) + }) + + test(`returned value not be greater than ${expected}`, () => { + expect(a + b).not.toBeGreaterThan(expected) + }) + + test(`returned value not be less than ${expected}`, () => { + expect(a + b).not.toBeLessThan(expected) + }) +}) diff --git a/test/core/test/hoist-import.test.ts b/test/core/test/hoist-import.test.ts index fc23a3ae0..37b1a12b1 100644 --- a/test/core/test/hoist-import.test.ts +++ b/test/core/test/hoist-import.test.ts @@ -12,6 +12,7 @@ vi.mock('../src/timeout.ts', () => { }) test('"vi" can be used inside factory with empty lines', () => { + // @ts-expect-error no types expect(globalThis.vi).toBeUndefined() expect(timeout).toBe(10_000) expect(vi.isMockFunction(fn)).toBe(true) diff --git a/test/core/test/jest-expect.test.ts b/test/core/test/jest-expect.test.ts index 4b5da6f97..7b9379baa 100644 --- a/test/core/test/jest-expect.test.ts +++ b/test/core/test/jest-expect.test.ts @@ -158,7 +158,7 @@ describe('jest-expect', () => { // https://jestjs.io/docs/expect#tostrictequalvalue class LaCroix { - constructor(public flavor) {} + constructor(public flavor: any) {} } describe('the La Croix cans on my desk', () => { @@ -173,7 +173,7 @@ describe('jest-expect', () => { expect([]).not.toBe([]) expect([]).toStrictEqual([]) - const foo = [] + const foo: any[] = [] expect(foo).toBe(foo) expect(foo).toStrictEqual(foo) @@ -195,21 +195,21 @@ describe('jest-expect', () => { describe('.toStrictEqual()', () => { class TestClassA { - constructor(public a, public b) {} + constructor(public a: any, public b: any) {} } class TestClassB { - constructor(public a, public b) {} + constructor(public a: any, public b: any) {} } const TestClassC = class Child extends TestClassA { - constructor(a, b) { + constructor(a: any, b: any) { super(a, b) } } const TestClassD = class Child extends TestClassB { - constructor(a, b) { + constructor(a: any, b: any) { super(a, b) } } diff --git a/test/core/test/jest-mock.test.ts b/test/core/test/jest-mock.test.ts index 0d7322574..869bf1bf8 100644 --- a/test/core/test/jest-mock.test.ts +++ b/test/core/test/jest-mock.test.ts @@ -32,6 +32,7 @@ describe('jest mock compat layer', () => { const Spy = vi.fn(() => {}) expect(Spy.mock.instances).toHaveLength(0) + // @ts-expect-error ignore // eslint-disable-next-line no-new new Spy() expect(Spy.mock.instances).toHaveLength(1) diff --git a/test/related/tests/not-related.test.ts b/test/related/tests/not-related.test.ts index 27066cbae..5a89c4a52 100644 --- a/test/related/tests/not-related.test.ts +++ b/test/related/tests/not-related.test.ts @@ -1,6 +1,7 @@ +import { expect, test } from 'vitest' import { B } from '../src/sourceB' -test('shouldnt run', () => { +test('shouldn\'t run', () => { expect(B).toBe('B') expect.fail() }) diff --git a/test/related/tests/related.test.ts b/test/related/tests/related.test.ts index c6f9304b7..5d04d7a3c 100644 --- a/test/related/tests/related.test.ts +++ b/test/related/tests/related.test.ts @@ -1,5 +1,6 @@ import { access } from 'fs' import { sep } from 'pathe' +import { expect, test } from 'vitest' import { A } from '../src/sourceA' test('A equals A', () => { diff --git a/test/related/tsconfig.json b/test/related/tsconfig.json deleted file mode 100644 index 9f9b0a6a9..000000000 --- a/test/related/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "types": ["vitest/global"], - } -} \ No newline at end of file diff --git a/test/reporters/custom-reporter.vitest.config.ts b/test/reporters/custom-reporter.vitest.config.ts index 381739e47..ddc045b58 100644 --- a/test/reporters/custom-reporter.vitest.config.ts +++ b/test/reporters/custom-reporter.vitest.config.ts @@ -6,7 +6,7 @@ import { defineConfig } from 'vite' class TestReporter implements Reporter { ctx!: Vitest - onInit(ctx) { + onInit(ctx: Vitest) { this.ctx = ctx } diff --git a/tsconfig.json b/tsconfig.json index 5f9ce0c22..db5ba4930 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,8 +30,8 @@ }, "exclude": [ "**/dist/**", + "./packages/vitest/dist/**", "./packages/ui/client/**", - "./test/**/*.*", "./examples/**/*.*", "./bench/**" ]