Skip to content

Commit 2b5a180

Browse files
authored
fix/COMPASS-9956 use more stable key for field component rendering (#154)
* fix/COMPASS-9956 use more stable key for field component rendering * better key and add tests * Add comment in test
1 parent d33fe5e commit 2b5a180

File tree

2 files changed

+73
-14
lines changed

2 files changed

+73
-14
lines changed

src/components/diagram.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ReactFlowProvider } from '@xyflow/react';
44
import { Diagram } from '@/components/diagram';
55
import { EMPLOYEES_NODE } from '@/mocks/datasets/nodes';
66
import { EMPLOYEES_TO_EMPLOYEES_EDGE } from '@/mocks/datasets/edges';
7+
import { NodeProps } from '@/types';
78

89
describe('Diagram', () => {
910
it('Should render diagram', () => {
@@ -19,4 +20,59 @@ describe('Diagram', () => {
1920
expect(screen.getByTestId('rf__minimap')).toBeInTheDocument();
2021
expect(screen.getByTestId('rf__node-employees')).toBeInTheDocument();
2122
});
23+
24+
it('Should correctly add / remove fields in the node on update', () => {
25+
const nodeWithFields: NodeProps = {
26+
id: 'node-1',
27+
title: 'Node 1',
28+
position: { x: 0, y: 0 },
29+
type: 'collection',
30+
fields: [{ name: 'field-a' }, { name: 'field-b' }, { name: 'field-c' }],
31+
};
32+
33+
// Render all fields first
34+
const { rerender } = render(
35+
<ReactFlowProvider>
36+
<Diagram nodes={[nodeWithFields]} edges={[]} />
37+
</ReactFlowProvider>,
38+
);
39+
40+
expect(screen.getByText('field-a')).toBeInTheDocument();
41+
expect(screen.getByText('field-b')).toBeInTheDocument();
42+
expect(screen.getByText('field-c')).toBeInTheDocument();
43+
44+
// Add a field in the middle of the list
45+
const nodeWithFieldAdded = {
46+
...nodeWithFields,
47+
fields: [nodeWithFields.fields[0], { name: 'field-after-a' }, nodeWithFields.fields[1], nodeWithFields.fields[2]],
48+
};
49+
50+
rerender(
51+
<ReactFlowProvider>
52+
<Diagram nodes={[nodeWithFieldAdded]} edges={[]} />
53+
</ReactFlowProvider>,
54+
);
55+
56+
expect(screen.getByText('field-a')).toBeInTheDocument();
57+
expect(screen.getByText('field-after-a')).toBeInTheDocument();
58+
expect(screen.getByText('field-b')).toBeInTheDocument();
59+
expect(screen.getByText('field-c')).toBeInTheDocument();
60+
61+
// Remove the field from the middle of the list
62+
const nodeWithFieldRemoved = {
63+
...nodeWithFields,
64+
fields: [nodeWithFields.fields[0], nodeWithFields.fields[2]],
65+
};
66+
67+
rerender(
68+
<ReactFlowProvider>
69+
<Diagram nodes={[nodeWithFieldRemoved]} edges={[]} />
70+
</ReactFlowProvider>,
71+
);
72+
73+
expect(screen.getByText('field-a')).toBeInTheDocument();
74+
expect(screen.getByText('field-c')).toBeInTheDocument();
75+
expect(() => screen.getByText('field-after-a')).toThrow();
76+
expect(() => screen.getByText('field-b')).toThrow();
77+
});
2278
});

src/components/field/field-list.tsx

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,23 @@ export const FieldList = ({ fields, nodeId, nodeType, isHovering }: Props) => {
3232
}, [fields, isFieldSelectionEnabled]);
3333
return (
3434
<NodeFieldWrapper>
35-
{fields.map(({ name, type: fieldType, ...rest }, i) => (
36-
<Field
37-
key={i}
38-
name={name}
39-
nodeId={nodeId}
40-
nodeType={nodeType}
41-
isHovering={isHovering}
42-
previewGroupArea={previewGroupArea[getPreviewId(i, name)] || DEFAULT_PREVIEW_GROUP_AREA}
43-
selectedGroupHeight={selectedGroupHeight?.[getSelectedId(i, name)]}
44-
type={fieldType}
45-
spacing={spacing}
46-
{...rest}
47-
/>
48-
))}
35+
{fields.map(({ id, name, type: fieldType, ...rest }, i) => {
36+
const key = id ? (Array.isArray(id) ? id.join('#') : id) : `${name}-${i}`;
37+
return (
38+
<Field
39+
key={key}
40+
name={name}
41+
nodeId={nodeId}
42+
nodeType={nodeType}
43+
isHovering={isHovering}
44+
previewGroupArea={previewGroupArea[getPreviewId(i, name)] || DEFAULT_PREVIEW_GROUP_AREA}
45+
selectedGroupHeight={selectedGroupHeight?.[getSelectedId(i, name)]}
46+
type={fieldType}
47+
spacing={spacing}
48+
{...rest}
49+
/>
50+
);
51+
})}
4952
</NodeFieldWrapper>
5053
);
5154
};

0 commit comments

Comments
 (0)