Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions packages/plugin-sdk-value/src/plugin.two-client.browser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,81 @@

await settleAndAssertConvergence({server, editorA, editorB})
})

test('deleting one of two exact duplicates while the peer types at the end', async () => {
// Field report: deleting text that exists as an exact duplicate during
// concurrent editing corrupts. The deletion travels as a
// `diffMatchPatch` whose context anchors are identical at both copies,
// so against a base shifted by the peer's typing it can anchor at the
// wrong copy and swallow the peer's text.
const copy = "I'm feeling pretty good honestly. "
const server = createTwoClientServer([makeBlock('b1', copy + copy)])
const {editorA, editorB, locatorA, locatorB, unmount} =
await renderTwoClients(server)
cleanup = unmount

// B types at the very end; A deletes the second copy. B's insert
// reaches the server first, so A's delete applies against a base
// shifted by text A never saw.
await locatorB.click()
selectRange(editorB, 'b1', 'b1-span', copy.length * 2, copy.length * 2)
editorB.send({type: 'insert.text', text: 'hi'})
await locatorA.click()
selectRange(editorA, 'b1', 'b1-span', copy.length, copy.length * 2)
editorA.send({type: 'delete'})

await vi.waitFor(() => {
expect(server.storeA.pushPatches).toHaveBeenCalled()
expect(server.storeB.pushPatches).toHaveBeenCalled()
})

await settleAndAssertConvergence({server, editorA, editorB})

// One copy deleted, the peer's text kept.
const texts = server
.getServerValue()
.map((block) =>
((block as {children?: Array<{text?: string}>}).children ?? [])
.map((child) => child.text ?? '')
.join(''),
)
expect(texts).toEqual([`${copy}hi`])

Check failure on line 393 in packages/plugin-sdk-value/src/plugin.two-client.browser.test.tsx

View workflow job for this annotation

GitHub Actions / Browser tests (webkit)

[browser (webkit)] src/plugin.two-client.browser.test.tsx > two clients through a shared patch-channel store > deleting one of two exact duplicates while the peer types at the end

AssertionError: expected [ Array(1) ] to deeply equal [ Array(1) ] - Expected + Received [ - "I'm feeling pretty good honestly. hi", + "I'm feeling pretty good honestly. ", ] ❯ src/plugin.two-client.browser.test.tsx:393:26

Check failure on line 393 in packages/plugin-sdk-value/src/plugin.two-client.browser.test.tsx

View workflow job for this annotation

GitHub Actions / Browser tests (firefox)

[browser (firefox)] src/plugin.two-client.browser.test.tsx > two clients through a shared patch-channel store > deleting one of two exact duplicates while the peer types at the end

AssertionError: expected [ Array(1) ] to deeply equal [ Array(1) ] - Expected + Received [ - "I'm feeling pretty good honestly. hi", + "I'm feeling pretty good honestly. ", ] ❯ toEqual src/plugin.two-client.browser.test.tsx:393:18

Check failure on line 393 in packages/plugin-sdk-value/src/plugin.two-client.browser.test.tsx

View workflow job for this annotation

GitHub Actions / Browser tests (chromium)

[browser (chromium)] src/plugin.two-client.browser.test.tsx > two clients through a shared patch-channel store > deleting one of two exact duplicates while the peer types at the end

AssertionError: expected [ Array(1) ] to deeply equal [ Array(1) ] - Expected + Received [ - "I'm feeling pretty good honestly. hi", + "I'm feeling pretty good honestly. ", ] ❯ toEqual src/plugin.two-client.browser.test.tsx:393:18
})

test('deleting one of two exact duplicates while the peer types inside the deleted copy', async () => {
const copy = "I'm feeling pretty good honestly. "
const server = createTwoClientServer([makeBlock('b1', copy + copy)])
const {editorA, editorB, locatorA, locatorB, unmount} =
await renderTwoClients(server)
cleanup = unmount

// B types twelve characters into the second copy; A deletes it. B's
// insert reaches the server first, so A's delete applies against a
// base shifted by text A never saw.
await locatorB.click()
selectRange(editorB, 'b1', 'b1-span', copy.length + 12, copy.length + 12)
editorB.send({type: 'insert.text', text: 'hi'})
await locatorA.click()
selectRange(editorA, 'b1', 'b1-span', copy.length, copy.length * 2)
editorA.send({type: 'delete'})

await vi.waitFor(() => {
expect(server.storeA.pushPatches).toHaveBeenCalled()
expect(server.storeB.pushPatches).toHaveBeenCalled()
})

await settleAndAssertConvergence({server, editorA, editorB})

// The delete wins the region, but the peer's text typed inside it
// should survive somewhere; at minimum nothing beyond the two intended
// edits may change. Pin the correct merge: one copy gone, "hi" kept.
const texts = server
.getServerValue()
.map((block) =>
((block as {children?: Array<{text?: string}>}).children ?? [])
.map((child) => child.text ?? '')
.join(''),
)
expect(texts).toEqual([`${copy.slice(0, 12)}hi${copy.slice(12)}`])

Check failure on line 430 in packages/plugin-sdk-value/src/plugin.two-client.browser.test.tsx

View workflow job for this annotation

GitHub Actions / Browser tests (webkit)

[browser (webkit)] src/plugin.two-client.browser.test.tsx > two clients through a shared patch-channel store > deleting one of two exact duplicates while the peer types inside the deleted copy

AssertionError: expected [ Array(1) ] to deeply equal [ Array(1) ] - Expected + Received [ - "I'm feeling hipretty good honestly. ", + "I'm feeling pretty good honestly. ", ] ❯ src/plugin.two-client.browser.test.tsx:430:26

Check failure on line 430 in packages/plugin-sdk-value/src/plugin.two-client.browser.test.tsx

View workflow job for this annotation

GitHub Actions / Browser tests (firefox)

[browser (firefox)] src/plugin.two-client.browser.test.tsx > two clients through a shared patch-channel store > deleting one of two exact duplicates while the peer types inside the deleted copy

AssertionError: expected [ Array(1) ] to deeply equal [ Array(1) ] - Expected + Received [ - "I'm feeling hipretty good honestly. ", + "I'm feeling pretty good honestly. ", ] ❯ toEqual src/plugin.two-client.browser.test.tsx:430:18

Check failure on line 430 in packages/plugin-sdk-value/src/plugin.two-client.browser.test.tsx

View workflow job for this annotation

GitHub Actions / Browser tests (chromium)

[browser (chromium)] src/plugin.two-client.browser.test.tsx > two clients through a shared patch-channel store > deleting one of two exact duplicates while the peer types inside the deleted copy

AssertionError: expected [ Array(1) ] to deeply equal [ Array(1) ] - Expected + Received [ - "I'm feeling hipretty good honestly. ", + "I'm feeling pretty good honestly. ", ] ❯ toEqual src/plugin.two-client.browser.test.tsx:430:18
})
})
Loading