Skip to content

Commit

Permalink
Convert return value for storage in a tuple
Browse files Browse the repository at this point in the history
Add more tests for `useEntitiesOptionsStorage`

Signed-off-by: guido <[email protected]>
  • Loading branch information
widoz committed Jan 25, 2024
1 parent a88627e commit 567c466
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Set } from '../vo/set';
export function CompositeEntitiesByKind<E, K>(
props: EntitiesSearch.CompositeEntitiesKinds<E, K>
): JSX.Element {
const { state, dispatch } = useEntitiesOptionsStorage<E, K>(
const [state, dispatch] = useEntitiesOptionsStorage<E, K>(
{
entities: props.entities.value,
kind: props.kind.value,
Expand Down
15 changes: 7 additions & 8 deletions sources/client/src/hooks/use-entities-options-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ type _Reducer<E, K> = Reducer<
export function useEntitiesOptionsStorage<E, K>(
initialState: Partial<EntitiesSearch.EntitiesState<E, K>>,
searchEntities: EntitiesSearch.SearchEntitiesFunction<E, K>
): Readonly<{
state: EntitiesSearch.EntitiesState<E, K>;
dispatch: Dispatch<EntitiesSearch.StoreAction<E, K>>;
}> {
): Readonly<
[
EntitiesSearch.EntitiesState<E, K>,
Dispatch<EntitiesSearch.StoreAction<E, K>>
]
> {
const [state, dispatch] = useReducer<_Reducer<E, K>>(
reducer,
makeInitialState<E, K>(initialState)
Expand Down Expand Up @@ -62,8 +64,5 @@ export function useEntitiesOptionsStorage<E, K>(
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return {
state,
dispatch,
};
return [state, dispatch] as const;
}
30 changes: 0 additions & 30 deletions tests/client/unit/hooks/use-entities-options-storage.test.ts

This file was deleted.

241 changes: 241 additions & 0 deletions tests/client/unit/hooks/use-entities-options-storage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import EntitiesSearch from '@types';
import React from 'react';

import { describe, expect, it, jest } from '@jest/globals';

import { act, render } from '@testing-library/react';

import { doAction } from '@wordpress/hooks';

import { useEntitiesOptionsStorage } from '../../../../sources/client/src/hooks/use-entities-options-storage';
import { Set } from '../../../../sources/client/src/vo/set';

jest.mock('@wordpress/hooks', () => ({
doAction: jest.fn(),
}));

describe('Use Posts Options Storage', () => {
it('Ensure seachEntities is called with the right data on state hydratation.', async () => {
const kind = new Set(['post']);
const entities = new Set([1, 2, 3]);
const searchEntities = jest.fn(() =>
Promise.resolve(
new Set([
{
label: 'post-title',
value: 1,
},
])
)
) as jest.Mock<EntitiesSearch.SearchEntitiesFunction<number, string>>;

const Component = () => {
useEntitiesOptionsStorage<number, string>(
{
kind,
entities,
},
searchEntities
);

return null;
};

await act(() => render(<Component />));

expect(searchEntities).toHaveBeenCalledWith('', kind, {
exclude: entities,
});
expect(searchEntities).toHaveBeenCalledWith('', kind, {
include: entities,
per_page: '-1',
});
});

it('Update the state based on the given kind and entities', async () => {
const kind = new Set(['post']);
const entities = new Set([1, 2, 3]);
const selectedEntitiesOptions = new Set([
{
label: 'post-title-1',
value: 1,
},
{
label: 'post-title-2',
value: 2,
},
{
label: 'post-title-3',
value: 3,
},
]);
const currentEntitiesOptions = new Set([
{
label: 'post-title-4',
value: 4,
},
{
label: 'post-title-5',
value: 5,
},
{
label: 'post-title-6',
value: 6,
},
]);

const searchEntities = jest.fn((_phrase, _kind, options) => {
if (options?.include) {
return Promise.resolve(selectedEntitiesOptions);
}

return options?.include
? Promise.resolve(selectedEntitiesOptions)
: Promise.resolve(currentEntitiesOptions);
}) as jest.Mock<EntitiesSearch.SearchEntitiesFunction<number, string>>;

const dispatch = jest.fn();
jest.spyOn(React, 'useReducer').mockImplementation((_, state) => [
state,
dispatch,
]);

const Component = () => {
useEntitiesOptionsStorage<number, string>(
{
kind,
entities,
},
searchEntities
);

return null;
};

await act(() => render(<Component />));

expect(dispatch).toHaveBeenCalledWith({
type: 'UPDATE_SELECTED_ENTITIES_OPTIONS',
selectedEntitiesOptions,
});
expect(dispatch).toHaveBeenCalledWith({
type: 'UPDATE_CONTEXTUAL_ENTITIES_OPTIONS',
contextualEntitiesOptions: currentEntitiesOptions,
});
expect(dispatch).toHaveBeenCalledWith({
type: 'UPDATE_CURRENT_ENTITIES_OPTIONS',
currentEntitiesOptions,
});
});

it('Sete the current and selected entities options to an empty set if searchEntities fails', async () => {
const kind = new Set(['post']);
const entities = new Set([1, 2, 3]);
const searchEntities = jest.fn(() =>
Promise.resolve(null)
) as jest.Mock<() => Promise<null>>;

const dispatch = jest.fn();
jest.spyOn(React, 'useReducer').mockImplementation((_, state) => [
state,
dispatch,
]);

const Component = () => {
useEntitiesOptionsStorage<number, string>(
{
kind,
entities,
},
// @ts-ignore
searchEntities
);

return null;
};

await act(() => render(<Component />));

const expectedSet = new Set();

expect(dispatch).toHaveBeenCalledWith({
type: 'UPDATE_SELECTED_ENTITIES_OPTIONS',
selectedEntitiesOptions: expectedSet,
});
expect(dispatch).toHaveBeenCalledWith({
type: 'UPDATE_CONTEXTUAL_ENTITIES_OPTIONS',
contextualEntitiesOptions: expectedSet,
});
expect(dispatch).toHaveBeenCalledWith({
type: 'UPDATE_CURRENT_ENTITIES_OPTIONS',
currentEntitiesOptions: expectedSet,
});
});

it('Does not call searchEntities with includes if entities is empty', async () => {
const kind = new Set(['post']);
const entities = new Set();
const searchEntities = jest.fn(() =>
Promise.resolve(
new Set([
{
label: 'post-title',
value: 1,
},
])
)
) as jest.Mock<EntitiesSearch.SearchEntitiesFunction<number, string>>;

const Component = () => {
useEntitiesOptionsStorage<number, string>(
{
kind,
// @ts-ignore
entities,
},
searchEntities
);

return null;
};

await act(() => render(<Component />));

expect(searchEntities).toHaveBeenCalledTimes(1);
expect(searchEntities).toHaveBeenCalledWith('', kind, {
exclude: entities,
});
expect(searchEntities).not.toHaveBeenCalledWith('', kind, {
include: entities,
per_page: '-1',
});
});

it('Execute the action wp-entities-search.on-storage-initialization.error when there is an error on searchEntites', async () => {
const kind = new Set(['post']);
const entities = new Set([1, 2, 3]);
const searchEntities = jest.fn(() =>
Promise.reject('Search Entities Failed.')
);

const Component = () => {
useEntitiesOptionsStorage<number, string>(
{
kind,
entities,
},
// @ts-ignore
searchEntities
);

return null;
};

await act(() => render(<Component />));

expect(doAction).toHaveBeenCalledWith(
'wp-entities-search.on-storage-initialization.error',
'Search Entities Failed.'
);
});
});

0 comments on commit 567c466

Please sign in to comment.