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

Property 'toBeOnTheScreen' does not exist on type 'JestMatchers<ReactTestInstance>' (TS project)

Open Aure77 opened this issue 3 years ago • 20 comments

  • react-native or expo: RN
  • @testing-library/react-native version: ^11.4.0
  • jest-preset: "react-native"
  • react-native version: 0.70.6
  • node version: 16

Relevant code or config:

const menuTitle = screen.getByText("My wonderful title");
expect(menuTitle).toBeOnTheScreen(); // tsc error

What you did:

Try to use custom matcher in a TS project that check types with tsc.

What happened:

Typescript check error.

Reproduction:

const menuTitle = screen.getByText("My wonderful title");
expect(menuTitle).toBeOnTheScreen(); // tsc error

Problem description:

Custom matcher of jest-native are not exposed as TS types. So a TS project have issue when build with TS compiler (tsc): Ex: Property 'toBeOnTheScreen' does not exist on type 'JestMatchers<ReactTestInstance>' (TS project)

Suggested solution:

expose types in package.json

Aure77 avatar Jan 20 '23 10:01 Aure77

@Aure77 we have an basic example app in RNTL repo that showcases correct config for RNTL + JestNative + TS. Pls compare your config with that.

Matchers should be properly exposed for TS. Make sure that you are using the latest version of Jest Native (5.4.1) because of #138.

mdjastrzebski avatar Jan 26 '23 12:01 mdjastrzebski

@Aure77 I had the same problem, in my setup I had .jest/setup.ts which meant that the include option in tsconfig.json wasn't including this file (since it was src/**/*). Maybe you have a similar issue.

jonathanj avatar Jan 26 '23 14:01 jonathanj

Hey, you have forgot to install testing-library/jest-native Install it and then check it will work.

Thanks,

komalharmale avatar Feb 03 '23 06:02 komalharmale

I had same issue. All my config files were ok.

I fixed it importing: import '@testing-library/jest-native/'; on every test.

Example:

import React from 'react';
import { render, screen } from '@testing-library/react-native';
import '@testing-library/jest-native/'; // HERE!!
import MyComponent from '../MyComponent';


it('should render with the correct props', () => {
  const onPress = jest.fn();

  render(
    <TestWrapper>
      <MyComponent text="Click Here" variant="filled" onPress={onPress} />
    </TestWrapper>
  );

  const btnText = screen.getByText('Click Here');
  
  expect(btnText).toBeOnTheScreen();

});

emflomed17 avatar Feb 10 '23 20:02 emflomed17

@emflomed17 did you follow the installation instructions at https://github.com/testing-library/jest-native#usage ?

In correct setting adding import '@testing-library/jest-native/extend-expect'; to your jest-setup.js (make sure it's setupFilesAfterEnv ) file should be enough to make matchers work correctly.

mdjastrzebski avatar Feb 17 '23 15:02 mdjastrzebski

I experience the same. It only goes away if like @emflomed17 mentions, you import it on the test or extend expect inline in the test file.

The only other thing to mention is I'm in a yarn workspace within a monorepo? Not sure that matters though. The error clearly goes away when you bring in the import line to the test file specifically. The tests all pass whether or not TS has an error about the matcher

package.json config

  "jest": {
    "preset": "@testing-library/react-native",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json"
    ],
    "setupFilesAfterEnv": [
      "./jest-setup.js"
    ],
    "setupFiles": [
      "../../node_modules/react-native-gesture-handler/jestSetup.js"
    ],
    "transformIgnorePatterns": [
      "../../node_modules/(?!(jest-)?@?react-native|@react-native-community|@react-navigation)"
    ],
    "collectCoverage": true,
    "coverageThreshold": {
      "global": {
        "branches": 7,
        "functions": 15,
        "lines": 20,
        "statements": 20
      }
    }
  }

jest-setup.js config

import { configure } from '@testing-library/react-native'

// Import Jest Native matchers
import '@testing-library/jest-native/extend-expect'

// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper')

// Mock Async storage
import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock'
jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage)

// Mock Safe Area insets
jest.mock('react-native-safe-area-context', () => {
  const inset = { top: 0, right: 0, bottom: 0, left: 0 }
  return {
    ...jest.requireActual('react-native-safe-area-context'),
    SafeAreaProvider: jest.fn(({ children }) => children),
    SafeAreaConsumer: jest.fn(({ children }) => children(inset)),
    useSafeAreaInsets: jest.fn(() => inset),
    useSafeAreaFrame: jest.fn(() => ({ x: 0, y: 0, width: 390, height: 844 })),
  }
})

// Mock Reanimated
jest.mock('react-native-reanimated', () => {
  const Reanimated = require('react-native-reanimated/mock')

  // The mock for `call` immediately calls the callback which is incorrect
  // So we override it with a no-op
  Reanimated.default.call = () => {}

  return Reanimated
})

// Enable excluding hidden elements from the queries by default
configure({
  defaultIncludeHiddenElements: false,
})

frankcalise avatar Mar 06 '23 15:03 frankcalise

@Aure77 @frankcalise @emflomed17 Does the issue affect only toBeOnTheScreen matcher or other marchers as well?

mdjastrzebski avatar Mar 07 '23 09:03 mdjastrzebski

