Guide
Test Runner

Test Runner

The heart TSTyche is the test runner. This page walks through its most important features.

This page assumes you already know how to install TSTyche and run type tests. If not, head to the Introduction first.

TypeScript Versions

The TSTyche test runner does not execute the code. Instead it passes the code through TypeScript’s type checker and reports back with the result. In a way you can see TSTyche as a type checker with benefits.

By default, the currently installed typescript package is used. To specify other version of TypeScript, pass it with the --target command line option (or use the target configuration option):

npx tstyche --target 4.8,current

If you run this command using the example from the Introduction, the report should include two versions of TypeScript:

adds TypeScript 4.8.4 to /Users/CandyCat/Library/TSTyche/typescript@4.8.4
uses TypeScript 4.8.4 with ./tsconfig.json
 
pass ./MethodLikeKeys.tst.ts
 
uses TypeScript 5.5.2 with ./tsconfig.json
 
pass ./MethodLikeKeys.tst.ts

At this point you can rest assured that typings can be used with TypeScript 4.8 and the currently installed version. Wondering about the future? Specify beta, latest, next or rc as the target tag.

The Store

First line of the above report tells that the requested version of TypeScript was added to the store. The TSTyche store is a tiny package manager which downloads the requested versions of typescript package. The packages are kept in the global cache, this means running TSTyche in any project will reuse already installed packages.

To know how to resolve tags like latest or next, every two hours the store fetches the typescript package metadata.

These are the command line options dedicated to the store:

  • --install adds the specified versions of TypeScript, useful if you are preparing to work offline,
  • --prune removes the whole cache directory, if you want to free up disk space or to resolve a store issue,
  • --update force updates the typescript package metadata from the registry.

Functional Tests

Any file which can be type checked can also be a type test. For instance, TSTyche assertions can be mixed into a usage examples or a functional tests:

./src/secondItem.ts
export function secondItem<T>(target: Array<T>): T | undefined {
  return target[1];
}
./src/__tests__/secondItem.test.ts
import assert from "node:assert";
import test from "node:test";
import * as tstyche from "tstyche";
import { secondItem } from "../secondItem.js";
 
test("handles numbers", () => {
  assert.strictEqual(secondItem([1, 2, 3]), 2);
 
  tstyche.expect(secondItem([1, 2, 3])).type.toBe<number | undefined>();
  });
});

Use the testFileMatch configuration option to include files in the test run:

./tstyche.config.json
{
  "testFileMatch": ["**/*.test.ts", "**/*.tst.ts"]
}

TSTyche assertions and testing helpers are just empty functions returning undefined. They do nothing when invoked by a JavaScript test runner.

Selecting Test Files

Passing one or more search strings to the tstyche command runs only the test files with matching paths. For example, if a project structure look like this:

      • lastItem.test.ts
      • secondItem.test.ts
    • lastItem.ts
    • secondItem.ts
  • The following will select only the secondItem.test.ts file:

    npx tstyche second

    Filtering Tests

    To organize a larger test file, the describe() and test() helpers can be used:

    import { describe, expect, test } from "tstyche";
    import type * as tstyche from "tstyche/tstyche";
     
    const options: tstyche.ConfigFileOptions = {};
     
    describe("ConfigFileOptions", () => {
      test("'failFast' option", () => {
        expect<Pick<tstyche.ConfigFileOptions, "failFast">>().type.toBe<{
          failFast?: boolean;
        }>();
      });
     
      test("'target' option", () => {
        expect<Pick<tstyche.ConfigFileOptions, "target">>().type.toBe<{
          target?: Array<string>;
        }>();
      });
    });

    This is a fragment of TSTyche’s ConfigFileOptions interface test. The type is generated by a script and this test makes sure that the resulting code is correct.

    While developing similar script, the run mode flags come in handy. Use .only to focus on or .skip to skip some of the tests:

    describe.only("ConfigFileOptions", () => {
      test.skip("'failFast' option", () => {
        // ...
      });
     
      test("'target' option", () => {
        // ...
      });
    });

    Tests can be selected by their name straight from the command line through the --only and --skip filters:

    npx tstyche --only configFile --skip failFast

    Filtering Assertions

    TSTyche assertions support the run mode flags too. Besides focusing and skipping you can also mark them as failing. A supposed to fail assertion raises an error only if it passes.

    import { expect } from "tstyche";
    import type * as tstyche from "tstyche/tstyche";
     
    expect.skip<tstyche.ConfigFileOptions>().type.toMatch<{
      failFast?: boolean;
    }>();
     
    expect.fail<tstyche.ConfigFileOptions>().type.toMatch<{
      target?: string;
    }>();

    Expecting Errors

    Speaking of assertions and errors, TSTyche has a special .toRaiseError() matcher. It checks if the provided type or expression raises a particular TypeScript error:

    import { expect } from "tstyche";
     
    function firstItem<T>(target: Array<T>): T | undefined {
      return target[0];
    }
     
    expect(firstItem()).type.toRaiseError("Expected 1 argument");