testing-library / jest-dom

:owl: Custom jest matchers to test the state of the DOM
https://testing-library.com/docs/ecosystem-jest-dom
MIT License
4.44k stars 401 forks source link

Does not work with vitest 1.x.x #567

Open kibertoad opened 10 months ago

kibertoad commented 10 months ago

jest-dom TypeScript build breaks if jest-dom assertions (such as toBeInTheDocument) are used in vitest files, when using newer version of vitest (1.x)

versions

Relevant code or config:

Test:

expect(screen.getByText('anytext')).toBeInTheDocument()

tsconfig.json:

"types": ["vite/client", "@testing-library/jest-dom/vitest"]

What you did:

Try to build tests via tsc

What happened:

- error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.

25   expect(screen.getByText('anytext')).toBeInTheDocument()

Reproduction:

See Relevant code or config

Problem description:

This prevents testing-library from working with newer vitest.

Suggested solution:

Support newer vitest versions within jest-dom.

This may be related to https://github.com/vitest-dev/vitest/issues/4688

andykenward commented 10 months ago

@kibertoad Have you followed the with vitest setup guide https://github.com/testing-library/jest-dom#with-vitest ?

// In your own vitest-setup.js (or any other name)
import '@testing-library/jest-dom/vitest'

// In vitest.config.js add (if you haven't already)
setupFiles: ['./vitest-setup.js']
kibertoad commented 10 months ago

yup. vite.config.ts:

        setupFiles: './test/setup.ts',

test/setup.ts:

/// <reference types="@lokalise/styled/dist/testing-setup" /> This includes global types (not handled by import below unfortunately)
import '@lokalise/styled/testing-setup'
import '@testing-library/jest-dom/vitest'

It works with 0.x vitest, but doesn't with 1.x

andykenward commented 10 months ago

In your tsconfig.json try adding to your include the setup.ts file.

{
  //..tsconfig.json
  "include": ["./test/setup.ts"]
}

I would remove the usage of "types": ["vite/client", "@testing-library/jest-dom/vitest"].

Be great if you could put up an example repo or codesandbox so we can recreate the issue and debug it.

MatthieuJnon commented 10 months ago

I had the same issue you had. This is how I fixed it, maybe it helps you.

Even though versions of vitest and related libraries were all updated in package.json, I did npm ls vitest and realized I still had a rogue 0.34 vitest. I think the issue is because I didn't upgrade with npm update, I reverted the package lock, and did npm update (with all the updated versions in package.json) and it was all good afterwards. No more rogue <1 version of vitest.

Horsty80 commented 10 months ago

I've update to

"vitest": "^1.2.0", "@testing-library/jest-dom": "^6.2.0",

with the @andykenward docs and everything is working fine for toBeInTheDocument assert I don't have TS error

raulfdm commented 10 months ago

Weird that it seems I have everything correctly but I still get the error:

The setup file inside ./tests/setupFiles/testingLibrary.ts

import '@testing-library/jest-dom/vitest'

My tsconfig.json:

{
  "include": [
    "remix.env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "./tests/setupFiles/testingLibrary.ts"
  ],
  // ...rest
  // baseUrl is "." in compiler options
}

My vitest.config.ts file:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    coverage: {
      include: ['app/**'],
    },
    clearMocks: true,
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./tests/setupFiles/testingLibrary.ts'],
    css: true,
    silent: process.env.CI === 'true',
    retry: 2,
  },
})

... and my package versions:

pnpm -F my-project ls @testing-library/jest-dom vitest typescript
Legend: production dependency, optional only, dev only

my-project /path/to/monorepo/apps/my-project

devDependencies:
@testing-library/jest-dom 6.2.0
typescript 5.3.3
vitest 1.2.0

With all that in place, I still get the error:

error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'

I notice one thing though, in the @testing-library/jest-dom/vitest, we're overriding @vitest/expect module:

import {type expect} from 'vitest'
import {type TestingLibraryMatchers} from './matchers'

export {}
declare module '@vitest/expect' {
  interface JestAssertion<T = any>
    extends TestingLibraryMatchers<
      ReturnType<typeof expect.stringContaining>,
      T
    > {}
}

https://github.com/testing-library/jest-dom/blob/1fb156c2b544e0069c56a72a2f1909fe04850f6c/types/vitest.d.ts

I don't have @vitest/expect listed in my package.json file and even though I know it's a dependency of vitest and it's being used under-the-hood, I guess that's the issue. That's because if I change the module declaration from @vitest/expect to vitest:

import {type expect} from 'vitest'
import {type TestingLibraryMatchers} from './matchers'

