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

Infer jest globals from @jest/globals #62037

Closed
Closed
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
1 change: 1 addition & 0 deletions types/expect-puppeteer/expect-puppeteer-tests.ts
@@ -1,5 +1,6 @@
import { ElementHandle, Page } from "puppeteer";
import { getDefaultOptions, setDefaultOptions } from 'expect-puppeteer';
import { expect } from 'expect';

const testGlobal = async (instance: ElementHandle | Page) => {
await expect(instance).toClick({ type: 'css', value: 'selector' });
Expand Down
28 changes: 12 additions & 16 deletions types/expect-puppeteer/index.d.ts
Expand Up @@ -5,8 +5,6 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 4.3

/// <reference types="jest" />

import { ElementHandle, Page, Dialog } from "puppeteer";

/**
Expand Down Expand Up @@ -90,20 +88,18 @@ interface ExpectPuppeteer {
toUploadFile(selector: string | MatchSelector, filePath: string, options?: ExpectTimingActions): Promise<void>;
}

declare global {
namespace jest {
interface Matchers<R, T> {
// These must all match the ExpectPuppeteer interface above.
// We can't extend from it directly because some method names conflict in type-incompatible ways.
toClick(selector: string | MatchSelector, options?: ExpectToClickOptions): Promise<void>;
toDisplayDialog(block: () => Promise<void>): Promise<Dialog>;
toFill(selector: string | MatchSelector, value: string, options?: ExpectTimingActions): Promise<void>;
toFillForm(selector: string | MatchSelector, value: { [key: string]: any}, options?: ExpectTimingActions): Promise<void>;
toMatch(matcher: string | RegExp, options?: ExpectTimingActions): Promise<void>;
toMatchElement(selector: string | MatchSelector, options?: ExpectToClickOptions): Promise<ElementHandle>;
toSelect(selector: string | MatchSelector, valueOrText: string, options?: ExpectTimingActions): Promise<void>;
toUploadFile(selector: string | MatchSelector, filePath: string, options?: ExpectTimingActions): Promise<void>;
}
declare module 'expect' {
interface Matchers<R> {
// These must all match the ExpectPuppeteer interface above.
// We can't extend from it directly because some method names conflict in type-incompatible ways.
toClick(selector: string | MatchSelector, options?: ExpectToClickOptions): Promise<void>;
toDisplayDialog(block: () => Promise<void>): Promise<Dialog>;
toFill(selector: string | MatchSelector, value: string, options?: ExpectTimingActions): Promise<void>;
toFillForm(selector: string | MatchSelector, value: { [key: string]: any}, options?: ExpectTimingActions): Promise<void>;
toMatch(matcher: string | RegExp, options?: ExpectTimingActions): Promise<void>;
toMatchElement(selector: string | MatchSelector, options?: ExpectToClickOptions): Promise<ElementHandle>;
toSelect(selector: string | MatchSelector, valueOrText: string, options?: ExpectTimingActions): Promise<void>;
toUploadFile(selector: string | MatchSelector, filePath: string, options?: ExpectTimingActions): Promise<void>;
}
}

Expand Down
6 changes: 6 additions & 0 deletions types/expect-puppeteer/package.json
@@ -0,0 +1,6 @@
{
"private": true,
"dependencies": {
"expect": "^29.0.0"
}
}
42 changes: 37 additions & 5 deletions types/heft-jest/index.d.ts
Expand Up @@ -3,10 +3,42 @@
// Definitions by: Pete Gonzalez <https://github.com/octogonz>
// Ian Clanton-Thuon <https://github.com/iclanton>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 4.3
// Minimum TypeScript Version: 4.5

/// <reference types="jest" />
/// <reference path="./mocked.d.ts" />
type MockInstance<T> = import('jest-mock').MockInstance<T>;

namespace mocked {
type MockableFunction = (...args: any[]) => any;
type MethodKeysOf<T> = { [K in keyof T]: T[K] extends MockableFunction ? K : never }[keyof T];
type PropertyKeysOf<T> = { [K in keyof T]: T[K] extends MockableFunction ? never : K }[keyof T];
type ArgumentsOf<T> = T extends (...args: infer A) => any ? A : never;
type ConstructorArgumentsOf<T> = T extends new (...args: infer A) => any ? A : never;

interface MockWithArgs<T extends MockableFunction> extends MockInstance<T> {
new (...args: ConstructorArgumentsOf<T>): T;
(...args: ArgumentsOf<T>): ReturnType<T>;
}

type MaybeMockedConstructor<T> = T extends new (...args: any[]) => infer R
? MockInstance<(...args: ConstructorArgumentsOf<T>) => R>
: {};
type MockedFunction<T extends MockableFunction> = MockWithArgs<T> & { [K in keyof T]: T[K] };
type MockedFunctionDeep<T extends MockableFunction> = MockWithArgs<T> & MockedObjectDeep<T>;
type MockedObject<T> = MaybeMockedConstructor<T> &
{ [K in MethodKeysOf<T>]: T[K] extends MockableFunction ? MockedFunction<T[K]> : T[K] } &
{ [K in PropertyKeysOf<T>]: T[K] };
type MockedObjectDeep<T> = MaybeMockedConstructor<T> &
{ [K in MethodKeysOf<T>]: T[K] extends MockableFunction ? MockedFunctionDeep<T[K]> : T[K] } &
{ [K in PropertyKeysOf<T>]: MaybeMockedDeep<T[K]> };

type MaybeMockedDeep<T> = T extends MockableFunction
? MockedFunctionDeep<T>
: T extends object
? MockedObjectDeep<T>
: T;

type MaybeMocked<T> = T extends MockableFunction ? MockedFunction<T> : T extends object ? MockedObject<T> : T;
}

/**
* Tests can use the `mocked()` function to access additional properties that
Expand All @@ -32,5 +64,5 @@
*
* https://kulshekhar.github.io/ts-jest/user/test-helpers
*/
declare function mocked<T>(item: T, deep?: false): mocked.MaybeMocked<T>;
declare function mocked<T>(item: T, deep: true): mocked.MaybeMockedDeep<T>;
function mocked<T>(item: T, deep?: false): mocked.MaybeMocked<T>;
function mocked<T>(item: T, deep: true): mocked.MaybeMockedDeep<T>;
Comment on lines +67 to +68
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this really necessary? Jest has jest.mocked() helper (it was moved from ts-jest), is that not sufficient?

By the way, typings of jest.mocked() were reworked recently and the copy above is already outdated. For reference see: https://github.com/facebook/jest/blob/835a93666a69202de2a0429cd5445cb5f56d2cea/packages/jest-mock/src/index.ts#L34-L92, and: https://github.com/facebook/jest/blob/835a93666a69202de2a0429cd5445cb5f56d2cea/packages/jest-mock/src/index.ts#L1219-L1230

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So should this be changed to the following then?

declare global mocked: typeof import('@jest/globals').mocked

I’m not familiar with heft-jest. It’s just affected by the updates.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was looking through Heft’s docs. The way they use Jest does not work with ts-jest, so to have mocked() working they copied it to @types/heft-jest. Seemed like they are fine to deprecate @types/heft-jest after Heft will ship Jest v28, which has jest.mocked() builtin. I think that would be the best solution. See microsoft/rushstack#3609

60 changes: 0 additions & 60 deletions types/heft-jest/mocked.d.ts

This file was deleted.

6 changes: 6 additions & 0 deletions types/heft-jest/package.json
@@ -0,0 +1,6 @@
{
"private": true,
"dependencies": {
"jest-mock": "^29.0.0"
}
}
12 changes: 5 additions & 7 deletions types/jest-axe/index.d.ts
Expand Up @@ -4,8 +4,6 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 4.3

/// <reference types="jest" />

import { AxeResults, Result, RunOptions, Spec } from 'axe-core';

export interface JestAxeConfigureOptions extends RunOptions {
Expand Down Expand Up @@ -69,13 +67,13 @@ export const toHaveNoViolations: {
toHaveNoViolations: IToHaveNoViolations;
};

declare global {
namespace jest {
interface Matchers<R, T> {
toHaveNoViolations(): R;
}
declare module 'expect' {
interface Matchers<R> {
toHaveNoViolations(): R;
}
}

declare global {
// axe-core depends on a global Node
interface Node {}
}
3 changes: 2 additions & 1 deletion types/jest-axe/package.json
@@ -1,6 +1,7 @@
{
"private": true,
"dependencies": {
"axe-core": "^3.5.5"
"axe-core": "^3.5.5",
"expect": "^29.0.0"
}
}
9 changes: 5 additions & 4 deletions types/jest-expect-message/index.d.ts
Expand Up @@ -5,17 +5,18 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 4.3

/// <reference types="jest"/>
import { Matchers } from 'expect';

declare namespace jest {
interface Expect {
// tslint:disable-next-line: no-single-declare-module
declare module 'expect' {
interface BaseExpect {
remcohaszing marked this conversation as resolved.
Show resolved Hide resolved
/**
* The `expect` function is used every time you want to test a value.
* You will rarely call `expect` by itself.
*
* @param actual The value to apply matchers against.
* @param message Clarification message
*/
<T = any>(actual: T, message: string): JestMatchers<T>;
(actual: any, message: string): Matchers<void>;
Comment on lines -19 to +20
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to be sure. Removal of the generic could possibly mess up other matchers. For example, does it work with .resolves chainer?

}
}
7 changes: 2 additions & 5 deletions types/jest-expect-message/jest-expect-message-tests.ts
@@ -1,6 +1,3 @@
import 'jest';
import 'jest-expect-message';
import { expect } from 'expect';

declare const expect: jest.Expect;

expect(2, "Two is always two").toBe(2);
expect(2, 'Two is always two').toBe(2);
6 changes: 6 additions & 0 deletions types/jest-expect-message/package.json
@@ -0,0 +1,6 @@
{
"private": true,
"dependencies": {
"expect": "^29.0.0"
}
}
10 changes: 3 additions & 7 deletions types/jest-image-snapshot/index.d.ts
Expand Up @@ -6,8 +6,6 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 4.3

/// <reference types="jest" />

import { PixelmatchOptions } from 'pixelmatch';
import { Options as SSIMOptions } from 'ssim.js';

Expand Down Expand Up @@ -140,10 +138,8 @@ export function updateSnapshotState<TObject, TPartial>(
partialSnapshotState: TPartial,
): TObject & TPartial;

declare global {
namespace jest {
interface Matchers<R, T> {
toMatchImageSnapshot(options?: MatchImageSnapshotOptions): R;
}
declare module 'expect' {
interface Matchers<R> {
toMatchImageSnapshot(options?: MatchImageSnapshotOptions): R;
}
}
3 changes: 3 additions & 0 deletions types/jest-image-snapshot/jest-image-snapshot-tests.ts
@@ -1,10 +1,13 @@
import { expect } from 'expect';
import {
configureToMatchImageSnapshot,
MatchImageSnapshotOptions,
toMatchImageSnapshot,
updateSnapshotState,
} from 'jest-image-snapshot';

declare const it: any;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be typed through @types/jest? Or perhaps simply to import {it} from '@jest/globals'?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The value of it is actually irrelevant. It just makes the tests look more representative. If it’s imported from @types/jest or @jest/globals, this would add a dependency (dev dependencies are not allowed in DefinitelyTyped).

Copy link
Contributor

Choose a reason for hiding this comment

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

Fine with me. It just felt like a regression. I am not a maintainer of any @types/* packages, just wanted to draw attention.


it('should be able to use toMatchImageSnapshot in a test', () => {
expect.extend({ toMatchImageSnapshot });

Expand Down
1 change: 1 addition & 0 deletions types/jest-image-snapshot/package.json
@@ -1,6 +1,7 @@
{
"private": true,
"dependencies": {
"expect": "^29.0.0",
"ssim.js": "^3.1.1"
}
}