React-testing-library: How to make this extend-expect work in Typescript?

Created on 2 Apr 2018  路  18Comments  路  Source: testing-library/react-testing-library

extend-expect throws a couple more things onto extend and of course typescript doesnt like that. Is there a way to also expand the types or otherwise modify index.d.ts to accommodate for the changed type signature of expect?

for google purposes this is the error i get:

[ts] Property 'toHaveTextContent' does not exist on type 'Matchers<void>'.
any
TypeScript

Most helpful comment

@simonhaenisch thanks. Since jest is not an imported module, in jest.d.ts, I also had to declare this as a global, so:

declare global {
    namespace jest {
      interface Matchers<R> {
        toEndWith(value: string): CustomMatcherResult;
      }
  }
}

All 18 comments

No idea. Perhaps there are clues in jest-extended?

i just scanned through their code, they dont even have types -at all- so they're actually worse off than react-testing-library 馃槀

ok so i worked out how to use them, we might want to 1) document this 2) put this into the index.d.ts.

// standard stuff from the example
import * as React from 'react';
import {render, Simulate, wait} from 'react-testing-library'

// extends
import 'react-testing-library/extend-expect';
interface ExtendedMatchers extends jest.Matchers<void> {
  toHaveTextContent: (htmlElement: string) => object;
  toBeInTheDOM: () => void;
}

//usage example
test('displays greeting when clicking Load Greeting', async () => {
  const { getByLabelText, getByText, getByTestId, container } = render(
    <Tooltip label="hello world">Child</Tooltip>
  );
  (getByLabelText('name') as HTMLInputElement).value = 'Mary';
  (expect(getByTestId('greeting-text')) as ExtendedMatchers).toHaveTextContent(
    'Hello Mary'
  );
})

let me know how you want this to proceed kent. i can take care of this entirely in userland, but you could help a very little bit by including this in the index.d.ts

Seems fine to me. I don't maintain the typings myself, but if you want to help take over maintaining the typings that'd be super.

I would be happy to do that. I just realized though that any types that this lib ships with would bind it to a particular testing frame work, eg jest. so this is probably actually best solved in userland. I will just submit a minor documentation PR for a typescript section.

Actually, _this_ file _is_ specific to Jest so if there's a way to only apply these types if this file is utilized then that'd be fine.

@tsiq-swyx Thanks for the fix. @kentcdodds Somehow, I'm not getting the notifications on this project, even though I'm watching it ;) Checking manually now :)

Just passing by looking for solution for a similar issue. I've found out a solution. You can probably fix the issue by putting the following code in the typings of react-testing-library:

declare namespace jest {
  interface Matchers<R> {
    toHaveTextContent: (htmlElement: string) => object;
    toBeInTheDOM: () => void;
  }

  interface Expect {
    toHaveTextContent: (htmlElement: string) => object;
    toBeInTheDOM: () => void;
  }
}

It uses Declaration Merging.

Ok I realized that it seems that the issue is already fixed here: https://github.com/gnapse/jest-dom/pull/11

I just ran into the same issue and found a nice solution, similar to what @michalstocki was suggesting, but wanted to clarify it more. If you create a file called jest.d.ts, its namespace declaration will be merged with the one provided by Jest itself. For example, for a custom matcher

expect('string').toEndWith('ing');

you would extend the namespace

// custom jest.d.ts somewhere in the source

declare namespace jest {
  interface Matchers<R> {
    toEndWith(value: string): CustomMatcherResult;
  }
}

and implement

expect.extend({
  toEndWith: (actualString: string, expectedEnding: string) => ({
    message: `expected that ${actualString} ends with ${expectedEnding}`,
    pass: actualString.endsWith(expectedEnding),
  }),
});

Thought I'd leave this here because this is the first search result that came up for me :nerd_face:

@simonhaenisch thanks. Since jest is not an imported module, in jest.d.ts, I also had to declare this as a global, so:

declare global {
    namespace jest {
      interface Matchers<R> {
        toEndWith(value: string): CustomMatcherResult;
      }
  }
}

If anyone else ends up here after running through the stuff from TestingJavascript.com and getting an error about react-testing-library's matchers not existing on type 'Assertion', the issue is actually due to a conflict between Jest and Cypress, and has nothing to do with react-testing-library. The easiest fix I found was just adding the cypress folder to the excludes in my tsconfig.json in the root of my project:

{
  ...lots of config,
  "exclude": [
    "node_modules",
    "webpack",
    "jest",
    "cypress",
  ]
}

Hopefully this helps someone!

I couldn't make any of the solutions above to work, so I went for a quick and dirty solution:.

const myExpect: any = Object.assign(expect);

myExpect.extend({
...

I couldn't make any of the solutions above to work, so I went for a quick and dirty solution:.

const myExpect: any = Object.assign(expect);

myExpect.extend({
...

In that case, one other way is to simply change the extension to .js if type checking is not that crucial in that test :)

None of the above options seemed to work for me (I'm using WebStorm 2019.2 and jest-dom 4.1.0).

I had to put the following in my test file.

I could NOT put these imports in a separate setupTests.ts or *.d.ts, that didn't work

import '@testing-library/jest-dom'
import '@testing-library/jest-dom/extend-expect'

Then I stopped getting warnings like "Error:(27, 16) TS2339: Property 'toBeVisible' does not exist on type 'Matchers'."

Was this page helpful?
0 / 5 - 0 ratings

Related issues

julienw picture julienw  路  4Comments

kangweichan picture kangweichan  路  3Comments

FlorianBurgevin picture FlorianBurgevin  路  3Comments

addamove picture addamove  路  3Comments

AirborneEagle picture AirborneEagle  路  3Comments