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

Missing type definitions for expect imported from @jest/globals #426

Open
arty-name opened this issue Jan 10, 2022 · 21 comments
Open

Missing type definitions for expect imported from @jest/globals #426

arty-name opened this issue Jan 10, 2022 · 21 comments
Labels
good first issue Good for newcomers

Comments

@arty-name
Copy link

  • @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.

@gnapse gnapse added the good first issue Good for newcomers label Jan 10, 2022
@gnapse
Copy link
Member

gnapse commented Jan 10, 2022

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.

@arty-name
Copy link
Author

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.

@IanVS
Copy link
Contributor

IanVS commented Jan 13, 2022

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. :(

@muratx10
Copy link

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

@JoSuzuki
Copy link

JoSuzuki commented Mar 9, 2022

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.

@rtruong
Copy link

rtruong commented Apr 13, 2022

Is there a solution for this yet?

@aalpgiray
Copy link

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);

@arty-name
Copy link
Author

Looks like Jest@28 should enable that

@yordis
Copy link

yordis commented May 29, 2022

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;

@mrazauskas
Copy link

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'.

@Vinnl
Copy link

Vinnl commented Jul 5, 2023

I submitted a PR to DefinitelyTyped that I think should fix this issue: DefinitelyTyped/DefinitelyTyped#65981

@MattyBalaam
Copy link

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

@gnapse
Copy link
Member

gnapse commented Jul 6, 2023

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
Copy link

Vinnl commented Jul 6, 2023

@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 :/

@abhi-works
Copy link

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.

DefinitelyTyped/DefinitelyTyped#65991 Can this reversal PR be temporarily approved to prevent any impact on the systems?

@Vinnl
Copy link

Vinnl commented Jul 6, 2023

@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?

@abhi-works
Copy link

@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
Copy link

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

@mrazauskas
Copy link

mrazauskas commented Jul 6, 2023

@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
Copy link

@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

@DevinXian
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests