jest-dom icon indicating copy to clipboard operation
jest-dom copied to clipboard

Missing type definitions for expect imported from @jest/globals

Open arty-name opened this issue 3 years ago • 22 comments

  • @testing-library/jest-dom version: 5.16.1
  • node version: v16.13.1
  • yarn version: 1.22.17

Relevant code or config:

import { expect } from '@jest/globals';
import '@testing-library/jest-dom';
expect(container).toHaveAttribute('hidden');

What you did:

I imported jest globals from '@jest/globals'

What happened:

I got the TypeScript error message: TS2339: Property 'toHaveAttribute' does not exist on type 'Matchers '.

Reproduction:

import { expect } from '@jest/globals';
import '@testing-library/jest-dom';
expect(container).toHaveAttribute('hidden');

Problem description:

The custom matchers provided by jest-dom cannot be used in TypeScript if the expect is imported from @jest/globals. Only the global expect is modified, apparently.

Suggested solution:

Extend the interface of expect in the @jest/globals as well.

arty-name avatar Jan 10 '22 11:01 arty-name

Thanks for reporting this.

I have to say, I see this more as a problem with jest than with jest-dom, if really the solution involves duplicating the code that extends the interface of expect's return type. I hope there would a better solution where you extend it once, and no matter where you get expect from, it should work.

gnapse avatar Jan 10 '22 13:01 gnapse

After a deeper look, I see that the types of jest-dom extend jest.Matchers

Meanwhile, the types of @jest/globals simply re-export the type of the expect package

I’d naively expect that it’s rather expect.Matchers that should be extended, but after some poking around, I feel that I am out of my depth here.

arty-name avatar Jan 10 '22 15:01 arty-name

I'm importing expect directly from the expect package, and also struggling to get types working, since the way that jest-dom extends the types is by modifying the jest module, it seems. But I don't have that, since I'm using expect outside of jest. :(

IanVS avatar Jan 13 '22 22:01 IanVS

In my case, I've just switched to expect that comes from jest, not from jest/globals and it works like a charm.

muratx10 avatar Jan 22 '22 09:01 muratx10

I wasn't able to solve it the proper way either, but I've made a patch on the types coming from @jest/globals, in a declarations.d.ts file at the root of my project I've added the following configuration:

import type { TestingLibraryMatchers } from '@types/testing-library__jest-dom/matchers';
// import type { expect } from '@jest/globals'; <-- this was necessary because of my specific setup of cypress + jest, otherwise it was inferring the wrong expect

declare module '@jest/globals/node_modules/expect/build/types' {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/ban-types
  export interface Matchers<R = void, T = {}>
    extends TestingLibraryMatchers<typeof expect.stringContaining, R> {}
}

this feels a bit risky because it relies on a path that could change at any moment (@jest/globals/node_modules/expect/build/types), but it was the best solution I could find for now.

JoSuzuki avatar Mar 09 '22 20:03 JoSuzuki

Is there a solution for this yet?

rtruong avatar Apr 13 '22 23:04 rtruong

I assumed this should worked but couldn't get it to work yet.

import matchers from '@testing-library/jest-dom/matchers';
import { expect } from '@jest/globals';

expect.extend(matchers);

aalpgiray avatar Apr 25 '22 11:04 aalpgiray

Looks like Jest@28 should enable that

arty-name avatar May 03 '22 09:05 arty-name

I added the following to my globals.d.ts file


import type { TestingLibraryMatchers } from '@types/testing-library__jest-dom/matchers';

declare module '@jest/expect' {
  export interface Matchers<R = void, T = {}> extends TestingLibraryMatchers<typeof expect.stringContaining, R> {}
}

@jest/globals exports from @jest/expect the expect function

import type { JestExpect } from '@jest/expect';
export declare const expect: JestExpect;

yordis avatar May 29 '22 02:05 yordis

Just to add: since Jest v28 the above should work equally with declare module 'expect' or declare module '@jest/expect'.

By the way, it might be a good idea to include this augmentation declaration in @types/testing-library__jest-dom. So that matchers would have correct types for those who import { expect } form '@jest/globals'.

mrazauskas avatar Jun 02 '22 12:06 mrazauskas

I submitted a PR to DefinitelyTyped that I think should fix this issue: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/65981

Vinnl avatar Jul 05 '23 14:07 Vinnl