@emflomed17 did you follow the installation instructions at https://github.com/testing-library/jest-native#usage ?

In correct setting adding import '@testing-library/jest-native/extend-expect'; to your jest-setup.js (make sure it's setupFilesAfterEnv ) file should be enough to make matchers work correctly.

setupFilesAfterEnv doesn't impact TS typing on jest files (may only be used at runtime by jest runner)

Aure77 avatar Mar 07 '23 10:03 Aure77

@mdjastrzebski

If affects all matchers extended by jest-native, none of them show up in the intellisense / are underlined taht the property doesn't exist. Same for toBeEnabled, toBeDisabled etc.

Although, this seemed to help in my tsconfig.json

  "compilerOptions": {
    "types": ["@testing-library/jest-native", "jest"]
  },

frankcalise avatar Mar 07 '23 14:03 frankcalise

"types": ["@testing-library/jest-native", "jest"]

With this workaround, you need to add all your types manually (including @types/node, @types/react-native & all your custom types from dependencies...). I prefer import "@testing-library/jest-native" in each test file instead (more explicit but boring)

Aure77 avatar Mar 07 '23 15:03 Aure77

I used a triple slash directive to get the correct types added:

/// <reference types="@testing-library/jest-native/extend-expect" />

This was in a .d.ts file that the ts compiler had visibility of (e.g. src/types/jest.d.ts)

callumskeet-bom avatar Mar 15 '23 02:03 callumskeet-bom

I was having issues getting types for this and reanimated's jest extensions. My updated file now looks like this:

import { JestNativeMatchers } from '@testing-library/jest-native/extend-expect'

declare global {
  namespace jest {
    interface Matchers<R> extends JestNativeMatchers<R> {
      // declaring this here as the library has the wrong typedef
      toHaveAnimatedStyle(
        style: Record<string, unknown>[] | Record<string, unknown>,
        options?: { exact?: boolean },
      ): R
    }
  }
}

callumskeet-bom avatar Mar 23 '23 04:03 callumskeet-bom

Recommended Workarounds 🚑

After some investigation I've found that the TS types (tsc --noEmit or intellisense in VSCode) work correctly in three alternative cases:

  1. You have a top-level declarations.d.ts file in your project and it contains:
/// <reference types="@testing-library/jest-native" />

This works because it causes typescript to globally import Jest type extension.

---- OR ----

  1. You use import '@testing-library/jest-native/extend-expect'; in your jest-setup.ts file (note: it has to be .ts), which is added to setupFilesAfterEnv Jest config.

Not sure why this works, but it works fine with allowJs: false TypeScript compiler option.

---- OR ----

  1. tsconfig.json includes allowJs: true as compiler option and you have jest-setup.js file which contains:
import '@testing-library/jest-native/extend-expect'; 

This basically disables type-checking on expect(...).toXxx matches, but the VS Code intellisense still works correctly.

mdjastrzebski avatar May 08 '23 21:05 mdjastrzebski

TBH I have no idea for "automatic" resolution, that would propagate Jest type extension just by including @testing-library/jest-native/extend-expect" in the setupFilesAfterEnv`.

Perhaps you folks will have any idea: @callumskeet-bom, @Aure77 , @frankcalise how to do such thing.

mdjastrzebski avatar May 08 '23 21:05 mdjastrzebski

I've added the documentation for official TS workarounds: https://github.com/testing-library/jest-native#typescript-support

mdjastrzebski avatar May 09 '23 09:05 mdjastrzebski

@mdjastrzebski thanks for the documentation.

As far as the "automatic" resolution, I have to dive deeper into it. However, I know jest-dom adds custom matchers and the setup is documented as so:

  • testing/library jest-dom: https://github.com/testing-library/jest-dom#usage

frankcalise avatar May 09 '23 13:05 frankcalise

Talking about VS Code intellisense, I've tried every workaround and only following solutions worked

  • adding following totsconfig.json
"compilerOptions": {
    "types": ["@testing-library/jest-native", "jest"]
  },
  • adding import '@testing-library/jest-native/extend-expect'; to every .test file

not sure why the declarations.d.ts solution is not working - is there anything additional I have to do? If I declare some random module there and try to import it, then the VS Code intellisense finds that module, so the file is loaded properly.

Using latest "@testing-library/jest-native": "^5.4.2", with "typescript": "^5.0.4"

CptFabulouso avatar May 17 '23 07:05 CptFabulouso

@CptFabulouso could you check if using TS 'jest-setup.ts' + 'include' option in 'tsconfig.json' as describe here solves the issue for you?

mdjastrzebski avatar May 17 '23 11:05 mdjastrzebski

@mdjastrzebski Yes, that change in tsconfig.json was the missing part, thank you. So to summarise I have:

  • jest-setup.ts file with:
import '@testing-library/jest-native/extend-expect';
  • and in tsconfig.json
 "include": [
    ...
    "./jest-setup.ts"
  ],

CptFabulouso avatar May 18 '23 05:05 CptFabulouso

I had the same issue. The error was the exclude option in tsconfig.json, which included the folder containing the test files. TypeScript will not attempt to type-check or compile them.

"exclude": ["src/__tests__"]

moriwang avatar Aug 13 '23 05:08 moriwang