From fda7116106e98b1cbc67e2f1ecdb5f226726fad1 Mon Sep 17 00:00:00 2001 From: travor20814 Date: Wed, 6 Dec 2023 11:00:11 +0800 Subject: [PATCH 1/6] feat(core/table): refactor table column typings, re #203, re #136 --- packages/core/src/table/table.ts | 49 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/core/src/table/table.ts b/packages/core/src/table/table.ts index b99938d6..9916ea14 100644 --- a/packages/core/src/table/table.ts +++ b/packages/core/src/table/table.ts @@ -51,10 +51,12 @@ export interface TableDataSourceWithID extends TableRecord { export type TableDataSource = TableDataSourceWithKey | TableDataSourceWithID; -export type TableColumn = { - dataIndex: string; +export interface TableColumnBase { + /** Column's primary key */ + key?: string; + dataIndex?: string; + render?(source: SourceType, index: number, column: ExpandedTableColumn): any; title?: string; - render?(source: SourceType, index: number, column: TableColumn): any; renderTitle?(classes: typeof tableClasses): any; renderTooltipTitle?(source: SourceType): string; // == Custom column style == @@ -64,7 +66,11 @@ export type TableColumn = { width?: number; // == Feature sorting == sorter?(a: any, b: any): number; - onSorted?(dataIndex: string, sortedType: string): void; + /** + * The `key` is automatically generated by mzn. If you need a more specific key, + * please provide `key` within the column. + */ + onSorted?(key: string, sortedType: string): void; // == Feature editing == editable?: boolean; setCellProps?(record: SourceType): TableRecord; @@ -73,7 +79,40 @@ export type TableColumn = { ellipsis?: boolean; /** force display tooltip whenever content is hovered */ forceShownTooltipWhenHovered?: boolean; -}; +} + +export interface TableColumnDataIndexAndTitle extends TableColumnBase { + dataIndex: string; + render?: never; + title: string; + renderTitle?: never; +} + +export interface TableColumnDataIndexAndRenderTitle extends TableColumnBase { + dataIndex: string; + render?: never; + title?: never; + renderTitle(classes: typeof tableClasses): any; +} + +export interface TableColumnRenderAndTitle extends TableColumnBase { + dataIndex?: never; + render(source: SourceType, index: number, column: ExpandedTableColumn): any; + title: string; + renderTitle?: never; +} + +export interface TableColumnRenderAndRenderTitle extends TableColumnBase { + dataIndex?: never; + render(source: SourceType, index: number, column: ExpandedTableColumn): any; + title?: never; + renderTitle(classes: typeof tableClasses): any; +} + +export type TableColumn = TableColumnDataIndexAndTitle +| TableColumnDataIndexAndRenderTitle +| TableColumnRenderAndTitle +| TableColumnRenderAndRenderTitle; export type ExpandedTableColumn = Omit>, 'title' | From 60515a2a65992428f4e3ad97949abcf4b6a78072 Mon Sep 17 00:00:00 2001 From: travor20814 Date: Wed, 6 Dec 2023 11:04:18 +0800 Subject: [PATCH 2/6] feat(react/table): implementing new table columns typings, resolve #203, resolve #136 --- packages/react/src/Table/TableBodyRow.tsx | 9 +++++---- packages/react/src/Table/TableContext.ts | 2 +- packages/react/src/Table/TableExpandedTable.tsx | 14 ++++++-------- packages/react/src/Table/TableHeader.tsx | 2 +- .../Table/editable/TableEditRenderWrapper.tsx | 10 +++++----- .../src/Table/sorting/TableSortingIcon.tsx | 11 ++++++++--- .../react/src/Table/sorting/useTableSorting.ts | 17 ++++++++++------- 7 files changed, 36 insertions(+), 29 deletions(-) diff --git a/packages/react/src/Table/TableBodyRow.tsx b/packages/react/src/Table/TableBodyRow.tsx index 6498f742..6993eb25 100644 --- a/packages/react/src/Table/TableBodyRow.tsx +++ b/packages/react/src/Table/TableBodyRow.tsx @@ -143,14 +143,15 @@ const TableBodyRow = forwardRef( ) : null} {(columns ?? []).map((column: TableColumn>, idx) => { - const ellipsis = !!(get(rowData, column.dataIndex)) && (column.ellipsis ?? true); + const autoGrabData = column.dataIndex ? get(rowData, column.dataIndex) : ''; + const ellipsis = !!(autoGrabData) && (column.ellipsis ?? true); const tooltipTitle = ( - column.renderTooltipTitle?.(rowData) ?? get(rowData, column.dataIndex) + column.renderTooltipTitle?.(rowData) ?? autoGrabData ) as (string | number); return ( ( rowData, rowIndex, column, - ) || get(rowData, column.dataIndex)} + ) || autoGrabData} diff --git a/packages/react/src/Table/TableContext.ts b/packages/react/src/Table/TableContext.ts index fe2a92b3..2f9a7e8a 100644 --- a/packages/react/src/Table/TableContext.ts +++ b/packages/react/src/Table/TableContext.ts @@ -20,7 +20,7 @@ export interface RowSelectionContext extends Pick /** typeof sorting */ export interface SortingContext { - onSort(v: Pick>, 'dataIndex' | 'sorter' | 'onSorted'>): void; + onSort(v: Pick>, 'key' | 'dataIndex' | 'sorter' | 'onSorted'>): void; onResetAll(): void; sortedOn: string; sortedType: string; diff --git a/packages/react/src/Table/TableExpandedTable.tsx b/packages/react/src/Table/TableExpandedTable.tsx index 0ef99ae2..7dd1c914 100644 --- a/packages/react/src/Table/TableExpandedTable.tsx +++ b/packages/react/src/Table/TableExpandedTable.tsx @@ -5,9 +5,7 @@ import { import { tableClasses as classes, TableDataSource, - TableColumn, ExpandedTableColumn, - TableRecord, getColumnStyle, getCellStyle, } from '@mezzanine-ui/core/table'; @@ -50,16 +48,16 @@ const TableExpandedTable = forwardRef(f > {((renderedExpandedContent.columns || columns) ?? []) - .map((column: TableColumn>, index: number) => { - const ellipsis = !!(get(source, column.dataIndex)) && (column.ellipsis ?? true); + .map((column: ExpandedTableColumn, index: number) => { + const autoGrabData = column.dataIndex ? get(source, column.dataIndex) : ''; + const ellipsis = !!(autoGrabData) && (column.ellipsis ?? true); const tooltipTitle = ( - column.renderTooltipTitle?.(source) ?? get(source, column.dataIndex) + column.renderTooltipTitle?.(source) ?? autoGrabData ) as (string | number); return (
(f source, sourceIndex, column, - ) || get(source, column.dataIndex)} + ) || autoGrabData}
); diff --git a/packages/react/src/Table/TableHeader.tsx b/packages/react/src/Table/TableHeader.tsx index 6c5f1efb..b7eb9254 100644 --- a/packages/react/src/Table/TableHeader.tsx +++ b/packages/react/src/Table/TableHeader.tsx @@ -71,7 +71,7 @@ const TableHeader = forwardRef>, idx) => ( , - TableColumn> { + TableColumnBase> { rowData: TableDataSource; } @@ -42,9 +42,9 @@ function TableEditRenderWrapper({ } return ( - + <> {children} - + ); } diff --git a/packages/react/src/Table/sorting/TableSortingIcon.tsx b/packages/react/src/Table/sorting/TableSortingIcon.tsx index c4637514..ccf0fcb9 100644 --- a/packages/react/src/Table/sorting/TableSortingIcon.tsx +++ b/packages/react/src/Table/sorting/TableSortingIcon.tsx @@ -31,16 +31,18 @@ const TableSortingIcon = forwardRef( ...rest } = props; + const uniqueId = useMemo(() => crypto.randomUUID(), []); + const { sorting, } = useContext(TableContext) || {}; const { - dataIndex, + key = uniqueId, } = column; /** styling */ - const currentType = (dataIndex === sorting?.sortedOn ? sorting.sortedType : 'none') as SortedType; + const currentType = (key === sorting?.sortedOn ? sorting.sortedType : 'none') as SortedType; const currentIconStyle: { color: IconColor, style: { transform: string } } = useMemo(() => ({ color: currentType === 'none' ? 'secondary' : 'primary', style: { @@ -62,7 +64,10 @@ const TableSortingIcon = forwardRef( onClick={(evt) => { evt.stopPropagation(); - sorting?.onSort?.(column); + sorting?.onSort?.({ + ...column, + key, + }); }} style={currentIconStyle.style} /> diff --git a/packages/react/src/Table/sorting/useTableSorting.ts b/packages/react/src/Table/sorting/useTableSorting.ts index 58f62259..7b3d2748 100644 --- a/packages/react/src/Table/sorting/useTableSorting.ts +++ b/packages/react/src/Table/sorting/useTableSorting.ts @@ -90,17 +90,17 @@ export function useTableSorting(props: UseTableSorting) { const onChange = useLastCallback<( v: Pick>, - 'dataIndex' | 'sorter' | 'onSorted'> + 'key' | 'dataIndex' | 'sorter' | 'onSorted'> ) => void>( (opts) => { - const { dataIndex, sorter, onSorted } = opts; - const isChosenFromOneToAnother = sortedOn && dataIndex !== sortedOn; + const { key = '', dataIndex, sorter, onSorted } = opts; + const isChosenFromOneToAnother = sortedOn && key !== sortedOn; const nextSortedType = getNextSortedType(isChosenFromOneToAnother ? 'none' : sortedType); const onMappingSources = (sources: TableDataSource[]) => { setDataSource(sources); - onSorted?.(dataIndex, nextSortedType); + onSorted?.(key, nextSortedType); }; // only apply changes when column sorter is given @@ -112,17 +112,20 @@ export function useTableSorting(props: UseTableSorting) { switch (nextSortedType) { case 'desc': case 'asc': { - // update current working dataIndex - setSortedOn(dataIndex); + // update current working key + setSortedOn(key); // getting new source instance (when switch between sorter, should use origin dataSource) let newSource = (isChosenFromOneToAnother ? dataSourceProp : dataSource).slice(0); if (typeof sorter === 'function') { + console.warn( + 'When using a `sorter` function, please provide the `dataIndex` to make sure it worked as expected.', + ); // sort by given sorter newSource = newSource.sort((a, b) => ( // reverse result when sorted type is ascending - (sorter(get(a, dataIndex), get(b, dataIndex))) * (nextSortedType === 'asc' ? -1 : 1) + (sorter(get(a, dataIndex || ''), get(b, dataIndex || ''))) * (nextSortedType === 'asc' ? -1 : 1) )); } From 73e204a6112c6444cc6760d15547a6c1801adf2c Mon Sep 17 00:00:00 2001 From: travor20814 Date: Wed, 6 Dec 2023 11:05:20 +0800 Subject: [PATCH 3/6] chore(react/table): correct table stories due to new changes --- packages/react/src/Table/Table.stories.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/react/src/Table/Table.stories.tsx b/packages/react/src/Table/Table.stories.tsx index 95137ef8..4b04049c 100644 --- a/packages/react/src/Table/Table.stories.tsx +++ b/packages/react/src/Table/Table.stories.tsx @@ -52,18 +52,19 @@ const columns: TableColumn[] = [{ return -1; }, // eslint-disable-next-line no-console - onSorted: (dataIndex, sortedType) => { console.log(dataIndex, sortedType); }, + onSorted: (key, sortedType) => { console.log(key, sortedType); }, }, { title: 'Address', dataIndex: 'address', }, { + key: 'age-column', title: 'Age', dataIndex: 'age', renderTooltipTitle: (source) => `${source.name} is age ${source.age}.`, forceShownTooltipWhenHovered: true, sorter: (a: number, b: number) => b - a, // eslint-disable-next-line no-console - onSorted: (dataIndex, sortedType) => { console.log(dataIndex, sortedType); }, + onSorted: (key, sortedType) => { console.log(key, sortedType); }, width: 80, }, { title: 'Tel', @@ -474,7 +475,6 @@ export const WithActions = () => { title: 'Age', dataIndex: 'age', }, { - dataIndex: '', renderTitle: renderHeaderActions, render: renderRowActions, // styling @@ -616,7 +616,7 @@ export const WithRefresh = () => { export const ExpandedWithString = () => { const customizedColumns: TableColumn[] = [{ title: 'Name', - dataIndex: 'name', + render: (source) => source.key, }, { title: 'Address', dataIndex: 'address', @@ -790,7 +790,7 @@ export const Editable = () => { ) : ( { /** actions column */ return { ...column, + dataIndex: undefined, render: renderRowActions, }; } From f8a5f3dc039ac6eccd8f91a0909763c6e7dca9b0 Mon Sep 17 00:00:00 2001 From: travor20814 Date: Wed, 6 Dec 2023 11:06:04 +0800 Subject: [PATCH 4/6] test(react/table): correct table test cases --- packages/react/src/Table/Table.spec.tsx | 1 + packages/react/src/Table/TableBody.spec.tsx | 1 + .../react/src/Table/TableBodyRow.spec.tsx | 12 +++++++++- .../src/Table/TableExpandedTable.spec.tsx | 7 +++++- packages/react/src/Table/TableHeader.spec.tsx | 6 ++++- .../editable/TableEditRenderWrapper.spec.tsx | 1 + .../Table/sorting/TableSortingIcon.spec.tsx | 23 +++++++++++-------- .../Table/sorting/useTableSorting.spec.tsx | 7 ++++++ 8 files changed, 45 insertions(+), 13 deletions(-) diff --git a/packages/react/src/Table/Table.spec.tsx b/packages/react/src/Table/Table.spec.tsx index 420f3d35..4485bd52 100644 --- a/packages/react/src/Table/Table.spec.tsx +++ b/packages/react/src/Table/Table.spec.tsx @@ -33,6 +33,7 @@ const defaultSources: DataType[] = [{ }]; const defaultColumns: TableColumn[] = [{ + key: 'foo', dataIndex: 'foo', title: 'foo', }]; diff --git a/packages/react/src/Table/TableBody.spec.tsx b/packages/react/src/Table/TableBody.spec.tsx index 14f94e28..be915617 100644 --- a/packages/react/src/Table/TableBody.spec.tsx +++ b/packages/react/src/Table/TableBody.spec.tsx @@ -23,6 +23,7 @@ const defaultSources: DataType[] = [{ }]; const defaultColumns: TableColumn[] = [{ + key: 'foo', dataIndex: 'foo', title: 'foo', }]; diff --git a/packages/react/src/Table/TableBodyRow.spec.tsx b/packages/react/src/Table/TableBodyRow.spec.tsx index 10b04d5a..d8d24e0b 100644 --- a/packages/react/src/Table/TableBodyRow.spec.tsx +++ b/packages/react/src/Table/TableBodyRow.spec.tsx @@ -81,13 +81,16 @@ describe('', () => { it('ellipsis control should set to true by default, and false when no data/disabled', () => { const columns: TableColumn[] = [{ + key: 'name', dataIndex: 'name', title: 'name', }, { + key: 'not-existed', dataIndex: 'not-existed', title: 'bar', ellipsis: true, }, { + key: 'name', dataIndex: 'name', title: 'foo', ellipsis: false, @@ -118,6 +121,7 @@ describe('', () => { describe('columns are given', () => { const columns: TableColumn[] = [{ + key: 'name', dataIndex: 'name', title: 'foo', headerClassName: undefined, @@ -127,11 +131,12 @@ describe('', () => { width: 80, align: 'center', }, { - dataIndex: 'bar', + key: 'bar', title: 'bar', align: 'start', render: () => 'bar-render', }, { + key: 'foo.bar', dataIndex: 'foo.bar', title: 'foo', }]; @@ -301,8 +306,10 @@ describe('', () => { name: 'bar', }], columns: [{ + key: 'name', dataIndex: 'name', }, { + key: 'name2', dataIndex: 'name', }], }), @@ -351,8 +358,10 @@ describe('', () => { expandedRowRender: () => ({ dataSource: [], columns: [{ + key: 'name', dataIndex: 'name', }, { + key: 'name2', dataIndex: 'name', }], }), @@ -391,6 +400,7 @@ describe('', () => { describe('exceptions handle', () => { it('column.width/column.align not given', () => { const columns: TableColumn[] = [{ + key: 'name', dataIndex: 'name', title: 'name', }]; diff --git a/packages/react/src/Table/TableExpandedTable.spec.tsx b/packages/react/src/Table/TableExpandedTable.spec.tsx index 9829c600..11a080ab 100644 --- a/packages/react/src/Table/TableExpandedTable.spec.tsx +++ b/packages/react/src/Table/TableExpandedTable.spec.tsx @@ -28,11 +28,13 @@ const dataSource: DataType[] = [{ }]; const columns: TableColumn[] = [{ + key: 'name', dataIndex: 'name', title: 'name', width: 80, align: 'center', }, { + key: 'age', dataIndex: 'age', title: 'foo', ellipsis: false, @@ -49,9 +51,12 @@ const expandedSources: DataType[] = [{ }]; const expandedColumns: TableColumn[] = [{ + key: 'name', dataIndex: 'name', + title: '', }, { - dataIndex: 'name', + key: 'name', + title: '', render: () => 'render name', }]; diff --git a/packages/react/src/Table/TableHeader.spec.tsx b/packages/react/src/Table/TableHeader.spec.tsx index d1ab72f3..44b631d9 100644 --- a/packages/react/src/Table/TableHeader.spec.tsx +++ b/packages/react/src/Table/TableHeader.spec.tsx @@ -19,6 +19,8 @@ type DataType = { key: string; }; +global.crypto.randomUUID = jest.fn().mockImplementation(() => 'UUID-UUID-UUID-UUID-UUID'); + describe('', () => { afterEach(cleanupHook); @@ -36,6 +38,7 @@ describe('', () => { describe('columns are given', () => { const columns: TableColumn[] = [{ + key: 'foo', dataIndex: 'foo', title: 'foo', headerClassName: undefined, @@ -44,8 +47,8 @@ describe('', () => { width: 80, align: 'center', }, { + key: 'bar', dataIndex: 'bar', - title: 'bar', align: 'start', renderTitle: () => 'bar', sorter: () => 1, @@ -158,6 +161,7 @@ describe('', () => { describe('exceptions handle', () => { it('column.width/column.align not given', () => { const columns: TableColumn[] = [{ + key: 'foo', dataIndex: 'foo', title: 'foo', }]; diff --git a/packages/react/src/Table/editable/TableEditRenderWrapper.spec.tsx b/packages/react/src/Table/editable/TableEditRenderWrapper.spec.tsx index d9cc3ad3..510085e3 100644 --- a/packages/react/src/Table/editable/TableEditRenderWrapper.spec.tsx +++ b/packages/react/src/Table/editable/TableEditRenderWrapper.spec.tsx @@ -42,6 +42,7 @@ describe('', () => { }} > 'UUID-UUID-UUID-UUID-UUID'); describe('', () => { afterEach(cleanupHook); it('should bind host class', () => { - const { getHostHTMLElement } = render(); + const { getHostHTMLElement } = render(); const element = getHostHTMLElement(); expect(element.classList.contains('mzn-table__icon')).toBeTruthy(); @@ -47,12 +50,12 @@ describe('', () => { ...defaultMockingContextValue, sorting: { ...defaultMockingContextValue.sorting, - sortedOn: dataIndex, + sortedOn: key, sortedType: mode, }, }} > - + , ); const element = getHostHTMLElement(); @@ -89,12 +92,12 @@ describe('', () => { sorting: { ...defaultMockingContextValue.sorting, onSort, - sortedOn: dataIndex, + sortedOn: key, sortedType: 'none', }, }} > - + , ); const element = getHostHTMLElement(); @@ -103,7 +106,7 @@ describe('', () => { fireEvent.click(element); }); - expect(valueGetFromOnSort).toStrictEqual({ dataIndex }); + expect(valueGetFromOnSort).toStrictEqual(defaultColumn); }); it('should icon remain default state when is not sorting on its column', () => { @@ -113,12 +116,12 @@ describe('', () => { ...defaultMockingContextValue, sorting: { ...defaultMockingContextValue.sorting, - sortedOn: `${dataIndex}-bar`, + sortedOn: `${key}-bar`, sortedType: 'asc', }, }} > - + , ); const element = getHostHTMLElement(); @@ -137,7 +140,7 @@ describe('', () => { beforeEach(() => { const { getHostHTMLElement } = render( - + , ); const element = getHostHTMLElement(); diff --git a/packages/react/src/Table/sorting/useTableSorting.spec.tsx b/packages/react/src/Table/sorting/useTableSorting.spec.tsx index 8b45eda6..61856d15 100644 --- a/packages/react/src/Table/sorting/useTableSorting.spec.tsx +++ b/packages/react/src/Table/sorting/useTableSorting.spec.tsx @@ -57,6 +57,7 @@ describe('useTableSorting()', () => { TestRenderer.act(() => { onChange({ + key: 'age', dataIndex: 'age', sorter: numberSorter, }); @@ -70,6 +71,7 @@ describe('useTableSorting()', () => { TestRenderer.act(() => { onChange({ + key: 'age', dataIndex: 'age', sorter: numberSorter, }); @@ -83,6 +85,7 @@ describe('useTableSorting()', () => { TestRenderer.act(() => { onChange({ + key: 'age', dataIndex: 'age', sorter: numberSorter, }); @@ -109,6 +112,7 @@ describe('useTableSorting()', () => { TestRenderer.act(() => { onChange({ + key: 'age', dataIndex: 'age', sorter: numberSorter, }); @@ -121,6 +125,7 @@ describe('useTableSorting()', () => { TestRenderer.act(() => { onChange({ + key: 'count', dataIndex: 'count', sorter: numberSorter, }); @@ -154,6 +159,7 @@ describe('useTableSorting()', () => { TestRenderer.act(() => { onChange({ + key: 'age', dataIndex: 'age', sorter: numberSorter, onSorted: onAgeSorted, @@ -208,6 +214,7 @@ describe('useTableSorting()', () => { TestRenderer.act(() => { onChange({ + key: 'age', dataIndex: 'age', }); }); From 0854361084dd346a44ecac58dff3ac2b67914904 Mon Sep 17 00:00:00 2001 From: travor20814 Date: Wed, 6 Dec 2023 11:28:26 +0800 Subject: [PATCH 5/6] feat(react/table): use crypto.getRandomValues to gen id for better browser support --- packages/react/src/Table/sorting/TableSortingIcon.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/Table/sorting/TableSortingIcon.tsx b/packages/react/src/Table/sorting/TableSortingIcon.tsx index ccf0fcb9..827e39a4 100644 --- a/packages/react/src/Table/sorting/TableSortingIcon.tsx +++ b/packages/react/src/Table/sorting/TableSortingIcon.tsx @@ -31,7 +31,7 @@ const TableSortingIcon = forwardRef( ...rest } = props; - const uniqueId = useMemo(() => crypto.randomUUID(), []); + const uniqueId = useMemo(() => `${crypto.getRandomValues(new Uint32Array(5))[0]}`, []); const { sorting, From b0a927ebda2032750c8cbac4c9254ba2d49474d4 Mon Sep 17 00:00:00 2001 From: travor20814 Date: Wed, 6 Dec 2023 11:28:56 +0800 Subject: [PATCH 6/6] test(react/table): correct table mocking crypto test cases --- packages/react/src/Table/TableHeader.spec.tsx | 2 -- packages/react/src/Table/sorting/TableSortingIcon.spec.tsx | 2 -- 2 files changed, 4 deletions(-) diff --git a/packages/react/src/Table/TableHeader.spec.tsx b/packages/react/src/Table/TableHeader.spec.tsx index 44b631d9..1d233d6c 100644 --- a/packages/react/src/Table/TableHeader.spec.tsx +++ b/packages/react/src/Table/TableHeader.spec.tsx @@ -19,8 +19,6 @@ type DataType = { key: string; }; -global.crypto.randomUUID = jest.fn().mockImplementation(() => 'UUID-UUID-UUID-UUID-UUID'); - describe('', () => { afterEach(cleanupHook); diff --git a/packages/react/src/Table/sorting/TableSortingIcon.spec.tsx b/packages/react/src/Table/sorting/TableSortingIcon.spec.tsx index c26f9c4a..4739be64 100644 --- a/packages/react/src/Table/sorting/TableSortingIcon.spec.tsx +++ b/packages/react/src/Table/sorting/TableSortingIcon.spec.tsx @@ -26,8 +26,6 @@ type DataType = { const key = 'foo'; const defaultColumn = { key: 'foo', title: '', dataIndex: '' }; -global.crypto.randomUUID = jest.fn().mockImplementation(() => 'UUID-UUID-UUID-UUID-UUID'); - describe('', () => { afterEach(cleanupHook);