import * as React from 'react';
import { renderHook, waitFor } from '@testing-library/react';
import { useRecordSelection } from './useRecordSelection';
import { StoreSetter, StoreContextProvider, memoryStore } from '../../store';
describe('useRecordSelection', () => {
const wrapper = ({ children }) => (
{children}
);
it('should return empty array by default', () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [selected] = result.current;
expect(selected).toEqual([]);
});
it('should use the stored value', () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper: ({ children }) => (
{children}
),
}
);
const [selected] = result.current;
expect(selected).toEqual([123, 456]);
});
it('should store in a new format after any operation', async () => {
const store = memoryStore();
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper: ({ children }) => (
{children}
),
}
);
const [, { select }] = result.current;
select([123, 456, 7]);
await waitFor(() => {
const stored = store.getItem('foo.selectedIds');
expect(stored).toEqual([123, 456, 7]);
});
});
describe('select', () => {
it('should allow to select a record', async () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [selected1, { select }] = result.current;
expect(selected1).toEqual([]);
select([123, 456]);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([123, 456]);
});
});
it('should ignore previous selection', async () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [selected1, { select }] = result.current;
expect(selected1).toEqual([]);
select([123, 456]);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([123, 456]);
});
select([123, 789]);
await waitFor(() => {
const [selected3] = result.current;
expect(selected3).toEqual([123, 789]);
});
});
});
describe('unselect', () => {
it('should allow to unselect a record', async () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [, { select, unselect }] = result.current;
select([123, 456]);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([123, 456]);
});
unselect([123]);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([456]);
});
});
it('should not fail if the record was not selected', async () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [, { select, unselect }] = result.current;
select([123, 456]);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([123, 456]);
});
unselect([789]);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([123, 456]);
});
});
});
describe('toggle', () => {
it('should allow to toggle a record selection', async () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [selected1, { toggle }] = result.current;
expect(selected1).toEqual([]);
toggle(123);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([123]);
});
toggle(456);
await waitFor(() => {
const [selected3] = result.current;
expect(selected3).toEqual([123, 456]);
});
toggle(123);
await waitFor(() => {
const [selected4] = result.current;
expect(selected4).toEqual([456]);
});
});
it('should allow to empty the selection', async () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [, { select, toggle }] = result.current;
select([123]);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([123]);
});
toggle(123);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([]);
});
});
});
describe('clearSelection', () => {
it('should allow to clear the selection', async () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [, { toggle, clearSelection }] = result.current;
toggle(123);
await waitFor(() => {
const [selected1] = result.current;
expect(selected1).toEqual([123]);
});
clearSelection();
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([]);
});
});
it('should not fail on empty selection', () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo' }),
{
wrapper,
}
);
const [, { clearSelection }] = result.current;
clearSelection();
const [selected] = result.current;
expect(selected).toEqual([]);
});
});
describe('using local state', () => {
it('should return empty array by default', () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [selected] = result.current;
expect(selected).toEqual([]);
});
it('should not use the stored value', () => {
const { result } = renderHook(
() =>
useRecordSelection({
disableSyncWithStore: true,
}),
{
wrapper: ({ children }) => (
{children}
),
}
);
const [selected] = result.current;
expect(selected).toEqual([]);
});
describe('select', () => {
it('should allow to select a record', async () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [selected1, { select }] = result.current;
expect(selected1).toEqual([]);
select([123, 456]);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([123, 456]);
});
});
it('should ignore previous selection', async () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [selected1, { select }] = result.current;
expect(selected1).toEqual([]);
select([123, 456]);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([123, 456]);
});
select([123, 789]);
await waitFor(() => {
const [selected3] = result.current;
expect(selected3).toEqual([123, 789]);
});
});
});
describe('unselect', () => {
it('should allow to unselect a record', async () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [, { select, unselect }] = result.current;
select([123, 456]);
await waitFor(() => {
const [selected1] = result.current;
expect(selected1).toEqual([123, 456]);
});
unselect([123]);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([456]);
});
});
it('should not fail if the record was not selected', async () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [, { select, unselect }] = result.current;
select([123, 456]);
await waitFor(() => {
const [selected1] = result.current;
expect(selected1).toEqual([123, 456]);
});
unselect([789]);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([123, 456]);
});
});
});
describe('toggle', () => {
it('should allow to toggle a record selection', async () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [selected1, { toggle }] = result.current;
expect(selected1).toEqual([]);
toggle(123);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([123]);
});
toggle(456);
await waitFor(() => {
const [selected3] = result.current;
expect(selected3).toEqual([123, 456]);
});
toggle(123);
await waitFor(() => {
const [selected4] = result.current;
expect(selected4).toEqual([456]);
});
});
it('should allow to empty the selection', async () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [, { select, toggle }] = result.current;
select([123]);
await waitFor(() => {
const [selected3] = result.current;
expect(selected3).toEqual([123]);
});
toggle(123);
await waitFor(() => {
const [selected] = result.current;
expect(selected).toEqual([]);
});
});
});
describe('clearSelection', () => {
it('should allow to clear the selection', async () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [, { toggle, clearSelection }] = result.current;
toggle(123);
await waitFor(() => {
const [selected2] = result.current;
expect(selected2).toEqual([123]);
});
clearSelection();
await waitFor(() => {
const [selected3] = result.current;
expect(selected3).toEqual([]);
});
});
it('should not fail on empty selection', () => {
const { result } = renderHook(() =>
useRecordSelection({
disableSyncWithStore: true,
})
);
const [, { clearSelection }] = result.current;
clearSelection();
const [selected] = result.current;
expect(selected).toEqual([]);
});
});
});
describe('using storeKey', () => {
it('should return empty array by default', () => {
const { result } = renderHook(
() =>
useRecordSelection({
resource: 'foo',
storeKey: 'bar',
}),
{ wrapper }
);
const [selected] = result.current;
expect(selected).toEqual([]);
});
it('should use the stored value', () => {
const { result } = renderHook(
() => useRecordSelection({ resource: 'foo', storeKey: 'bar' }),
{
wrapper: ({ children }) => (
{children}
),
}
);
const [selected] = result.current;
expect(selected).toEqual([123, 456]);
});
it('should allow to unselect from all storeKeys', async () => {
const { result } = renderHook(
() => [
useRecordSelection({ resource: 'foo', storeKey: 'bar1' }),
useRecordSelection({ resource: 'foo', storeKey: 'bar2' }),
],
{
wrapper,
}
);
const [, { toggle: toggle1 }] = result.current[0];
const [, { toggle: toggle2 }] = result.current[1];
toggle1(123);
await waitFor(() => {});
toggle2(123);
await waitFor(() => {});
toggle2(456);
await waitFor(() => {
const [selected1] = result.current[0];
expect(selected1).toEqual([123]);
const [selected2] = result.current[1];
expect(selected2).toEqual([123, 456]);
});
const [, { unselect }] = result.current[0];
unselect([123], true);
await waitFor(() => {
const [selected1] = result.current[0];
expect(selected1).toEqual([]);
const [selected2] = result.current[1];
expect(selected2).toEqual([456]);
});
});
it('should allow to clear the selection from all storeKeys', async () => {
const { result } = renderHook(
() => [
useRecordSelection({
resource: 'foo',
storeKey: 'bar1',
}),
useRecordSelection({
resource: 'foo',
storeKey: 'bar2',
}),
],
{
wrapper,
}
);
const [, { toggle: toggle1 }] = result.current[0];
const [, { toggle: toggle2 }] = result.current[1];
toggle1(123);
// `set` in useStore doesn't chain set calls happened in one render cycle...
await waitFor(() => {});
toggle2(456);
await waitFor(() => {
const [selected1] = result.current[0];
expect(selected1).toEqual([123]);
const [selected2] = result.current[1];
expect(selected2).toEqual([456]);
});
const [, { clearSelection }] = result.current[0];
clearSelection(true);
await waitFor(() => {
const [selected1] = result.current[0];
expect(selected1).toEqual([]);
const [selected2] = result.current[1];
expect(selected2).toEqual([]);
});
});
describe('using stored storeKeys', () => {
it('should keep final storeKey in the store', async () => {
const store = memoryStore();
renderHook(
() =>
useRecordSelection({
resource: 'foo',
storeKey: 'bar',
}),
{
wrapper: ({ children }) => (
{children}
),
}
);
await waitFor(() => {
const storeKeys = store.getItem(
'foo.selectedIds.storeKeys'
);
expect(storeKeys).toEqual(['bar.selectedIds']);
});
});
it('should check all storeKeys listed in store when `fromAllStoreKeys` is `true`', async () => {
const store = memoryStore();
const { result } = renderHook(
() => {
return useRecordSelection({
resource: 'foo',
storeKey: 'bar1',
});
},
{
wrapper: ({ children }) => (
{children}
),
}
);
const [, { clearSelection }] = result.current;
clearSelection(true);
await waitFor(() => {
expect(store.getItem('bar1.selectedIds')).toEqual([]);
expect(store.getItem('bar2.selectedIds')).toEqual([]);
});
});
});
});
});