diff --git a/@types/index.d.ts b/@types/index.d.ts index 83d7c50..1f6b7fe 100644 --- a/@types/index.d.ts +++ b/@types/index.d.ts @@ -42,11 +42,6 @@ declare namespace EntitiesSearch { queryArguments?: EntitiesSearch.QueryArguments ) => Promise>; - type ControlOption = Readonly<{ - value: V; - label: string; - }>; - type SingularControl = { [K in keyof BaseControl]: K extends 'value' ? V @@ -55,6 +50,20 @@ declare namespace EntitiesSearch { : BaseControl[K]; }; + interface Record { + get(key: string, fallback?: F): T | F | undefined; + set(key: string, value: T): Record; + } + + interface ControlOption extends Readonly<{ + value: V; + label: string; + }> {} + + interface EnrichedControlOption extends ControlOption, Readonly<{ + readonly extra: Record; + }> {} + interface BaseControl extends Readonly<{ value: Set; diff --git a/sources/client/src/api/search-entities.ts b/sources/client/src/api/search-entities.ts index d49436e..58ec4c9 100644 --- a/sources/client/src/api/search-entities.ts +++ b/sources/client/src/api/search-entities.ts @@ -13,7 +13,7 @@ import { doAction } from '@wordpress/hooks'; */ import { abortControllers } from '../services/abort-controllers'; import { ContextualAbortController } from '../services/contextual-abort-controller'; -import { Set } from '../vo/set'; +import { Set } from '../models/set'; import { fetch } from './fetch'; export async function searchEntities< E >( diff --git a/sources/client/src/components/composite-entities-by-kind.tsx b/sources/client/src/components/composite-entities-by-kind.tsx index 9c1e28f..334fd0b 100644 --- a/sources/client/src/components/composite-entities-by-kind.tsx +++ b/sources/client/src/components/composite-entities-by-kind.tsx @@ -16,7 +16,7 @@ import { useEntitiesOptionsStorage } from '../hooks/use-entities-options-storage import { useSearch } from '../hooks/use-search'; import { orderSelectedOptionsAtTheTop } from '../utils/order-selected-options-at-the-top'; import { uniqueControlOptions } from '../utils/unique-control-options'; -import { Set } from '../vo/set'; +import { Set } from '../models/set'; /** * A composite component that provides a way to search for entities by kind. diff --git a/sources/client/src/components/plural-select-control.tsx b/sources/client/src/components/plural-select-control.tsx index a3cbebb..6d33acb 100644 --- a/sources/client/src/components/plural-select-control.tsx +++ b/sources/client/src/components/plural-select-control.tsx @@ -8,7 +8,7 @@ import React, { JSX } from 'react'; /** * Internal dependencies */ -import { Set } from '../vo/set'; +import { Set } from '../models/set'; import { NoOptionsMessage } from './no-options-message'; export function PluralSelectControl( diff --git a/sources/client/src/hooks/use-entities-options-storage.ts b/sources/client/src/hooks/use-entities-options-storage.ts index 0736a53..a2c2ea0 100644 --- a/sources/client/src/hooks/use-entities-options-storage.ts +++ b/sources/client/src/hooks/use-entities-options-storage.ts @@ -14,7 +14,7 @@ import { doAction } from '@wordpress/hooks'; */ import { makeInitialState } from '../storage/entities/initial-state'; import { reducer } from '../storage/entities/reducer'; -import { Set } from '../vo/set'; +import { Set } from '../models/set'; type _Reducer< E, K > = Reducer< EntitiesSearch.EntitiesState< E, K >, diff --git a/sources/client/src/hooks/use-entity-records.ts b/sources/client/src/hooks/use-entity-records.ts index 4725fcc..dc29632 100644 --- a/sources/client/src/hooks/use-entity-records.ts +++ b/sources/client/src/hooks/use-entity-records.ts @@ -11,7 +11,7 @@ import { useEntityRecords as useCoreEntityRecords } from '@wordpress/core-data'; /** * Internal dependencies */ -import { Set } from '../vo/set'; +import { Set } from '../models/set'; enum ResolveStatus { ERROR = 'ERROR', diff --git a/sources/client/src/hooks/use-query-viewable-post-types.ts b/sources/client/src/hooks/use-query-viewable-post-types.ts index 8f161a2..a5456ee 100644 --- a/sources/client/src/hooks/use-query-viewable-post-types.ts +++ b/sources/client/src/hooks/use-query-viewable-post-types.ts @@ -6,7 +6,7 @@ import EntitiesSearch from '@types'; /** * Internal dependencies */ -import { Set } from '../vo/set'; +import { Set } from '../models/set'; import { useEntityRecords } from './use-entity-records'; /** diff --git a/sources/client/src/hooks/use-query-viewable-taxonomies.ts b/sources/client/src/hooks/use-query-viewable-taxonomies.ts index 66b61e1..d64b0d0 100644 --- a/sources/client/src/hooks/use-query-viewable-taxonomies.ts +++ b/sources/client/src/hooks/use-query-viewable-taxonomies.ts @@ -6,7 +6,7 @@ import EntitiesSearch from '@types'; /** * Internal dependencies */ -import { Set } from '../vo/set'; +import { Set } from '../models/set'; import { useEntityRecords } from './use-entity-records'; /** diff --git a/sources/client/src/hooks/use-search.ts b/sources/client/src/hooks/use-search.ts index 51beef6..9d05191 100644 --- a/sources/client/src/hooks/use-search.ts +++ b/sources/client/src/hooks/use-search.ts @@ -13,7 +13,7 @@ import { doAction } from '@wordpress/hooks'; /** * Internal dependencies */ -import { Set } from '../vo/set'; +import { Set } from '../models/set'; type SearchPhrase = Parameters< EntitiesSearch.SearchControl[ 'onChange' ] diff --git a/sources/client/src/index.ts b/sources/client/src/index.ts index 346be17..222cb22 100644 --- a/sources/client/src/index.ts +++ b/sources/client/src/index.ts @@ -12,10 +12,12 @@ export * from './hooks/use-entity-records'; export * from './hooks/use-query-viewable-post-types'; export * from './hooks/use-query-viewable-taxonomies'; +export * from './models/set'; +export * from './models/immutable-record'; + export * from './utils/convert-entities-to-control-options'; export * from './utils/is-control-option'; -export * from './utils/order-selected-options-at-the-top'; export * from './utils/unique-control-options'; +export * from './utils/order-selected-options-at-the-top'; -export * from './vo/control-option'; -export * from './vo/set'; +export * from './value-objects/control-option'; diff --git a/sources/client/src/models/immutable-record.ts b/sources/client/src/models/immutable-record.ts new file mode 100644 index 0000000..b1e894d --- /dev/null +++ b/sources/client/src/models/immutable-record.ts @@ -0,0 +1,20 @@ +/** + * External dependencies + */ +import EntitiesSearch from '@types'; + +export class ImmutableRecord< T > implements EntitiesSearch.Record< T > { + readonly #map: Record< string, T > = {}; + + public constructor( map: Record< string, T > = {} ) { + this.#map = map; + } + + public get< F >( key: string, fallback?: F ): T | F | undefined { + return this.#map[ key ] ?? fallback; + } + + public set( key: string, value: T ): ImmutableRecord< T > { + return new ImmutableRecord( { ...this.#map, [ key ]: value } ); + } +} diff --git a/sources/client/src/vo/set.ts b/sources/client/src/models/set.ts similarity index 100% rename from sources/client/src/vo/set.ts rename to sources/client/src/models/set.ts diff --git a/sources/client/src/storage/entities/initial-state.ts b/sources/client/src/storage/entities/initial-state.ts index 6041023..6901552 100644 --- a/sources/client/src/storage/entities/initial-state.ts +++ b/sources/client/src/storage/entities/initial-state.ts @@ -6,7 +6,7 @@ import EntitiesSearch from '@types'; /** * Internal dependencies */ -import { Set } from '../../vo/set'; +import { Set } from '../../models/set'; type Options< V > = EntitiesSearch.ControlOption< V >; diff --git a/sources/client/src/storage/entities/reducer.ts b/sources/client/src/storage/entities/reducer.ts index 913d516..8f1e0c6 100644 --- a/sources/client/src/storage/entities/reducer.ts +++ b/sources/client/src/storage/entities/reducer.ts @@ -6,7 +6,7 @@ import EntitiesSearch from '@types'; /** * Internal dependencies */ -import { Set } from '../../vo/set'; +import { Set } from '../../models/set'; /** * @internal diff --git a/sources/client/src/utils/convert-entities-to-control-options.ts b/sources/client/src/utils/convert-entities-to-control-options.ts index b86ce72..798c3e8 100644 --- a/sources/client/src/utils/convert-entities-to-control-options.ts +++ b/sources/client/src/utils/convert-entities-to-control-options.ts @@ -6,9 +6,10 @@ import EntitiesSearch from '@types'; /** * Internal dependencies */ -import { ControlOption } from '../vo/control-option'; -import { Set } from '../vo/set'; +import { ControlOption } from '../value-objects/control-option'; +import { Set } from '../models/set'; import { assert } from './assert'; +import { ImmutableRecord } from '../models/immutable-record'; export function convertEntitiesToControlOptions< V, @@ -16,12 +17,19 @@ export function convertEntitiesToControlOptions< >( entities: Set< EntitiesFields >, labelKey: string, - valueKey: string + valueKey: string, + ...extraKeys: Array< string > ): Set< EntitiesSearch.ControlOption< V > > { return entities.map( ( entity ) => { const label = entity[ labelKey ]; const value = entity[ valueKey ]; - assert( typeof label === 'string', 'Label Key must be a string' ); - return new ControlOption( label, value ); + assert( typeof label === 'string', 'Label key must be a string' ); + + const extra = extraKeys.reduce( + ( record, key ) => ( { ...record, [ key ]: entity[ key ] } ), + {} + ); + + return new ControlOption( label, value, new ImmutableRecord( extra ) ); } ); } diff --git a/sources/client/src/utils/order-selected-options-at-the-top.ts b/sources/client/src/utils/order-selected-options-at-the-top.ts index af0f19e..c9a28ad 100644 --- a/sources/client/src/utils/order-selected-options-at-the-top.ts +++ b/sources/client/src/utils/order-selected-options-at-the-top.ts @@ -6,7 +6,7 @@ import EntitiesSearch from '@types'; /** * Internal dependencies */ -import { Set } from '../vo/set'; +import { Set } from '../models/set'; export function orderSelectedOptionsAtTheTop< V >( options: Set< EntitiesSearch.ControlOption< V > >, diff --git a/sources/client/src/utils/unique-control-options.ts b/sources/client/src/utils/unique-control-options.ts index e675c3e..43e7a83 100644 --- a/sources/client/src/utils/unique-control-options.ts +++ b/sources/client/src/utils/unique-control-options.ts @@ -6,7 +6,7 @@ import EntitiesSearch from '@types'; /** * Internal dependencies */ -import { Set } from '../vo/set'; +import { Set } from '../models/set'; // TODO Is this necessary due the new Set implementation? export function uniqueControlOptions< V >( diff --git a/sources/client/src/vo/control-option.ts b/sources/client/src/value-objects/control-option.ts similarity index 55% rename from sources/client/src/vo/control-option.ts rename to sources/client/src/value-objects/control-option.ts index 4eb46a7..7267fe0 100644 --- a/sources/client/src/vo/control-option.ts +++ b/sources/client/src/value-objects/control-option.ts @@ -7,12 +7,20 @@ import EntitiesSearch from '@types'; * Internal dependencies */ import { assert } from '../utils/assert'; +import { ImmutableRecord } from '../models/immutable-record'; -export class ControlOption< V > implements EntitiesSearch.ControlOption< V > { +export class ControlOption< V > + implements EntitiesSearch.EnrichedControlOption< V > +{ public readonly label: string; public readonly value: V; + public readonly extra: EntitiesSearch.Record< unknown >; - public constructor( label: string, value: V ) { + public constructor( + label: string, + value: V, + extra: EntitiesSearch.Record< unknown > = new ImmutableRecord() + ) { assert( label !== '', 'ControlOption: Label must be a non empty string.' @@ -24,5 +32,6 @@ export class ControlOption< V > implements EntitiesSearch.ControlOption< V > { this.label = label; this.value = value; + this.extra = extra; } } diff --git a/tests/client/integration/components/composite-entities-by-kind.test.tsx b/tests/client/integration/components/composite-entities-by-kind.test.tsx index 1fc699c..c2c312c 100644 --- a/tests/client/integration/components/composite-entities-by-kind.test.tsx +++ b/tests/client/integration/components/composite-entities-by-kind.test.tsx @@ -21,7 +21,7 @@ import { CompositeEntitiesByKind } from '../../../../sources/client/src/componen import { PluralSelectControl } from '../../../../sources/client/src/components/plural-select-control'; import { SearchControl } from '../../../../sources/client/src/components/search-control'; import { SingularSelectControl } from '../../../../sources/client/src/components/singular-select-control'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; jest.mock( '@wordpress/hooks', () => ( { doAction: jest.fn(), @@ -36,7 +36,11 @@ describe( 'CompositeEntitiesByKind', () => { const rendered = render( Promise.resolve( new Set() ) } + searchEntities={ () => + Promise.resolve( + new Set< EntitiesSearch.ControlOption< any > >() + ) + } entities={ { value: new Set(), onChange: () => {}, @@ -92,7 +96,9 @@ describe( 'CompositeEntitiesByKind', () => { } } kind={ { value: new Set( [ 'post' ] ), - options: new Set(), + options: new Set< + EntitiesSearch.ControlOption< any > + >(), onChange: () => {}, } } > @@ -335,7 +341,9 @@ describe( 'CompositeEntitiesByKind', () => { } } kind={ { value: new Set( [ 'post' ] ), - options: new Set(), + options: new Set< + EntitiesSearch.ControlOption< any > + >(), onChange: () => {}, } } > @@ -381,7 +389,9 @@ describe( 'CompositeEntitiesByKind', () => { } } kind={ { value: new Set( [ 'post' ] ), - options: new Set(), + options: new Set< + EntitiesSearch.ControlOption< any > + >(), onChange: () => {}, } } > @@ -414,7 +424,9 @@ describe( 'CompositeEntitiesByKind', () => { } } kind={ { value: new Set( [ 'post' ] ), - options: new Set(), + options: new Set< + EntitiesSearch.ControlOption< any > + >(), onChange: () => {}, } } > @@ -485,7 +497,11 @@ describe( 'CompositeEntitiesByKind', () => { const rendered = render( Promise.resolve( new Set() ) } + searchEntities={ () => + Promise.resolve( + new Set< EntitiesSearch.ControlOption< any > >() + ) + } entities={ { value: new Set(), onChange: () => {}, diff --git a/tests/client/unit/api/search-entities.test.ts b/tests/client/unit/api/search-entities.test.ts index 18dc60a..3426a3d 100644 --- a/tests/client/unit/api/search-entities.test.ts +++ b/tests/client/unit/api/search-entities.test.ts @@ -15,7 +15,7 @@ import { doAction } from '@wordpress/hooks'; */ import { fetch } from '../../../../sources/client/src/api/fetch'; import { searchEntities } from '../../../../sources/client/src/api/search-entities'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; jest.mock( '@wordpress/hooks', () => ( { doAction: jest.fn(), diff --git a/tests/client/unit/components/plural-select-control.test.tsx b/tests/client/unit/components/plural-select-control.test.tsx index 38e6fbc..076e38e 100644 --- a/tests/client/unit/components/plural-select-control.test.tsx +++ b/tests/client/unit/components/plural-select-control.test.tsx @@ -15,7 +15,7 @@ import { faker } from '@faker-js/faker'; * Internal dependencies */ import { PluralSelectControl } from '../../../../sources/client/src/components/plural-select-control'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; import { buildOptions } from '../utils'; describe( 'Posts Select', () => { diff --git a/tests/client/unit/components/radio-control.test.tsx b/tests/client/unit/components/radio-control.test.tsx index 02580cc..f005ec5 100644 --- a/tests/client/unit/components/radio-control.test.tsx +++ b/tests/client/unit/components/radio-control.test.tsx @@ -12,7 +12,7 @@ import { render, screen, fireEvent } from '@testing-library/react'; * Internal dependencies */ import { RadioControl } from '../../../../sources/client/src/components/radio-control'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; describe( 'KindRadioControl', () => { it( 'renders the component', () => { diff --git a/tests/client/unit/components/singular-select-control.test.tsx b/tests/client/unit/components/singular-select-control.test.tsx index 1f61d83..8c50077 100644 --- a/tests/client/unit/components/singular-select-control.test.tsx +++ b/tests/client/unit/components/singular-select-control.test.tsx @@ -15,7 +15,7 @@ import { faker } from '@faker-js/faker'; * Internal dependencies */ import { SingularSelectControl } from '../../../../sources/client/src/components/singular-select-control'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; import { buildOptions } from '../utils'; describe( 'Post Types Select', () => { diff --git a/tests/client/unit/components/toggle-control.test.tsx b/tests/client/unit/components/toggle-control.test.tsx index c149621..d1db0cc 100644 --- a/tests/client/unit/components/toggle-control.test.tsx +++ b/tests/client/unit/components/toggle-control.test.tsx @@ -12,7 +12,7 @@ import userEvent from '@testing-library/user-event'; * Internal dependencies */ import { ToggleControl } from '../../../../sources/client/src/components/toggle-control'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; const options = new Set( [ { label: 'Option 1', value: '1' }, diff --git a/tests/client/unit/hooks/use-entities-options-storage.test.tsx b/tests/client/unit/hooks/use-entities-options-storage.test.tsx index 851b8e9..18ac548 100644 --- a/tests/client/unit/hooks/use-entities-options-storage.test.tsx +++ b/tests/client/unit/hooks/use-entities-options-storage.test.tsx @@ -17,7 +17,7 @@ import { doAction } from '@wordpress/hooks'; * Internal dependencies */ import { useEntitiesOptionsStorage } from '../../../../sources/client/src/hooks/use-entities-options-storage'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; jest.mock( '@wordpress/hooks', () => ( { doAction: jest.fn(), diff --git a/tests/client/unit/hooks/use-query-viewable-post-types.test.ts b/tests/client/unit/hooks/use-query-viewable-post-types.test.ts index c05a1a9..abd30a5 100644 --- a/tests/client/unit/hooks/use-query-viewable-post-types.test.ts +++ b/tests/client/unit/hooks/use-query-viewable-post-types.test.ts @@ -11,7 +11,7 @@ import { describe, it, jest, expect } from '@jest/globals'; */ import { useEntityRecords } from '../../../../sources/client/src/hooks/use-entity-records'; import { useQueryViewablePostTypes } from '../../../../sources/client/src/hooks/use-query-viewable-post-types'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; jest.mock( '@wordpress/data', () => { return { diff --git a/tests/client/unit/hooks/use-query-viewable-taxonomies.test.ts b/tests/client/unit/hooks/use-query-viewable-taxonomies.test.ts index cfdff7c..e0f4028 100644 --- a/tests/client/unit/hooks/use-query-viewable-taxonomies.test.ts +++ b/tests/client/unit/hooks/use-query-viewable-taxonomies.test.ts @@ -11,7 +11,7 @@ import { describe, expect, it, jest } from '@jest/globals'; */ import { useEntityRecords } from '../../../../sources/client/src/hooks/use-entity-records'; import { useQueryViewableTaxonomies } from '../../../../sources/client/src/hooks/use-query-viewable-taxonomies'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; jest.mock( '../../../../sources/client/src/hooks/use-entity-records', () => { return { diff --git a/tests/client/unit/hooks/use-search.test.ts b/tests/client/unit/hooks/use-search.test.ts index fa2ee60..75e4b71 100644 --- a/tests/client/unit/hooks/use-search.test.ts +++ b/tests/client/unit/hooks/use-search.test.ts @@ -22,7 +22,7 @@ import { doAction } from '@wordpress/hooks'; * Internal dependencies */ import { useSearch } from '../../../../sources/client/src/hooks/use-search'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; jest.mock( '@wordpress/compose', () => ( { useThrottle: ( callback: ( phrase: string ) => void ) => callback, diff --git a/tests/client/unit/models/immutable-record.test.ts b/tests/client/unit/models/immutable-record.test.ts new file mode 100644 index 0000000..741bfa9 --- /dev/null +++ b/tests/client/unit/models/immutable-record.test.ts @@ -0,0 +1,28 @@ +/** + * External dependencies + */ +import { describe, it, expect } from '@jest/globals'; + +/** + * Internal dependencies + */ +import { ImmutableRecord } from '../../../../sources/client/src/models/immutable-record'; + +describe( 'ImmutableRecord', () => { + it( 'should get a value from the map', () => { + const immutableRecord = new ImmutableRecord( { key: 'value' } ); + expect( immutableRecord.get( 'key' ) ).toBe( 'value' ); + } ); + + it( 'should get a fallback value from the map', () => { + const immutableRecord = new ImmutableRecord(); + expect( immutableRecord.get( 'key', 'fallback' ) ).toBe( 'fallback' ); + } ); + + it( 'record is immutable', () => { + const immutableRecord = new ImmutableRecord( { key: 'value' } ); + const newRecord = immutableRecord.set( 'key', 'newValue' ); + expect( newRecord.get( 'key' ) ).toBe( 'newValue' ); + expect( immutableRecord.get( 'key' ) ).toBe( 'value' ); + } ); +} ); diff --git a/tests/client/unit/vo/set.test.ts b/tests/client/unit/models/set.test.ts similarity index 98% rename from tests/client/unit/vo/set.test.ts rename to tests/client/unit/models/set.test.ts index 6174fbb..a0e77c6 100644 --- a/tests/client/unit/vo/set.test.ts +++ b/tests/client/unit/models/set.test.ts @@ -6,7 +6,7 @@ import { describe, expect, it } from '@jest/globals'; /** * Internal dependencies */ -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; describe( 'Set', () => { it( 'Should be empty when created', () => { diff --git a/tests/client/unit/storage/reducer.test.ts b/tests/client/unit/storage/reducer.test.ts index 4dd7024..0baaa28 100644 --- a/tests/client/unit/storage/reducer.test.ts +++ b/tests/client/unit/storage/reducer.test.ts @@ -11,7 +11,7 @@ import { faker } from '@faker-js/faker'; * Internal dependencies */ import { reducer } from '../../../../sources/client/src/storage/entities/reducer'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; let state: EntitiesSearch.EntitiesState< number, string >; diff --git a/tests/client/unit/utils.ts b/tests/client/unit/utils.ts index 6bd695f..adfd168 100644 --- a/tests/client/unit/utils.ts +++ b/tests/client/unit/utils.ts @@ -8,7 +8,7 @@ import { faker } from '@faker-js/faker'; /** * Internal dependencies */ -import { Set } from '../../../sources/client/src/vo/set'; +import { Set } from '../../../sources/client/src/models/set'; export function buildOptions(): Set< EntitiesSearch.ControlOption< string > > { let options = new Set< EntitiesSearch.ControlOption< string > >(); diff --git a/tests/client/unit/utils/convert-entities-to-control-options.test.ts b/tests/client/unit/utils/convert-entities-to-control-options.test.ts index 2d4eb86..ddb6f43 100644 --- a/tests/client/unit/utils/convert-entities-to-control-options.test.ts +++ b/tests/client/unit/utils/convert-entities-to-control-options.test.ts @@ -12,23 +12,26 @@ import { faker } from '@faker-js/faker'; * Internal dependencies */ import { convertEntitiesToControlOptions } from '../../../../sources/client/src/utils/convert-entities-to-control-options'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; + +type ExtendedSearchEntityFields = EntitiesSearch.SearchEntityFields & { + type: string; + excerpt: string; +}; describe( 'Convert Entities To Control Options', () => { it( 'correctly convert entities to control options', () => { const rawEntities = []; for ( let count = 0; count < 10; ++count ) { rawEntities.push( - fromPartial< EntitiesSearch.SearchEntityFields >( { + fromPartial< ExtendedSearchEntityFields >( { title: faker.word.noun(), id: faker.number.int(), } ) ); } - const entities = new Set< EntitiesSearch.SearchEntityFields >( - rawEntities - ); + const entities = new Set< ExtendedSearchEntityFields >( rawEntities ); const options = convertEntitiesToControlOptions( entities, @@ -44,20 +47,42 @@ describe( 'Convert Entities To Control Options', () => { const rawEntities = []; for ( let count = 0; count < 10; ++count ) { rawEntities.push( - fromPartial< EntitiesSearch.SearchEntityFields >( { + fromPartial< ExtendedSearchEntityFields >( { title: faker.word.noun(), id: faker.number.int(), } ) ); } - const entities = new Set< EntitiesSearch.SearchEntityFields >( - rawEntities - ); + const entities = new Set< ExtendedSearchEntityFields >( rawEntities ); expect( () => { // To make the test fail, we pass the id as the label key convertEntitiesToControlOptions( entities, 'id', 'id' ); } ).toThrow(); } ); + + it( 'add extra data to the control options', () => { + const rawEntity = fromPartial< ExtendedSearchEntityFields >( { + title: faker.word.noun(), + id: faker.number.int(), + type: faker.helpers.arrayElement( [ 'post', 'page', 'product' ] ), + excerpt: faker.lorem.sentence(), + } ); + + const entities = new Set< ExtendedSearchEntityFields >( [ rawEntity ] ); + const options = convertEntitiesToControlOptions( + entities, + 'title', + 'id', + 'type', + 'excerpt' + ); + + const option = options.first(); + // @ts-ignore + expect( option?.extra.get( 'type' ) ).toEqual( rawEntity.type ); + // @ts-ignore + expect( option?.extra.get( 'excerpt' ) ).toEqual( rawEntity.excerpt ); + } ); } ); diff --git a/tests/client/unit/utils/ordered-selected-options-at-the-top.test.ts b/tests/client/unit/utils/ordered-selected-options-at-the-top.test.ts index 8a2c213..f667b42 100644 --- a/tests/client/unit/utils/ordered-selected-options-at-the-top.test.ts +++ b/tests/client/unit/utils/ordered-selected-options-at-the-top.test.ts @@ -11,7 +11,7 @@ import { faker } from '@faker-js/faker'; * Internal dependencies */ import { orderSelectedOptionsAtTheTop } from '../../../../sources/client/src/utils/order-selected-options-at-the-top'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; describe( 'Ordered Selected Options at the Top', () => { /* diff --git a/tests/client/unit/utils/unique-control-options.test.ts b/tests/client/unit/utils/unique-control-options.test.ts index 6482f1a..8d2ee40 100644 --- a/tests/client/unit/utils/unique-control-options.test.ts +++ b/tests/client/unit/utils/unique-control-options.test.ts @@ -9,7 +9,7 @@ import { describe, expect, it } from '@jest/globals'; * Internal dependencies */ import { uniqueControlOptions } from '../../../../sources/client/src/utils/unique-control-options'; -import { Set } from '../../../../sources/client/src/vo/set'; +import { Set } from '../../../../sources/client/src/models/set'; describe( 'Unique Control Options', () => { it( 'Do not allow same control options within the same set', () => { diff --git a/tests/client/unit/vo/control-option.test.ts b/tests/client/unit/value-objects/control-option.test.ts similarity index 64% rename from tests/client/unit/vo/control-option.test.ts rename to tests/client/unit/value-objects/control-option.test.ts index 89744a6..9660cdc 100644 --- a/tests/client/unit/vo/control-option.test.ts +++ b/tests/client/unit/value-objects/control-option.test.ts @@ -6,7 +6,8 @@ import { describe, it, expect } from '@jest/globals'; /** * Internal dependencies */ -import { ControlOption } from '../../../../sources/client/src/vo/control-option'; +import { ControlOption } from '../../../../sources/client/src/value-objects/control-option'; +import { ImmutableRecord } from '../../../../sources/client/src/models/immutable-record'; describe( 'ControlOption', () => { it( 'should create a new ControlOption', () => { @@ -26,4 +27,15 @@ describe( 'ControlOption', () => { 'ControlOption: Value must be a non empty string.' ); } ); + + it( 'should create a new ControlOption with extra data', () => { + const controlOption = new ControlOption( + 'label', + 'value', + new ImmutableRecord( { + key: 'value', + } ) + ); + expect( controlOption.extra.get( 'key' ) ).toBe( 'value' ); + } ); } );