first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,549 @@
|
||||
import { mocked } from 'vitest-mock-extended';
|
||||
|
||||
import { type IConnection, type IConnections } from '../src';
|
||||
import { compareConnections } from '../src/connections-diff';
|
||||
|
||||
// Mock IConnection for testing
|
||||
const createConnection = (node: string, type: IConnection['type'], index: number): IConnection =>
|
||||
mocked<IConnection>({
|
||||
node,
|
||||
type,
|
||||
index,
|
||||
});
|
||||
|
||||
describe('compareConnections', () => {
|
||||
describe('empty states', () => {
|
||||
it('should return empty diff when both prev and next are empty', () => {
|
||||
const prev: IConnections = {};
|
||||
const next: IConnections = {};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
|
||||
it('should detect all connections as added when prev is empty', () => {
|
||||
const prev: IConnections = {};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node0', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
|
||||
it('should detect all connections as removed when next is empty', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node0', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('no changes', () => {
|
||||
it('should return empty diff when connections are identical', () => {
|
||||
const connections: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(connections, connections);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
|
||||
it('should handle identical complex structures', () => {
|
||||
const connections: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0), createConnection('node2', 'main', 0)]],
|
||||
},
|
||||
node2: {
|
||||
main: [[createConnection('node1', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(connections, connections);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('simple additions and removals', () => {
|
||||
it('should detect a single added connection', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0), createConnection('node2', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 1, connection: createConnection('node2', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
|
||||
it('should detect a single removed connection', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0), createConnection('node2', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 1, connection: createConnection('node2', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should detect connection replacement', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node2', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node2', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node0', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple nodes', () => {
|
||||
it('should handle changes across multiple nodes', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
node2: {
|
||||
main: [[createConnection('node1', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
node2: {
|
||||
main: [[createConnection('node3', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node2: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node3', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({
|
||||
node2: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node1', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should detect new node with connections', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
node2: {
|
||||
main: [[createConnection('node1', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node2: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node1', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
|
||||
it('should detect removed node with connections', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
node2: {
|
||||
main: [[createConnection('node1', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({
|
||||
node2: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node1', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple inputs', () => {
|
||||
it('should handle multiple input types on same node', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
aux: [[createConnection('node2', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
aux: [[createConnection('node3', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
aux: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node3', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({
|
||||
node1: {
|
||||
aux: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node2', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should detect new input type', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
aux: [[createConnection('node2', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
aux: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node2', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple source indices', () => {
|
||||
it('should handle multiple source indices (switch-like nodes)', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [
|
||||
[createConnection('node0', 'main', 0)],
|
||||
null,
|
||||
[createConnection('node2', 'main', 0)],
|
||||
],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [
|
||||
[createConnection('node0', 'main', 0)],
|
||||
[createConnection('node3', 'main', 0)],
|
||||
[createConnection('node2', 'main', 0)],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 1,
|
||||
value: { index: 0, connection: createConnection('node3', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
|
||||
it('should detect removed connection at specific source index', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [
|
||||
[createConnection('node0', 'main', 0)],
|
||||
[createConnection('node3', 'main', 0)],
|
||||
[createConnection('node2', 'main', 0)],
|
||||
],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [
|
||||
[createConnection('node0', 'main', 0)],
|
||||
null,
|
||||
[createConnection('node2', 'main', 0)],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 1,
|
||||
value: { index: 0, connection: createConnection('node3', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('complex scenarios', () => {
|
||||
it('should handle multiple changes simultaneously', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
node2: {
|
||||
main: [[createConnection('node1', 'main', 0)], [createConnection('node3', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0), createConnection('node4', 'main', 0)]],
|
||||
},
|
||||
node2: {
|
||||
main: [[createConnection('node1', 'main', 0)]],
|
||||
},
|
||||
node3: {
|
||||
main: [[createConnection('node2', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 1, connection: createConnection('node4', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
node3: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node2', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({
|
||||
node2: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 1,
|
||||
value: { index: 0, connection: createConnection('node3', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle connections with different indices but same node', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 0)]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [[createConnection('node0', 'main', 1)]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
// These should be considered different connections
|
||||
expect(result.added).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node0', 'main', 1) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.removed).toEqual({
|
||||
node1: {
|
||||
main: [
|
||||
{
|
||||
sourceIndex: 0,
|
||||
value: { index: 0, connection: createConnection('node0', 'main', 0) },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty arrays vs null', () => {
|
||||
const prev: IConnections = {
|
||||
node1: {
|
||||
main: [[]],
|
||||
},
|
||||
};
|
||||
const next: IConnections = {
|
||||
node1: {
|
||||
main: [null],
|
||||
},
|
||||
};
|
||||
|
||||
const result = compareConnections(prev, next);
|
||||
|
||||
expect(result.added).toEqual({});
|
||||
expect(result.removed).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user