@object-ui/fields 14.0.0 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +173 -0
- package/README.md +11 -0
- package/dist/__tests__/lookupCellDisplayField.test.d.ts +0 -0
- package/dist/__tests__/lookupCellDisplayName.test.d.ts +0 -0
- package/dist/index.cjs +5 -5
- package/dist/index.d.ts +20 -8
- package/dist/index.js +1222 -1033
- package/dist/widgets/FileField.d.ts +22 -0
- package/dist/widgets/GridField.d.ts +6 -2
- package/dist/widgets/SelectField.d.ts +1 -1
- package/package.json +7 -7
- package/src/__tests__/DateCellRenderer.test.tsx +27 -4
- package/src/__tests__/lookupCellDisplayField.test.tsx +107 -0
- package/src/__tests__/lookupCellDisplayName.test.tsx +119 -0
- package/src/index.tsx +219 -39
- package/src/standard-widgets.test.tsx +35 -0
- package/src/widgets/CurrencyField.tsx +5 -0
- package/src/widgets/FileField.tsx +170 -28
- package/src/widgets/GridField.test.tsx +84 -1
- package/src/widgets/GridField.tsx +32 -2
- package/src/widgets/LookupField.tsx +12 -2
- package/src/widgets/NumberField.tsx +14 -2
- package/src/widgets/PeoplePicker.test.tsx +6 -0
- package/src/widgets/PeoplePicker.tsx +11 -2
- package/src/widgets/SelectField.cascade.test.tsx +3 -3
- package/src/widgets/SelectField.tsx +1 -1
|
@@ -6,3 +6,25 @@ import { FieldWidgetProps } from './types';
|
|
|
6
6
|
* L2: File size validation, per-file progress indicators, error messages.
|
|
7
7
|
*/
|
|
8
8
|
export declare function FileField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<any>): React.JSX.Element;
|
|
9
|
+
/**
|
|
10
|
+
* FileCell — compact upload control for a line-item grid cell (objectui#2360).
|
|
11
|
+
*
|
|
12
|
+
* Same value shape and upload pipeline as {@link FileField}, sized for a 32px
|
|
13
|
+
* grid row: existing files render as removable chips (image thumbnail / file
|
|
14
|
+
* icon + name) and a small button opens the native file picker. No
|
|
15
|
+
* drag-and-drop zone — a grid cell has no room for one; the per-row expand
|
|
16
|
+
* form still offers the full-size FileField.
|
|
17
|
+
*/
|
|
18
|
+
export declare function FileCell({ value, onChange, disabled, multiple, accept, maxSize, 'aria-label': ariaLabel, 'data-cell': dataCell, }: {
|
|
19
|
+
value: any;
|
|
20
|
+
onChange: (value: any) => void;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
multiple?: boolean;
|
|
23
|
+
/** Comma-joined accept list for the native picker (e.g. `"image/*,.pdf"`). */
|
|
24
|
+
accept?: string;
|
|
25
|
+
/** Max file size in bytes (oversize picks are rejected with an inline error). */
|
|
26
|
+
maxSize?: number;
|
|
27
|
+
'aria-label'?: string;
|
|
28
|
+
/** Focus-grid coordinate (see GridField keyboard navigation). */
|
|
29
|
+
'data-cell'?: string;
|
|
30
|
+
}): React.JSX.Element;
|
|
@@ -11,7 +11,7 @@ import { FieldWidgetProps } from './types';
|
|
|
11
11
|
*
|
|
12
12
|
* Column config (a subset of `GridColumnDefinition`):
|
|
13
13
|
* { field, label?, type?, options?, width?, required?, prefix?, step? }
|
|
14
|
-
* type ∈ 'text' | 'number' | 'currency' | 'date' | 'select'
|
|
14
|
+
* type ∈ 'text' | 'number' | 'currency' | 'date' | 'select' | 'lookup' | 'file'
|
|
15
15
|
*
|
|
16
16
|
* Field-level config (from `GridFieldMetadata`):
|
|
17
17
|
* columns, min_rows, max_rows, allow_add, allow_delete, total_field
|
|
@@ -19,7 +19,7 @@ import { FieldWidgetProps } from './types';
|
|
|
19
19
|
export interface GridColumn {
|
|
20
20
|
field: string;
|
|
21
21
|
label?: string;
|
|
22
|
-
type?: 'text' | 'number' | 'currency' | 'date' | 'select' | 'lookup';
|
|
22
|
+
type?: 'text' | 'number' | 'currency' | 'date' | 'select' | 'lookup' | 'file';
|
|
23
23
|
options?: Array<{
|
|
24
24
|
label: string;
|
|
25
25
|
value: string;
|
|
@@ -32,7 +32,11 @@ export interface GridColumn {
|
|
|
32
32
|
reference?: string;
|
|
33
33
|
displayField?: string;
|
|
34
34
|
idField?: string;
|
|
35
|
+
/** Multi-value column: multi-record lookup, or multi-file upload cell. */
|
|
35
36
|
multiple?: boolean;
|
|
37
|
+
/** For `type: 'file'` — accepted MIME types / extensions for the picker
|
|
38
|
+
* (e.g. `['image/*', '.pdf']`). Omit to accept anything. */
|
|
39
|
+
accept?: string[];
|
|
36
40
|
/**
|
|
37
41
|
* Hidden from the grid by default but revealable via the column chooser.
|
|
38
42
|
* Set by `deriveColumns` for fields beyond the default-visible budget — the
|
|
@@ -6,7 +6,7 @@ import { FieldWidgetProps } from './types';
|
|
|
6
6
|
* Supports cascading / role-gated options (#2284): each option may carry a
|
|
7
7
|
* `visibleWhen` CEL predicate, evaluated against the live form record +
|
|
8
8
|
* `current_user`, so the offered set narrows as a controlling field changes
|
|
9
|
-
* (`record.country == 'cn'`) or by role (`'admin' in current_user.
|
|
9
|
+
* (`record.country == 'cn'`) or by role (`'admin' in current_user.positions`). A
|
|
10
10
|
* field declares which sibling fields drive its list via `dependsOn`; while any
|
|
11
11
|
* of those is empty the control is gated with a "select the parent first" hint,
|
|
12
12
|
* mirroring the dependent-lookup UX.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/fields",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.0.0",
|
|
4
4
|
"description": "Field renderers and registry for Object UI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
"rehype-sanitize": "^6.0.0",
|
|
31
31
|
"remark-gfm": "^4.0.1",
|
|
32
32
|
"tailwind-merge": "^3.6.0",
|
|
33
|
-
"@object-ui/components": "
|
|
34
|
-
"@object-ui/core": "
|
|
35
|
-
"@object-ui/i18n": "
|
|
36
|
-
"@object-ui/providers": "
|
|
37
|
-
"@object-ui/react": "
|
|
38
|
-
"@object-ui/types": "
|
|
33
|
+
"@object-ui/components": "15.0.0",
|
|
34
|
+
"@object-ui/core": "15.0.0",
|
|
35
|
+
"@object-ui/i18n": "15.0.0",
|
|
36
|
+
"@object-ui/providers": "15.0.0",
|
|
37
|
+
"@object-ui/react": "15.0.0",
|
|
38
|
+
"@object-ui/types": "15.0.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -23,16 +23,39 @@ describe('formatRelativeDate', () => {
|
|
|
23
23
|
expect(formatRelativeDate(daysAgo(3), { dueLike: true })).toBe('Overdue 3d');
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
it('renders neutral "
|
|
27
|
-
expect(formatRelativeDate(daysAgo(3))).toBe('
|
|
28
|
-
expect(formatRelativeDate(daysAgo(3), { dueLike: false })).toBe('
|
|
26
|
+
it('renders neutral "N days ago" for a past date that is not due-like', () => {
|
|
27
|
+
expect(formatRelativeDate(daysAgo(3))).toBe('3 days ago');
|
|
28
|
+
expect(formatRelativeDate(daysAgo(3), { dueLike: false })).toBe('3 days ago');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('localizes the near-today window per locale (framework#3040)', () => {
|
|
32
|
+
expect(formatRelativeDate(daysAgo(0), { locale: 'zh-CN' })).toBe('今天');
|
|
33
|
+
expect(formatRelativeDate(daysAgo(-1), { locale: 'zh-CN' })).toBe('明天');
|
|
34
|
+
expect(formatRelativeDate(daysAgo(1), { locale: 'zh-CN' })).toBe('昨天');
|
|
35
|
+
expect(formatRelativeDate(daysAgo(-3), { locale: 'zh-CN' })).toBe('3天后');
|
|
36
|
+
expect(formatRelativeDate(daysAgo(3), { locale: 'zh-CN' })).toBe('3天前');
|
|
37
|
+
// English output is sentence-cased.
|
|
38
|
+
expect(formatRelativeDate(daysAgo(-1))).toBe('Tomorrow');
|
|
39
|
+
expect(formatRelativeDate(daysAgo(-3))).toBe('In 3 days');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('resolves the overdue phrase through the i18n translate fn when provided', () => {
|
|
43
|
+
const t = (key: string, params?: Record<string, unknown>) =>
|
|
44
|
+
key === 'fields.relativeDate.overdue' ? `逾期 ${params?.count} 天` : key;
|
|
45
|
+
expect(formatRelativeDate(daysAgo(3), { dueLike: true, t })).toBe('逾期 3 天');
|
|
46
|
+
// A t() that misses (returns the key) keeps the English fallback.
|
|
47
|
+
expect(formatRelativeDate(daysAgo(3), { dueLike: true, t: (k) => k })).toBe('Overdue 3d');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('degrades to English when the locale tag is invalid', () => {
|
|
51
|
+
expect(formatRelativeDate(daysAgo(3), { locale: 'not a locale' })).toBe('3 days ago');
|
|
29
52
|
});
|
|
30
53
|
});
|
|
31
54
|
|
|
32
55
|
describe('DateCellRenderer', () => {
|
|
33
56
|
it('does not label a past start_date as "Overdue" (regression: field-role-agnostic formatter)', () => {
|
|
34
57
|
render(<DateCellRenderer value={daysAgo(6)} field={{ type: 'date', name: 'start_date' } as any} />);
|
|
35
|
-
expect(screen.getByText('
|
|
58
|
+
expect(screen.getByText('6 days ago')).toBeInTheDocument();
|
|
36
59
|
expect(screen.queryByText(/Overdue/)).not.toBeInTheDocument();
|
|
37
60
|
});
|
|
38
61
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [framework#2926 ⑧] LookupCellRenderer must honor the target object's
|
|
3
|
+
* configured display field. ObjectGrid forwards `display_field` on the
|
|
4
|
+
* column meta (RELATIONAL_META_KEYS) exactly like `reference`, but the read
|
|
5
|
+
* cell used to ignore it and always ran the hardcoded heuristics — `name`
|
|
6
|
+
* first — so a target object whose displayNameField is a localized/label
|
|
7
|
+
* field still rendered the raw API `name`.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
10
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
11
|
+
import '@testing-library/jest-dom';
|
|
12
|
+
import React from 'react';
|
|
13
|
+
|
|
14
|
+
import { LookupCellRenderer } from '../index';
|
|
15
|
+
import { SchemaRendererProvider } from '@object-ui/react';
|
|
16
|
+
|
|
17
|
+
const ID_A = '01ARZ3NDEKTSV4RRFFQ69G5FAA';
|
|
18
|
+
const ID_B = '01ARZ3NDEKTSV4RRFFQ69G5FAB';
|
|
19
|
+
|
|
20
|
+
function makeDataSource() {
|
|
21
|
+
const findOne = vi.fn(async (object: string, id: string) => {
|
|
22
|
+
if (object === 'showcase_category') {
|
|
23
|
+
// Record carries BOTH the raw API name and a localized label field.
|
|
24
|
+
if (id === ID_A) return { id, name: 'cat_hardware', label_zh: '硬件' };
|
|
25
|
+
if (id === ID_B) return { id, name: 'cat_software', label_zh: '软件' };
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
});
|
|
29
|
+
return { findOne, find: vi.fn() } as any;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('LookupCellRenderer — display_field resolution', () => {
|
|
33
|
+
it('prefers the configured display_field over the heuristic `name`', async () => {
|
|
34
|
+
const ds = makeDataSource();
|
|
35
|
+
render(
|
|
36
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
37
|
+
<LookupCellRenderer
|
|
38
|
+
value={ID_A}
|
|
39
|
+
field={{ type: 'lookup', reference: 'showcase_category', display_field: 'label_zh' } as any}
|
|
40
|
+
/>
|
|
41
|
+
</SchemaRendererProvider>,
|
|
42
|
+
);
|
|
43
|
+
await waitFor(() => {
|
|
44
|
+
expect(screen.getByText('硬件')).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
expect(screen.queryByText('cat_hardware')).not.toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('keeps the heuristic (`name` first) when no display_field is configured', async () => {
|
|
50
|
+
const ds = makeDataSource();
|
|
51
|
+
render(
|
|
52
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
53
|
+
<LookupCellRenderer
|
|
54
|
+
value={ID_A}
|
|
55
|
+
field={{ type: 'lookup', reference: 'showcase_category' } as any}
|
|
56
|
+
/>
|
|
57
|
+
</SchemaRendererProvider>,
|
|
58
|
+
);
|
|
59
|
+
await waitFor(() => {
|
|
60
|
+
expect(screen.getByText('cat_hardware')).toBeInTheDocument();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('uses display_field on server-expanded nested objects (no fetch path)', () => {
|
|
65
|
+
const ds = makeDataSource();
|
|
66
|
+
render(
|
|
67
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
68
|
+
<LookupCellRenderer
|
|
69
|
+
value={{ id: ID_A, name: 'cat_hardware', label_zh: '硬件' } as any}
|
|
70
|
+
field={{ type: 'lookup', reference: 'showcase_category', display_field: 'label_zh' } as any}
|
|
71
|
+
/>
|
|
72
|
+
</SchemaRendererProvider>,
|
|
73
|
+
);
|
|
74
|
+
expect(screen.getByText('硬件')).toBeInTheDocument();
|
|
75
|
+
expect(ds.findOne).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('does not serve a cached heuristic name to a display_field column (cache key isolation)', async () => {
|
|
79
|
+
const ds = makeDataSource();
|
|
80
|
+
// First: a column WITHOUT display_field resolves and caches the heuristic name.
|
|
81
|
+
const first = render(
|
|
82
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
83
|
+
<LookupCellRenderer
|
|
84
|
+
value={ID_B}
|
|
85
|
+
field={{ type: 'lookup', reference: 'showcase_category' } as any}
|
|
86
|
+
/>
|
|
87
|
+
</SchemaRendererProvider>,
|
|
88
|
+
);
|
|
89
|
+
await waitFor(() => {
|
|
90
|
+
expect(screen.getByText('cat_software')).toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
first.unmount();
|
|
93
|
+
// Then: a column WITH display_field for the same record must show the
|
|
94
|
+
// configured field, not the previously cached heuristic name.
|
|
95
|
+
render(
|
|
96
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
97
|
+
<LookupCellRenderer
|
|
98
|
+
value={ID_B}
|
|
99
|
+
field={{ type: 'lookup', reference: 'showcase_category', display_field: 'label_zh' } as any}
|
|
100
|
+
/>
|
|
101
|
+
</SchemaRendererProvider>,
|
|
102
|
+
);
|
|
103
|
+
await waitFor(() => {
|
|
104
|
+
expect(screen.getByText('软件')).toBeInTheDocument();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression for objectstack-ai/objectui#2357: the lookup chip
|
|
3
|
+
* (LookupCellRenderer — record header highlight + detail sections) resolved
|
|
4
|
+
* display names via the local key heuristic (`pickRecordDisplayName`), whose
|
|
5
|
+
* `_number`/`_code` suffix scan surfaced an autonumber (`0001`) over the
|
|
6
|
+
* record's real name whenever the referenced object declared its title in
|
|
7
|
+
* `nameField`/`titleFormat`. The picker (LookupField) already resolved via the
|
|
8
|
+
* unified ADR-0079 resolver, so the two surfaces disagreed.
|
|
9
|
+
*
|
|
10
|
+
* The chip must now resolve through the referenced object's schema
|
|
11
|
+
* (`dataSource.getObjectSchema`) with the precedence
|
|
12
|
+
* `displayField → nameField/titleFormat → type-aware derivation`, keeping the
|
|
13
|
+
* key heuristic only as the no-schema fallback.
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
16
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
17
|
+
import '@testing-library/jest-dom';
|
|
18
|
+
import React from 'react';
|
|
19
|
+
|
|
20
|
+
import { LookupCellRenderer } from '../index';
|
|
21
|
+
import { SchemaRendererProvider } from '@object-ui/react';
|
|
22
|
+
|
|
23
|
+
// The expanded record: the autonumber (`req_number`) precedes the real name
|
|
24
|
+
// (`req_name`) in key order, so the OLD heuristic-only path rendered "0001".
|
|
25
|
+
const EXPANDED = { id: 'rec1', req_number: '0001', req_name: 'Annual Maintenance' };
|
|
26
|
+
|
|
27
|
+
function makeDataSource(objectName: string, schema: any, record?: any) {
|
|
28
|
+
return {
|
|
29
|
+
find: vi.fn(),
|
|
30
|
+
findOne: vi.fn(async (object: string, id: string) =>
|
|
31
|
+
object === objectName && record && id === record.id ? record : null,
|
|
32
|
+
),
|
|
33
|
+
getObjectSchema: vi.fn(async (object: string) =>
|
|
34
|
+
object === objectName ? schema : null,
|
|
35
|
+
),
|
|
36
|
+
} as any;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe('LookupCellRenderer — schema-aware display name (issue #2357)', () => {
|
|
40
|
+
it('expanded object: nameField beats the autonumber suffix heuristic', async () => {
|
|
41
|
+
const ds = makeDataSource('mtc_request_a', { nameField: 'req_name' });
|
|
42
|
+
render(
|
|
43
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
44
|
+
<LookupCellRenderer
|
|
45
|
+
value={EXPANDED}
|
|
46
|
+
field={{ type: 'lookup', reference_to: 'mtc_request_a' } as any}
|
|
47
|
+
/>
|
|
48
|
+
</SchemaRendererProvider>,
|
|
49
|
+
);
|
|
50
|
+
await waitFor(() => {
|
|
51
|
+
expect(screen.getByText('Annual Maintenance')).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
expect(screen.queryByText('0001')).not.toBeInTheDocument();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('expanded object: titleFormat template resolves when no nameField', async () => {
|
|
57
|
+
const ds = makeDataSource('mtc_request_b', { titleFormat: '{req_name} - {req_number}' });
|
|
58
|
+
render(
|
|
59
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
60
|
+
<LookupCellRenderer
|
|
61
|
+
value={{ ...EXPANDED }}
|
|
62
|
+
field={{ type: 'lookup', reference_to: 'mtc_request_b' } as any}
|
|
63
|
+
/>
|
|
64
|
+
</SchemaRendererProvider>,
|
|
65
|
+
);
|
|
66
|
+
await waitFor(() => {
|
|
67
|
+
expect(screen.getByText('Annual Maintenance - 0001')).toBeInTheDocument();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('explicit displayField wins over the schema nameField', async () => {
|
|
72
|
+
const ds = makeDataSource('mtc_request_c', { nameField: 'req_name' });
|
|
73
|
+
render(
|
|
74
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
75
|
+
<LookupCellRenderer
|
|
76
|
+
value={{ ...EXPANDED }}
|
|
77
|
+
field={{ type: 'lookup', reference_to: 'mtc_request_c', display_field: 'req_number' } as any}
|
|
78
|
+
/>
|
|
79
|
+
</SchemaRendererProvider>,
|
|
80
|
+
);
|
|
81
|
+
// Author explicitly asked for the number — honour it (also the documented
|
|
82
|
+
// workaround in the issue).
|
|
83
|
+
expect(await screen.findByText('0001')).toBeInTheDocument();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('fetch-on-demand primitive id resolves via the schema nameField too', async () => {
|
|
87
|
+
// Opaque ULID-ish id so the old path would have resolved the fetched
|
|
88
|
+
// record through the heuristic and shown its autonumber.
|
|
89
|
+
const id = '01ARZ3NDEKTSV4RRFFQ69G5FBB';
|
|
90
|
+
const record = { id, req_number: '0007', req_name: 'Pump Overhaul' };
|
|
91
|
+
const ds = makeDataSource('mtc_request_d', { nameField: 'req_name' }, record);
|
|
92
|
+
render(
|
|
93
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
94
|
+
<LookupCellRenderer
|
|
95
|
+
value={id}
|
|
96
|
+
field={{ type: 'lookup', reference_to: 'mtc_request_d' } as any}
|
|
97
|
+
/>
|
|
98
|
+
</SchemaRendererProvider>,
|
|
99
|
+
);
|
|
100
|
+
await waitFor(() => {
|
|
101
|
+
expect(screen.getByText('Pump Overhaul')).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
expect(screen.queryByText('0007')).not.toBeInTheDocument();
|
|
104
|
+
expect(ds.getObjectSchema).toHaveBeenCalledWith('mtc_request_d');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('falls back to the key heuristic when the data source has no schema API', () => {
|
|
108
|
+
const ds = { find: vi.fn(), findOne: vi.fn() } as any; // no getObjectSchema
|
|
109
|
+
render(
|
|
110
|
+
<SchemaRendererProvider dataSource={ds}>
|
|
111
|
+
<LookupCellRenderer
|
|
112
|
+
value={{ id: 'rec2', framework_name: 'SOX' }}
|
|
113
|
+
field={{ type: 'lookup', reference_to: 'mtc_request_e' } as any}
|
|
114
|
+
/>
|
|
115
|
+
</SchemaRendererProvider>,
|
|
116
|
+
);
|
|
117
|
+
expect(screen.getByText('SOX')).toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
});
|