Cover the array item modal before refactoring it
This round trip - item schema to dialog fields and back to an object - is the machinery an optional-group modal wants to reuse, and nothing covered it: the dialog mock in this spec resolved null, so no test ever reached the builder or the parser. Six characterisation tests pin what it does today: which fields it builds and with what labels and types, that it writes the parsed item into the array, that it edits in place rather than appending, and that a cancelled dialog changes nothing. One of them pins behaviour I intend to change and deliberately does not endorse: an emptied required number becomes 0. Writing it down is the point - the optional case has to differ, and the difference should be visible as a changed assertion rather than as a silent shift. 584 frontend tests green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b53a22dcc4
commit
1e381aa0ef
|
|
@ -127,6 +127,96 @@ describe('GenericNodeComponent', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('the array item modal, as it behaves today', () => {
|
||||
/**
|
||||
* Characterisation tests. This round trip - schema to dialog fields and back to an object - is
|
||||
* the machinery an optional-group modal wants to reuse, and nothing covered it: the dialog mock
|
||||
* resolved null, so no test ever reached the builder or the parser. These pin what it does now,
|
||||
* so extracting it cannot change it by accident.
|
||||
*/
|
||||
const itemSchema = {
|
||||
type: 'object',
|
||||
required: ['name', 'weight'],
|
||||
properties: {
|
||||
name: { type: 'string', 'x-ui-label': 'Skill name' },
|
||||
weight: { type: 'integer' },
|
||||
enabled: { type: 'boolean' }
|
||||
}
|
||||
};
|
||||
|
||||
function withArrayField() {
|
||||
const component = fixture.componentInstance as any;
|
||||
component.arrayFieldDefinitions = [{
|
||||
path: 'skills',
|
||||
label: 'Skills',
|
||||
itemSchema,
|
||||
uniqueBy: null,
|
||||
ui: { structural: false, visibleWhen: [], enabledWhen: [] }
|
||||
}];
|
||||
return component;
|
||||
}
|
||||
|
||||
it('builds one dialog field per item property, honouring labels and types', async () => {
|
||||
const component = withArrayField();
|
||||
const open = TestBed.inject(NodeSettingsDialogService).open as ReturnType<typeof vi.fn>;
|
||||
open.mockResolvedValue(null);
|
||||
|
||||
await component.addArrayItem('skills');
|
||||
|
||||
const dialog = open.mock.calls.at(-1)?.[0];
|
||||
expect(dialog.fields.map((field: any) => [field.key, field.type])).toEqual([
|
||||
['name', 'text'], ['weight', 'text'], ['enabled', 'checkbox']
|
||||
]);
|
||||
expect(dialog.fields[0].label).toBe('Skill name');
|
||||
});
|
||||
|
||||
it('writes the parsed item into the array', async () => {
|
||||
const component = withArrayField();
|
||||
const open = TestBed.inject(NodeSettingsDialogService).open as ReturnType<typeof vi.fn>;
|
||||
open.mockResolvedValue({ name: 'summarise', weight: '3', enabled: true });
|
||||
|
||||
await component.addArrayItem('skills');
|
||||
|
||||
const config = component.ensureBlockConfiguration();
|
||||
expect(config['skills']).toEqual([{ name: 'summarise', weight: 3, enabled: true }]);
|
||||
});
|
||||
|
||||
it('turns an emptied required number into 0, which is what it has always done', async () => {
|
||||
// Not an endorsement: it is the behaviour a refactor must not change silently. The optional
|
||||
// case is the one that has to differ, and it differs deliberately.
|
||||
const component = withArrayField();
|
||||
const open = TestBed.inject(NodeSettingsDialogService).open as ReturnType<typeof vi.fn>;
|
||||
open.mockResolvedValue({ name: 'x', weight: '', enabled: false });
|
||||
|
||||
await component.addArrayItem('skills');
|
||||
|
||||
expect(component.ensureBlockConfiguration()['skills'][0].weight).toBe(0);
|
||||
});
|
||||
|
||||
it('edits an existing item in place rather than appending', async () => {
|
||||
const component = withArrayField();
|
||||
const config = component.ensureBlockConfiguration();
|
||||
config['skills'] = [{ name: 'first', weight: 1, enabled: false }];
|
||||
const open = TestBed.inject(NodeSettingsDialogService).open as ReturnType<typeof vi.fn>;
|
||||
open.mockResolvedValue({ name: 'renamed', weight: '2', enabled: true });
|
||||
|
||||
await component.editArrayItem('skills', 0);
|
||||
|
||||
expect(config['skills']).toEqual([{ name: 'renamed', weight: 2, enabled: true }]);
|
||||
});
|
||||
|
||||
it('leaves the array untouched when the dialog is cancelled', async () => {
|
||||
const component = withArrayField();
|
||||
const config = component.ensureBlockConfiguration();
|
||||
config['skills'] = [{ name: 'first', weight: 1, enabled: false }];
|
||||
(TestBed.inject(NodeSettingsDialogService).open as ReturnType<typeof vi.fn>).mockResolvedValue(null);
|
||||
|
||||
await component.addArrayItem('skills');
|
||||
|
||||
expect(config['skills']).toEqual([{ name: 'first', weight: 1, enabled: false }]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue