@open-mercato/ui 0.4.11-develop.1971.0f53c78f63 → 0.4.11-develop.1980.243750a91b
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/package.json +3 -3
- package/src/backend/__tests__/AppShell.test.tsx +23 -0
- package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +24 -3
- package/src/backend/__tests__/CrudForm.render.test.tsx +21 -0
- package/src/backend/__tests__/CrudForm.transformData.test.tsx +1 -0
- package/src/backend/__tests__/CrudForm.unsavedNavigation.test.tsx +12 -0
- package/src/backend/__tests__/CrudForm.validation.test.tsx +28 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/ui",
|
|
3
|
-
"version": "0.4.11-develop.
|
|
3
|
+
"version": "0.4.11-develop.1980.243750a91b",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -132,12 +132,12 @@
|
|
|
132
132
|
"recharts": "^2.15.0"
|
|
133
133
|
},
|
|
134
134
|
"peerDependencies": {
|
|
135
|
-
"@open-mercato/shared": "0.4.11-develop.
|
|
135
|
+
"@open-mercato/shared": "0.4.11-develop.1980.243750a91b",
|
|
136
136
|
"react": ">=18.0.0",
|
|
137
137
|
"react-dom": ">=18.0.0"
|
|
138
138
|
},
|
|
139
139
|
"devDependencies": {
|
|
140
|
-
"@open-mercato/shared": "0.4.11-develop.
|
|
140
|
+
"@open-mercato/shared": "0.4.11-develop.1980.243750a91b",
|
|
141
141
|
"@testing-library/dom": "^10.4.1",
|
|
142
142
|
"@testing-library/jest-dom": "^6.9.1",
|
|
143
143
|
"@testing-library/react": "^16.3.1",
|
|
@@ -37,10 +37,29 @@ jest.mock('../injection/InjectionSpot', () => ({
|
|
|
37
37
|
},
|
|
38
38
|
}))
|
|
39
39
|
|
|
40
|
+
jest.mock('../injection/useInjectedMenuItems', () => ({
|
|
41
|
+
useInjectedMenuItems: () => ({
|
|
42
|
+
items: [],
|
|
43
|
+
isLoading: false,
|
|
44
|
+
}),
|
|
45
|
+
}))
|
|
46
|
+
|
|
47
|
+
jest.mock('../injection/eventBridge', () => ({
|
|
48
|
+
useEventBridge: jest.fn(),
|
|
49
|
+
}))
|
|
50
|
+
|
|
51
|
+
jest.mock('../injection/StatusBadgeInjectionSpot', () => ({
|
|
52
|
+
StatusBadgeInjectionSpot: () => <div data-testid="status-badge-injection-spot" />,
|
|
53
|
+
}))
|
|
54
|
+
|
|
40
55
|
jest.mock('../operations/LastOperationBanner', () => ({
|
|
41
56
|
LastOperationBanner: () => <div data-testid="last-operation-banner" />,
|
|
42
57
|
}))
|
|
43
58
|
|
|
59
|
+
jest.mock('../progress/ProgressTopBar', () => ({
|
|
60
|
+
ProgressTopBar: () => <div data-testid="progress-top-bar" />,
|
|
61
|
+
}))
|
|
62
|
+
|
|
44
63
|
jest.mock('../indexes/PartialIndexBanner', () => ({
|
|
45
64
|
PartialIndexBanner: () => <div data-testid="partial-index-banner" />,
|
|
46
65
|
}))
|
|
@@ -57,6 +76,10 @@ jest.mock('../upgrades/UpgradeActionBanner', () => ({
|
|
|
57
76
|
UpgradeActionBanner: () => <div data-testid="upgrade-action-banner" />,
|
|
58
77
|
}))
|
|
59
78
|
|
|
79
|
+
jest.mock('../devtools', () => ({
|
|
80
|
+
UmesDevToolsPanel: () => null,
|
|
81
|
+
}))
|
|
82
|
+
|
|
60
83
|
const dict = {
|
|
61
84
|
'appShell.productName': 'Mercato',
|
|
62
85
|
'appShell.menu': 'Menu',
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
|
+
jest.setTimeout(15000)
|
|
2
3
|
|
|
3
4
|
const fetchCustomFieldFormStructureMock = jest.fn()
|
|
4
5
|
const buildFormFieldFromCustomFieldDefMock = jest.fn()
|
|
6
|
+
const triggerInjectionEventMock = jest.fn(async (_event: string, data: Record<string, unknown>) => ({
|
|
7
|
+
ok: true,
|
|
8
|
+
data,
|
|
9
|
+
}))
|
|
5
10
|
|
|
6
11
|
jest.mock('next/navigation', () => ({
|
|
7
12
|
useRouter: () => ({ push: jest.fn() }),
|
|
@@ -16,6 +21,16 @@ jest.mock('../confirm-dialog', () => ({
|
|
|
16
21
|
ConfirmDialogElement: null,
|
|
17
22
|
}),
|
|
18
23
|
}))
|
|
24
|
+
jest.mock('../injection/InjectionSpot', () => ({
|
|
25
|
+
__esModule: true,
|
|
26
|
+
InjectionSpot: () => null,
|
|
27
|
+
useInjectionWidgets: () => ({ widgets: [], loading: false, error: null }),
|
|
28
|
+
useInjectionSpotEvents: () => ({ triggerEvent: triggerInjectionEventMock }),
|
|
29
|
+
}))
|
|
30
|
+
jest.mock('../injection/useInjectionDataWidgets', () => ({
|
|
31
|
+
__esModule: true,
|
|
32
|
+
useInjectionDataWidgets: () => ({ widgets: [], isLoading: false, error: null }),
|
|
33
|
+
}))
|
|
19
34
|
jest.mock('../custom-fields/FieldDefinitionsManager', () => {
|
|
20
35
|
const React = require('react')
|
|
21
36
|
return {
|
|
@@ -31,7 +46,7 @@ jest.mock('../utils/customFieldForms', () => ({
|
|
|
31
46
|
}))
|
|
32
47
|
|
|
33
48
|
import * as React from 'react'
|
|
34
|
-
import { act, fireEvent, screen } from '@testing-library/react'
|
|
49
|
+
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
|
|
35
50
|
import { renderWithProviders } from '@open-mercato/shared/lib/testing/renderWithProviders'
|
|
36
51
|
import { CrudForm, type CrudField, type CrudFormGroup } from '../CrudForm'
|
|
37
52
|
|
|
@@ -53,6 +68,7 @@ describe('CrudForm custom field loading', () => {
|
|
|
53
68
|
beforeEach(() => {
|
|
54
69
|
fetchCustomFieldFormStructureMock.mockReset()
|
|
55
70
|
buildFormFieldFromCustomFieldDefMock.mockReset()
|
|
71
|
+
triggerInjectionEventMock.mockClear()
|
|
56
72
|
buildFormFieldFromCustomFieldDefMock.mockReturnValue(null)
|
|
57
73
|
fetchCustomFieldFormStructureMock.mockResolvedValue({
|
|
58
74
|
fields: [],
|
|
@@ -149,9 +165,14 @@ describe('CrudForm custom field loading', () => {
|
|
|
149
165
|
},
|
|
150
166
|
)
|
|
151
167
|
|
|
152
|
-
|
|
168
|
+
await waitFor(() => {
|
|
169
|
+
expect(fetchCustomFieldFormStructureMock).toHaveBeenCalledTimes(1)
|
|
170
|
+
})
|
|
171
|
+
const manageButton = await screen.findByRole('button', { name: 'Manage fields' }, { timeout: 3000 })
|
|
153
172
|
|
|
154
|
-
|
|
173
|
+
await act(async () => {
|
|
174
|
+
fireEvent.click(manageButton)
|
|
175
|
+
})
|
|
155
176
|
|
|
156
177
|
expect(handleSubmit).not.toHaveBeenCalled()
|
|
157
178
|
expect(await screen.findByText('Edit custom fields')).toBeInTheDocument()
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
|
+
jest.setTimeout(15000)
|
|
3
|
+
|
|
4
|
+
const triggerInjectionEventMock = jest.fn(async (_event: string, data: Record<string, unknown>) => ({
|
|
5
|
+
ok: true,
|
|
6
|
+
data,
|
|
7
|
+
}))
|
|
8
|
+
|
|
2
9
|
jest.mock('next/navigation', () => ({
|
|
3
10
|
useRouter: () => ({ push: () => {} }),
|
|
4
11
|
usePathname: () => '/',
|
|
@@ -6,6 +13,16 @@ jest.mock('next/navigation', () => ({
|
|
|
6
13
|
}))
|
|
7
14
|
jest.mock('remark-gfm', () => ({ __esModule: true, default: {} }))
|
|
8
15
|
jest.mock('@uiw/react-md-editor', () => ({ __esModule: true, default: () => null }))
|
|
16
|
+
jest.mock('../injection/InjectionSpot', () => ({
|
|
17
|
+
__esModule: true,
|
|
18
|
+
InjectionSpot: () => null,
|
|
19
|
+
useInjectionWidgets: () => ({ widgets: [], loading: false, error: null }),
|
|
20
|
+
useInjectionSpotEvents: () => ({ triggerEvent: triggerInjectionEventMock }),
|
|
21
|
+
}))
|
|
22
|
+
jest.mock('../injection/useInjectionDataWidgets', () => ({
|
|
23
|
+
__esModule: true,
|
|
24
|
+
useInjectionDataWidgets: () => ({ widgets: [], isLoading: false, error: null }),
|
|
25
|
+
}))
|
|
9
26
|
|
|
10
27
|
import * as React from 'react'
|
|
11
28
|
import { renderToString } from 'react-dom/server'
|
|
@@ -39,6 +56,10 @@ describe('CrudForm SSR render', () => {
|
|
|
39
56
|
describe('CrudForm initialValues', () => {
|
|
40
57
|
const fields: CrudField[] = [{ id: 'name', label: 'Name', type: 'text' }]
|
|
41
58
|
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
triggerInjectionEventMock.mockClear()
|
|
61
|
+
})
|
|
62
|
+
|
|
42
63
|
function getInput(container: HTMLElement): HTMLInputElement {
|
|
43
64
|
return container.querySelector('[data-crud-field-id="name"] input[type="text"]') as HTMLInputElement
|
|
44
65
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
|
+
jest.setTimeout(15000)
|
|
3
|
+
|
|
2
4
|
const pushMock = jest.fn()
|
|
3
5
|
const confirmDialogMock = jest.fn()
|
|
4
6
|
|
|
@@ -15,6 +17,16 @@ jest.mock('../confirm-dialog', () => ({
|
|
|
15
17
|
ConfirmDialogElement: null,
|
|
16
18
|
}),
|
|
17
19
|
}))
|
|
20
|
+
jest.mock('../injection/InjectionSpot', () => ({
|
|
21
|
+
__esModule: true,
|
|
22
|
+
InjectionSpot: () => null,
|
|
23
|
+
useInjectionWidgets: () => ({ widgets: [], loading: false, error: null }),
|
|
24
|
+
useInjectionSpotEvents: () => ({ triggerEvent: jest.fn() }),
|
|
25
|
+
}))
|
|
26
|
+
jest.mock('../injection/useInjectionDataWidgets', () => ({
|
|
27
|
+
__esModule: true,
|
|
28
|
+
useInjectionDataWidgets: () => ({ widgets: [], isLoading: false, error: null }),
|
|
29
|
+
}))
|
|
18
30
|
|
|
19
31
|
import * as React from 'react'
|
|
20
32
|
import { act, fireEvent } from '@testing-library/react'
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
|
+
jest.setTimeout(15000)
|
|
3
|
+
|
|
2
4
|
jest.mock('next/navigation', () => ({
|
|
3
5
|
useRouter: () => ({ push: () => {} }),
|
|
4
6
|
usePathname: () => '/',
|
|
@@ -6,9 +8,19 @@ jest.mock('next/navigation', () => ({
|
|
|
6
8
|
}))
|
|
7
9
|
jest.mock('remark-gfm', () => ({ __esModule: true, default: {} }))
|
|
8
10
|
jest.mock('@uiw/react-md-editor', () => ({ __esModule: true, default: () => null }))
|
|
11
|
+
jest.mock('../injection/InjectionSpot', () => ({
|
|
12
|
+
__esModule: true,
|
|
13
|
+
InjectionSpot: () => null,
|
|
14
|
+
useInjectionWidgets: () => ({ widgets: [], loading: false, error: null }),
|
|
15
|
+
useInjectionSpotEvents: () => ({ triggerEvent: jest.fn() }),
|
|
16
|
+
}))
|
|
17
|
+
jest.mock('../injection/useInjectionDataWidgets', () => ({
|
|
18
|
+
__esModule: true,
|
|
19
|
+
useInjectionDataWidgets: () => ({ widgets: [], isLoading: false, error: null }),
|
|
20
|
+
}))
|
|
9
21
|
|
|
10
22
|
import * as React from 'react'
|
|
11
|
-
import { act, fireEvent } from '@testing-library/react'
|
|
23
|
+
import { act, fireEvent, waitFor } from '@testing-library/react'
|
|
12
24
|
import { z } from 'zod'
|
|
13
25
|
import { renderWithProviders } from '@open-mercato/shared/lib/testing/renderWithProviders'
|
|
14
26
|
import { CrudForm, type CrudField } from '../CrudForm'
|
|
@@ -38,22 +50,32 @@ describe('CrudForm validation state', () => {
|
|
|
38
50
|
)
|
|
39
51
|
|
|
40
52
|
const form = container.querySelector('form')
|
|
53
|
+
const nameField = container.querySelector('[data-crud-field-id="name"]')
|
|
54
|
+
const gatewayField = container.querySelector('[data-crud-field-id="gatewayProviderKey"]')
|
|
41
55
|
const nameInput = container.querySelector('[data-crud-field-id="name"] input[type="text"]')
|
|
42
56
|
|
|
43
57
|
expect(form).not.toBeNull()
|
|
58
|
+
expect(nameField).not.toBeNull()
|
|
59
|
+
expect(gatewayField).not.toBeNull()
|
|
44
60
|
expect(nameInput).not.toBeNull()
|
|
45
61
|
|
|
46
62
|
await act(async () => {
|
|
47
63
|
fireEvent.submit(form as HTMLFormElement)
|
|
48
64
|
})
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
await waitFor(() => {
|
|
67
|
+
expect(nameField?.querySelector('.text-xs.text-red-600')).toHaveTextContent('This field is required')
|
|
68
|
+
expect(gatewayField?.querySelector('.text-xs.text-red-600')).toHaveTextContent('This field is required')
|
|
69
|
+
})
|
|
51
70
|
|
|
52
71
|
await act(async () => {
|
|
53
72
|
fireEvent.change(nameInput as HTMLInputElement, { target: { value: 'QA test link' } })
|
|
54
73
|
})
|
|
55
74
|
|
|
56
|
-
|
|
75
|
+
await waitFor(() => {
|
|
76
|
+
expect(nameField?.querySelector('.text-xs.text-red-600')).toBeNull()
|
|
77
|
+
expect(gatewayField?.querySelector('.text-xs.text-red-600')).toHaveTextContent('This field is required')
|
|
78
|
+
})
|
|
57
79
|
expect(container.textContent).toContain('Gateway provider')
|
|
58
80
|
})
|
|
59
81
|
|
|
@@ -97,7 +119,9 @@ describe('CrudForm validation state', () => {
|
|
|
97
119
|
fireEvent.submit(form as HTMLFormElement)
|
|
98
120
|
})
|
|
99
121
|
|
|
100
|
-
|
|
122
|
+
await waitFor(() => {
|
|
123
|
+
expect(getByText('Use camelCase starting with a letter.')).toBeInTheDocument()
|
|
124
|
+
})
|
|
101
125
|
})
|
|
102
126
|
|
|
103
127
|
it('validates number fields on blur', async () => {
|