Here is a really simple—and also secretly flawed—solution:
import reducer, {
add,
remove,
toggle,
markAllAsUnpacked,
update,
} from './items-slice';
it('returns an empty object as the initial state', () => {
expect(reducer(undefined, { type: 'noop' })).toEqual([]);
});
it('supports adding an item', () => {
expect(reducer([], add({ name: 'iPhone' }))).toEqual([
expect.objectContaining({ name: 'iPhone' }),
]);
});
it('prefixes ids with "item-"', () => {
expect(reducer([], add({ name: 'iPhone' }))).toEqual([
expect.objectContaining({ id: expect.stringMatching(/^item-/) }),
]);
});
it('defaults new items to a packed status of false', () => {
expect(reducer([], add({ name: 'iPhone' }))).toEqual([
expect.objectContaining({ packed: false }),
]);
});
it('supports removing an item', () => {
const state = [
{
id: '1',
name: 'iPhone',
packed: false,
},
];
const result = reducer(state, remove({ id: '1' }));
expect(result).toEqual([]);
});
it('supports toggling an item', () => {
const state = [
{
id: '1',
name: 'iPhone',
packed: false,
},
];
const result = reducer(state, toggle({ id: '1' }));
expect(result).toEqual([
{
id: '1',
name: 'iPhone',
packed: true,
},
]);
});
it('supports updating an item', () => {
const state = [
{
id: '1',
name: 'iPhone',
packed: false,
},
];
const result = reducer(
state,
update({ id: '1', name: 'Samsung Galaxy S23' }),
);
expect(result).toEqual([
{
id: '1',
name: 'Samsung Galaxy S23',
packed: false,
},
]);
});
it('supports marking all items as unpacked', () => {
const state = [
{
id: '1',
name: 'iPhone',
packed: true,
},
{
id: '2',
name: 'iPhone Charger',
packed: true,
},
];
const result = reducer(state, markAllAsUnpacked());
expect(result).toEqual([
{
id: '1',
name: 'iPhone',
packed: false,
},
{
id: '2',
name: 'iPhone Charger',
packed: false,
},
]);
});
We could go even father with the asymmetric matching, but I'm not going to just to prove a point: It's all about the trade offs considering what provides the most value? If we found that this data structure was changing a lot and a little bit more more flexibility was helpful, then I might go for it. But, until then I'm adopting a YAGNI philosophy about this in a half-baked attempt to set an example for you.
There are the tests I write when I am developing the code and the tests that I write when I am maintaining the code.
- I might combine the first few tests into one test since if any part of that failed, I'd get a decent failure message.
- If I ended up adding something like
dateCreated
orlastModified
, you would definitely see me getting a little looser with those later tests.