From b5e0c5634ff3b608ea2a04e26dd5630559256d2e Mon Sep 17 00:00:00 2001 From: Antonio Stoilkov Date: Wed, 13 Sep 2023 11:21:46 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=97=20=F0=9F=94=A5=20remove=20Jest,=20?= =?UTF-8?q?use=20Vitest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintignore | 1 + package.json | 13 ++++++------- test/{browser.tsx => browser.test.tsx} | 25 +++++++++++++++---------- test/{server.tsx => server.test.tsx} | 11 ++++------- tsconfig.json | 6 +++--- vitest.config.ts | 9 +++++++++ 6 files changed, 38 insertions(+), 27 deletions(-) rename test/{browser.tsx => browser.test.tsx} (96%) rename test/{server.tsx => server.test.tsx} (93%) create mode 100644 vitest.config.ts diff --git a/.eslintignore b/.eslintignore index 6494ec8..634563a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ /test *.d.ts +vitest.config.ts diff --git a/package.json b/package.json index bac1e3c..449b459 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "build": "tsc", "size": "yarn run build && size-limit", "lint": "eslint --cache --format=pretty --ext=.ts ./", - "test": "yarn run build && yarn run lint && if [[ -z $CI ]]; then jest --coverage --coverageReporters=text; else jest --coverage; fi", + "test": "yarn run build && yarn run lint && if [[ -z $CI ]]; then vitest --run --coverage.enabled --coverage.reporter=text --coverage.reporter=html --coverage.provider=istanbul; else vitest --run --coverage.enabled --coverage.provider=istanbul; fi", "release": "yarn run build && np", "prettier": "prettier --write --config .prettierrc.yaml {*.ts,*.json}" }, @@ -51,12 +51,12 @@ }, "devDependencies": { "@size-limit/preset-small-lib": "^8.0.0", - "@testing-library/react": "^13.3.0", - "@types/jest": "^28.1.6", + "@testing-library/react": "^14.0.0", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", "@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/parser": "^6.3.0", + "@vitest/coverage-istanbul": "^0.34.4", "confusing-browser-globals": "^1.0.11", "eslint": "^8.21.0", "eslint-config-strictest": "^0.8.1", @@ -65,8 +65,7 @@ "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.5.0", "eslint-plugin-unicorn": "^43.0.2", - "jest": "^29.4.1", - "jest-environment-jsdom": "^29.4.1", + "jsdom": "^22.1.0", "np": "^7.6.3", "prettier": "^2.6.2", "react": "^18.1.0", @@ -74,8 +73,8 @@ "react-test-renderer": "^18.1.0", "size-limit": "^8.0.0", "superjson": "^1.9.1", - "ts-jest": "^28.0.7", - "typescript": "^5.1.6" + "typescript": "^5.1.6", + "vitest": "^0.34.4" }, "size-limit": [ { diff --git a/test/browser.tsx b/test/browser.test.tsx similarity index 96% rename from test/browser.tsx rename to test/browser.test.tsx index 2bc35d6..6844ced 100644 --- a/test/browser.tsx +++ b/test/browser.test.tsx @@ -1,8 +1,13 @@ -import util from 'util' +/** + * @vitest-environment jsdom + */ + +import util from 'node:util' import superjson from 'superjson' import { act, render, renderHook } from '@testing-library/react' import React, { useEffect, useLayoutEffect, useMemo } from 'react' -import useLocalStorageState, { inMemoryData } from '../src/useLocalStorageState' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' +import useLocalStorageState, { inMemoryData } from '../src/useLocalStorageState.js' beforeEach(() => { // Throw an error when `console.error()` is called. This is especially useful in a React tests @@ -19,7 +24,7 @@ beforeEach(() => { // - "Warning: Cannot update a component (`Component`) while rendering a different component // (`Component`). To locate the bad setState() call inside `Component`, follow the stack trace // as described in https://reactjs.org/link/setstate-in-render" - jest.spyOn(console, 'error').mockImplementation((format: string, ...args: any[]) => { + vi.spyOn(console, 'error').mockImplementation((format: string, ...args: any[]) => { throw new Error(util.format(format, ...args)) }) }) @@ -130,7 +135,7 @@ describe('useLocalStorageState()', () => { }) test('handles errors thrown by localStorage', () => { - jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { throw new Error() }) @@ -150,7 +155,7 @@ describe('useLocalStorageState()', () => { test('simulate blocking all the cookies in Safari', () => { // in Safari, even just accessing `localStorage` throws "SecurityError: The operation is // insecure." - jest.spyOn(window, 'localStorage', 'get').mockImplementation(() => { + vi.spyOn(window, 'localStorage', 'get').mockImplementation(() => { throw new Error() }) @@ -235,7 +240,7 @@ describe('useLocalStorageState()', () => { }) test('returns the same update function when the value is saved', () => { - const functionMock = jest.fn() + const functionMock = vi.fn() const { rerender } = renderHook(() => { const [, setTodos] = useLocalStorageState('todos', { defaultValue: ['first', 'second'], @@ -550,7 +555,7 @@ describe('useLocalStorageState()', () => { describe('in memory fallback', () => { test('can retrieve data from in memory storage', () => { - jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { throw new Error() }) @@ -580,7 +585,7 @@ describe('useLocalStorageState()', () => { }) test('isPersistent returns true when localStorage.setItem() throws an error but the value is the default value', () => { - jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { throw new Error() }) @@ -593,7 +598,7 @@ describe('useLocalStorageState()', () => { }) test('isPersistent returns false when localStorage.setItem() throws an error', () => { - jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { throw new Error() }) @@ -616,7 +621,7 @@ describe('useLocalStorageState()', () => { useLocalStorageState('todos', { defaultValue: ['first', 'second'] }), ) - jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { throw new Error() }) diff --git a/test/server.tsx b/test/server.test.tsx similarity index 93% rename from test/server.tsx rename to test/server.test.tsx index d9b4e40..d3fc975 100644 --- a/test/server.tsx +++ b/test/server.test.tsx @@ -1,11 +1,8 @@ -/** - * @jest-environment node - */ - -import util from 'util' +import util from 'node:util' import ReactDOM from 'react-dom/server' import React, { MutableRefObject } from 'react' -import useLocalStorageState from '../src/useLocalStorageState' +import useLocalStorageState from '../src/useLocalStorageState.js' +import { beforeEach, describe, expect, test, vi } from 'vitest' function renderHookOnServer(useHook: () => T): { result: MutableRefObject } { const result: MutableRefObject = { @@ -37,7 +34,7 @@ beforeEach(() => { // - "Warning: Cannot update a component (`Component`) while rendering a different component // (`Component`). To locate the bad setState() call inside `Component`, follow the stack trace // as described in https://reactjs.org/link/setstate-in-render" - jest.spyOn(console, 'error').mockImplementation((format: string, ...args: any[]) => { + vi.spyOn(console, 'error').mockImplementation((format: string, ...args: any[]) => { throw new Error(util.format(format, ...args)) }) }) diff --git a/tsconfig.json b/tsconfig.json index b90fed8..9fd14e0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,11 @@ { "compilerOptions": { "target": "ES6", - "module": "ES2015", + "module": "NodeNext", "jsx": "react", "esModuleInterop": true, - "moduleResolution": "Node16", "declaration": true, + "moduleResolution": "nodenext", // strict options ensuring more stable code "strict": true, @@ -16,7 +16,7 @@ "noFallthroughCasesInSwitch": true, "forceConsistentCasingInFileNames": true, - "types": ["node", "jest"], + "types": ["node"], // - ℹī¸ https://www.typescriptlang.org/tsconfig#isolatedModules // - 😃 Deno requires "isolatedModules" to be set to `true` diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..4ceeaff --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + restoreMocks: true, + // otherwise @testing-library/react can't cleanup after tests + globals: true, + }, +})