Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jest-runner): export TestRunner interface types and reexport types from other packages #12715

Merged
merged 2 commits into from Apr 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -49,7 +49,7 @@
- `[jest-resolve]` Expose `JestResolver`, `AsyncResolver`, `SyncResolver`, `PackageFilter`, `PathFilter` and `PackageJSON` types ([#12707](https://github.com/facebook/jest/pull/12707), ([#12712](https://github.com/facebook/jest/pull/12712))
- `[jest-runner]` Allow `setupFiles` module to export an async function ([#12042](https://github.com/facebook/jest/pull/12042))
- `[jest-runner]` Allow passing `testEnvironmentOptions` via docblocks ([#12470](https://github.com/facebook/jest/pull/12470))
- `[jest-runner]` Exposing `CallbackTestRunner`, `EmittingTestRunner` abstract classes to help typing third party runners ([#12646](https://github.com/facebook/jest/pull/12646))
- `[jest-runner]` Expose `CallbackTestRunner`, `EmittingTestRunner` abstract classes and `CallbackTestRunnerInterface`, `EmittingTestRunnerInterface` to help typing third party runners ([#12646](https://github.com/facebook/jest/pull/12646), [#12715](https://github.com/facebook/jest/pull/12715))
- `[jest-runtime]` [**BREAKING**] `Runtime.createHasteMap` now returns a promise ([#12008](https://github.com/facebook/jest/pull/12008))
- `[jest-runtime]` Calling `jest.resetModules` function will clear FS and transform cache ([#12531](https://github.com/facebook/jest/pull/12531))
- `[jest-runtime]` [**BREAKING**] Remove `Context` type export, it must be imported from `@jest/test-result` ([#12685](https://github.com/facebook/jest/pull/12685))
Expand Down
66 changes: 63 additions & 3 deletions packages/jest-runner/__typetests__/jest-runner.test.ts
Expand Up @@ -6,18 +6,21 @@
*/

import {expectType} from 'tsd-lite';
import type {Test, TestEvents} from '@jest/test-result';
import type {Config} from '@jest/types';
import {CallbackTestRunner, EmittingTestRunner} from 'jest-runner';
import type {
CallbackTestRunnerInterface,
Config,
EmittingTestRunnerInterface,
Comment on lines -9 to +13
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks way better.

OnTestFailure,
OnTestStart,
OnTestSuccess,
Test,
TestEvents,
TestRunnerContext,
TestRunnerOptions,
TestWatcher,
UnsubscribeFn,
} from 'jest-runner';
import type {TestWatcher} from 'jest-watcher';

const globalConfig = {} as Config.GlobalConfig;
const runnerContext = {} as TestRunnerContext;
Expand Down Expand Up @@ -45,6 +48,32 @@ const callbackRunner = new CallbackRunner(globalConfig, runnerContext);
expectType<boolean | undefined>(callbackRunner.isSerial);
expectType<false>(callbackRunner.supportsEventEmitters);

// CallbackTestRunnerInterface

class CustomCallbackRunner implements CallbackTestRunnerInterface {
readonly #maxConcurrency: number;
readonly #globalConfig: Config.GlobalConfig;

constructor(globalConfig: Config.GlobalConfig) {
this.#globalConfig = globalConfig;
this.#maxConcurrency = globalConfig.maxWorkers;
}
Comment on lines +53 to +60
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that context is omitted in constructor and members are named differently than in extends CallbackTestRunner example above. It is possible have implements CallbackTestRunner too, but then this sweet flexibility is not allowed. This code is from my actual use case. Learned something new.


async runTests(
tests: Array<Test>,
watcher: TestWatcher,
onStart: OnTestStart,
onResult: OnTestSuccess,
onFailure: OnTestFailure,
options: TestRunnerOptions,
): Promise<void> {
expectType<Config.GlobalConfig>(this.#globalConfig);
expectType<number>(this.#maxConcurrency);

return;
}
}

// EmittingRunner

class EmittingRunner extends EmittingTestRunner {
Expand All @@ -71,3 +100,34 @@ const emittingRunner = new EmittingRunner(globalConfig, runnerContext);

expectType<boolean | undefined>(emittingRunner.isSerial);
expectType<true>(emittingRunner.supportsEventEmitters);

// EmittingTestRunnerInterface

class CustomEmittingRunner implements EmittingTestRunnerInterface {
readonly #maxConcurrency: number;
readonly #globalConfig: Config.GlobalConfig;
readonly supportsEventEmitters = true;

constructor(globalConfig: Config.GlobalConfig) {
this.#globalConfig = globalConfig;
this.#maxConcurrency = globalConfig.maxWorkers;
}

async runTests(
tests: Array<Test>,
watcher: TestWatcher,
options: TestRunnerOptions,
): Promise<void> {
expectType<Config.GlobalConfig>(this.#globalConfig);
expectType<number>(this.#maxConcurrency);

return;
}

on<Name extends keyof TestEvents>(
eventName: string,
listener: (eventData: TestEvents[Name]) => void | Promise<void>,
): UnsubscribeFn {
return () => {};
}
}
5 changes: 5 additions & 0 deletions packages/jest-runner/src/index.ts
Expand Up @@ -27,8 +27,13 @@ interface WorkerInterface extends Worker {
worker: typeof worker;
}

export type {Test, TestEvents} from '@jest/test-result';
export type {Config} from '@jest/types';
export type {TestWatcher} from 'jest-watcher';
export {CallbackTestRunner, EmittingTestRunner} from './types';
export type {
CallbackTestRunnerInterface,
EmittingTestRunnerInterface,
OnTestFailure,
OnTestStart,
OnTestSuccess,
Expand Down
40 changes: 38 additions & 2 deletions packages/jest-runner/src/types.ts
Expand Up @@ -57,6 +57,36 @@ export type TestRunnerSerializedContext = {

export type UnsubscribeFn = () => void;

export interface CallbackTestRunnerInterface {
readonly isSerial?: boolean;
readonly supportsEventEmitters?: boolean;

runTests(
tests: Array<Test>,
watcher: TestWatcher,
onStart: OnTestStart,
onResult: OnTestSuccess,
onFailure: OnTestFailure,
options: TestRunnerOptions,
): Promise<void>;
}

export interface EmittingTestRunnerInterface {
readonly isSerial?: boolean;
readonly supportsEventEmitters: true;

runTests(
tests: Array<Test>,
watcher: TestWatcher,
options: TestRunnerOptions,
): Promise<void>;

on<Name extends keyof TestEvents>(
eventName: Name,
listener: (eventData: TestEvents[Name]) => void | Promise<void>,
): UnsubscribeFn;
}

abstract class BaseTestRunner {
readonly isSerial?: boolean;
abstract readonly supportsEventEmitters: boolean;
Expand All @@ -67,7 +97,10 @@ abstract class BaseTestRunner {
) {}
}

export abstract class CallbackTestRunner extends BaseTestRunner {
export abstract class CallbackTestRunner
extends BaseTestRunner
implements CallbackTestRunnerInterface
{
readonly supportsEventEmitters = false;

abstract runTests(
Expand All @@ -80,7 +113,10 @@ export abstract class CallbackTestRunner extends BaseTestRunner {
): Promise<void>;
}

export abstract class EmittingTestRunner extends BaseTestRunner {
export abstract class EmittingTestRunner
extends BaseTestRunner
implements EmittingTestRunnerInterface
{
readonly supportsEventEmitters = true;

abstract runTests(
Expand Down