Wow, thanks @Vinnl I hit this problem yesterday and your fix has got rid of my issue :)

MattyBalaam avatar Jul 06 '23 06:07 MattyBalaam

I'm glad that this has fixed the issue for some. Unfortunately, it seems to be a source of problem for others. See https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/65987#discussioncomment-6371630

And we already have a pull request proposing to revert the changes: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/65990

I'm not clear what to do here. Would appreciate some help.

gnapse avatar Jul 06 '23 14:07 gnapse

@gnapse Hmm, I'm also not sure. I don't know exactly how to reproduce, but looking at the error message, it looks like the problem might be that we're setting T = {}, whereas in expect, it's unknown:

https://github.com/jestjs/jest/blob/1f019afdcdfc54a6664908bb45f343db4e3d0848/packages/expect/src/types.ts#L139

However, if I try to change it in the @testing-library/jest-dom type definitions for the jest namespace, I get the same error message - because @types/jest does define it to be {}:

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e42746838dabadb4aa0542017f178a3c118f4e18/types/jest/index.d.ts#L844

I've submitted a followup PR that only changes it for expect and hope that that fixes it, but I can't verify because I don't know how to reproduce, and I'm not 100% confident about what I'm doing :/

Vinnl avatar Jul 06 '23 14:07 Vinnl

I'm glad that this has fixed the issue for some. Unfortunately, it seems to be a source of problem for others. See DefinitelyTyped/DefinitelyTyped#65987 (comment)

And we already have a pull request proposing to revert the changes: DefinitelyTyped/DefinitelyTyped#65990

I'm not clear what to do here. Would appreciate some help.

@Vinnl @gnapse We face this issue while generating dist folder with script like "build:esm":"tsc" in package.json node_modules/@types/testing-library__jest-dom/index.d.ts:21:15 - error TS2428: All declarations of 'Matchers' must have identical type parameters. node_modules/expect/build/index.d.ts:107:26 - error TS2428: All declarations of 'Matchers' must have identical type parameters.

https://github.com/DefinitelyTyped/DefinitelyTyped/pull/65991 Can this reversal PR be temporarily approved to prevent any impact on the systems?

abhi-works avatar Jul 06 '23 15:07 abhi-works

@abhi-works Is your code public somewhere that I could try it out? Or alternatively, could you open node_modules/@types/testing-library__jest-dom/index.d.ts and apply these changes (i.e. replace the first {} by unknown on line 21) manually, and report back whether that fixes the issue for you?

Vinnl avatar Jul 06 '23 17:07 Vinnl

@Vinnl This issue occurs specifically when utilizing the tsc (TypeScript compiler) to generate a compiled distribution bundle. Code is not public,Will try manually in my local

abhi-works avatar Jul 06 '23 17:07 abhi-works

Alternatively, you can replicate the issue by creating a simple React TypeScript component and its corresponding test case that makes use of @testing-library/jest-dom. Afterwards, you can generate the build using tsc to observe the problem @Vinnl

abhi-works avatar Jul 06 '23 17:07 abhi-works

@abhi-works Could you tell Jest and TS version you are using?

If I remember it right, the type arguments if the Matchers interface differ between versions of Jest. That might be tricky.

mrazauskas avatar Jul 06 '23 17:07 mrazauskas

@abhi-works Is your code public somewhere that I could try it out? Or alternatively, could you open node_modules/@types/testing-library__jest-dom/index.d.ts and apply these changes (i.e. replace the first {} by unknown on line 21) manually, and report back whether that fixes the issue for you?

@Vinnl This issue occurs specifically when utilizing the tsc (TypeScript compiler) to generate a compiled distribution bundle. Code is not public,Will try manually in my local

@Vinnl @gnapse https://github.com/DefinitelyTyped/DefinitelyTyped/pull/65991/files Works locally

abhi-works avatar Jul 06 '23 18:07 abhi-works

I added the following to my globals.d.ts file

import type { TestingLibraryMatchers } from '@types/testing-library__jest-dom/matchers';

declare module '@jest/expect' {
  export interface Matchers<R = void, T = {}> extends TestingLibraryMatchers<typeof expect.stringContaining, R> {}
}

@jest/globals exports from @jest/expect the expect function

import type { JestExpect } from '@jest/expect';
export declare const expect: JestExpect;

we'd better to install @jest/expect explicitly

DevinXian avatar Apr 16 '24 02:04 DevinXian