recoil
Version:
Recoil - A state management library for React
150 lines (131 loc) • 4.36 kB
Flow
/**
* 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+recoil
* @flow strict-local
* @format
*/
;
const {
getRecoilTestFn,
} = require('recoil-shared/__test_utils__/Recoil_TestingUtils');
let React,
useRef,
useState,
act,
atom,
counterAtom,
renderElements,
useRecoilInterface;
const testRecoil = getRecoilTestFn(() => {
React = require('react');
({useRef, useState} = require('react'));
({act} = require('ReactTestUtils'));
atom = require('../../recoil_values/Recoil_atom');
({
renderElements,
} = require('recoil-shared/__test_utils__/Recoil_TestingUtils'));
({useRecoilInterface} = require('../Recoil_Hooks'));
counterAtom = atom({
key: `counterAtom`,
default: 0,
});
});
testRecoil('Interface for non-react code - useRecoilState', () => {
function nonReactCode(recoilInterface) {
return recoilInterface.getRecoilState(counterAtom);
}
let updateValue;
const Component = () => {
const recoilInterface = useRecoilInterface();
const [value, _updateValue] = nonReactCode(recoilInterface);
updateValue = _updateValue;
return value;
};
const container = renderElements(<Component />);
expect(container.textContent).toEqual('0');
act(() => updateValue(1));
expect(container.textContent).toEqual('1');
});
testRecoil('Interface for non-react code - useRecoilStateNoThrow', () => {
function nonReactCode(recoilInterface) {
const [loadable, setValue] =
recoilInterface.getRecoilStateLoadable(counterAtom);
const value = loadable.state === 'hasValue' ? loadable.contents : null;
return [value, setValue];
}
let updateValue;
const Component = () => {
const recoilInterface = useRecoilInterface();
const [value, _updateValue] = nonReactCode(recoilInterface);
updateValue = _updateValue;
return value;
};
const container = renderElements(<Component />);
expect(container.textContent).toEqual('0');
act(() => updateValue(1));
expect(container.textContent).toEqual('1');
});
testRecoil(
'Interface for non-react code - useRecoilValue, useSetRecoilState',
() => {
function nonReactCode(recoilInterface) {
return [
recoilInterface.getRecoilValue(counterAtom),
recoilInterface.getSetRecoilState(counterAtom),
];
}
let updateValue;
const Component = () => {
const recoilInterface = useRecoilInterface();
const [value, _updateValue] = nonReactCode(recoilInterface);
updateValue = _updateValue;
return value;
};
const container = renderElements(<Component />);
expect(container.textContent).toEqual('0');
act(() => updateValue(1));
expect(container.textContent).toEqual('1');
},
);
testRecoil('Interface for non-react code - useRecoilValueNoThrow', () => {
function nonReactCode(recoilInterface) {
const value = recoilInterface
.getRecoilValueLoadable(counterAtom)
.valueMaybe();
const setValue = recoilInterface.getSetRecoilState(counterAtom);
return [value, setValue];
}
let updateValue;
const Component = () => {
const recoilInterface = useRecoilInterface();
const [value, _updateValue] = nonReactCode(recoilInterface);
updateValue = _updateValue;
return value;
};
const container = renderElements(<Component />);
expect(container.textContent).toEqual('0');
act(() => updateValue(1));
expect(container.textContent).toEqual('1');
});
// Test that we always get a consistent instance of the interface object and
// hooks from useRecoilInterface() (at least for a given <AppRoot> store)
testRecoil('Consistent interface object', () => {
let setValue;
const Component = () => {
const [value, _setValue] = useState(0);
const recoilInterface = useRecoilInterface();
const recoilInterfaceRef = useRef(recoilInterface);
expect(recoilInterface).toBe(recoilInterfaceRef.current);
expect(recoilInterface.getRecoilState).toBe(recoilInterface.getRecoilState);
setValue = _setValue;
return value;
};
const out = renderElements(<Component />);
expect(out.textContent).toBe('0');
act(() => setValue(1)); // Force a re-render of the Component
expect(out.textContent).toBe('1');
});