Skip to content

A preprocessor for Jest to snapshot test TypeScript declaration (.d.ts) files

License

Notifications You must be signed in to change notification settings

ikatyang/dts-jest

Repository files navigation

dts-jest

npm build coverage

A preprocessor for Jest to snapshot test TypeScript declaration (.d.ts) files

Changelog

Install

# using npm
npm install --save-dev dts-jest jest typescript

# using yarn
yarn add --dev dts-jest jest typescript
  • require jest@>=28 and typescript@>=4

    dts-jest jest typescript
    26 >=28 >=4
    25 >=28 <30 >=2.3 <5
    24 27 >=2.3 <5
    23 >=22 <27 >=2.3 <5

Usage

Modify your Jest config so that looks something like:

(./package.json)

{
  "scripts": {
    "test": "jest"
  },
  "jest": {
    "moduleFileExtensions": ["ts", "js", "json"],
    "testRegex": "/dts-jest/.+\\.ts$",
    "transform": {"/dts-jest/.+\\.ts$": "dts-jest/transform"}
  }
}

This setup allow you to test files **/dts-jest/**/*.ts via dts-jest.

Writing Tests

The test cases must start with a comment @dts-jest, and the next line should be an expression that you want to test its type or value.

(./dts-jest/example.ts)

// @dts-jest:pass:snap
Math.max(1);

// @dts-jest:pass
Math.min(1, 2, 3); //=> 1

// @dts-jest:fail:snap
Math.max('123');

// @ts-expect-error:snap
Math.max('123');

Patterns

Patterns for Testing

// @dts-jest[flags] [description]
expression //=> expected

// @ts-expect-error[flags] [description]
expression //=> expected

Note: @ts-expect-error is treated as an alias of @dts-jest:fail in dts-jest.

Patterns for Grouping

Test cases after this pattern will be marked as that group.

// @dts-jest:group[flag] [description]

If you need a block scope for your tests you can use a Block Statement.

// @dts-jest:group[flag] [description]
{
  // your tests
}

Patterns for File-Level Config

File-level config uses the first comment to set, only docblock will be detected.

/** @dts-jest [action:option] ... */
  • action:
    • enable: set to true
    • disable: set to false
  • option:
    • test-type: test_type option in configs
    • test-value: test_value option in configs

Testing

It's recommended you to run Jest in watching mode via --watch flag.

npm run test -- --watch

NOTE: If you had changed the version of dts-jest, you might have to use --no-cache flag since Jest may use the older cache.

After running the example tests with npm run test, you'll get the following result:

 PASS  tests/example.ts
  Math.max(1)
    ✓ (type) should not throw error
    ✓ (type) should match snapshot
  Math.max('123')
    ✓ (type) should throw error
    ✓ (type) should match snapshot
  Math.min(1, 2, 3)
    ✓ (type) should not throw error

Snapshot Summary
 › 2 snapshots written in 1 test suite.

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   2 added, 2 total
Time:        0.000s
Ran all test suites.

Since snapshot testing will always pass and write the result at the first time, it's reommended you to use :show flag to see the result first without writing results.

(./dts-jest/example.ts)

// @dts-jest:pass:show
Math.max(1);

// @dts-jest:fail:show
Math.max('123');

// @dts-jest:pass
Math.min(1, 2, 3); //=> 1
 PASS  dts-jest/example.ts
  Math.max(1)
    ✓ (type) should show report
    ✓ (type) should not throw error
  Math.max('123')
    ✓ (type) should show report
    ✓ (type) should throw error
  Math.min(1, 2, 3)
    ✓ (type) should not throw error

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        0.000s
Ran all test suites.

  console.log dts-jest/example.ts:2

    Inferred

      Math.max(1)

    to be

      number

  console.log dts-jest/example.ts:5

    Inferring

      Math.max('123')

    but throw

      Argument of type '"123"' is not assignable to parameter of type 'number'.

Configs

Configs are in _dts_jest_ field of Jest config globals.

There are several options

  • test_type
  • test_value
  • enclosing_declaration
    • default: false
    • unwrap type alias
  • typescript
    • default: typescript (node resolution)
    • specify which path of typescript to use
    • <cwd> available
  • compiler_options
    • default: {}
    • specify which path of tsconfig.json (string) or compilerOptions (object) (deprecated, does not support typeRoots for object) to use
  • type_format_flags
    • default: ts.TypeFormatFlags.NoTruncation
    • specify type format
  • transpile
    • default: true
    • transpile code before testing, only affect tests that needs to test value
    • transpiling code will cause line number incorrect, it's better to disable this option if possible

For example:

(./package.json)

{
  "jest": {
    "globals": {
      "_dts_jest_": {
        "compiler_options": {
          "strict": true,
          "target": "es6"
        }
      }
    }
  }
}

Generate diff-friendly snapshots

Originally, snapshots and source content are in different files, it is hard to check their difference before/after, so here comes the dts-jest-remap for generating diff-friendly snapshots.

(./tests/example.ts)

// @dts-jest:snap
Math.max(1, 2, 3);

(./tests/__snapshots__/example.ts.snap) note this file is generated by Jest

// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Math.max(1, 2, 3) 1`] = `"number"`;

This command will combine both snapshots and source content in one file:

dts-jest-remap ./tests/example.ts --outDir ./snapshots

(./snapshots/example.ts)

// @dts-jest:snap -> number
Math.max(1, 2, 3);
Usage: dts-jest-remap [--outDir <path>] [--rename <template>] <TestFileGlob> ...

Options:
  --check, -c          Throw error if target content is different from output
                       content                                         [boolean]
  --help, -h           Show help                                       [boolean]
  --listDifferent, -l  Print the filenames of files that their target content is
                       different from output content                   [boolean]
  --outDir, -o         Redirect output structure to the directory       [string]
  --rename, -r         Rename output filename using template {{variable}},
                       available variable: filename, basename, extname  [string]
  --typescript, -t     Specify which TypeScript source to use           [string]
  --version, -v        Show version number                             [boolean]

Reporter

If you'd like to know which typescript you are using, add dts-jest/reporter to your Jest reporters, for example:

{
  "reporters": [
    "default",
    "dts-jest/reporter"
  ]
}

It'll show the TS version and path after testing:

[dts-jest] using TypeScript v0.0.0 from path/to/typescript

FAQ

  • Compiler option 'lib' requires a value of type list
    • Arrays in jest > globals > _dts_jest_ will be transformed into objects.
    • Consider to use setupFiles to set configs (globals._dts_jest_ = { ... }).
    • See jest#2093 for details.
  • Debug Failure
    • This is mostly caused by regex literal due to the printer bug TypeScript#18071 (fixed in TS v2.6).
    • Workaround: use regex instance instead, e.g. new RegExp('something').

Development

# lint
yarn run lint

# test
yarn run test

# build
yarn run build

Related

  • dtslint: A utility built on TSLint for linting TypeScript declaration (.d.ts) files
  • typings-checker: Positive and negative assertions about TypeScript types and errors

License

MIT © Ika