|
2 | 2 | * @vitest-environment node |
3 | 3 | */ |
4 | 4 | import { describe, expect, it } from 'vitest' |
| 5 | +import { remapConditionEdgeHandle } from '@/lib/workflows/condition-ids' |
5 | 6 | import { |
6 | 7 | coerceObjectArray, |
| 8 | + remapConditionIdsInSubBlocks, |
7 | 9 | remapWorkflowReferencesInSubBlocks, |
8 | 10 | type SubBlockRecord, |
9 | 11 | } from '@/lib/workflows/persistence/remap-internal-ids' |
@@ -378,6 +380,77 @@ describe('remapWorkflowReferencesInSubBlocks', () => { |
378 | 380 | }) |
379 | 381 | }) |
380 | 382 |
|
| 383 | +describe('remapConditionIdsInSubBlocks', () => { |
| 384 | + const OLD_ID = 'old-block' |
| 385 | + const NEW_ID = 'new-block' |
| 386 | + const conditionsValue = JSON.stringify([ |
| 387 | + { id: `${OLD_ID}-if`, title: 'if', value: '<a.b> > 1' }, |
| 388 | + { id: `${OLD_ID}-else`, title: 'else', value: '' }, |
| 389 | + ]) |
| 390 | + |
| 391 | + it('remaps condition row ids on a condition block', () => { |
| 392 | + const subBlocks: SubBlockRecord = { |
| 393 | + conditions: { id: 'conditions', type: 'condition-input', value: conditionsValue }, |
| 394 | + } |
| 395 | + const result = remapConditionIdsInSubBlocks(subBlocks, 'condition', OLD_ID, NEW_ID) |
| 396 | + const rows = JSON.parse(result.conditions.value as string) |
| 397 | + expect(rows.map((row: { id: string }) => row.id)).toEqual([`${NEW_ID}-if`, `${NEW_ID}-else`]) |
| 398 | + }) |
| 399 | + |
| 400 | + /** |
| 401 | + * Regression: a fallback writer stamped the conditions subblock `short-input`. |
| 402 | + * The remap must key on block type + subblock key, not the drifted stored type, |
| 403 | + * so the row ids and the edge handle move together (previously the ids stayed |
| 404 | + * stale while the handle remapped, orphaning every edge out of the block). |
| 405 | + */ |
| 406 | + it('remaps condition row ids even when the stored subblock type drifted', () => { |
| 407 | + const subBlocks: SubBlockRecord = { |
| 408 | + conditions: { id: 'conditions', type: 'short-input', value: conditionsValue }, |
| 409 | + } |
| 410 | + const result = remapConditionIdsInSubBlocks(subBlocks, 'condition', OLD_ID, NEW_ID) |
| 411 | + const rows = JSON.parse(result.conditions.value as string) |
| 412 | + const handle = remapConditionEdgeHandle(`condition-${OLD_ID}-else`, OLD_ID, NEW_ID) |
| 413 | + expect(handle).toBe(`condition-${NEW_ID}-else`) |
| 414 | + expect(rows.map((row: { id: string }) => row.id)).toContain(`${NEW_ID}-else`) |
| 415 | + }) |
| 416 | + |
| 417 | + it('remaps route ids on a router_v2 block', () => { |
| 418 | + const subBlocks: SubBlockRecord = { |
| 419 | + routes: { |
| 420 | + id: 'routes', |
| 421 | + type: 'router-input', |
| 422 | + value: JSON.stringify([{ id: `${OLD_ID}-route1`, title: 'Route 1', value: 'desc' }]), |
| 423 | + }, |
| 424 | + } |
| 425 | + const result = remapConditionIdsInSubBlocks(subBlocks, 'router_v2', OLD_ID, NEW_ID) |
| 426 | + const rows = JSON.parse(result.routes.value as string) |
| 427 | + expect(rows[0].id).toBe(`${NEW_ID}-route1`) |
| 428 | + }) |
| 429 | + |
| 430 | + it('leaves rows with a foreign block-id prefix untouched (matches the edge-handle remap)', () => { |
| 431 | + const subBlocks: SubBlockRecord = { |
| 432 | + conditions: { |
| 433 | + id: 'conditions', |
| 434 | + type: 'condition-input', |
| 435 | + value: JSON.stringify([{ id: 'foreign-block-if', title: 'if', value: '' }]), |
| 436 | + }, |
| 437 | + } |
| 438 | + const result = remapConditionIdsInSubBlocks(subBlocks, 'condition', OLD_ID, NEW_ID) |
| 439 | + expect(result.conditions).toBe(subBlocks.conditions) |
| 440 | + expect(remapConditionEdgeHandle('condition-foreign-block-if', OLD_ID, NEW_ID)).toBe( |
| 441 | + 'condition-foreign-block-if' |
| 442 | + ) |
| 443 | + }) |
| 444 | + |
| 445 | + it('does not touch subblocks on non-dynamic-handle block types', () => { |
| 446 | + const subBlocks: SubBlockRecord = { |
| 447 | + conditions: { id: 'conditions', type: 'condition-input', value: conditionsValue }, |
| 448 | + } |
| 449 | + const result = remapConditionIdsInSubBlocks(subBlocks, 'function', OLD_ID, NEW_ID) |
| 450 | + expect(result.conditions).toBe(subBlocks.conditions) |
| 451 | + }) |
| 452 | +}) |
| 453 | + |
381 | 454 | describe('coerceObjectArray', () => { |
382 | 455 | it('returns arrays directly', () => { |
383 | 456 | expect(coerceObjectArray([{ a: 1 }])).toEqual({ array: [{ a: 1 }], wasString: false }) |
|
0 commit comments