diff --git a/.c8rc.json b/.c8rc.json index 3409cc347..6fcd26a66 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -1,7 +1,7 @@ { "all": true, "exclude": [ - "{coverage,examples,media,test,test-d,test-tap,types}/**", + "{coverage,examples,media,test,test-types,test-tap,types}/**", "*.config.cjs", "*.d.*(c|m)ts" ], diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 879aa88ab..93e235296 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ts-version: [~4.4, ~4.5, ~4.6, ~4.7] + ts-version: [~4.7] steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 @@ -55,9 +55,8 @@ jobs: - run: npm i typescript@${TS_VERSION} env: TS_VERSION: ${{ matrix.ts-version }} - - run: npm ls typescript - continue-on-error: true - - run: npx tsd + - run: ./node_modules/typescript/bin/tsc --version + - run: ./node_modules/typescript/bin/tsc --noEmit lockfile_churn: name: Test package-lock for unexpected modifications diff --git a/.xo-config.cjs b/.xo-config.cjs index 74b2df577..896e8001f 100644 --- a/.xo-config.cjs +++ b/.xo-config.cjs @@ -49,6 +49,15 @@ module.exports = { 'unicorn/no-empty-file': 'off', }, }, + { + files: 'test-types/**', + rules: { + 'ava/assertion-arguments': 'off', + 'ava/no-ignored-test-files': 'off', + 'ava/no-skip-assert': 'off', + 'ava/use-t': 'off', + }, + }, { // TODO: Update tests. files: 'test/**', diff --git a/ava.config.js b/ava.config.js index 6a542a4e9..57992596c 100644 --- a/ava.config.js +++ b/ava.config.js @@ -1,6 +1,6 @@ export default { // eslint-disable-line import/no-anonymous-default-export files: ['test/**', '!test/**/{fixtures,helpers}/**'], - ignoredByWatcher: ['{coverage,docs,media,test-d,test-tap}/**'], + ignoredByWatcher: ['{coverage,docs,media,test-types,test-tap}/**'], environmentVariables: { AVA_FAKE_SCM_ROOT: '.fake-root', // This is an internal test flag. }, diff --git a/docs/recipes/typescript.md b/docs/recipes/typescript.md index 3831d529b..bd2083a66 100644 --- a/docs/recipes/typescript.md +++ b/docs/recipes/typescript.md @@ -4,7 +4,7 @@ Translations: [Español](https://github.com/avajs/ava-docs/blob/main/es_ES/docs/ AVA comes bundled with a TypeScript definition file. This allows developers to leverage TypeScript for writing tests. -This guide assumes you've already set up TypeScript for your project. Note that AVA's definition expects at least version 4.4. +This guide assumes you've already set up TypeScript for your project. Note that AVA's definition expects at least version 4.7. ## Enabling AVA's support for TypeScript test files diff --git a/entrypoints/index.d.cts b/entrypoints/index.d.cts deleted file mode 100644 index 91c40063f..000000000 --- a/entrypoints/index.d.cts +++ /dev/null @@ -1,2 +0,0 @@ -export {default} from '../index.js'; -export * from '../index.js'; diff --git a/entrypoints/main.d.cts b/entrypoints/main.d.cts new file mode 100644 index 000000000..94d834ba6 --- /dev/null +++ b/entrypoints/main.d.cts @@ -0,0 +1,2 @@ +export {default} from './main.js'; +export * from './main.js'; diff --git a/entrypoints/main.d.ts b/entrypoints/main.d.ts new file mode 100644 index 000000000..f12fc65b0 --- /dev/null +++ b/entrypoints/main.d.ts @@ -0,0 +1,12 @@ +import type {TestFn} from '../types/test-fn.js'; + +export * from '../types/assertions.js'; +export * from '../types/try-fn.js'; +export * from '../types/test-fn.js'; +export * from '../types/subscribable.js'; + +/** Call to declare a test, or chain to declare hooks or test modifiers */ +declare const test: TestFn; + +/** Call to declare a test, or chain to declare hooks or test modifiers */ +export default test; diff --git a/entrypoints/plugin.d.cts b/entrypoints/plugin.d.cts index b66e07dcb..837235148 100644 --- a/entrypoints/plugin.d.cts +++ b/entrypoints/plugin.d.cts @@ -1 +1 @@ -export * from '../plugin.js' +export * from './plugin.js' diff --git a/plugin.d.ts b/entrypoints/plugin.d.ts similarity index 100% rename from plugin.d.ts rename to entrypoints/plugin.d.ts diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index 50f1570d7..000000000 --- a/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type {TestFn} from './types/test-fn.js'; - -export * from './types/assertions.js'; -export * from './types/try-fn.js'; -export * from './types/test-fn.js'; -export * from './types/subscribable.js'; - -/** Call to declare a test, or chain to declare hooks or test modifiers */ -declare const test: TestFn; - -/** Call to declare a test, or chain to declare hooks or test modifiers */ -export default test; diff --git a/package-lock.json b/package-lock.json index 1a6dc06e3..e7a4511f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,7 @@ "devDependencies": { "@ava/test": "github:avajs/test", "@ava/typescript": "^3.0.1", + "@sindresorhus/tsconfig": "^3.0.1", "@sinonjs/fake-timers": "^9.1.2", "ansi-escapes": "^5.0.0", "c8": "^7.11.3", @@ -75,7 +76,7 @@ "tempy": "^2.0.0", "touch": "^3.1.0", "tsd": "^0.20.0", - "typescript": "^4.7.2", + "typescript": "^4.7.3", "xo": "^0.49.0", "zen-observable": "^0.8.15" }, @@ -1149,6 +1150,15 @@ "node": ">= 8" } }, + "node_modules/@sindresorhus/tsconfig": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/tsconfig/-/tsconfig-3.0.1.tgz", + "integrity": "sha512-0/gtPNTY3++0J2BZM5nHHULg0BIMw886gqdn8vWN+Av6bgF5ZU2qIcHubAn+Z9KNvJhO8WFE+9kDOU3n6OcKtA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -9992,9 +10002,9 @@ } }, "node_modules/typescript": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", - "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 10ce03b6f..224c391cb 100644 --- a/package.json +++ b/package.json @@ -11,18 +11,18 @@ "exports": { ".": { "import": { - "types": "./index.d.ts", + "types": "./entrypoints/main.d.ts", "default": "./entrypoints/main.mjs" }, "require": { - "types": "./entrypoints/index.d.cts", + "types": "./entrypoints/main.d.cts", "default": "./entrypoints/main.cjs" } }, "./eslint-plugin-helper": "./entrypoints/eslint-plugin-helper.cjs", "./plugin": { "import": { - "types": "./plugin.d.ts", + "types": "./entrypoints/plugin.d.ts", "default": "./entrypoints/plugin.mjs" }, "require": { @@ -37,14 +37,12 @@ }, "scripts": { "cover": "c8 --report=none test-ava && c8 --report=none --no-clean tap && c8 report", - "test": "xo && tsd && npm run -s cover" + "test": "xo && tsc --noEmit && npm run -s cover" }, "files": [ "entrypoints", "lib", - "types", - "index.d.ts", - "plugin.d.ts" + "types" ], "keywords": [ "🦄", @@ -131,6 +129,7 @@ "devDependencies": { "@ava/test": "github:avajs/test", "@ava/typescript": "^3.0.1", + "@sindresorhus/tsconfig": "^3.0.1", "@sinonjs/fake-timers": "^9.1.2", "ansi-escapes": "^5.0.0", "c8": "^7.11.3", @@ -145,7 +144,7 @@ "tempy": "^2.0.0", "touch": "^3.1.0", "tsd": "^0.20.0", - "typescript": "^4.7.2", + "typescript": "^4.7.3", "xo": "^0.49.0", "zen-observable": "^0.8.15" }, diff --git a/test-tap/fixture/snapshots/test-sourcemaps/src/feature/__tests__/test.ts b/test-tap/fixture/snapshots/test-sourcemaps/src/feature/__tests__/test.ts index a35f134f2..859d3890d 100644 --- a/test-tap/fixture/snapshots/test-sourcemaps/src/feature/__tests__/test.ts +++ b/test-tap/fixture/snapshots/test-sourcemaps/src/feature/__tests__/test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ import test from '../../../../../../../entrypoints/main.cjs'; test('feature test title', t => { diff --git a/test-tap/fixture/snapshots/test-sourcemaps/src/test.ts b/test-tap/fixture/snapshots/test-sourcemaps/src/test.ts index 3927a6496..17d6155d1 100644 --- a/test-tap/fixture/snapshots/test-sourcemaps/src/test.ts +++ b/test-tap/fixture/snapshots/test-sourcemaps/src/test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ import test from '../../../../../entrypoints/main.cjs'; test('top level test title', t => { diff --git a/test-tap/fixture/snapshots/test-sourcemaps/src/test/test.ts b/test-tap/fixture/snapshots/test-sourcemaps/src/test/test.ts index b4bff440e..d265daf43 100644 --- a/test-tap/fixture/snapshots/test-sourcemaps/src/test/test.ts +++ b/test-tap/fixture/snapshots/test-sourcemaps/src/test/test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ import test from '../../../../../../entrypoints/main.cjs'; test('test title', t => { diff --git a/test-d/.gitignore b/test-types/.gitignore similarity index 100% rename from test-d/.gitignore rename to test-types/.gitignore diff --git a/test-types/import-in-cts/assertions-as-type-guards.cts b/test-types/import-in-cts/assertions-as-type-guards.cts new file mode 100644 index 000000000..45f2518a5 --- /dev/null +++ b/test-types/import-in-cts/assertions-as-type-guards.cts @@ -0,0 +1,40 @@ +import test from 'ava'; +import {expectType} from 'tsd'; + +type Expected = {foo: 'bar'}; +const expected: Expected = {foo: 'bar'}; + +test('deepEqual', t => { + const actual: unknown = {}; + if (t.deepEqual(actual, expected)) { + expectType(actual); + } +}); + +test('like', t => { + const actual: unknown = {}; + if (t.like(actual, expected)) { + expectType(actual); + } +}); + +test('is', t => { + const actual: unknown = 2; + if (t.is(actual, 3 as const)) { + expectType<3>(actual); + } +}); + +test('false', t => { + const actual: unknown = true; + if (t.false(actual)) { + expectType(actual); + } +}); + +test('true', t => { + const actual: unknown = false; + if (t.true(actual)) { + expectType(actual); + } +}); diff --git a/test-types/import-in-cts/context.cts b/test-types/import-in-cts/context.cts new file mode 100644 index 000000000..f2901be88 --- /dev/null +++ b/test-types/import-in-cts/context.cts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ +import anyTest, {ExecutionContext, TestFn} from 'ava'; +import {expectError, expectType} from 'tsd'; + +interface Context { + foo: string; +} + +const test = anyTest as TestFn; + +const macro = test.macro((t, _expected: number) => { + expectType(t.context.foo); +}); + +test.beforeEach(t => { + expectType(t.context); +}); + +// @ts-expect-error TS2769 +expectError(test('foo is bar', macro, 'bar')); // eslint-disable-line @typescript-eslint/no-confusing-void-expression + +anyTest('default context is unknown', t => { + expectType(t.context); +}); + +// See https://github.com/avajs/ava/issues/2253 +interface Covariant extends Context { + bar: number; +} + +const test2 = anyTest as TestFn; +const hook = (_t: ExecutionContext) => {}; +test2.beforeEach(hook); diff --git a/test-types/import-in-cts/deep-equal.cts b/test-types/import-in-cts/deep-equal.cts new file mode 100644 index 000000000..acb850262 --- /dev/null +++ b/test-types/import-in-cts/deep-equal.cts @@ -0,0 +1,29 @@ +import test from 'ava'; +import {expectType} from 'tsd'; + +test('actual extends expected', t => { + type Expected = {foo: [1, 2, 3]}; + const expected: Expected = {foo: [1, 2, 3]}; + const actual = {foo: [1, 2, 3]}; + if (t.deepEqual(actual, expected)) { + expectType(actual); + } +}); + +test('expected extends actual', t => { + type Expected = {foo: Array}; + type Actual = {foo: number[]}; + const expected: Expected = {foo: [1, 2, 3]}; + const actual: Actual = {foo: [1, 2, 3]}; + if (t.deepEqual(actual, expected)) { + expectType(expected); + } +}); + +test('neither extends the each other', t => { + type Expected = {readonly foo: readonly [1, 2, 3]}; + type Actual = {foo: number[]}; + const expected: Expected = {foo: [1, 2, 3]}; + const actual: Actual = {foo: [1, 2, 3]}; + t.deepEqual(actual, expected); +}); diff --git a/test-types/import-in-cts/implementation-result.cts b/test-types/import-in-cts/implementation-result.cts new file mode 100644 index 000000000..ea3ccfcda --- /dev/null +++ b/test-types/import-in-cts/implementation-result.cts @@ -0,0 +1,20 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ +import test from 'ava'; + +test.after('return anything else', _t => ({ + foo: 'bar', + subscribe() {}, + then() {}, // eslint-disable-line unicorn/no-thenable +})); + +test('return a promise-like', _t => ({ + then(resolve) { // eslint-disable-line unicorn/no-thenable + resolve?.(); // eslint-disable-line @typescript-eslint/no-floating-promises + }, +})); + +test('return a subscribable', _t => ({ + subscribe({complete}) { + complete(); + }, +})); diff --git a/test-types/import-in-cts/like.cts b/test-types/import-in-cts/like.cts new file mode 100644 index 000000000..ecc641097 --- /dev/null +++ b/test-types/import-in-cts/like.cts @@ -0,0 +1,25 @@ +import test from 'ava'; + +test('like', t => { + t.like({ + map: new Map([['foo', 'bar']]), + nested: { + baz: 'thud', + qux: 'quux', + }, + }, { + map: new Map([['foo', 'bar']]), + nested: { + baz: 'thud', + }, + }); + + type Foo = { + foo?: 'foo'; + bar?: 'bar'; + }; + + const foo: Foo = {bar: 'bar'}; + const {foo: _, ...expected} = foo; + t.like(expected, {bar: 'bar'}); +}); diff --git a/test-types/import-in-cts/macros.cts b/test-types/import-in-cts/macros.cts new file mode 100644 index 000000000..f775ed7aa --- /dev/null +++ b/test-types/import-in-cts/macros.cts @@ -0,0 +1,126 @@ +/* eslint-disable no-lone-blocks */ +import test, {ExecutionContext} from 'ava'; +import {expectType} from 'tsd'; + +// Typed arguments through generics. +{ + const hasLength = test.macro<[string, number]>((t, input, expected) => { + expectType(input); + expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); + }); + + test('bar has length 3', hasLength, 'bar', 3); +} + +{ + const hasLength = test.macro<[string, number]>({ + exec(t, input, expected) { + expectType(input); + expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); + }, + title(_providedTitle, input, expected) { + expectType(input); + expectType(expected); + return 'title'; + }, + }); + + test('bar has length 3', hasLength, 'bar', 3); +} + +// Typed arguments in execution function. +{ + const hasLength = test.macro((t, input: string, expected: number) => { + // @ts-expect-error TS2345 + t.is(input, expected); + }); + + test('bar has length 3', hasLength, 'bar', 3); +} + +{ + const hasLength = test.macro({ + exec(t, input: string, expected: number) { + // @ts-expect-error TS2345 + t.is(input, expected); + }, + title(_providedTitle, input, expected) { + expectType(input); + expectType(expected); + return 'title'; + }, + }); + + test('bar has length 3', hasLength, 'bar', 3); +} + +// Untyped arguments +{ + const hasLength = test.macro((t, input, expected) => { + expectType(input); + expectType(expected); + t.is(input, expected); + }); + + test('bar has length 3', hasLength, 'bar', 3); +} + +// Usable without title, even if the macro lacks a title function. +{ + const hasLength = test.macro<[string, number]>((t, input, expected) => { + // @ts-expect-error TS2345 + t.is(input, expected); + }); + + test(hasLength, 'bar', 3); +} + +// No arguments +{ + const pass = test.macro<[]>({ // eslint-disable-line @typescript-eslint/ban-types + exec(_t, ...args) { + expectType<[]>(args); // eslint-disable-line @typescript-eslint/ban-types + }, + title(providedTitle, ...args) { + expectType(providedTitle); + expectType<[]>(args); // eslint-disable-line @typescript-eslint/ban-types + return ''; + }, + }); + + test(pass); +} + +// Without test.macro() +{ + const hasLength = (t: ExecutionContext, input: string, expected: number) => { + t.is(input.length, expected); + }; + + test('bar has length 3', hasLength, 'bar', 3); +} + +// Inline function with explicit argument types. +test('has length 3', (t: ExecutionContext, input: string, expected: number) => { + // @ts-expect-error TS2345 + t.is(input, expected); +}, 'bar', 3); + +// Completely inferred arguments for inline functions. +test('has length 3', (t, input, expected) => { + expectType(input); + expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); +}, 'foo', 3); + +test.skip('skip', (t, input, expected) => { + expectType(input); + expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); +}, 'foo', 3); diff --git a/test-types/import-in-cts/plugin.cts b/test-types/import-in-cts/plugin.cts new file mode 100644 index 000000000..f6ad0f19b --- /dev/null +++ b/test-types/import-in-cts/plugin.cts @@ -0,0 +1,18 @@ +import plugin from 'ava/plugin'; +import {expectType} from 'tsd'; + +expectType(plugin.registerSharedWorker({filename: '', supportedProtocols: ['ava-4']})); + +const factory: plugin.SharedWorker.Factory = ({negotiateProtocol}) => { + const protocol = negotiateProtocol(['ava-4']); + expectType(protocol); + + (async () => { + for await (const w of protocol.testWorkers()) { + expectType<() => Promise>(w.teardown(() => {})); // eslint-disable-line @typescript-eslint/no-empty-function + expectType<() => Promise>(w.teardown(async () => {})); // eslint-disable-line @typescript-eslint/no-empty-function + } + })(); +}; + +export default factory; diff --git a/test-types/import-in-cts/snapshot.cts b/test-types/import-in-cts/snapshot.cts new file mode 100644 index 000000000..ab166b253 --- /dev/null +++ b/test-types/import-in-cts/snapshot.cts @@ -0,0 +1,16 @@ +import test from 'ava'; +import {expectError} from 'tsd'; + +test('snapshot', t => { + t.snapshot({foo: 'bar'}); + t.snapshot(null, 'a snapshot with a message'); + // @ts-expect-error TS2345 + expectError(t.snapshot('hello world', null)); // eslint-disable-line @typescript-eslint/no-confusing-void-expression +}); + +test('snapshot.skip', t => { + t.snapshot.skip({foo: 'bar'}); + t.snapshot.skip(null, 'a snapshot with a message'); + // @ts-expect-error TS2345 + expectError(t.snapshot.skip('hello world', null)); // eslint-disable-line @typescript-eslint/no-confusing-void-expression +}); diff --git a/test-types/import-in-cts/teardown.cts b/test-types/import-in-cts/teardown.cts new file mode 100644 index 000000000..baaa4628e --- /dev/null +++ b/test-types/import-in-cts/teardown.cts @@ -0,0 +1,6 @@ +import test from 'ava'; + +test('test', t => { + t.teardown(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function + t.teardown(async () => {}); // eslint-disable-line @typescript-eslint/no-empty-function +}); diff --git a/test-types/import-in-cts/throws.cts b/test-types/import-in-cts/throws.cts new file mode 100644 index 000000000..126dd174b --- /dev/null +++ b/test-types/import-in-cts/throws.cts @@ -0,0 +1,26 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ +import test from 'ava'; +import {expectType} from 'tsd'; + +class CustomError extends Error { + foo: string; + + constructor() { + super(); + this.foo = 'foo'; + } +} + +test('throws', t => { + expectType(t.throws(() => {})); + const error2: CustomError | undefined = t.throws(() => {}); + expectType(error2); + expectType(t.throws(() => {})); +}); + +test('throwsAsync', async t => { + expectType(await t.throwsAsync(async () => {})); + expectType(await t.throwsAsync(async () => {})); + expectType(await t.throwsAsync(Promise.reject())); + expectType(await t.throwsAsync(Promise.reject())); +}); diff --git a/test-types/import-in-cts/try-commit.cts b/test-types/import-in-cts/try-commit.cts new file mode 100644 index 000000000..c207a050b --- /dev/null +++ b/test-types/import-in-cts/try-commit.cts @@ -0,0 +1,67 @@ +import test, {ExecutionContext} from 'ava'; +import {expectType} from 'tsd'; + +test('attempt', async t => { + const attempt = await t.try( + (u, a, b) => { + expectType(u); + expectType(a); + expectType(b); + }, + 'string', + 6, + ); + attempt.commit(); +}); + +test('attempt with title', async t => { + const attempt = await t.try( + 'attempt title', + (u, a, b) => { + expectType(u); + expectType(a); + expectType(b); + }, + 'string', + 6, + ); + attempt.commit(); +}); + +const lengthCheck = (t: ExecutionContext, a: string, b: number): void => { + t.is(a.length, b); +}; + +test('attempt with helper', async t => { + const attempt = await t.try(lengthCheck, 'string', 6); + attempt.commit(); +}); + +test('attempt with title', async t => { + const attempt = await t.try('title', lengthCheck, 'string', 6); + attempt.commit(); +}); + +test('all possible variants to pass to t.try', async t => { + // No params + void t.try(tt => tt.pass()); + + void t.try('test', tt => tt.pass()); + + // Some params + void t.try((tt, a, b) => tt.is(a.length, b), 'hello', 5); + + void t.try('test', (tt, a, b) => tt.is(a.length, b), 'hello', 5); + + // Macro with title + const macro1 = test.macro<[string, number]>({ + exec: (tt, a, b) => tt.is(a.length, b), + title: (title, a, b) => `${title ? `${String(title)} ` : ''}str: "${String(a)}" with len: "${String(b)}"`, + }); + const macro2 = test.macro<[string, number]>((tt, a, b) => tt.is(a.slice(b), '')); + + void t.try(macro1, 'hello', 5); + void t.try(macro2, 'hello', 5); + void t.try('title', macro1, 'hello', 5); + void t.try('title', macro2, 'hello', 5); +}); diff --git a/test-d/assertions-as-type-guards.ts b/test-types/module/assertions-as-type-guards.ts similarity index 96% rename from test-d/assertions-as-type-guards.ts rename to test-types/module/assertions-as-type-guards.ts index 364189b95..45f2518a5 100644 --- a/test-d/assertions-as-type-guards.ts +++ b/test-types/module/assertions-as-type-guards.ts @@ -1,7 +1,6 @@ +import test from 'ava'; import {expectType} from 'tsd'; -import test from '..'; - type Expected = {foo: 'bar'}; const expected: Expected = {foo: 'bar'}; diff --git a/test-d/context.ts b/test-types/module/context.ts similarity index 77% rename from test-d/context.ts rename to test-types/module/context.ts index 476cddf0a..f2901be88 100644 --- a/test-d/context.ts +++ b/test-types/module/context.ts @@ -1,15 +1,14 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +import anyTest, {ExecutionContext, TestFn} from 'ava'; import {expectError, expectType} from 'tsd'; -import anyTest, {ExecutionContext, TestFn} from '..'; - interface Context { foo: string; } const test = anyTest as TestFn; -const macro = test.macro((t, expected: number) => { +const macro = test.macro((t, _expected: number) => { expectType(t.context.foo); }); @@ -17,6 +16,7 @@ test.beforeEach(t => { expectType(t.context); }); +// @ts-expect-error TS2769 expectError(test('foo is bar', macro, 'bar')); // eslint-disable-line @typescript-eslint/no-confusing-void-expression anyTest('default context is unknown', t => { @@ -29,5 +29,5 @@ interface Covariant extends Context { } const test2 = anyTest as TestFn; -const hook = (t: ExecutionContext) => {}; +const hook = (_t: ExecutionContext) => {}; test2.beforeEach(hook); diff --git a/test-d/deep-equal.ts b/test-types/module/deep-equal.ts similarity index 97% rename from test-d/deep-equal.ts rename to test-types/module/deep-equal.ts index 7cc0f1b72..acb850262 100644 --- a/test-d/deep-equal.ts +++ b/test-types/module/deep-equal.ts @@ -1,7 +1,6 @@ +import test from 'ava'; import {expectType} from 'tsd'; -import test from '..'; - test('actual extends expected', t => { type Expected = {foo: [1, 2, 3]}; const expected: Expected = {foo: [1, 2, 3]}; diff --git a/test-d/implementation-result.ts b/test-types/module/implementation-result.ts similarity index 70% rename from test-d/implementation-result.ts rename to test-types/module/implementation-result.ts index e7a21ad52..ea3ccfcda 100644 --- a/test-d/implementation-result.ts +++ b/test-types/module/implementation-result.ts @@ -1,20 +1,20 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -import test from '..'; +import test from 'ava'; -test('return a promise-like', t => ({ +test.after('return anything else', _t => ({ + foo: 'bar', + subscribe() {}, + then() {}, // eslint-disable-line unicorn/no-thenable +})); + +test('return a promise-like', _t => ({ then(resolve) { // eslint-disable-line unicorn/no-thenable resolve?.(); // eslint-disable-line @typescript-eslint/no-floating-promises }, })); -test('return a subscribable', t => ({ +test('return a subscribable', _t => ({ subscribe({complete}) { complete(); }, })); - -test.after('return anything else', t => ({ - foo: 'bar', - subscribe() {}, - then() {}, // eslint-disable-line unicorn/no-thenable -})); diff --git a/test-d/like.ts b/test-types/module/like.ts similarity index 84% rename from test-d/like.ts rename to test-types/module/like.ts index 47bfaf427..ecc641097 100644 --- a/test-d/like.ts +++ b/test-types/module/like.ts @@ -1,4 +1,4 @@ -import test from '..'; +import test from 'ava'; test('like', t => { t.like({ @@ -21,5 +21,5 @@ test('like', t => { const foo: Foo = {bar: 'bar'}; const {foo: _, ...expected} = foo; - t.like({bar: 'bar'}, expected); + t.like(expected, {bar: 'bar'}); }); diff --git a/test-d/macros.ts b/test-types/module/macros.ts similarity index 74% rename from test-d/macros.ts rename to test-types/module/macros.ts index 26cf2780c..f775ed7aa 100644 --- a/test-d/macros.ts +++ b/test-types/module/macros.ts @@ -1,13 +1,14 @@ -/* eslint-disable no-lone-blocks, @typescript-eslint/no-empty-function */ +/* eslint-disable no-lone-blocks */ +import test, {ExecutionContext} from 'ava'; import {expectType} from 'tsd'; -import test, {ExecutionContext} from '..'; - // Typed arguments through generics. { const hasLength = test.macro<[string, number]>((t, input, expected) => { expectType(input); expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); }); test('bar has length 3', hasLength, 'bar', 3); @@ -18,8 +19,10 @@ import test, {ExecutionContext} from '..'; exec(t, input, expected) { expectType(input); expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); }, - title(providedTitle, input, expected) { + title(_providedTitle, input, expected) { expectType(input); expectType(expected); return 'title'; @@ -31,15 +34,21 @@ import test, {ExecutionContext} from '..'; // Typed arguments in execution function. { - const hasLength = test.macro((t, input: string, expected: number) => {}); + const hasLength = test.macro((t, input: string, expected: number) => { + // @ts-expect-error TS2345 + t.is(input, expected); + }); test('bar has length 3', hasLength, 'bar', 3); } { const hasLength = test.macro({ - exec(t, input: string, expected: number) {}, - title(providedTitle, input, expected) { + exec(t, input: string, expected: number) { + // @ts-expect-error TS2345 + t.is(input, expected); + }, + title(_providedTitle, input, expected) { expectType(input); expectType(expected); return 'title'; @@ -54,6 +63,7 @@ import test, {ExecutionContext} from '..'; const hasLength = test.macro((t, input, expected) => { expectType(input); expectType(expected); + t.is(input, expected); }); test('bar has length 3', hasLength, 'bar', 3); @@ -61,7 +71,10 @@ import test, {ExecutionContext} from '..'; // Usable without title, even if the macro lacks a title function. { - const hasLength = test.macro<[string, number]>((t, input, expected) => {}); + const hasLength = test.macro<[string, number]>((t, input, expected) => { + // @ts-expect-error TS2345 + t.is(input, expected); + }); test(hasLength, 'bar', 3); } @@ -69,7 +82,7 @@ import test, {ExecutionContext} from '..'; // No arguments { const pass = test.macro<[]>({ // eslint-disable-line @typescript-eslint/ban-types - exec(t, ...args) { + exec(_t, ...args) { expectType<[]>(args); // eslint-disable-line @typescript-eslint/ban-types }, title(providedTitle, ...args) { @@ -92,15 +105,22 @@ import test, {ExecutionContext} from '..'; } // Inline function with explicit argument types. -test('has length 3', (t: ExecutionContext, input: string, expected: number) => {}, 'bar', 3); +test('has length 3', (t: ExecutionContext, input: string, expected: number) => { + // @ts-expect-error TS2345 + t.is(input, expected); +}, 'bar', 3); // Completely inferred arguments for inline functions. test('has length 3', (t, input, expected) => { expectType(input); expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); }, 'foo', 3); test.skip('skip', (t, input, expected) => { expectType(input); expectType(expected); + // @ts-expect-error TS2345 + t.is(input, expected); }, 'foo', 3); diff --git a/test-d/plugin.ts b/test-types/module/plugin.ts similarity index 89% rename from test-d/plugin.ts rename to test-types/module/plugin.ts index cd6fd4413..c85f6fa35 100644 --- a/test-d/plugin.ts +++ b/test-types/module/plugin.ts @@ -1,7 +1,6 @@ +import * as plugin from 'ava/plugin'; import {expectType} from 'tsd'; -import * as plugin from '../plugin'; // eslint-disable-line import/extensions - expectType(plugin.registerSharedWorker({filename: '', supportedProtocols: ['ava-4']})); const factory: plugin.SharedWorker.Factory = ({negotiateProtocol}) => { @@ -15,3 +14,5 @@ const factory: plugin.SharedWorker.Factory = ({negotiateProtocol}) => { } })(); }; + +export default factory; diff --git a/test-d/snapshot.ts b/test-types/module/snapshot.ts similarity index 86% rename from test-d/snapshot.ts rename to test-types/module/snapshot.ts index 87e025aa8..ab166b253 100644 --- a/test-d/snapshot.ts +++ b/test-types/module/snapshot.ts @@ -1,15 +1,16 @@ +import test from 'ava'; import {expectError} from 'tsd'; -import test from '..'; - test('snapshot', t => { t.snapshot({foo: 'bar'}); t.snapshot(null, 'a snapshot with a message'); + // @ts-expect-error TS2345 expectError(t.snapshot('hello world', null)); // eslint-disable-line @typescript-eslint/no-confusing-void-expression }); test('snapshot.skip', t => { t.snapshot.skip({foo: 'bar'}); t.snapshot.skip(null, 'a snapshot with a message'); + // @ts-expect-error TS2345 expectError(t.snapshot.skip('hello world', null)); // eslint-disable-line @typescript-eslint/no-confusing-void-expression }); diff --git a/test-d/teardown.ts b/test-types/module/teardown.ts similarity index 89% rename from test-d/teardown.ts rename to test-types/module/teardown.ts index 4627d1798..baaa4628e 100644 --- a/test-d/teardown.ts +++ b/test-types/module/teardown.ts @@ -1,4 +1,4 @@ -import test from '..'; +import test from 'ava'; test('test', t => { t.teardown(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function diff --git a/test-d/throws.ts b/test-types/module/throws.ts similarity index 97% rename from test-d/throws.ts rename to test-types/module/throws.ts index 3e7addb45..126dd174b 100644 --- a/test-d/throws.ts +++ b/test-types/module/throws.ts @@ -1,8 +1,7 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +import test from 'ava'; import {expectType} from 'tsd'; -import test from '..'; - class CustomError extends Error { foo: string; diff --git a/test-d/try-commit.ts b/test-types/module/try-commit.ts similarity index 97% rename from test-d/try-commit.ts rename to test-types/module/try-commit.ts index adc7bde69..c207a050b 100644 --- a/test-d/try-commit.ts +++ b/test-types/module/try-commit.ts @@ -1,7 +1,6 @@ +import test, {ExecutionContext} from 'ava'; import {expectType} from 'tsd'; -import test, {ExecutionContext} from '..'; - test('attempt', async t => { const attempt = await t.try( (u, a, b) => { diff --git a/test/configurable-module-format/custom.js b/test/configurable-module-format/custom.js index 9c6f461c1..aa99fff81 100644 --- a/test/configurable-module-format/custom.js +++ b/test/configurable-module-format/custom.js @@ -2,16 +2,16 @@ import test from '@ava/test'; import {fixture} from '../helpers/exec.js'; -test('load ts as commonjs (using an extensions array)', async t => { - const result = await fixture(['*.ts', '--config', 'array-custom.config.js']); +test('load cts as commonjs (using an extensions array)', async t => { + const result = await fixture(['*.cts', '--config', 'array-custom.config.js']); const files = new Set(result.stats.passed.map(({file}) => file)); t.is(files.size, 1); - t.true(files.has('test.ts')); + t.true(files.has('test.cts')); }); -test('load ts as commonjs (using an extensions object)', async t => { - const result = await fixture(['*.ts', '--config', 'object-custom.config.js']); +test('load cts as commonjs (using an extensions object)', async t => { + const result = await fixture(['*.cts', '--config', 'object-custom.config.js']); const files = new Set(result.stats.passed.map(({file}) => file)); t.is(files.size, 1); - t.true(files.has('test.ts')); + t.true(files.has('test.cts')); }); diff --git a/test/configurable-module-format/fixtures/array-custom.config.js b/test/configurable-module-format/fixtures/array-custom.config.js index 7257e6860..2e2a5fd57 100644 --- a/test/configurable-module-format/fixtures/array-custom.config.js +++ b/test/configurable-module-format/fixtures/array-custom.config.js @@ -1,3 +1,3 @@ export default { - extensions: ['js', 'ts'], + extensions: ['js', 'cts'], }; diff --git a/test/configurable-module-format/fixtures/object-custom.config.js b/test/configurable-module-format/fixtures/object-custom.config.js index 14fc59704..a859b9d69 100644 --- a/test/configurable-module-format/fixtures/object-custom.config.js +++ b/test/configurable-module-format/fixtures/object-custom.config.js @@ -1,6 +1,6 @@ export default { extensions: { js: true, - ts: 'commonjs', + cts: 'commonjs', }, }; diff --git a/test/configurable-module-format/fixtures/test.cts b/test/configurable-module-format/fixtures/test.cts new file mode 100644 index 000000000..12216fccf --- /dev/null +++ b/test/configurable-module-format/fixtures/test.cts @@ -0,0 +1,8 @@ +const test = require('ava'); // eslint-disable-line ava/no-ignored-test-files + +// @ts-expect-error TS2345 +test('always passing test', t => { + const numberWithTypes = 0; + + t.is(numberWithTypes, 0); +}); diff --git a/test/configurable-module-format/fixtures/test.ts b/test/configurable-module-format/fixtures/test.ts deleted file mode 100644 index d206a854b..000000000 --- a/test/configurable-module-format/fixtures/test.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */ -const test = require('ava'); // eslint-disable-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires, ava/no-ignored-test-files, unicorn/prefer-module - -test('always passing test', t => { - const numberWithTypes = 0; - - t.is(numberWithTypes, 0); -}); diff --git a/tsconfig.json b/tsconfig.json index 4880954bb..5c8401b8f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,8 @@ { + "extends": "@sindresorhus/tsconfig", "include": [ "test", - "test-d", - "test-tap" + "test-tap", + "test-types" ] }