UNPKG

recoil

Version:

Recoil - A state management library for React

183 lines (179 loc) 6.01 kB
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @emails oncall+obviz * @flow strict-local * @format */ 'use strict'; const { getRecoilTestFn } = require('../../testing/Recoil_TestingUtils'); let React, useState, act, freshSnapshot, useGotoRecoilSnapshot, useRecoilCallback, useRecoilValue, atom, constSelector, selector, ReadsAtom, asyncSelector, componentThatReadsAndWritesAtom, flushPromisesAndTimers, renderElements; const testRecoil = getRecoilTestFn(() => { React = require('React'); ({ useState } = require('React')); ({ act } = require('ReactTestUtils')); ({ freshSnapshot } = require('../../core/Recoil_Snapshot')); ({ useGotoRecoilSnapshot, useRecoilCallback, useRecoilValue } = require('../../hooks/Recoil_Hooks')); atom = require('../../recoil_values/Recoil_atom'); constSelector = require('../../recoil_values/Recoil_constSelector'); selector = require('../../recoil_values/Recoil_selector'); ({ ReadsAtom, asyncSelector, componentThatReadsAndWritesAtom, flushPromisesAndTimers, renderElements } = require('../../testing/Recoil_TestingUtils')); }); testRecoil('Goto mapped snapshot', async () => { const snapshot = freshSnapshot(); const myAtom = atom({ key: 'Goto Snapshot Atom', default: 'DEFAULT' }); const [ReadsAndWritesAtom, setAtom] = componentThatReadsAndWritesAtom(myAtom); const mySelector = constSelector(myAtom); const updatedSnapshot = snapshot.map(({ set }) => { set(myAtom, 'SET IN SNAPSHOT'); }); let gotoRecoilSnapshot; declare function GotoRecoilSnapshot(): any; const c = renderElements(<> <ReadsAndWritesAtom /> <ReadsAtom atom={mySelector} /> <GotoRecoilSnapshot /> </>); expect(c.textContent).toEqual('"DEFAULT""DEFAULT"'); act(() => setAtom('SET IN CURRENT')); expect(c.textContent).toEqual('"SET IN CURRENT""SET IN CURRENT"'); await expect(updatedSnapshot.getPromise(myAtom)).resolves.toEqual('SET IN SNAPSHOT'); act(() => gotoRecoilSnapshot(updatedSnapshot)); expect(c.textContent).toEqual('"SET IN SNAPSHOT""SET IN SNAPSHOT"'); act(() => setAtom('SET AGAIN IN CURRENT')); expect(c.textContent).toEqual('"SET AGAIN IN CURRENT""SET AGAIN IN CURRENT"'); // Test that atoms set after snapshot were created are reset act(() => gotoRecoilSnapshot(snapshot)); expect(c.textContent).toEqual('"DEFAULT""DEFAULT"'); }); testRecoil('Goto callback snapshot', () => { const myAtom = atom({ key: 'Goto Snapshot From Callback', default: 'DEFAULT' }); const [ReadsAndWritesAtom, setAtom] = componentThatReadsAndWritesAtom(myAtom); const mySelector = constSelector(myAtom); let cb; declare function RecoilCallback(): any; const c = renderElements(<> <ReadsAndWritesAtom /> <ReadsAtom atom={mySelector} /> <RecoilCallback /> </>); expect(c.textContent).toEqual('"DEFAULT""DEFAULT"'); act(() => setAtom('SET IN CURRENT')); expect(c.textContent).toEqual('"SET IN CURRENT""SET IN CURRENT"'); act(cb); expect(c.textContent).toEqual('"SET IN SNAPSHOT""SET IN SNAPSHOT"'); }); testRecoil('Goto snapshot with dependent async selector', async () => { const snapshot = freshSnapshot(); const myAtom = atom({ key: 'atom for dep async snapshot', default: 'DEFAULT' }); const [ReadsAndWritesAtom, setAtom] = componentThatReadsAndWritesAtom(myAtom); const mySelector = selector({ key: 'selector for async snapshot', get: ({ get }) => { const dep = get(myAtom); return Promise.resolve(dep); } }); const updatedSnapshot = snapshot.map(({ set }) => { set(myAtom, 'SET IN SNAPSHOT'); }); let gotoRecoilSnapshot; declare function GotoRecoilSnapshot(): any; const c = renderElements(<> <ReadsAndWritesAtom /> <ReadsAtom atom={mySelector} /> <GotoRecoilSnapshot /> </>); expect(c.textContent).toEqual('loading'); await flushPromisesAndTimers(); await flushPromisesAndTimers(); expect(c.textContent).toEqual('"DEFAULT""DEFAULT"'); act(() => setAtom('SET IN CURRENT')); await flushPromisesAndTimers(); expect(c.textContent).toEqual('"SET IN CURRENT""SET IN CURRENT"'); await expect(updatedSnapshot.getPromise(myAtom)).resolves.toEqual('SET IN SNAPSHOT'); act(() => gotoRecoilSnapshot(updatedSnapshot)); await flushPromisesAndTimers(); expect(c.textContent).toEqual('"SET IN SNAPSHOT""SET IN SNAPSHOT"'); }); testRecoil('Goto snapshot with async selector', async () => { const snapshot = freshSnapshot(); const [mySelector, resolve] = asyncSelector(); let gotoRecoilSnapshot; declare function GotoRecoilSnapshot(): any; const c = renderElements(<> <ReadsAtom atom={mySelector} /> <GotoRecoilSnapshot /> </>); expect(c.textContent).toEqual('loading'); act(() => resolve('RESOLVE')); await flushPromisesAndTimers(); await flushPromisesAndTimers(); expect(c.textContent).toEqual('"RESOLVE"'); act(() => gotoRecoilSnapshot(snapshot)); expect(c.textContent).toEqual('"RESOLVE"'); }); // Test that going to a snapshot where an atom was not yet initialized will // not cause the atom to be re-initialized when used again. testRecoil('Effects going to previous snapshot', () => { let init = 0; const myAtom = atom({ key: 'gotoSnapshot effect', default: 'DEFAULT', effects_UNSTABLE: [() => { init++; }] }); let forceUpdate; declare function ReadAtom(): any; let gotoRecoilSnapshot; declare function GotoRecoilSnapshot(): any; expect(init).toEqual(0); renderElements(<> <ReadAtom /> <GotoRecoilSnapshot /> </>); expect(init).toEqual(1); act(forceUpdate); expect(init).toEqual(1); gotoRecoilSnapshot?.(freshSnapshot()); expect(init).toEqual(1); act(forceUpdate); expect(init).toEqual(1); act(forceUpdate); expect(init).toEqual(1); });