jest-dom
jest-dom copied to clipboard
Missing type definitions for expect imported from @jest/globals
@testing-library/jest-domversion: 5.16.1nodeversion: v16.13.1yarnversion: 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.
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.
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.
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. :(
In my case, I've just switched to expect that comes from jest, not from jest/globals and it works like a charm.
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.
Is there a solution for this yet?
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);
Looks like Jest@28 should enable that
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;
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'.
I submitted a PR to DefinitelyTyped that I think should fix this issue: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/65981
Wow, thanks @Vinnl I hit this problem yesterday and your fix has got rid of my issue :)
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 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 :/
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 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
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 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.
@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.tsand apply these changes (i.e. replace the first{}byunknownon 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
I added the following to my
globals.d.tsfileimport 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/globalsexports from@jest/expecttheexpectfunctionimport type { JestExpect } from '@jest/expect'; export declare const expect: JestExpect;
we'd better to install @jest/expect explicitly