| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690 |
- // @ts-nocheck
- import { describe, expect, test } from 'vitest'
- import {
- operationMatchesRow,
- resolveDeleteRowConflicts,
- resolveEditCellConflicts,
- upsertOperation,
- } from './queueConflictResolution'
- import {
- QueuedOperation,
- QueuedOperationType,
- type NewAddRowOperation,
- type NewDeleteRowOperation,
- type NewEditCellContentOperation,
- } from '@/state/table-editor-operation-queue.types'
- describe('operationMatchesRow', () => {
- const mockTable = {} as any
- test('should match EDIT_CELL_CONTENT operation with same row identifiers', () => {
- const operation: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'old',
- newValue: 'new',
- table: mockTable,
- },
- }
- expect(operationMatchesRow(operation, 1, { id: 1 })).toBe(true)
- })
- test('should not match EDIT_CELL_CONTENT operation with different row identifiers', () => {
- const operation: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'old',
- newValue: 'new',
- table: mockTable,
- },
- }
- expect(operationMatchesRow(operation, 1, { id: 2 })).toBe(false)
- })
- test('should not match operation from different table', () => {
- const operation: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'old',
- newValue: 'new',
- table: mockTable,
- },
- }
- expect(operationMatchesRow(operation, 2, { id: 1 })).toBe(false)
- })
- test('should match DELETE_ROW operation with same row identifiers', () => {
- const operation: QueuedOperation = {
- id: 'delete_row:1:id:1',
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- originalRow: { idx: 1, id: 1, name: 'test' },
- table: mockTable,
- },
- }
- expect(operationMatchesRow(operation, 1, { id: 1 })).toBe(true)
- })
- test('should return false for ADD_ROW operations', () => {
- const operation: QueuedOperation = {
- id: 'add_row:1:temp123',
- type: QueuedOperationType.ADD_ROW,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- tempId: 'temp123',
- rowData: { idx: 1, __tempId: '1', name: 'new' },
- table: mockTable,
- },
- }
- expect(operationMatchesRow(operation, 1, { id: 1 })).toBe(false)
- })
- })
- describe('resolveDeleteRowConflicts', () => {
- const mockTable = {} as any
- test('should skip delete and remove ADD_ROW when deleting a newly added row', () => {
- const addRowOp: QueuedOperation = {
- id: 'add_row:1:-12345',
- type: QueuedOperationType.ADD_ROW,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- tempId: '-12345',
- rowData: { idx: -12345, __tempId: '-12345', name: 'new row' },
- table: mockTable,
- },
- }
- const operations = [addRowOp]
- const deleteOperation: NewDeleteRowOperation = {
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- payload: {
- rowIdentifiers: { __tempId: '-12345' },
- originalRow: { idx: -12345, __tempId: '-12345', name: 'new row' },
- table: mockTable,
- },
- }
- const result = resolveDeleteRowConflicts(operations, deleteOperation)
- expect(result.action).toBe('skip')
- expect(result.filteredOperations).toEqual([])
- })
- test('should skip delete and remove ADD_ROW and related EDIT_CELLs when deleting a newly added row', () => {
- const addRowOp: QueuedOperation = {
- id: 'add_row:1:-12345',
- type: QueuedOperationType.ADD_ROW,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- tempId: '-12345',
- rowData: { idx: -12345, __tempId: '-12345', name: 'new row' },
- table: mockTable,
- },
- }
- const editCellOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:__tempId:-12345',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { __tempId: '-12345' },
- columnName: 'name',
- oldValue: 'new row',
- newValue: 'edited',
- table: mockTable,
- },
- }
- const otherEditOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:99',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 99 },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const operations = [addRowOp, editCellOp, otherEditOp]
- const deleteOperation: NewDeleteRowOperation = {
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- payload: {
- rowIdentifiers: { __tempId: '-12345' },
- originalRow: { idx: -12345, __tempId: '-12345', name: 'new row' },
- table: mockTable,
- },
- }
- const result = resolveDeleteRowConflicts(operations, deleteOperation)
- expect(result.action).toBe('skip')
- expect(result.filteredOperations).toHaveLength(1)
- expect(result.filteredOperations[0]).toEqual(otherEditOp)
- })
- test('should add delete and remove EDIT_CELLs for existing row being deleted', () => {
- const editCellOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'edited',
- table: mockTable,
- },
- }
- const otherEditOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:2',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 2 },
- columnName: 'name',
- oldValue: 'other',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const operations = [editCellOp, otherEditOp]
- const deleteOperation: NewDeleteRowOperation = {
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- originalRow: { idx: 1, id: 1, name: 'original' },
- table: mockTable,
- },
- }
- const result = resolveDeleteRowConflicts(operations, deleteOperation)
- expect(result.action).toBe('add')
- expect(result.filteredOperations).toHaveLength(1)
- expect(result.filteredOperations[0]).toEqual(otherEditOp)
- })
- test('should add delete with no changes when there are no conflicts', () => {
- const otherEditOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:2',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 2 },
- columnName: 'name',
- oldValue: 'other',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const operations = [otherEditOp]
- const deleteOperation: NewDeleteRowOperation = {
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- originalRow: { idx: 1, id: 1, name: 'original' },
- table: mockTable,
- },
- }
- const result = resolveDeleteRowConflicts(operations, deleteOperation)
- expect(result.action).toBe('add')
- expect(result.filteredOperations).toEqual(operations)
- })
- })
- describe('resolveEditCellConflicts', () => {
- const mockTable = {} as any
- test('should reject edit on a row pending deletion', () => {
- const deleteOp: QueuedOperation = {
- id: 'delete_row:1:id:1',
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- originalRow: { idx: 1, id: 1, name: 'to delete' },
- table: mockTable,
- },
- }
- const operations = [deleteOp]
- const editOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'to delete',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const result = resolveEditCellConflicts(operations, editOperation)
- expect(result.action).toBe('reject')
- if (result.action === 'reject') {
- expect(result.reason).toContain('pending deletion')
- }
- })
- test('should merge edit into ADD_ROW for a newly added row', () => {
- const addRowOp: QueuedOperation = {
- id: 'add_row:1:-12345',
- type: QueuedOperationType.ADD_ROW,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- tempId: '-12345',
- rowData: { idx: -12345, __tempId: '-12345', name: 'new row' },
- table: mockTable,
- },
- }
- const operations = [addRowOp]
- const editOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { __tempId: '-12345' },
- columnName: 'name',
- oldValue: 'new row',
- newValue: 'edited value',
- table: mockTable,
- },
- }
- const result = resolveEditCellConflicts(operations, editOperation)
- expect(result.action).toBe('merge')
- if (result.action === 'merge') {
- expect(result.updatedOperations).toHaveLength(1)
- const updatedAddRow = result.updatedOperations[0]
- expect(updatedAddRow.type).toBe(QueuedOperationType.ADD_ROW)
- expect((updatedAddRow.payload as any).rowData.name).toBe('edited value')
- }
- })
- test('should return add action for normal edit on existing row', () => {
- const otherOp: QueuedOperation = {
- id: 'edit_cell_content:1:email:id:2',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 2 },
- columnName: 'email',
- oldValue: 'old@test.com',
- newValue: 'new@test.com',
- table: mockTable,
- },
- }
- const operations = [otherOp]
- const editOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const result = resolveEditCellConflicts(operations, editOperation)
- expect(result.action).toBe('add')
- })
- test('should return add when editing tempId row but ADD_ROW not found', () => {
- const operations: QueuedOperation[] = []
- const editOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { __tempId: '-99999' },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const result = resolveEditCellConflicts(operations, editOperation)
- expect(result.action).toBe('add')
- })
- })
- describe('upsertOperation', () => {
- const mockTable = {} as any
- test('should add new operation to empty queue', () => {
- const operations: QueuedOperation[] = []
- const newOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(1)
- expect(result.operations[0].type).toBe(QueuedOperationType.EDIT_CELL_CONTENT)
- expect(result.operations[0].id).toBe('edit_cell_content:1:name:id:1')
- })
- test('should add new operation to existing queue', () => {
- const existingOp: QueuedOperation = {
- id: 'edit_cell_content:1:email:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'email',
- oldValue: 'old@test.com',
- newValue: 'new@test.com',
- table: mockTable,
- },
- }
- const operations = [existingOp]
- const newOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(2)
- })
- test('should update existing EDIT_CELL operation and preserve original oldValue', () => {
- const existingOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now() - 1000,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'very first value',
- newValue: 'intermediate',
- table: mockTable,
- },
- }
- const operations = [existingOp]
- const newOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'intermediate',
- newValue: 'final value',
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(1)
- const updated = result.operations[0]
- expect((updated.payload as any).oldValue).toBe('very first value')
- expect((updated.payload as any).newValue).toBe('final value')
- })
- test('should remove operation when value is reverted to original', () => {
- const existingOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now() - 1000,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const otherOp: QueuedOperation = {
- id: 'edit_cell_content:1:email:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'email',
- oldValue: 'old@test.com',
- newValue: 'new@test.com',
- table: mockTable,
- },
- }
- const operations = [existingOp, otherOp]
- const newOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'changed',
- newValue: 'original',
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(1)
- expect(result.operations[0]).toEqual(otherOp)
- })
- test('should remove operation when number oldValue matches string newValue', () => {
- const existingOp: QueuedOperation = {
- id: 'edit_cell_content:1:age:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now() - 1000,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'age',
- oldValue: 42,
- newValue: 'changed',
- table: mockTable,
- },
- }
- const operations = [existingOp]
- const newOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'age',
- oldValue: 'changed',
- newValue: '42',
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(0)
- })
- test('should remove operation when string oldValue matches JSON object newValue', () => {
- const existingOp: QueuedOperation = {
- id: 'edit_cell_content:1:metadata:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now() - 1000,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'metadata',
- oldValue: '{"key":"value","count":3}',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const operations = [existingOp]
- const newOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'metadata',
- oldValue: 'changed',
- newValue: { key: 'value', count: 3 },
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(0)
- })
- test('should update existing DELETE_ROW operation', () => {
- const existingOp: QueuedOperation = {
- id: 'delete_row:1:id:1',
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- timestamp: Date.now() - 1000,
- payload: {
- rowIdentifiers: { id: 1 },
- originalRow: { idx: 1, id: 1, name: 'old data' },
- table: mockTable,
- },
- }
- const operations = [existingOp]
- const newOperation: NewDeleteRowOperation = {
- type: QueuedOperationType.DELETE_ROW,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 1 },
- originalRow: { idx: 1, id: 1, name: 'updated data' },
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(1)
- expect((result.operations[0].payload as any).originalRow.name).toBe('updated data')
- })
- test('should not mutate original operations array', () => {
- const existingOp: QueuedOperation = {
- id: 'edit_cell_content:1:name:id:1',
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- timestamp: Date.now(),
- payload: {
- rowIdentifiers: { id: 1 },
- columnName: 'name',
- oldValue: 'original',
- newValue: 'changed',
- table: mockTable,
- },
- }
- const operations = [existingOp]
- const originalOperations = [...operations]
- const newOperation: NewEditCellContentOperation = {
- type: QueuedOperationType.EDIT_CELL_CONTENT,
- tableId: 1,
- payload: {
- rowIdentifiers: { id: 2 },
- columnName: 'name',
- oldValue: 'original2',
- newValue: 'changed2',
- table: mockTable,
- },
- }
- upsertOperation(operations, newOperation)
- expect(operations).toEqual(originalOperations)
- })
- test('should handle ADD_ROW operation', () => {
- const operations: QueuedOperation[] = []
- const newOperation: NewAddRowOperation = {
- type: QueuedOperationType.ADD_ROW,
- tableId: 1,
- payload: {
- tempId: '-12345',
- rowData: { idx: -12345, __tempId: '-12345', name: 'new row' },
- table: mockTable,
- },
- }
- const result = upsertOperation(operations, newOperation)
- expect(result.operations).toHaveLength(1)
- expect(result.operations[0].id).toBe('add_row:1:-12345')
- })
- })
|