From 78554eb791116fcfefa07fc48ade944ef4f9f6ba Mon Sep 17 00:00:00 2001 From: Marcin Date: Mon, 11 Nov 2024 22:09:00 +0100 Subject: [PATCH] test: add jest-dom matchers and eslint plugin --- .eslintrc.json | 2 + package.json | 2 + pnpm-lock.yaml | 89 ++++++++++++++++++++++++++++++++++++++++++ tests/setup.ts | 1 + tests/shallow.test.tsx | 8 ++-- tests/ssr.test.tsx | 8 ++-- tsconfig.json | 3 +- vitest.config.ts | 1 + 8 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 tests/setup.ts diff --git a/.eslintrc.json b/.eslintrc.json index c98b6b693c..0a045cca95 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -21,6 +21,7 @@ "react-hooks", "import", "@vitest", + "jest-dom", "testing-library", "eslint-plugin-react-compiler" ], @@ -107,6 +108,7 @@ "overrides": [ { "extends": [ + "plugin:jest-dom/recommended", "plugin:testing-library/react", "plugin:@vitest/legacy-recommended" ], diff --git a/package.json b/package.json index 975dc0ddad..9e4fd25633 100644 --- a/package.json +++ b/package.json @@ -112,6 +112,7 @@ "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-replace": "^6.0.1", "@rollup/plugin-typescript": "^12.1.1", + "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", "@types/node": "^22.8.4", "@types/react": "^18.3.12", @@ -127,6 +128,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jest-dom": "^5.4.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-compiler": "19.0.0-beta-6fc168f-20241025", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 93ef8e885a..995f9b1cb8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ devDependencies: '@rollup/plugin-typescript': specifier: ^12.1.1 version: 12.1.1(rollup@4.24.3)(typescript@5.6.3) + '@testing-library/jest-dom': + specifier: ^6.6.3 + version: 6.6.3 '@testing-library/react': specifier: ^16.0.1 version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@19.0.0-rc.0)(react@19.0.0-rc.0) @@ -65,6 +68,9 @@ devDependencies: eslint-plugin-import: specifier: ^2.31.0 version: 2.31.0(@typescript-eslint/parser@8.12.2)(eslint@8.57.0) + eslint-plugin-jest-dom: + specifier: ^5.4.0 + version: 5.4.0(@testing-library/dom@10.4.0)(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.2.1 version: 5.2.1(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.3.3) @@ -125,6 +131,10 @@ devDependencies: packages: + /@adobe/css-tools@4.4.0: + resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} + dev: true + /@ampproject/remapping@2.3.0: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -1203,6 +1213,19 @@ packages: pretty-format: 27.5.1 dev: true + /@testing-library/jest-dom@6.6.3: + resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + dependencies: + '@adobe/css-tools': 4.4.0 + aria-query: 5.3.0 + chalk: 3.0.0 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + lodash: 4.17.21 + redent: 3.0.0 + dev: true + /@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@19.0.0-rc.0)(react@19.0.0-rc.0): resolution: {integrity: sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==} engines: {node: '>=18'} @@ -1840,6 +1863,14 @@ packages: pathval: 2.0.0 dev: true + /chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -1888,6 +1919,10 @@ packages: which: 2.0.2 dev: true + /css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + dev: true + /cssstyle@4.1.0: resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} engines: {node: '>=18'} @@ -2040,6 +2075,10 @@ packages: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} dev: true + /dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dev: true + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true @@ -2347,6 +2386,22 @@ packages: - supports-color dev: true + /eslint-plugin-jest-dom@5.4.0(@testing-library/dom@10.4.0)(eslint@8.57.0): + resolution: {integrity: sha512-yBqvFsnpS5Sybjoq61cJiUsenRkC9K32hYQBFS9doBR7nbQZZ5FyO+X7MlmfM1C48Ejx/qTuOCgukDUNyzKZ7A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6', yarn: '>=1'} + peerDependencies: + '@testing-library/dom': ^8.0.0 || ^9.0.0 || ^10.0.0 + eslint: ^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + peerDependenciesMeta: + '@testing-library/dom': + optional: true + dependencies: + '@babel/runtime': 7.26.0 + '@testing-library/dom': 10.4.0 + eslint: 8.57.0 + requireindex: 1.2.0 + dev: true + /eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.3.3): resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -2919,6 +2974,11 @@ packages: engines: {node: '>=0.8.19'} dev: true + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: @@ -3303,6 +3363,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3375,6 +3439,11 @@ packages: mime-db: 1.52.0 dev: true + /min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -3681,6 +3750,14 @@ packages: resolve: 1.22.8 dev: true + /redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + dev: true + /redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} dev: true @@ -3712,6 +3789,11 @@ packages: set-function-name: 2.0.2 dev: true + /requireindex@1.2.0: + resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} + engines: {node: '>=0.10.5'} + dev: true + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -4039,6 +4121,13 @@ packages: engines: {node: '>=4'} dev: true + /strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: true + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 0000000000..a9d0dd31aa --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest' diff --git a/tests/shallow.test.tsx b/tests/shallow.test.tsx index 431b4651cc..8a885f85da 100644 --- a/tests/shallow.test.tsx +++ b/tests/shallow.test.tsx @@ -140,7 +140,7 @@ describe('useShallow', () => { render() expect(countRenders).toBe(1) - expect(screen.getByTestId('test-shallow').textContent).toBe('a,b,c') + expect(screen.getByTestId('test-shallow')).toHaveTextContent('a,b,c') act(() => { useMyStore.setState({ a: 4 }) // This will not cause a re-render. @@ -153,7 +153,7 @@ describe('useShallow', () => { }) expect(countRenders).toBe(2) - expect(screen.getByTestId('test-shallow').textContent).toBe('a,b,c,d') + expect(screen.getByTestId('test-shallow')).toHaveTextContent('a,b,c,d') }) it('does not cause stale closure issues', () => { @@ -178,10 +178,10 @@ describe('useShallow', () => { render() - expect(screen.getByTestId('test-shallow').textContent).toBe('a,b,c,0') + expect(screen.getByTestId('test-shallow')).toHaveTextContent('a,b,c,0') fireEvent.click(screen.getByTestId('test-shallow')) - expect(screen.getByTestId('test-shallow').textContent).toBe('a,b,c,1') + expect(screen.getByTestId('test-shallow')).toHaveTextContent('a,b,c,1') }) }) diff --git a/tests/ssr.test.tsx b/tests/ssr.test.tsx index 155afe884c..e325fe2d2e 100644 --- a/tests/ssr.test.tsx +++ b/tests/ssr.test.tsx @@ -50,7 +50,7 @@ describe.skipIf(!React.version.startsWith('18'))( document.body.appendChild(container) container.innerHTML = view - expect(container.textContent).toContain('bears: 0') + expect(container).toHaveTextContent(/bears: 0/) await act(async () => { hydrateRoot( @@ -62,7 +62,7 @@ describe.skipIf(!React.version.startsWith('18'))( }) const bearCountText = await screen.findByText('bears: 1') - expect(bearCountText).not.toBeNull() + expect(bearCountText).toBeInTheDocument() document.body.removeChild(container) }) it('should not have hydration errors', async () => { @@ -90,7 +90,7 @@ describe.skipIf(!React.version.startsWith('18'))( document.body.appendChild(container) container.innerHTML = view - expect(container.textContent).toContain('bears: 0') + expect(container).toHaveTextContent(/bears: 0/) const consoleMock = vi.spyOn(console, 'error') @@ -111,7 +111,7 @@ describe.skipIf(!React.version.startsWith('18'))( expect(consoleMock).toHaveBeenCalledTimes(0) const bearCountText = await screen.findByText('bears: 1') - expect(bearCountText).not.toBeNull() + expect(bearCountText).toBeInTheDocument() document.body.removeChild(container) }) }, diff --git a/tsconfig.json b/tsconfig.json index b430476d47..0da73c70af 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,6 +13,7 @@ "verbatimModuleSyntax": true, "declaration": true, "isolatedDeclarations": true, + "types": ["@testing-library/jest-dom"], "noEmit": true, "baseUrl": ".", "paths": { @@ -20,6 +21,6 @@ "zustand/*": ["./src/*.ts"] } }, - "include": ["src/**/*", "tests/**/*"], + "include": ["src/**/*", "tests/**/*", "tests/setup.ts"], "exclude": ["node_modules", "dist"] } diff --git a/vitest.config.ts b/vitest.config.ts index ae40c35d47..f842619583 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -17,6 +17,7 @@ export default defineConfig({ environment: 'jsdom', dir: 'tests', reporters: 'basic', + setupFiles: ['tests/setup.ts'], coverage: { include: ['src/**/'], reporter: ['text', 'json', 'html', 'text-summary'],