export {}
-declare module '@vitest/expect' {
+declare module 'vitest' {
  interface JestAssertion<T = any>
    extends TestingLibraryMatchers<
      ReturnType<typeof expect.stringContaining>,
      T
    > {}
}

... it worked as intended.

I don't know if it's something related to pnpm, or monorepos.

My workaround was doing by hand what the testing-library/vitest abstraction is doing:

import * as matchers from '@testing-library/jest-dom/matchers'
import { expect } from 'vitest'

expect.extend(matchers)

declare module 'vitest' { // vitest instead `@vitest/expect`
  interface JestAssertion<T = any>
    extends matchers.TestingLibraryMatchers<
      ReturnType<typeof expect.stringContaining>,
      T
    > {}
}
carlosvq commented 9 months ago

I'm having the same issue after upgrading from 0.34 to 1.2.2

bracki commented 9 months ago

I couldn't get it to work. My problem was having the tests in a tests folder. So the when I change the include in tsconfig.json to read it works:

"include": ["src", "tests"]
opswiz commented 7 months ago

Weird that it seems I have everything correctly but I still get the error:

The setup file inside ./tests/setupFiles/testingLibrary.ts

import '@testing-library/jest-dom/vitest'

My tsconfig.json:

{
  "include": [
    "remix.env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "./tests/setupFiles/testingLibrary.ts"
  ],
  // ...rest
  // baseUrl is "." in compiler options
}

My vitest.config.ts file:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    coverage: {
      include: ['app/**'],
    },
    clearMocks: true,
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./tests/setupFiles/testingLibrary.ts'],
    css: true,
    silent: process.env.CI === 'true',
    retry: 2,
  },
})

... and my package versions:

pnpm -F my-project ls @testing-library/jest-dom vitest typescript
Legend: production dependency, optional only, dev only

my-project /path/to/monorepo/apps/my-project

devDependencies:
@testing-library/jest-dom 6.2.0
typescript 5.3.3
vitest 1.2.0

With all that in place, I still get the error:

error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'

I notice one thing though, in the @testing-library/jest-dom/vitest, we're overriding @vitest/expect module:

import {type expect} from 'vitest'
import {type TestingLibraryMatchers} from './matchers'

export {}
declare module '@vitest/expect' {
  interface JestAssertion<T = any>
    extends TestingLibraryMatchers<
      ReturnType<typeof expect.stringContaining>,
      T
    > {}
}

https://github.com/testing-library/jest-dom/blob/1fb156c2b544e0069c56a72a2f1909fe04850f6c/types/vitest.d.ts

I don't have @vitest/expect listed in my package.json file and even though I know it's a dependency of vitest and it's being used under-the-hood, I guess that's the issue. That's because if I change the module declaration from @vitest/expect to vitest:

import {type expect} from 'vitest'
import {type TestingLibraryMatchers} from './matchers'

export {}
-declare module '@vitest/expect' {
+declare module 'vitest' {
  interface JestAssertion<T = any>
    extends TestingLibraryMatchers<
      ReturnType<typeof expect.stringContaining>,
      T
    > {}
}

... it worked as intended.

I don't know if it's something related to pnpm, or monorepos.

My workaround was doing by hand what the testing-library/vitest abstraction is doing:

import * as matchers from '@testing-library/jest-dom/matchers'
import { expect } from 'vitest'

expect.extend(matchers)

declare module 'vitest' { // vitest instead `@vitest/expect`
  interface JestAssertion<T = any>
    extends matchers.TestingLibraryMatchers<
      ReturnType<typeof expect.stringContaining>,
      T
    > {}
}

Facing this same issue with pnpm with monorepos.

jtiala commented 7 months ago

I notice one thing though, in the @testing-library/jest-dom/vitest, we're overriding @vitest/expect module:

import {type expect} from 'vitest'
import {type TestingLibraryMatchers} from './matchers'

export {}
declare module '@vitest/expect' {
  interface JestAssertion<T = any>
    extends TestingLibraryMatchers<
      ReturnType<typeof expect.stringContaining>,
      T
    > {}
}

https://github.com/testing-library/jest-dom/blob/1fb156c2b544e0069c56a72a2f1909fe04850f6c/types/vitest.d.ts

I don't have @vitest/expect listed in my package.json file and even though I know it's a dependency of vitest and it's being used under-the-hood, I guess that's the issue.

I found out that if you install @vitest/expect manually it fixes the TS error.

MWhite-22 commented 4 months ago

PNPM wont allow the dependencies of dependencies to be accessed from workspaces.

You can no-hoist vitest and its dependencies, or optionally install @vitest/expect directly.