@nocobase/client-v2 2.1.31 → 2.1.32
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/es/flow/actions/linkageRules.d.ts +1 -0
- package/es/flow/models/base/ActionModelCore.d.ts +4 -2
- package/es/index.mjs +8 -8
- package/lib/index.js +26 -26
- package/package.json +7 -7
- package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +203 -4
- package/src/flow/actions/linkageRules.tsx +25 -4
- package/src/flow/models/base/ActionModelCore.tsx +11 -2
- package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +49 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/client-v2",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.32",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.mjs",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@formily/antd-v5": "1.2.3",
|
|
28
28
|
"@formily/react": "^2.2.27",
|
|
29
29
|
"@formily/shared": "^2.2.27",
|
|
30
|
-
"@nocobase/evaluators": "2.1.
|
|
31
|
-
"@nocobase/flow-engine": "2.1.
|
|
32
|
-
"@nocobase/sdk": "2.1.
|
|
33
|
-
"@nocobase/shared": "2.1.
|
|
34
|
-
"@nocobase/utils": "2.1.
|
|
30
|
+
"@nocobase/evaluators": "2.1.32",
|
|
31
|
+
"@nocobase/flow-engine": "2.1.32",
|
|
32
|
+
"@nocobase/sdk": "2.1.32",
|
|
33
|
+
"@nocobase/shared": "2.1.32",
|
|
34
|
+
"@nocobase/utils": "2.1.32",
|
|
35
35
|
"ahooks": "^3.7.2",
|
|
36
36
|
"antd": "5.24.2",
|
|
37
37
|
"antd-style": "3.7.1",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"react-i18next": "^11.15.1",
|
|
49
49
|
"react-router-dom": "^6.30.1"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "737a1324f650d7bc66594203b68eb0180553a551"
|
|
52
52
|
}
|
|
@@ -11,7 +11,7 @@ import { FlowEngine } from '@nocobase/flow-engine';
|
|
|
11
11
|
import { describe, expect, it, vi } from 'vitest';
|
|
12
12
|
import { ActionModel as ConfiguredActionModel } from '../../models/base/ActionModel';
|
|
13
13
|
import { ActionModel } from '../../models/base/ActionModelCore';
|
|
14
|
-
import { actionLinkageRules, linkageSetActionProps } from '../linkageRules';
|
|
14
|
+
import { actionLinkageRules, linkageSetActionProps, updateLinkageRules } from '../linkageRules';
|
|
15
15
|
|
|
16
16
|
class TestActionModel extends ActionModel {}
|
|
17
17
|
|
|
@@ -73,16 +73,180 @@ describe('action linkage rules on action forks', () => {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
expect(fork.getProps().title).toBe('Updated');
|
|
76
|
-
expect(fork.serialize().props
|
|
76
|
+
expect(fork.serialize().props).toMatchObject({ title: 'Updated' });
|
|
77
|
+
expect(fork.serialize().props).not.toHaveProperty('disabled');
|
|
77
78
|
|
|
78
79
|
const refreshedFork = master.createFork({ className: 'row-action' });
|
|
79
80
|
expect(refreshedFork.getProps().title).toBe('Updated');
|
|
80
81
|
});
|
|
81
82
|
|
|
83
|
+
it.each(['disable', 'delete'] as const)(
|
|
84
|
+
'restores a row action when linkage rules are %sd without persisting disabled',
|
|
85
|
+
async (change) => {
|
|
86
|
+
const engine = new FlowEngine();
|
|
87
|
+
engine.registerModels({ ConfiguredActionModel });
|
|
88
|
+
engine.registerActions({ actionLinkageRules, linkageSetActionProps });
|
|
89
|
+
|
|
90
|
+
let savedData: ReturnType<ConfiguredActionModel['serialize']> | undefined;
|
|
91
|
+
engine.setModelRepository({
|
|
92
|
+
save: async (model) => {
|
|
93
|
+
savedData = model.serialize();
|
|
94
|
+
return savedData;
|
|
95
|
+
},
|
|
96
|
+
} as Parameters<FlowEngine['setModelRepository']>[0]);
|
|
97
|
+
|
|
98
|
+
const enabledRules = [
|
|
99
|
+
{
|
|
100
|
+
key: 'disable-edit',
|
|
101
|
+
enable: true,
|
|
102
|
+
condition: { logic: '$and', items: [] },
|
|
103
|
+
actions: [{ name: 'linkageSetActionProps', params: { value: 'disabled' } }],
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
const master = engine.createModel<ConfiguredActionModel>({
|
|
107
|
+
use: 'ConfiguredActionModel',
|
|
108
|
+
props: { title: 'Edit' },
|
|
109
|
+
stepParams: {
|
|
110
|
+
buttonSettings: {
|
|
111
|
+
linkageRules: { value: enabledRules },
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
const fork = master.createFork({ className: 'row-action' });
|
|
116
|
+
|
|
117
|
+
await fork.dispatchEvent('beforeRender', undefined, { useCache: false });
|
|
118
|
+
expect(fork.getProps().disabled).toBe(true);
|
|
119
|
+
|
|
120
|
+
const nextRules =
|
|
121
|
+
change === 'disable'
|
|
122
|
+
? updateLinkageRules(enabledRules, (rules) => {
|
|
123
|
+
rules[0].enable = false;
|
|
124
|
+
})
|
|
125
|
+
: [];
|
|
126
|
+
fork.setStepParams('buttonSettings', 'linkageRules', { value: nextRules });
|
|
127
|
+
await fork.saveStepParams();
|
|
128
|
+
await fork.rerender();
|
|
129
|
+
|
|
130
|
+
expect(savedData).toBeDefined();
|
|
131
|
+
expect(savedData?.props).not.toHaveProperty('disabled');
|
|
132
|
+
expect(savedData?.stepParams.buttonSettings.linkageRules.value).toEqual(nextRules);
|
|
133
|
+
expect(fork.getProps().disabled).toBeUndefined();
|
|
134
|
+
|
|
135
|
+
const reloadedEngine = new FlowEngine();
|
|
136
|
+
reloadedEngine.registerModels({ ConfiguredActionModel });
|
|
137
|
+
reloadedEngine.registerActions({ actionLinkageRules, linkageSetActionProps });
|
|
138
|
+
const reloadedMaster = reloadedEngine.createModel<ConfiguredActionModel>({
|
|
139
|
+
use: 'ConfiguredActionModel',
|
|
140
|
+
props: savedData?.props,
|
|
141
|
+
stepParams: savedData?.stepParams,
|
|
142
|
+
});
|
|
143
|
+
const reloadedFork = reloadedMaster.createFork({ className: 'row-action' });
|
|
144
|
+
|
|
145
|
+
await reloadedFork.dispatchEvent('beforeRender', undefined, { useCache: false });
|
|
146
|
+
expect(reloadedFork.getProps().disabled).toBeUndefined();
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
it.each(['disabled', 'deleted'] as const)(
|
|
151
|
+
'ignores a historical disabled prop after the linkage rule is %s',
|
|
152
|
+
async (state) => {
|
|
153
|
+
const engine = new FlowEngine();
|
|
154
|
+
engine.registerModels({ ConfiguredActionModel });
|
|
155
|
+
engine.registerActions({ actionLinkageRules, linkageSetActionProps });
|
|
156
|
+
const rules =
|
|
157
|
+
state === 'disabled'
|
|
158
|
+
? [
|
|
159
|
+
{
|
|
160
|
+
key: 'disable-edit',
|
|
161
|
+
enable: false,
|
|
162
|
+
condition: { logic: '$and', items: [] },
|
|
163
|
+
actions: [{ name: 'linkageSetActionProps', params: { value: 'disabled' } }],
|
|
164
|
+
},
|
|
165
|
+
]
|
|
166
|
+
: [];
|
|
167
|
+
const master = engine.createModel<ConfiguredActionModel>({
|
|
168
|
+
use: 'ConfiguredActionModel',
|
|
169
|
+
props: { title: 'Edit', disabled: true },
|
|
170
|
+
stepParams: {
|
|
171
|
+
buttonSettings: {
|
|
172
|
+
linkageRules: { value: rules },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
const fork = master.createFork({ className: 'row-action' });
|
|
177
|
+
|
|
178
|
+
expect(master.getProps()).not.toHaveProperty('disabled');
|
|
179
|
+
await fork.dispatchEvent('beforeRender', undefined, { useCache: false });
|
|
180
|
+
|
|
181
|
+
expect(fork.getProps().disabled).toBeUndefined();
|
|
182
|
+
},
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
it('still applies an enabled linkage rule after dropping a historical disabled prop', async () => {
|
|
186
|
+
const engine = new FlowEngine();
|
|
187
|
+
engine.registerModels({ ConfiguredActionModel });
|
|
188
|
+
engine.registerActions({ actionLinkageRules, linkageSetActionProps });
|
|
189
|
+
const master = engine.createModel<ConfiguredActionModel>({
|
|
190
|
+
use: 'ConfiguredActionModel',
|
|
191
|
+
props: { title: 'Edit', disabled: true },
|
|
192
|
+
stepParams: {
|
|
193
|
+
buttonSettings: {
|
|
194
|
+
linkageRules: {
|
|
195
|
+
value: [
|
|
196
|
+
{
|
|
197
|
+
key: 'disable-edit',
|
|
198
|
+
enable: true,
|
|
199
|
+
condition: { logic: '$and', items: [] },
|
|
200
|
+
actions: [{ name: 'linkageSetActionProps', params: { value: 'disabled' } }],
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
const fork = master.createFork({ className: 'row-action' });
|
|
208
|
+
|
|
209
|
+
expect(master.getProps()).not.toHaveProperty('disabled');
|
|
210
|
+
await fork.dispatchEvent('beforeRender', undefined, { useCache: false });
|
|
211
|
+
|
|
212
|
+
expect(fork.getProps().disabled).toBe(true);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('preserves a default disabled state as runtime-only state', async () => {
|
|
216
|
+
class DefaultDisabledActionModel extends ConfiguredActionModel {
|
|
217
|
+
defaultProps = { ...this.defaultProps, disabled: true };
|
|
218
|
+
}
|
|
219
|
+
const engine = new FlowEngine();
|
|
220
|
+
engine.registerModels({ DefaultDisabledActionModel });
|
|
221
|
+
engine.registerActions({ actionLinkageRules, linkageSetActionProps });
|
|
222
|
+
const master = engine.createModel<DefaultDisabledActionModel>({
|
|
223
|
+
use: 'DefaultDisabledActionModel',
|
|
224
|
+
props: { title: 'Edit' },
|
|
225
|
+
stepParams: {
|
|
226
|
+
buttonSettings: {
|
|
227
|
+
linkageRules: { value: [] },
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
const fork = master.createFork({ className: 'row-action' });
|
|
232
|
+
|
|
233
|
+
await fork.dispatchEvent('beforeRender', undefined, { useCache: false });
|
|
234
|
+
|
|
235
|
+
expect(fork.getProps().disabled).toBe(true);
|
|
236
|
+
expect(fork.serialize().props).not.toHaveProperty('disabled');
|
|
237
|
+
});
|
|
238
|
+
|
|
82
239
|
it('updates a disabled row action title through the real beforeRender flow', async () => {
|
|
83
240
|
const engine = new FlowEngine();
|
|
84
241
|
engine.registerModels({ ConfiguredActionModel });
|
|
85
242
|
engine.registerActions({ actionLinkageRules, linkageSetActionProps });
|
|
243
|
+
let savedData: ReturnType<ConfiguredActionModel['serialize']> | undefined;
|
|
244
|
+
engine.setModelRepository({
|
|
245
|
+
save: async (model) => {
|
|
246
|
+
savedData = model.serialize();
|
|
247
|
+
return savedData;
|
|
248
|
+
},
|
|
249
|
+
} as Parameters<FlowEngine['setModelRepository']>[0]);
|
|
86
250
|
const master = engine.createModel<ConfiguredActionModel>({
|
|
87
251
|
use: 'ConfiguredActionModel',
|
|
88
252
|
props: { title: 'Edit' },
|
|
@@ -107,9 +271,44 @@ describe('action linkage rules on action forks', () => {
|
|
|
107
271
|
await fork.dispatchEvent('beforeRender', undefined, { useCache: false });
|
|
108
272
|
expect(fork.getProps()).toMatchObject({ title: 'Edit', disabled: true });
|
|
109
273
|
|
|
110
|
-
|
|
111
|
-
await
|
|
274
|
+
fork.setStepParams('buttonSettings', 'general', { title: 'Updated' });
|
|
275
|
+
await fork.saveStepParams();
|
|
276
|
+
await fork.rerender();
|
|
112
277
|
|
|
278
|
+
expect(savedData?.props).not.toHaveProperty('disabled');
|
|
279
|
+
expect(savedData?.stepParams.buttonSettings.general.title).toBe('Updated');
|
|
113
280
|
expect(fork.getProps()).toMatchObject({ title: 'Updated', disabled: true });
|
|
281
|
+
|
|
282
|
+
const reloadedEngine = new FlowEngine();
|
|
283
|
+
reloadedEngine.registerModels({ ConfiguredActionModel });
|
|
284
|
+
reloadedEngine.registerActions({ actionLinkageRules, linkageSetActionProps });
|
|
285
|
+
const reloadedMaster = reloadedEngine.createModel<ConfiguredActionModel>({
|
|
286
|
+
use: 'ConfiguredActionModel',
|
|
287
|
+
props: savedData?.props,
|
|
288
|
+
stepParams: savedData?.stepParams,
|
|
289
|
+
});
|
|
290
|
+
const reloadedFork = reloadedMaster.createFork({ className: 'row-action' });
|
|
291
|
+
|
|
292
|
+
await reloadedFork.dispatchEvent('beforeRender', undefined, { useCache: false });
|
|
293
|
+
expect(reloadedFork.getProps()).toMatchObject({ title: 'Updated', disabled: true });
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('creates a new rules value when disabling a linkage rule', () => {
|
|
297
|
+
const rules = [
|
|
298
|
+
{
|
|
299
|
+
key: 'disable-edit',
|
|
300
|
+
title: 'Linkage rule',
|
|
301
|
+
enable: true,
|
|
302
|
+
condition: { logic: '$and', items: [] },
|
|
303
|
+
actions: [],
|
|
304
|
+
},
|
|
305
|
+
];
|
|
306
|
+
const nextRules = updateLinkageRules(rules, (next) => {
|
|
307
|
+
next[0].enable = false;
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(nextRules).toEqual([expect.objectContaining({ key: 'disable-edit', enable: false })]);
|
|
311
|
+
expect(nextRules).not.toBe(rules);
|
|
312
|
+
expect(rules[0].enable).toBe(true);
|
|
114
313
|
});
|
|
115
314
|
});
|
|
@@ -72,6 +72,12 @@ interface LinkageRule {
|
|
|
72
72
|
}[];
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
export function updateLinkageRules<T>(rules: T[], updater: (nextRules: T[]) => void): T[] {
|
|
76
|
+
const nextRules = _.cloneDeep(rules);
|
|
77
|
+
updater(nextRules);
|
|
78
|
+
return nextRules;
|
|
79
|
+
}
|
|
80
|
+
|
|
75
81
|
const previewValueForLog = (value: any) => {
|
|
76
82
|
if (value == null) return value;
|
|
77
83
|
const t = typeof value;
|
|
@@ -1469,13 +1475,26 @@ async function resolveLinkageRulesParamsPreservingRunJsScripts(ctx: FlowContext,
|
|
|
1469
1475
|
}
|
|
1470
1476
|
|
|
1471
1477
|
const LinkageRulesUI = observer(
|
|
1472
|
-
(props: {
|
|
1473
|
-
|
|
1478
|
+
(props: {
|
|
1479
|
+
readonly value: LinkageRule[];
|
|
1480
|
+
onChange?: (value: LinkageRule[]) => void;
|
|
1481
|
+
supportedActions: string[];
|
|
1482
|
+
title?: string;
|
|
1483
|
+
}) => {
|
|
1484
|
+
const { value: rules = [], onChange, supportedActions } = props;
|
|
1474
1485
|
const ctx = useFlowContext();
|
|
1475
1486
|
const flowEngine = useFlowEngine();
|
|
1476
1487
|
const t = ctx.model.translate.bind(ctx.model);
|
|
1477
1488
|
const assignPriorityTip = t('Assignment takes precedence over form field assignment');
|
|
1478
1489
|
|
|
1490
|
+
const replaceRules = (updater: (nextRules: LinkageRule[]) => void) => {
|
|
1491
|
+
if (onChange) {
|
|
1492
|
+
onChange(updateLinkageRules(rules, updater));
|
|
1493
|
+
} else {
|
|
1494
|
+
updater(rules);
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
|
|
1479
1498
|
// 创建新规则的默认值
|
|
1480
1499
|
const createNewRule = (): LinkageRule => ({
|
|
1481
1500
|
key: uid(),
|
|
@@ -1492,7 +1511,7 @@ const LinkageRulesUI = observer(
|
|
|
1492
1511
|
|
|
1493
1512
|
// 删除规则
|
|
1494
1513
|
const handleDeleteRule = (index: number) => {
|
|
1495
|
-
|
|
1514
|
+
replaceRules((nextRules) => nextRules.splice(index, 1));
|
|
1496
1515
|
};
|
|
1497
1516
|
|
|
1498
1517
|
// 上移规则
|
|
@@ -1531,7 +1550,9 @@ const LinkageRulesUI = observer(
|
|
|
1531
1550
|
|
|
1532
1551
|
// 切换规则启用状态
|
|
1533
1552
|
const handleToggleEnable = (index: number, enable: boolean) => {
|
|
1534
|
-
|
|
1553
|
+
replaceRules((nextRules) => {
|
|
1554
|
+
nextRules[index].enable = enable;
|
|
1555
|
+
});
|
|
1535
1556
|
};
|
|
1536
1557
|
|
|
1537
1558
|
// 获取可用的动作类型
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { FlowModel, tExpr, useFlowModel } from '@nocobase/flow-engine';
|
|
11
|
+
import type { DefaultStructure, FlowModelOptions } from '@nocobase/flow-engine';
|
|
11
12
|
import { Icon } from '../../../components';
|
|
12
13
|
import { Button, Tooltip } from 'antd';
|
|
13
14
|
import type { ButtonProps } from 'antd/es/button';
|
|
@@ -86,8 +87,10 @@ export class ActionModel<T extends DefaultStructure = DefaultStructure> extends
|
|
|
86
87
|
return null;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
onInit(options:
|
|
90
|
+
onInit(options: FlowModelOptions<T>): void {
|
|
90
91
|
super.onInit(options);
|
|
92
|
+
// Action disabled state is computed at runtime and must never be restored from persisted props.
|
|
93
|
+
delete this.props.disabled;
|
|
91
94
|
this.context.defineProperty('actionName', {
|
|
92
95
|
get: () => {
|
|
93
96
|
return this.getAclActionName();
|
|
@@ -96,6 +99,12 @@ export class ActionModel<T extends DefaultStructure = DefaultStructure> extends
|
|
|
96
99
|
});
|
|
97
100
|
}
|
|
98
101
|
|
|
102
|
+
serialize() {
|
|
103
|
+
const data = super.serialize();
|
|
104
|
+
delete data.props.disabled;
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
|
|
99
108
|
getInputArgs() {
|
|
100
109
|
const inputArgs: Record<string, any> = {};
|
|
101
110
|
const defaultKeys: string[] = [];
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
import { render, screen } from '@nocobase/test/client';
|
|
2
11
|
import { FlowEngine, FlowEngineProvider } from '@nocobase/flow-engine';
|
|
3
12
|
import { App, ConfigProvider } from 'antd';
|
|
@@ -35,3 +44,43 @@ describe('ActionModel rendering', () => {
|
|
|
35
44
|
expect(screen.getByRole('button', { name: 'Open details' })).toBeInTheDocument();
|
|
36
45
|
});
|
|
37
46
|
});
|
|
47
|
+
|
|
48
|
+
describe('ActionModel disabled state persistence', () => {
|
|
49
|
+
it('drops disabled from persisted props during initialization', () => {
|
|
50
|
+
const engine = new FlowEngine();
|
|
51
|
+
engine.registerModels({ NoIconActionModel });
|
|
52
|
+
const model = engine.createModel<NoIconActionModel>({
|
|
53
|
+
use: 'NoIconActionModel',
|
|
54
|
+
props: { title: 'Open details', disabled: true },
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(model.getProps()).not.toHaveProperty('disabled');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('keeps runtime disabled state without serializing it', () => {
|
|
61
|
+
const engine = new FlowEngine();
|
|
62
|
+
engine.registerModels({ NoIconActionModel });
|
|
63
|
+
const model = engine.createModel<NoIconActionModel>({
|
|
64
|
+
use: 'NoIconActionModel',
|
|
65
|
+
props: { title: 'Open details' },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
model.setProps('disabled', true);
|
|
69
|
+
|
|
70
|
+
expect(model.getProps().disabled).toBe(true);
|
|
71
|
+
expect(model.serialize().props).toEqual({ title: 'Open details' });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('does not serialize fork-local disabled state', () => {
|
|
75
|
+
const engine = new FlowEngine();
|
|
76
|
+
engine.registerModels({ NoIconActionModel });
|
|
77
|
+
const model = engine.createModel<NoIconActionModel>({
|
|
78
|
+
use: 'NoIconActionModel',
|
|
79
|
+
props: { title: 'Open details' },
|
|
80
|
+
});
|
|
81
|
+
const fork = model.createFork({ disabled: true });
|
|
82
|
+
|
|
83
|
+
expect(fork.getProps().disabled).toBe(true);
|
|
84
|
+
expect(fork.serialize().props).toEqual({ title: 'Open details' });
|
|
85
|
+
});
|
|
86
|
+
});
|