Skip to content

Commit

Permalink
Unit tests for getting/setting/initing atoms via transaction
Browse files Browse the repository at this point in the history
Summary:
Add unit tests for getting/setting atoms via `useRecoilTransaction_UNSTABLE()`

NOTE: Not sure how to test setting an atom as Jest is complaining about updates not wrapped in `act(...)`...

Differential Revision: D32774468

fbshipit-source-id: ec92166e04008331c1d19d97e7fbe970ebb4ceaf
  • Loading branch information
drarmstr authored and facebook-github-bot committed Dec 14, 2021
1 parent eeacab4 commit 3ed34d3
Showing 1 changed file with 145 additions and 53 deletions.
198 changes: 145 additions & 53 deletions packages/recoil/hooks/__tests__/Recoil_useTransaction-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
*/
'use strict';

const {act} = require('ReactTestUtils');

const {
getRecoilTestFn,
} = require('recoil-shared/__test_utils__/Recoil_TestingUtils');
Expand All @@ -28,84 +30,174 @@ const testRecoil = getRecoilTestFn(() => {
} = require('recoil-shared/__test_utils__/Recoil_TestingUtils'));
});

testRecoil(
'Atom effects are initialized once if first seen on transaction and then on root store',
() => {
let numTimesEffectInit = 0;
describe('Atoms', () => {
testRecoil('Get with transaction', () => {
const myAtom = atom({key: 'useTransaction atom get', default: 'DEFAULT'});

let readAtom;
let ranTransaction = false;
function Component() {
readAtom = useRecoilTransaction(({get}) => () => {
expect(get(myAtom)).toEqual('DEFAULT');
ranTransaction = true;
});
return null;
}
renderElements(<Component />);
expect(ranTransaction).toBe(false);

act(readAtom);
expect(ranTransaction).toBe(true);
});

// TODO Unable to test setting from a transaction as Jest complains about
// updates not wrapped in act(...)...
// testRecoil('Set with transaction', () => {
// const myAtom = atom<string>({
// key: 'useTransaction atom set',
// default: 'DEFAULT',
// });

// let setAtom;
// let updateAtom;
// function Component() {
// setAtom = useRecoilTransaction(({set}) => value => {
// act(() => {
// set(myAtom, value);
// });
// });
// updateAtom = useRecoilTransaction(({set}) => value => {
// set(myAtom, old => {
// expect(old).toEqual('SET');
// return value;
// });
// });
// return null;
// }
// const c = renderElements(
// <>
// <ReadsAtom atom={myAtom} />
// <Component />
// </>,
// );
// expect(c.textContent).toEqual('"DEFAULT"');

// act(() => setAtom('SET'));
// expect(c.textContent).toEqual('"SET"');

// act(() => updateAtom('UPDATE'));
// expect(c.textContent).toEqual('UPDATE');
// });
});

describe('Atom Effects', () => {
testRecoil('Atom effects can initialize for a transaction', async () => {
let numTimesEffectInit = 0;
const atomWithEffect = atom({
key: 'atomWithEffect',
default: 0,
key: 'atom effect init transaction',
default: 'DEFAULT',
effects_UNSTABLE: [
() => {
({setSelf}) => {
setSelf('INIT');
numTimesEffectInit++;
},
],
});

let initAtomWithTransaction;
const Component = () => {
const readAtomFromSnapshot = useRecoilTransaction(({get}) => () => {
get(atomWithEffect);
initAtomWithTransaction = useRecoilTransaction(({get}) => () => {
expect(get(atomWithEffect)).toEqual('INIT');
});
return null;
};

readAtomFromSnapshot(); // first initialization
renderElements(<Component />);

expect(numTimesEffectInit).toBe(1);
act(() => initAtomWithTransaction());

/**
* Transactions do not use a snapshot under the hood, so any initialized
* effects from a transaction will be reflected in root store
*/
useRecoilValue(atomWithEffect);
expect(numTimesEffectInit).toBe(1);
});

testRecoil(
'Atom effects are initialized once if first seen on transaction and then on root store',
() => {
let numTimesEffectInit = 0;

const atomWithEffect = atom({
key: 'useTransaction effect first get transaction',
default: 0,
effects_UNSTABLE: [
() => {
numTimesEffectInit++;
},
],
});

expect(numTimesEffectInit).toBe(1);
const Component = () => {
const readAtomFromSnapshot = useRecoilTransaction(({get}) => () => {
get(atomWithEffect);
});

return null;
};
readAtomFromSnapshot(); // first initialization

renderElements(<Component />);
expect(numTimesEffectInit).toBe(1);

expect(numTimesEffectInit).toBe(1);
},
);
/**
* Transactions do not use a snapshot under the hood, so any initialized
* effects from a transaction will be reflected in root store
*/
useRecoilValue(atomWithEffect);

testRecoil(
'Atom effects are initialized once if first seen on root store and then on snapshot',
() => {
let numTimesEffectInit = 0;
expect(numTimesEffectInit).toBe(1);

const atomWithEffect = atom({
key: 'atomWithEffect2',
default: 0,
effects_UNSTABLE: [
() => {
numTimesEffectInit++;
},
],
});
return null;
};

const Component = () => {
const readAtomFromSnapshot = useRecoilTransaction(({get}) => () => {
get(atomWithEffect);
renderElements(<Component />);

expect(numTimesEffectInit).toBe(1);
},
);

testRecoil(
'Atom effects are initialized once if first seen on root store and then on snapshot',
() => {
let numTimesEffectInit = 0;

const atomWithEffect = atom({
key: 'atom effect first get root',
default: 0,
effects_UNSTABLE: [
() => {
numTimesEffectInit++;
},
],
});

useRecoilValue(atomWithEffect); // first initialization
const Component = () => {
const readAtomFromSnapshot = useRecoilTransaction(({get}) => () => {
get(atomWithEffect);
});

expect(numTimesEffectInit).toBe(1);
useRecoilValue(atomWithEffect); // first initialization

/**
* Transactions do not use a snapshot under the hood, so any initialized
* effects from a transaction will be reflected in root store
*/
readAtomFromSnapshot();
expect(numTimesEffectInit).toBe(1);

expect(numTimesEffectInit).toBe(1);
/**
* Transactions do not use a snapshot under the hood, so any initialized
* effects from a transaction will be reflected in root store
*/
readAtomFromSnapshot();

return null;
};
expect(numTimesEffectInit).toBe(1);

renderElements(<Component />);
return null;
};

expect(numTimesEffectInit).toBe(1);
},
);
renderElements(<Component />);

expect(numTimesEffectInit).toBe(1);
},
);
});

0 comments on commit 3ed34d3

Please sign in to comment.