952 lines
26 KiB
TypeScript
952 lines
26 KiB
TypeScript
import { describe, it, beforeEach } from '@jest/globals';
|
|
import { screen, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { renderWithProviders } from '../../../../test-utils/test-utils.tsx';
|
|
import NormNode, {
|
|
NormReduce,
|
|
type NormNodeData,
|
|
NormConnectionSource, NormConnectionTarget
|
|
} from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode';
|
|
import useFlowStore from '../../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores';
|
|
import type { Node } from '@xyflow/react';
|
|
import '@testing-library/jest-dom'
|
|
import { NormNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.default.ts';
|
|
import { BasicBeliefNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.default.ts';
|
|
import BasicBeliefNode, { BasicBeliefConnectionSource } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.tsx';
|
|
|
|
describe('NormNode', () => {
|
|
let user: ReturnType<typeof userEvent.setup>;
|
|
|
|
beforeEach(() => {
|
|
user = userEvent.setup();
|
|
});
|
|
|
|
describe('Rendering', () => {
|
|
it('should render the norm node with default data', () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {...JSON.parse(JSON.stringify(NormNodeDefaults))},
|
|
};
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByPlaceholderText('Pepper should ...')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render with pre-populated norm text', () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'Be respectful to humans',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByDisplayValue('Be respectful to humans');
|
|
expect(input).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render with selected state', () => {
|
|
const mockNode: Node<NormNodeData> = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
conditions: [],
|
|
norm: '',
|
|
hasReduce: true,
|
|
critical: false
|
|
},
|
|
};
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const norm = screen.getByText("Norm :")
|
|
expect(norm).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render with dragging state', () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'Dragged norm',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByDisplayValue('Dragged norm');
|
|
expect(input).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('User Interactions', () => {
|
|
it('should update norm text when user types in the input field', async () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: '',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByPlaceholderText('Pepper should ...');
|
|
await user.type(input, 'Be polite to guests{enter}');
|
|
|
|
await waitFor(() => {
|
|
const state = useFlowStore.getState();
|
|
const updatedNode = state.nodes.find(n => n.id === 'norm-1');
|
|
expect(updatedNode?.data.norm).toBe('Be polite to guests');
|
|
});
|
|
});
|
|
|
|
it('should handle clearing the norm text', async () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'Initial norm text',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByDisplayValue('Initial norm text') as HTMLInputElement;
|
|
|
|
// clearing the norm text is the same as just deleting all characters one by one
|
|
// TODO: FIGURE OUT A MORE EFFICIENT WAY, I"M SORRY, user.clear() just doesn't work:/
|
|
for (let a = 0; a < 'Initial norm text'.length; a++){
|
|
await user.type(input, '{backspace}')
|
|
}
|
|
await user.type(input,'{enter}')
|
|
|
|
await waitFor(() => {
|
|
const state = useFlowStore.getState();
|
|
const updatedNode = state.nodes.find(n => n.id === 'norm-1');
|
|
expect(updatedNode?.data.norm).toBe('');
|
|
});
|
|
});
|
|
|
|
it('should update norm text multiple times', async () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: '',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByPlaceholderText('Pepper should ...');
|
|
await user.type(input, 'First norm{enter}');
|
|
await waitFor(() => {
|
|
expect(useFlowStore.getState().nodes[0].data.norm).toBe('First norm');
|
|
});
|
|
|
|
|
|
// TODO: FIGURE OUT A MORE EFFICIENT WAY, I"M SORRY, user.clear() just doesn't work:/
|
|
for (let a = 0; a < 'First norm'.length; a++){
|
|
await user.type(input, '{backspace}')
|
|
}
|
|
|
|
await user.type(input, 'Second norm{enter}');
|
|
await waitFor(() => {
|
|
expect(useFlowStore.getState().nodes[0].data.norm).toBe('Second norm');
|
|
});
|
|
});
|
|
|
|
it('should handle special characters in norm text', async () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: '',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByPlaceholderText('Pepper should ...');
|
|
await user.type(input, "Don't harm & be nice!{enter}" );
|
|
|
|
await waitFor(() => {
|
|
expect(useFlowStore.getState().nodes[0].data.norm).toBe("Don't harm & be nice!");
|
|
});
|
|
});
|
|
|
|
it('should handle long norm text', async () => {
|
|
const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: '',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByPlaceholderText('Pepper should ...');
|
|
await user.type(input, longText);
|
|
await user.type(input, "{enter}")
|
|
|
|
await waitFor(() => {
|
|
expect(useFlowStore.getState().nodes[0].data.norm).toBe(longText);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('NormReduce Function', () => {
|
|
it('should reduce a norm node to its essential data', () => {
|
|
|
|
const condition: Node = {
|
|
id: "belief-1",
|
|
type: 'basic_belief',
|
|
position: {x: 10, y: 10},
|
|
data: {
|
|
...JSON.parse(JSON.stringify(BasicBeliefNodeDefaults))
|
|
}
|
|
}
|
|
|
|
const normNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Safety Norm',
|
|
droppable: true,
|
|
norm: 'Never harm humans',
|
|
hasReduce: true,
|
|
condition: "belief-1"
|
|
},
|
|
};
|
|
|
|
const allNodes: Node[] = [normNode, condition];
|
|
const result = NormReduce(normNode, allNodes);
|
|
expect(result).toEqual({
|
|
id: 'norm-1',
|
|
label: 'Safety Norm',
|
|
norm: 'Never harm humans',
|
|
critical: false,
|
|
condition: {
|
|
id: "belief-1",
|
|
keyword: ""
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should reduce multiple norm nodes independently', () => {
|
|
const norm1: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Norm 1',
|
|
droppable: true,
|
|
norm: 'Be helpful',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
const norm2: Node = {
|
|
id: 'norm-2',
|
|
type: 'norm',
|
|
position: { x: 100, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Norm 2',
|
|
droppable: true,
|
|
norm: 'Be honest',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
const allNodes: Node[] = [norm1, norm2];
|
|
|
|
const result1 = NormReduce(norm1, allNodes);
|
|
const result2 = NormReduce(norm2, allNodes);
|
|
|
|
expect(result1.id).toBe('norm-1');
|
|
expect(result1.norm).toBe('Be helpful');
|
|
expect(result2.id).toBe('norm-2');
|
|
expect(result2.norm).toBe('Be honest');
|
|
});
|
|
|
|
it('should handle empty norm text', () => {
|
|
const normNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Empty Norm',
|
|
droppable: true,
|
|
norm: '',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
const result = NormReduce(normNode, [normNode]);
|
|
|
|
expect(result.norm).toBe('');
|
|
expect(result.id).toBe('norm-1');
|
|
});
|
|
|
|
it('should preserve node label in reduction', () => {
|
|
const normNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Custom Label',
|
|
droppable: false,
|
|
norm: 'Test norm',
|
|
hasReduce: false,
|
|
},
|
|
};
|
|
|
|
const result = NormReduce(normNode, [normNode]);
|
|
|
|
expect(result.label).toBe('Custom Label');
|
|
});
|
|
});
|
|
|
|
describe('NormConnects Function', () => {
|
|
it('should handle connection without errors', () => {
|
|
const normNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'Test',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
const phaseNode: Node = {
|
|
id: 'phase-1',
|
|
type: 'phase',
|
|
position: { x: 100, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Phase 1',
|
|
droppable: true,
|
|
children: [],
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
expect(() => {
|
|
NormConnectionSource(normNode, phaseNode.id);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should handle connection when norm is target', () => {
|
|
const normNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'Test',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
const phaseNode: Node = {
|
|
id: 'phase-1',
|
|
type: 'phase',
|
|
position: { x: 100, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Phase 1',
|
|
droppable: true,
|
|
children: [],
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
expect(() => {
|
|
NormConnectionTarget(normNode, phaseNode.id);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should handle self-connection', () => {
|
|
const normNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...NormNodeDefaults,
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'Test',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
expect(() => {
|
|
NormConnectionTarget(normNode, normNode.id);
|
|
NormConnectionSource(normNode, normNode.id);
|
|
}).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('Integration with Store', () => {
|
|
it('should properly update the store when editing norm text', async () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: '',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByPlaceholderText('Pepper should ...');
|
|
|
|
// TODO: FIGURE OUT A MORE EFFICIENT WAY, I"M SORRY, user.clear() just doesn't work:/
|
|
for (let a = 0; a < 20; a++){
|
|
await user.type(input, '{backspace}')
|
|
}
|
|
await user.type(input, 'New norm value{enter}');
|
|
|
|
await waitFor(() => {
|
|
const state = useFlowStore.getState();
|
|
expect(state.nodes).toHaveLength(1);
|
|
expect(state.nodes[0].id).toBe('norm-1');
|
|
expect(state.nodes[0].data.norm).toBe('New norm value');
|
|
});
|
|
});
|
|
|
|
it('should properly update the store when editing critical checkbox', async () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: '',
|
|
hasReduce: true,
|
|
critical: false,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const checkbox = screen.getByLabelText('Critical:');
|
|
await user.click(checkbox);
|
|
|
|
await waitFor(() => {
|
|
const state = useFlowStore.getState();
|
|
expect(state.nodes).toHaveLength(1);
|
|
expect(state.nodes[0].id).toBe('norm-1');
|
|
expect(state.nodes[0].data.norm).toBe('');
|
|
expect(state.nodes[0].data.critical).toBe(true);
|
|
});
|
|
});
|
|
|
|
it('should not affect other nodes when updating one norm node', async () => {
|
|
const norm1: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Norm 1',
|
|
droppable: true,
|
|
norm: 'Original norm 1',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
const norm2: Node = {
|
|
id: 'norm-2',
|
|
type: 'norm',
|
|
position: { x: 100, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Norm 2',
|
|
droppable: true,
|
|
norm: 'Original norm 2',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [norm1, norm2],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={norm1.id}
|
|
type={norm1.type as string}
|
|
data={norm1.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByDisplayValue('Original norm 1') as HTMLInputElement;
|
|
|
|
|
|
// TODO: FIGURE OUT A MORE EFFICIENT WAY, I"M SORRY, user.clear() just doesn't work:/
|
|
for (let a = 0; a < 20; a++){
|
|
await user.type(input, '{backspace}')
|
|
}
|
|
await user.type(input, 'Updated norm 1{enter}');
|
|
|
|
await waitFor(() => {
|
|
const state = useFlowStore.getState();
|
|
const updatedNorm1 = state.nodes.find(n => n.id === 'norm-1');
|
|
const unchangedNorm2 = state.nodes.find(n => n.id === 'norm-2');
|
|
|
|
expect(updatedNorm1?.data.norm).toBe('Updated norm 1');
|
|
expect(unchangedNorm2?.data.norm).toBe('Original norm 2');
|
|
});
|
|
});
|
|
|
|
it('should maintain data consistency with multiple rapid updates', async () => {
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...NormNodeDefaults,
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'haa haa fuyaaah - link',
|
|
hasReduce: true,
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode],
|
|
edges: [],
|
|
});
|
|
|
|
renderWithProviders(
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
const input = screen.getByPlaceholderText('Pepper should ...');
|
|
expect(input).toBeDefined()
|
|
|
|
await user.type(input, 'a{enter}');
|
|
await waitFor(() => {
|
|
expect(useFlowStore.getState().nodes[0].data.norm).toBe('haa haa fuyaaah - linka');
|
|
});
|
|
|
|
await user.type(input, 'b{enter}');
|
|
await waitFor(() => {
|
|
expect(useFlowStore.getState().nodes[0].data.norm).toBe('haa haa fuyaaah - linkab');
|
|
});
|
|
|
|
await user.type(input, 'c{enter}');
|
|
await waitFor(() => {
|
|
expect(useFlowStore.getState().nodes[0].data.norm).toBe('haa haa fuyaaah - linkabc');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Integration beliefs', () => {
|
|
it('should update visually when adding beliefs', async () => {
|
|
// Setup state
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'haa haa fuyaaah - link',
|
|
hasReduce: true,
|
|
}
|
|
};
|
|
|
|
const mockBelief: Node = {
|
|
id: 'basic_belief-1',
|
|
type: 'basic_belief',
|
|
position: {x:100, y:100},
|
|
data: {
|
|
...JSON.parse(JSON.stringify(BasicBeliefNodeDefaults))
|
|
}
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode, mockBelief],
|
|
edges: [],
|
|
});
|
|
|
|
// Simulate connecting
|
|
NormConnectionTarget(mockNode, mockBelief.id);
|
|
BasicBeliefConnectionSource(mockBelief, mockNode.id)
|
|
|
|
renderWithProviders(
|
|
<div>
|
|
<NormNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
<BasicBeliefNode
|
|
id={mockBelief.id}
|
|
type={mockBelief.type as string}
|
|
data={mockBelief.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
</div>
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByTestId('norm-condition-information')).toBeInTheDocument();
|
|
});
|
|
|
|
|
|
});
|
|
|
|
it('should update the data when adding beliefs', async () => {
|
|
// Setup state
|
|
const mockNode: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Test Norm',
|
|
droppable: true,
|
|
norm: 'haa haa fuyaaah - link',
|
|
hasReduce: true,
|
|
}
|
|
};
|
|
|
|
const mockBelief1: Node = {
|
|
id: 'basic_belief-1',
|
|
type: 'basic_belief',
|
|
position: {x:100, y:100},
|
|
data: {
|
|
...JSON.parse(JSON.stringify(BasicBeliefNodeDefaults))
|
|
}
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [mockNode, mockBelief1],
|
|
edges: [],
|
|
});
|
|
|
|
// Simulate connecting
|
|
useFlowStore.getState().onConnect({
|
|
source: 'basic_belief-1',
|
|
target: 'norm-1',
|
|
sourceHandle: null,
|
|
targetHandle: null,
|
|
});
|
|
|
|
|
|
const state = useFlowStore.getState();
|
|
const updatedNorm = state.nodes.find(n => n.id === 'norm-1');
|
|
expect(updatedNorm?.data.condition).toEqual("basic_belief-1");
|
|
});
|
|
});
|
|
}); |