chore(tests): migrate to vitest (#1753)

* test: migrate to vitest

* test: try #1 remove CI-MATRIX tags

* test: try 2 remove import/require replace

* chore: remove unused scripts/assignments

* chore(test-multiple-builds.yml): remove import/require replace script

* fix merging main

---------

Co-authored-by: daishi <daishi@axlight.com>
This commit is contained in:
Arjun Vegda 2023-05-04 00:25:24 -04:00 committed by GitHub
parent 630ba1a3e4
commit 496a466c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 876 additions and 1514 deletions

View File

@ -20,7 +20,7 @@
"prettier",
"react-hooks",
"import",
"jest"
"vitest"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
@ -48,10 +48,12 @@
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"jest/consistent-test-it": [
"vitest/consistent-test-it": [
"error",
{ "fn": "it", "withinDescribe": "it" }
],
"import/namespace": "off",
"import/named": "off",
"import/order": [
"error",
{

View File

@ -68,8 +68,6 @@ jobs:
if: ${{ matrix.build == 'umd' && matrix.env == 'development' }}
run: |
sed -i~ "s/<rootDir>\/src\(.*\)\.ts/<rootDir>\/dist\/umd\1.development.js/" package.json
sed -i~ 's/"test:ci":.*,$/"test:ci": "jest",/' package.json
sed -i~ 's/= await import(/= require(/' tests/devtools.test.tsx
sed -i~ "s/it('\[${DEVTOOLS_SKIP}\]/it.skip('/" tests/devtools.test.tsx
env:
DEVTOOLS_SKIP: ${{ matrix.devtools-skip }}
@ -77,8 +75,6 @@ jobs:
if: ${{ matrix.build == 'umd' && matrix.env == 'production' }}
run: |
sed -i~ "s/<rootDir>\/src\(.*\)\.ts/<rootDir>\/dist\/umd\1.production.js/" package.json
sed -i~ 's/"test:ci":.*,$/"test:ci": "jest",/' package.json
sed -i~ 's/= await import(/= require(/' tests/devtools.test.tsx
sed -i~ "s/it('\[${DEVTOOLS_SKIP}\]/it.skip('/" tests/devtools.test.tsx
env:
DEVTOOLS_SKIP: ${{ matrix.devtools-skip }}

View File

@ -68,8 +68,6 @@ jobs:
sed -i~ '1s/^/import React from "react";/' tests/*.tsx
sed -i~ 's/"jsx": "react-jsx"/"jsx": "react"/' tsconfig.json
sed -i~ 's/import\.meta\.env[?]\.MODE/"DEVELOPMENT".toLowerCase()/' src/*.ts src/*/*.ts
sed -i~ 's/"test:ci":.*,$/"test:ci": "jest",/' package.json
sed -i~ 's/= await import(/= require(/' tests/devtools.test.tsx
sed -i~ "s/it('\[${DEVTOOLS_SKIP}\]/it.skip('/" tests/devtools.test.tsx
env:
DEVTOOLS_SKIP: ${{ matrix.devtools-skip }}

View File

@ -46,5 +46,4 @@ jobs:
- name: Test ${{ matrix.typescript }}
run: |
yarn add -D typescript@${{ matrix.typescript }}
rm -r node_modules/parse5
yarn tsc --noEmit

View File

@ -91,12 +91,10 @@
"eslint": "eslint --no-eslintrc --c .eslintrc.json --fix '*.{js,json}' '{src,tests}/**/*.{ts,tsx}'",
"eslint:ci": "eslint --no-eslintrc --c .eslintrc.json '*.{js,json}' '{src,tests}/**/*.{ts,tsx}'",
"pretest": "tsc --noEmit",
"test": "yarn node --experimental-vm-modules $(yarn bin jest)",
"test:ci": "yarn node --experimental-vm-modules $(yarn bin jest)",
"test:dev": "yarn node --experimental-vm-modules $(yarn bin jest) --watch --no-coverage",
"test:coverage:watch": "yarn node --experimental-vm-modules $(yarn bin jest) --watch",
"test": "vitest --ui --coverage",
"test:ci": "vitest",
"patch-d-ts": "node -e \"var {entries}=require('./rollup.config.js');require('shelljs').find('dist/**/*.d.ts').forEach(f=>{entries.forEach(({find,replacement})=>require('shelljs').sed('-i',new RegExp(' from \\''+find.source.slice(0,-1)+'\\';$'),' from \\''+replacement+'\\';',f));require('shelljs').sed('-i',/ from '(\\.[^']+)\\.ts';$/,' from \\'\\$1\\';',f)})\"",
"copy": "shx cp -r dist/src/* dist/esm && shx cp -r dist/src/* dist && shx rm -rf dist/src && shx rm -rf dist/{src,tests} && downlevel-dts dist dist/ts3.4 && shx cp package.json readme.md LICENSE dist && json -I -f dist/package.json -e \"this.private=false; this.devDependencies=undefined; this.optionalDependencies=undefined; this.scripts=undefined; this.prettier=undefined; this.jest=undefined;\"",
"copy": "shx cp -r dist/src/* dist/esm && shx cp -r dist/src/* dist && shx rm -rf dist/src && shx rm -rf dist/{src,tests} && downlevel-dts dist dist/ts3.4 && shx cp package.json readme.md LICENSE dist && json -I -f dist/package.json -e \"this.private=false; this.devDependencies=undefined; this.optionalDependencies=undefined; this.scripts=undefined; this.prettier=undefined;\"",
"patch-esm-ts": "node -e \"require('shelljs').find('dist/esm/**/*.d.ts').forEach(f=>{var f2=f.replace(/\\.ts$/,'.mts');require('fs').copyFileSync(f,f2);require('shelljs').sed('-i',/ from '(\\.[^']+)';$/,' from \\'\\$1.mjs\\';',f2);require('shelljs').sed('-i',/^declare module '(\\.[^']+)'/,'declare module \\'\\$1.mjs\\'',f2)})\""
},
"engines": {
@ -132,44 +130,9 @@
"url": "https://github.com/pmndrs/zustand/issues"
},
"homepage": "https://github.com/pmndrs/zustand",
"jest": {
"rootDir": ".",
"testEnvironment": "jsdom",
"preset": "ts-jest/presets/default-esm",
"transform": {
"^.+\\.(t|j)sx?$": [
"ts-jest",
{
"useESM": true
}
]
},
"extensionsToTreatAsEsm": [
".ts",
".tsx"
],
"moduleNameMapper": {
"^zustand$": "<rootDir>/src/index.ts",
"^zustand/(.*)$": "<rootDir>/src/$1.ts"
},
"modulePathIgnorePatterns": [
"dist"
],
"testRegex": "test.(js|ts|tsx)$",
"coverageDirectory": "./coverage/",
"collectCoverage": true,
"coverageReporters": [
"json",
"html",
"text",
"text-summary"
],
"collectCoverageFrom": [
"src/**/*.{js,ts,tsx}",
"tests/**/*.{js,ts,tsx}"
]
},
"dependencies": {
"@vitest/ui": "^0.30.1",
"eslint-plugin-vitest": "^0.1.4",
"use-sync-external-store": "1.2.0"
},
"devDependencies": {
@ -192,6 +155,7 @@
"@types/use-sync-external-store": "^0.0.3",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"@vitest/coverage-c8": "^0.30.1",
"concurrently": "^8.0.1",
"downlevel-dts": "^0.11.0",
"esbuild": "^0.17.14",
@ -199,13 +163,11 @@
"eslint-config-prettier": "^8.8.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"immer": "^9.0.21",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"jsdom": "^21.1.1",
"json": "^11.0.0",
"prettier": "^2.8.7",
"react": "^18.2.0",
@ -214,8 +176,8 @@
"rollup": "^3.20.2",
"rollup-plugin-esbuild": "^5.0.0",
"shx": "^0.3.4",
"ts-jest": "^29.0.5",
"typescript": "^5.0.3"
"typescript": "^5.0.3",
"vitest": "^0.30.1"
},
"peerDependencies": {
"immer": ">=9.0",

View File

@ -6,9 +6,9 @@ import {
useLayoutEffect,
useState,
} from 'react'
import { afterEach, expect, it, jest } from '@jest/globals'
import { act, fireEvent, render } from '@testing-library/react'
import ReactDOM from 'react-dom'
import { afterEach, expect, it, vi } from 'vitest'
import { create } from 'zustand'
import type { StoreApi } from 'zustand'
@ -306,7 +306,7 @@ it('can call useBoundStore with progressively more arguments', async () => {
})
it('can throw an error in selector', async () => {
console.error = jest.fn()
console.error = vi.fn()
type State = { value: string | number }
const initialState: State = { value: 'foo' }
@ -353,7 +353,7 @@ it('can throw an error in selector', async () => {
})
it('can throw an error in equality checker', async () => {
console.error = jest.fn()
console.error = vi.fn()
type State = { value: string | number }
const initialState: State = { value: 'foo' }
@ -442,7 +442,7 @@ it('can set the store', () => {
it('both NaN should not update', () => {
const { setState, subscribe } = create<number>(() => NaN)
const fn = jest.fn()
const fn = vi.fn()
subscribe(fn)
setState(NaN)

View File

@ -6,8 +6,8 @@ import {
useEffect,
useState,
} from 'react'
import { afterEach, it, jest } from '@jest/globals'
import { render } from '@testing-library/react'
import { afterEach, it, vi } from 'vitest'
import { create } from 'zustand'
import type { StoreApi } from 'zustand'
import createContext from 'zustand/context'
@ -123,7 +123,7 @@ it('uses context store api', async () => {
})
it('throws error when not using provider', async () => {
console.error = jest.fn()
console.error = vi.fn()
class ErrorBoundary extends ClassComponent<
{ children?: ReactNode | undefined },

View File

@ -1,11 +1,4 @@
import {
afterEach,
beforeEach,
describe,
expect,
it,
jest,
} from '@jest/globals'
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { devtools, redux } from 'zustand/middleware'
import { StoreApi, createStore } from 'zustand/vanilla'
@ -23,12 +16,12 @@ type TupleOfEqualLength<Arr extends unknown[], T> = number extends Arr['length']
type Connection = {
subscribers: ((message: unknown) => void)[]
api: {
subscribe: jest.Mock<(f: (message: unknown) => void) => void>
unsubscribe: jest.Mock<any>
send: jest.Mock<any>
init: jest.Mock<any>
error: jest.Mock<any>
dispatch?: jest.Mock<any>
subscribe: Mock<[f: (m: unknown) => void], () => void>
unsubscribe: Mock<any>
send: Mock<any>
init: Mock<any>
error: Mock<any>
dispatch?: Mock<any>
}
}
const namedConnections = new Map<string | undefined, Connection>()
@ -89,7 +82,7 @@ function getKeyFromOptions(options: any): string | undefined {
}
const extensionConnector = {
connect: jest.fn((options: any) => {
connect: vi.fn((options: any) => {
const key = getKeyFromOptions(options)
//console.log('options', options)
const areNameUndefinedMapsNeeded =
@ -99,14 +92,14 @@ const extensionConnector = {
: namedConnections
const subscribers: Connection['subscribers'] = []
const api = {
subscribe: jest.fn((f: (m: unknown) => void) => {
subscribe: vi.fn((f: (m: unknown) => void) => {
subscribers.push(f)
return () => {}
}),
unsubscribe: jest.fn(),
send: jest.fn(),
init: jest.fn(),
error: jest.fn(),
unsubscribe: vi.fn(),
send: vi.fn(),
init: vi.fn(),
error: vi.fn(),
}
connectionMap.set(
areNameUndefinedMapsNeeded ? options.testConnectionId : key,
@ -121,7 +114,7 @@ const extensionConnector = {
;(window as any).__REDUX_DEVTOOLS_EXTENSION__ = extensionConnector
beforeEach(() => {
jest.resetModules()
vi.resetModules()
extensionConnector.connect.mockClear()
namedConnections.clear()
unnamedConnections.clear()
@ -142,7 +135,7 @@ describe('If there is no extension installed...', () => {
let savedConsoleWarn: any
beforeEach(() => {
savedConsoleWarn = console.warn
console.warn = jest.fn()
console.warn = vi.fn()
;(window as any).__REDUX_DEVTOOLS_EXTENSION__ = undefined
})
afterEach(() => {
@ -214,7 +207,7 @@ describe('when it receives a message of type...', () => {
it('does nothing', async () => {
const initialState = { count: 0 }
const api = createStore(devtools(() => initialState, { enabled: true }))
const setState = jest.spyOn(api, 'setState')
const setState = vi.spyOn(api, 'setState')
const [subscriber] = getNamedConnectionSubscribers(undefined)
subscriber({
@ -242,8 +235,8 @@ describe('when it receives a message of type...', () => {
it('does nothing even if there is `api.dispatch`', async () => {
const initialState = { count: 0 }
const api = createStore(devtools(() => initialState, { enabled: true }))
;(api as any).dispatch = jest.fn()
const setState = jest.spyOn(api, 'setState')
;(api as any).dispatch = vi.fn()
const setState = vi.spyOn(api, 'setState')
const [connectionSubscriber] = getNamedConnectionSubscribers(undefined)
connectionSubscriber({
@ -259,9 +252,9 @@ describe('when it receives a message of type...', () => {
it('dispatches with `api.dispatch` when `api.dispatchFromDevtools` is set to true', async () => {
const initialState = { count: 0 }
const api = createStore(devtools(() => initialState, { enabled: true }))
;(api as any).dispatch = jest.fn()
;(api as any).dispatch = vi.fn()
;(api as any).dispatchFromDevtools = true
const setState = jest.spyOn(api, 'setState')
const setState = vi.spyOn(api, 'setState')
const [connectionSubscriber] = getNamedConnectionSubscribers(undefined)
connectionSubscriber({
@ -279,11 +272,11 @@ describe('when it receives a message of type...', () => {
it('does not throw for unsupported payload', async () => {
const initialState = { count: 0 }
const api = createStore(devtools(() => initialState, { enabled: true }))
;(api as any).dispatch = jest.fn()
;(api as any).dispatch = vi.fn()
;(api as any).dispatchFromDevtools = true
const setState = jest.spyOn(api, 'setState')
const setState = vi.spyOn(api, 'setState')
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const [connectionSubscriber] = getNamedConnectionSubscribers(undefined)
expect(() => {
@ -388,7 +381,7 @@ describe('when it receives a message of type...', () => {
const initialState = { count: 0, increment }
const api = createStore(devtools(() => initialState, { enabled: true }))
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const [connection] = getNamedConnectionApis(undefined)
connection.init.mockClear()
@ -441,7 +434,7 @@ describe('when it receives a message of type...', () => {
const initialState = { count: 0, increment: () => {} }
const api = createStore(devtools(() => initialState, { enabled: true }))
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const [connection] = getNamedConnectionApis(undefined)
connection.send.mockClear()
@ -492,7 +485,7 @@ describe('when it receives a message of type...', () => {
const initialState = { count: 0, increment }
const api = createStore(devtools(() => initialState, { enabled: true }))
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const [connection] = getNamedConnectionApis(undefined)
connection.send.mockClear()
@ -632,7 +625,7 @@ describe('with redux middleware', () => {
it('[DEV-ONLY] warns about misusage', () => {
const originalConsoleWarn = console.warn
console.warn = jest.fn()
console.warn = vi.fn()
;(api as any).dispatch({ type: '__setState' as any })
expect(console.warn).toHaveBeenLastCalledWith(
'[zustand devtools middleware] "__setState" action type is reserved ' +
@ -1129,9 +1122,9 @@ describe('when create devtools was called multiple times with `name` option unde
...options3,
})
)
const setState1 = jest.spyOn(api1, 'setState')
const setState2 = jest.spyOn(api2, 'setState')
const setState3 = jest.spyOn(api3, 'setState')
const setState1 = vi.spyOn(api1, 'setState')
const setState2 = vi.spyOn(api2, 'setState')
const setState3 = vi.spyOn(api3, 'setState')
const [subscriber] = getUnnamedConnectionSubscribers(
options1.testConnectionId
@ -1195,12 +1188,12 @@ describe('when create devtools was called multiple times with `name` option unde
const api3 = createStore(
devtools(() => initialState3, { enabled: true, ...options3 })
)
;(api1 as any).dispatch = jest.fn()
;(api2 as any).dispatch = jest.fn()
;(api3 as any).dispatch = jest.fn()
const setState1 = jest.spyOn(api1, 'setState')
const setState2 = jest.spyOn(api2, 'setState')
const setState3 = jest.spyOn(api3, 'setState')
;(api1 as any).dispatch = vi.fn()
;(api2 as any).dispatch = vi.fn()
;(api3 as any).dispatch = vi.fn()
const setState1 = vi.spyOn(api1, 'setState')
const setState2 = vi.spyOn(api2, 'setState')
const setState3 = vi.spyOn(api3, 'setState')
const subscribers = getUnnamedConnectionSubscribers(
options1.testConnectionId,
@ -1240,15 +1233,15 @@ describe('when create devtools was called multiple times with `name` option unde
const api3 = createStore(
devtools(() => initialState3, { enabled: true, ...options3 })
)
;(api1 as any).dispatch = jest.fn()
;(api1 as any).dispatch = vi.fn()
;(api1 as any).dispatchFromDevtools = true
;(api2 as any).dispatch = jest.fn()
;(api2 as any).dispatch = vi.fn()
;(api2 as any).dispatchFromDevtools = true
;(api3 as any).dispatch = jest.fn()
;(api3 as any).dispatch = vi.fn()
;(api3 as any).dispatchFromDevtools = true
const setState1 = jest.spyOn(api1, 'setState')
const setState2 = jest.spyOn(api2, 'setState')
const setState3 = jest.spyOn(api3, 'setState')
const setState1 = vi.spyOn(api1, 'setState')
const setState2 = vi.spyOn(api2, 'setState')
const setState3 = vi.spyOn(api3, 'setState')
const subscribers = getUnnamedConnectionSubscribers(
options1.testConnectionId,
@ -1294,17 +1287,17 @@ describe('when create devtools was called multiple times with `name` option unde
const api3 = createStore(
devtools(() => initialState3, { enabled: true, ...options3 })
)
;(api1 as any).dispatch = jest.fn()
;(api1 as any).dispatch = vi.fn()
;(api1 as any).dispatchFromDevtools = true
;(api2 as any).dispatch = jest.fn()
;(api2 as any).dispatch = vi.fn()
;(api2 as any).dispatchFromDevtools = true
;(api3 as any).dispatch = jest.fn()
;(api3 as any).dispatch = vi.fn()
;(api3 as any).dispatchFromDevtools = true
const setState1 = jest.spyOn(api1, 'setState')
const setState2 = jest.spyOn(api2, 'setState')
const setState3 = jest.spyOn(api3, 'setState')
const setState1 = vi.spyOn(api1, 'setState')
const setState2 = vi.spyOn(api2, 'setState')
const setState3 = vi.spyOn(api3, 'setState')
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const [
connectionSubscriber1,
@ -1610,7 +1603,7 @@ describe('when create devtools was called multiple times with `name` option unde
devtools(() => initialState3, { enabled: true, ...options3 })
)
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const connections = getUnnamedConnectionApis(
options1.testConnectionId,
@ -1774,7 +1767,7 @@ describe('when create devtools was called multiple times with `name` option unde
devtools(() => initialState3, { enabled: true, ...options3 })
)
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const connections = getUnnamedConnectionApis(
options1.testConnectionId,
@ -1936,7 +1929,7 @@ describe('when create devtools was called multiple times with `name` option unde
devtools(() => initialState3, { enabled: true, ...options3 })
)
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const connections = getUnnamedConnectionApis(
options1.testConnectionId,
@ -2280,10 +2273,10 @@ describe('when create devtools was called multiple times with `name` and `store`
...options2,
})
)
const setState1 = jest.spyOn(api1, 'setState')
const setState2 = jest.spyOn(api2, 'setState')
const setState3 = jest.spyOn(api3, 'setState')
const setState4 = jest.spyOn(api4, 'setState')
const setState1 = vi.spyOn(api1, 'setState')
const setState2 = vi.spyOn(api2, 'setState')
const setState3 = vi.spyOn(api3, 'setState')
const setState4 = vi.spyOn(api4, 'setState')
const [subscriber] = getUnnamedConnectionSubscribers(
options1.testConnectionId
@ -2327,7 +2320,7 @@ describe('when create devtools was called multiple times with `name` and `store`
devtools(() => initialState2, { enabled: true, ...options2 })
)
const originalConsoleError = console.error
console.error = jest.fn()
console.error = vi.fn()
const [connectionSubscriber] = getNamedConnectionSubscribers(
getKeyFromOptions(options1)
@ -2386,10 +2379,10 @@ describe('when create devtools was called multiple times with `name` and `store`
const api2 = createStore(
newDevtools(() => initialState2, { enabled: true, ...options2 })
)
;(api1 as any).dispatch = jest.fn()
;(api2 as any).dispatch = jest.fn()
const setState1 = jest.spyOn(api1, 'setState')
const setState2 = jest.spyOn(api2, 'setState')
;(api1 as any).dispatch = vi.fn()
;(api2 as any).dispatch = vi.fn()
const setState1 = vi.spyOn(api1, 'setState')
const setState2 = vi.spyOn(api2, 'setState')
const subscribers = getNamedConnectionSubscribers(
getKeyFromOptions(options1),
@ -2435,12 +2428,12 @@ describe('when create devtools was called multiple times with `name` and `store`
const api2 = createStore(
newDevtools(() => initialState2, { enabled: true, ...options2 })
)
;(api1 as any).dispatch = jest.fn()
;(api1 as any).dispatch = vi.fn()
;(api1 as any).dispatchFromDevtools = true
;(api2 as any).dispatch = jest.fn()
;(api2 as any).dispatch = vi.fn()
;(api2 as any).dispatchFromDevtools = true
const setState1 = jest.spyOn(api1, 'setState')
const setState2 = jest.spyOn(api2, 'setState')
const setState1 = vi.spyOn(api1, 'setState')
const setState2 = vi.spyOn(api2, 'setState')
const subscribers = getNamedConnectionSubscribers(
getKeyFromOptions(options1),

View File

@ -1,4 +1,4 @@
import { describe, it } from '@jest/globals'
import { describe, it } from 'vitest'
import { create } from 'zustand'
import type { StoreApi } from 'zustand'
import {

View File

@ -1,6 +1,6 @@
import { StrictMode, useEffect } from 'react'
import { afterEach, describe, expect, it, jest } from '@jest/globals'
import { act, render, waitFor } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'
import { replacer, reviver } from './test-utils'
@ -22,9 +22,9 @@ const createPersistantStore = (initialValue: string | null) => {
state = null
}
const getItemSpy = jest.fn()
const setItemSpy = jest.fn()
const removeItemSpy = jest.fn()
const getItemSpy = vi.fn()
const setItemSpy = vi.fn()
const removeItemSpy = vi.fn()
return {
storage: { getItem, setItem, removeItem },
@ -41,7 +41,7 @@ describe('persist middleware with async configuration', () => {
})
it('can rehydrate state', async () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: async (name: string) =>
JSON.stringify({
@ -90,7 +90,7 @@ describe('persist middleware with async configuration', () => {
})
it('can throw rehydrate error', async () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: async () => {
@ -132,7 +132,7 @@ describe('persist middleware with async configuration', () => {
const { storage, setItemSpy } = createPersistantStore(null)
const createStore = () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
@ -192,9 +192,9 @@ describe('persist middleware with async configuration', () => {
})
it('can migrate persisted state', async () => {
const setItemSpy = jest.fn<() => void>()
const onRehydrateStorageSpy = jest.fn()
const migrateSpy = jest.fn(() => ({ count: 99 }))
const setItemSpy = vi.fn()
const onRehydrateStorageSpy = vi.fn()
const migrateSpy = vi.fn(() => ({ count: 99 }))
const storage = {
getItem: async () =>
@ -301,8 +301,8 @@ describe('persist middleware with async configuration', () => {
})
it('can correclty handle a missing migrate function', async () => {
console.error = jest.fn()
const onRehydrateStorageSpy = jest.fn()
console.error = vi.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: async () =>
JSON.stringify({
@ -341,8 +341,8 @@ describe('persist middleware with async configuration', () => {
})
it('can throw migrate error', async () => {
console.error = jest.fn()
const onRehydrateStorageSpy = jest.fn()
console.error = vi.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: async () =>
@ -387,8 +387,7 @@ describe('persist middleware with async configuration', () => {
})
it('passes the latest state to onRehydrateStorage and onHydrate on first hydrate', async () => {
const onRehydrateStorageSpy =
jest.fn<<S>(s: S) => (s?: S, e?: unknown) => void>()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: async () => JSON.stringify({ state: { count: 1 } }),
@ -410,7 +409,7 @@ describe('persist middleware with async configuration', () => {
* the 'onHydrate' listener set (which will be empty) is evaluated before the
* 'persist' API is exposed to the caller of 'create'/'createStore'.
*
* const onHydrateSpy = jest.fn()
* const onHydrateSpy = vi.fn()
* useBoundStore.persist.onHydrate(onHydrateSpy)
* ...
* await waitFor(() => expect(onHydrateSpy).toBeCalledWith({ count: 0 }))
@ -437,7 +436,7 @@ describe('persist middleware with async configuration', () => {
})
it('gives the merged state to onRehydrateStorage', async () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: async () =>
@ -623,7 +622,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(
() => ({
@ -701,7 +700,7 @@ describe('persist middleware with async configuration', () => {
})
it('can rehydrate state with custom deserialized Map', async () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: async () =>
JSON.stringify({
@ -749,7 +748,7 @@ describe('persist middleware with async configuration', () => {
const map = new Map()
const createStore = () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(() => ({ map }), {
name: 'test-storage',

View File

@ -1,4 +1,4 @@
import { afterEach, describe, expect, it, jest } from '@jest/globals'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'
import { replacer, reviver } from './test-utils'
@ -19,9 +19,9 @@ const createPersistentStore = (initialValue: string | null) => {
state = null
}
const getItemSpy = jest.fn()
const setItemSpy = jest.fn()
const removeItemSpy = jest.fn()
const getItemSpy = vi.fn()
const setItemSpy = vi.fn()
const removeItemSpy = vi.fn()
return {
storage: { getItem, setItem, removeItem },
@ -47,7 +47,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(
() => ({
@ -81,7 +81,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const spy = jest.fn()
const spy = vi.fn()
create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
@ -97,7 +97,7 @@ describe('persist middleware with sync configuration', () => {
const { storage, setItemSpy } = createPersistentStore(null)
const createStore = () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
@ -132,9 +132,9 @@ describe('persist middleware with sync configuration', () => {
})
it('can migrate persisted state', () => {
const setItemSpy = jest.fn<() => void>()
const onRehydrateStorageSpy = jest.fn()
const migrateSpy = jest.fn(() => ({ count: 99 }))
const setItemSpy = vi.fn()
const onRehydrateStorageSpy = vi.fn()
const migrateSpy = vi.fn(() => ({ count: 99 }))
const storage = {
getItem: () =>
@ -169,8 +169,8 @@ describe('persist middleware with sync configuration', () => {
})
it('can correclty handle a missing migrate function', () => {
console.error = jest.fn()
const onRehydrateStorageSpy = jest.fn()
console.error = vi.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: () =>
JSON.stringify({
@ -196,7 +196,7 @@ describe('persist middleware with sync configuration', () => {
})
it('can throw migrate error', () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: () =>
@ -228,8 +228,7 @@ describe('persist middleware with sync configuration', () => {
})
it('passes the latest state to onRehydrateStorage and onHydrate on first hydrate', () => {
const onRehydrateStorageSpy =
jest.fn<<S>(s: S) => (s?: S, e?: unknown) => void>()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: () => JSON.stringify({ state: { count: 1 } }),
@ -251,7 +250,7 @@ describe('persist middleware with sync configuration', () => {
* the 'onHydrate' listener set (which will be empty) is evaluated before the
* 'persist' API is exposed to the caller of 'create'/'createStore'.
*
* const onHydrateSpy = jest.fn()
* const onHydrateSpy = vi.fn()
* useBoundStore.persist.onHydrate(onHydrateSpy)
* expect(onHydrateSpy).toBeCalledWith({ count: 0 })
*/
@ -263,7 +262,7 @@ describe('persist middleware with sync configuration', () => {
})
it('gives the merged state to onRehydrateStorage', () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const storage = {
getItem: () =>
@ -356,7 +355,7 @@ describe('persist middleware with sync configuration', () => {
})
it('can filter the persisted value', () => {
const setItemSpy = jest.fn<() => void>()
const setItemSpy = vi.fn()
const storage = {
getItem: () => '',
@ -423,7 +422,7 @@ describe('persist middleware with sync configuration', () => {
it('can access the options through the api', () => {
const storage = {
getItem: () => null,
setItem: jest.fn<() => void>(),
setItem: vi.fn(),
removeItem: () => {},
}
@ -438,7 +437,7 @@ describe('persist middleware with sync configuration', () => {
})
it('can change the options through the api', () => {
const setItemSpy = jest.fn<() => void>()
const setItemSpy = vi.fn()
const storage = {
getItem: () => null,
@ -475,7 +474,7 @@ describe('persist middleware with sync configuration', () => {
})
it('can clear the storage through the api', () => {
const removeItemSpy = jest.fn<() => void>()
const removeItemSpy = vi.fn()
const storage = {
getItem: () => null,
@ -541,10 +540,10 @@ describe('persist middleware with sync configuration', () => {
const storageValue1 = '{"state":{"count":1},"version":0}'
const storageValue2 = '{"state":{"count":2},"version":0}'
const onHydrateSpy1 = jest.fn()
const onHydrateSpy2 = jest.fn()
const onFinishHydrationSpy1 = jest.fn()
const onFinishHydrationSpy2 = jest.fn()
const onHydrateSpy1 = vi.fn()
const onHydrateSpy2 = vi.fn()
const onFinishHydrationSpy1 = vi.fn()
const onFinishHydrationSpy2 = vi.fn()
const storage = {
getItem: () => '',
@ -595,7 +594,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(
() => ({
@ -671,7 +670,7 @@ describe('persist middleware with sync configuration', () => {
}
const map = new Map()
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(
() => ({
@ -697,7 +696,7 @@ describe('persist middleware with sync configuration', () => {
const map = new Map()
const createStore = () => {
const onRehydrateStorageSpy = jest.fn()
const onRehydrateStorageSpy = vi.fn()
const useBoundStore = create(
persist(() => ({ map }), {
name: 'test-storage',

View File

@ -1,4 +1,4 @@
import { describe, expect, it } from '@jest/globals'
import { describe, expect, it } from 'vitest'
import { create } from 'zustand'
import { shallow } from 'zustand/shallow'

View File

@ -1,10 +1,10 @@
import { describe, expect, it, jest } from '@jest/globals'
import { describe, expect, it, vi } from 'vitest'
import { create } from 'zustand'
import { subscribeWithSelector } from 'zustand/middleware'
describe('subscribe()', () => {
it('should not be called if new state identity is the same', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(() => initialState)
@ -14,7 +14,7 @@ describe('subscribe()', () => {
})
it('should be called if new state identity is different', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, getState, subscribe } = create(() => initialState)
@ -24,7 +24,7 @@ describe('subscribe()', () => {
})
it('should not be called when state slice is the same', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
@ -36,7 +36,7 @@ describe('subscribe()', () => {
})
it('should be called when state slice changes', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
@ -49,7 +49,7 @@ describe('subscribe()', () => {
})
it('should not be called when equality checker returns true', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
@ -61,7 +61,7 @@ describe('subscribe()', () => {
})
it('should be called when equality checker returns false', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
@ -74,7 +74,7 @@ describe('subscribe()', () => {
})
it('should unsubscribe correctly', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
@ -91,7 +91,7 @@ describe('subscribe()', () => {
})
it('should keep consistent behavior with equality check', () => {
const spy = jest.fn()
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { getState, setState, subscribe } = create(
subscribeWithSelector(() => initialState)
@ -100,7 +100,7 @@ describe('subscribe()', () => {
const isRoughEqual = (x: number, y: number) => Math.abs(x - y) < 1
setState({ value: 0 })
spy.mockReset()
const spy2 = jest.fn()
const spy2 = vi.fn()
let prevValue = getState().value
const unsub = subscribe((s) => {
if (isRoughEqual(prevValue, s.value)) {

View File

@ -1,4 +1,4 @@
import { expect, it } from '@jest/globals'
import { expect, it } from 'vitest'
import { create } from 'zustand'
import type {
StateCreator,

23
vitest.config.ts Normal file
View File

@ -0,0 +1,23 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
resolve: {
alias: [
{ find: /^zustand$/, replacement: './src/index.ts' },
{ find: /^zustand(.*)$/, replacement: './src/$1.ts' },
],
},
test: {
name: 'zustand',
// Keeping globals to true triggers React Testing Library's auto cleanup
// https://vitest.dev/guide/migration.html
globals: true,
environment: 'jsdom',
dir: 'tests',
reporters: 'basic',
coverage: {
reporter: ['text', 'json', 'html', 'text-summary'],
reportsDirectory: './coverage/',
},
},
})

2027
yarn.lock

File diff suppressed because it is too large Load Diff