diff --git a/__tests__/ScopeProvider/01_basic_spec.tsx b/__tests__/ScopeProvider/01_basic_spec.test.tsx similarity index 100% rename from __tests__/ScopeProvider/01_basic_spec.tsx rename to __tests__/ScopeProvider/01_basic_spec.test.tsx diff --git a/__tests__/ScopeProvider/02_removeScope.tsx b/__tests__/ScopeProvider/02_removeScope.test.tsx similarity index 100% rename from __tests__/ScopeProvider/02_removeScope.tsx rename to __tests__/ScopeProvider/02_removeScope.test.tsx diff --git a/__tests__/ScopeProvider/03_nested.tsx b/__tests__/ScopeProvider/03_nested.test.tsx similarity index 100% rename from __tests__/ScopeProvider/03_nested.tsx rename to __tests__/ScopeProvider/03_nested.test.tsx diff --git a/__tests__/ScopeProvider/04_derived.tsx b/__tests__/ScopeProvider/04_derived.test.tsx similarity index 100% rename from __tests__/ScopeProvider/04_derived.tsx rename to __tests__/ScopeProvider/04_derived.test.tsx diff --git a/__tests__/ScopeProvider/05_derived_self.tsx b/__tests__/ScopeProvider/05_derived_self.test.tsx similarity index 100% rename from __tests__/ScopeProvider/05_derived_self.tsx rename to __tests__/ScopeProvider/05_derived_self.test.tsx diff --git a/__tests__/ScopeProvider/06_implicit_parent.tsx b/__tests__/ScopeProvider/06_implicit_parent.test.tsx similarity index 100% rename from __tests__/ScopeProvider/06_implicit_parent.tsx rename to __tests__/ScopeProvider/06_implicit_parent.test.tsx diff --git a/__tests__/ScopeProvider/07_writable.tsx b/__tests__/ScopeProvider/07_writable.test.tsx similarity index 100% rename from __tests__/ScopeProvider/07_writable.tsx rename to __tests__/ScopeProvider/07_writable.test.tsx diff --git a/__tests__/ScopeProvider/08_family.tsx b/__tests__/ScopeProvider/08_family.test.tsx similarity index 100% rename from __tests__/ScopeProvider/08_family.tsx rename to __tests__/ScopeProvider/08_family.test.tsx diff --git a/__tests__/ScopeProvider/09_scope_provider.tsx b/__tests__/ScopeProvider/09_mount.test.tsx similarity index 65% rename from __tests__/ScopeProvider/09_scope_provider.tsx rename to __tests__/ScopeProvider/09_mount.test.tsx index f223c20..61a3cc8 100644 --- a/__tests__/ScopeProvider/09_scope_provider.tsx +++ b/__tests__/ScopeProvider/09_mount.test.tsx @@ -41,3 +41,33 @@ describe('ScopeProvider', () => { expect(container.querySelector(base)).toBe(null) }) }) + +it('computed atom mounts once for the unscoped and once for the scoped', () => { + const baseAtom = atom(0) + const deriveAtom = atom( + (get) => get(baseAtom), + () => {}, + ) + const onUnmount = jest.fn() + const onMount = jest.fn(() => onUnmount) + deriveAtom.onMount = onMount + function Component() { + return useAtomValue(deriveAtom) + } + function App() { + return ( + <> + + + + + + + + ) + } + const { unmount } = render() + expect(onMount).toHaveBeenCalledTimes(2) + unmount() + expect(onUnmount).toHaveBeenCalledTimes(2) +}) diff --git a/__tests__/createIsolation/01_basic_spec.tsx b/__tests__/createIsolation/01_basic_spec.test.tsx similarity index 100% rename from __tests__/createIsolation/01_basic_spec.tsx rename to __tests__/createIsolation/01_basic_spec.test.tsx diff --git a/__tests__/utils.ts b/__tests__/utils.ts index d08ffa0..0d210fe 100644 --- a/__tests__/utils.ts +++ b/__tests__/utils.ts @@ -1,4 +1,6 @@ import { fireEvent } from '@testing-library/react' +import { Store } from 'src/ScopeProvider/types' +import { INTERNAL_DevStoreRev4, INTERNAL_PrdStore } from 'jotai/vanilla/store' function getElements(container: HTMLElement, querySelectors: string[]): Element[] { return querySelectors.map((querySelector) => { @@ -21,3 +23,30 @@ export function clickButton(container: HTMLElement, querySelector: string) { } fireEvent.click(button) } + +export function getDevStore(store: Store): INTERNAL_PrdStore & INTERNAL_DevStoreRev4 { + if (!isDevStore(store)) { + throw new Error('Store is not a dev store') + } + return store +} + +export function isDevStore(store: Store): store is INTERNAL_PrdStore & INTERNAL_DevStoreRev4 { + return ( + 'dev4_get_internal_weak_map' in store && + 'dev4_get_mounted_atoms' in store && + 'dev4_restore_atoms' in store + ) +} + +export function assertIsDevStore( + store: Store, +): asserts store is INTERNAL_PrdStore & INTERNAL_DevStoreRev4 { + if (!isDevStore(store)) { + throw new Error('Store is not a dev store') + } +} + +export function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} diff --git a/package.json b/package.json index 354addb..4869ae4 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,8 @@ "jest": { "testEnvironment": "jsdom", "preset": "ts-jest/presets/js-with-ts", - "testPathIgnorePatterns": [ - "utils.ts" + "testMatch": [ + "**/__tests__/**/*.test.*" ] }, "keywords": [ @@ -59,6 +59,7 @@ "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", "@types/jest": "^29.5.6", + "@types/minimalistic-assert": "^1.0.3", "@types/node": "^20.8.7", "@types/react": "^18.2.31", "@types/react-dom": "^18.2.14", @@ -75,8 +76,8 @@ "html-webpack-plugin": "^5.5.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "jotai": "2.9.2", "microbundle": "^0.15.1", + "minimalistic-assert": "^1.0.1", "npm-run-all": "^4.1.5", "prettier": "^3.0.3", "react": "^18.2.0", @@ -90,7 +91,7 @@ "webpack-dev-server": "^4.15.1" }, "peerDependencies": { - "jotai": ">=2.9.2", + "jotai": ">=2.9.3", "react": ">=17.0.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b6cbad..4a0209d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +dependencies: + jotai: + specifier: '>=2.9.3' + version: 2.9.3(@types/react@18.2.31)(react@18.2.0) + devDependencies: '@testing-library/dom': specifier: ^9.3.3 @@ -17,6 +22,9 @@ devDependencies: '@types/jest': specifier: ^29.5.6 version: 29.5.6 + '@types/minimalistic-assert': + specifier: ^1.0.3 + version: 1.0.3 '@types/node': specifier: ^20.8.7 version: 20.8.7 @@ -65,12 +73,12 @@ devDependencies: jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 - jotai: - specifier: 2.9.2 - version: 2.9.2(@types/react@18.2.31)(react@18.2.0) microbundle: specifier: ^0.15.1 version: 0.15.1 + minimalistic-assert: + specifier: ^1.0.1 + version: 1.0.1 npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -2102,6 +2110,10 @@ packages: resolution: {integrity: sha512-i8MBln35l856k5iOhKk2XJ4SeAWg75mLIpZB4v6imOagKL6twsukBZGDMNhdOVk7yRFTMPpfILocMos59Q1otQ==} dev: true + /@types/minimalistic-assert@1.0.3: + resolution: {integrity: sha512-Ku87cam4YxiXcEpeUemo+vO8QWGQ7U2CwEEcLcYFhxG8b4CK8gWxSX/oWjePWKwqPaWWxxVqXAdAjGdlJtVzDA==} + dev: true + /@types/node@20.8.7: resolution: {integrity: sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==} dependencies: @@ -2114,7 +2126,6 @@ packages: /@types/prop-types@15.7.9: resolution: {integrity: sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==} - dev: true /@types/qs@6.9.9: resolution: {integrity: sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==} @@ -2136,7 +2147,6 @@ packages: '@types/prop-types': 15.7.9 '@types/scheduler': 0.16.5 csstype: 3.1.2 - dev: true /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} @@ -2150,7 +2160,6 @@ packages: /@types/scheduler@0.16.5: resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==} - dev: true /@types/semver@7.5.4: resolution: {integrity: sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==} @@ -3521,7 +3530,6 @@ packages: /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - dev: true /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -5938,8 +5946,8 @@ packages: - ts-node dev: true - /jotai@2.9.2(@types/react@18.2.31)(react@18.2.0): - resolution: {integrity: sha512-jIBXEadOHCziOuMY6HAy2KQcHipGhnsbF+twqh8Lcmcz/Yei0gdBtW5mOYdKmbQxGqkvfvXM3w/oHtJ2WNGSFg==} + /jotai@2.9.3(@types/react@18.2.31)(react@18.2.0): + resolution: {integrity: sha512-IqMWKoXuEzWSShjd9UhalNsRGbdju5G2FrqNLQJT+Ih6p41VNYe2sav5hnwQx4HJr25jq9wRqvGSWGviGG6Gjw==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=17.0.0' @@ -5952,11 +5960,10 @@ packages: dependencies: '@types/react': 18.2.31 react: 18.2.0 - dev: true + dev: false /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} @@ -6203,7 +6210,6 @@ packages: hasBin: true dependencies: js-tokens: 4.0.0 - dev: true /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -7439,7 +7445,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: true /read-pkg@3.0.0: resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==}