@portabletext/patches
Version:
Portable Text Patches
396 lines (365 loc) • 8.85 kB
text/typescript
import {makeDiff, makePatches, stringifyPatches} from '@sanity/diff-match-patch'
import {describe, expect, test} from 'vitest'
import applyPatch from './applyPatch'
describe(applyPatch.name, () => {
const keyGenerator = createTestKeyGenerator()
const span = {
_type: 'span',
_key: keyGenerator(),
text: 'Hello',
}
const block = {
_type: 'block',
_key: keyGenerator(),
children: [span],
}
const image1 = {
_type: 'image',
_key: keyGenerator(),
src: 'https://sanity.io/image1.jpg',
}
const image2 = {
_type: 'image',
_key: keyGenerator(),
src: 'https://sanity.io/image2.jpg',
}
const gallery = {
_type: 'gallery',
_key: keyGenerator(),
images: [image1],
}
describe('`diffMatchPatch`', () => {
describe('text block', () => {
test('add text', () => {
expect(
applyPatch([block], {
type: 'diffMatchPatch',
path: [0, 'children', 0, 'text'],
value: stringifyPatches(
makePatches(makeDiff('Hello', 'Hello there')),
),
}),
).toEqual([
{
...block,
children: [{...span, text: 'Hello there'}],
},
])
})
test('remove text', () => {
expect(
applyPatch([block], {
type: 'diffMatchPatch',
path: [0, 'children', 0, 'text'],
value: stringifyPatches(makePatches(makeDiff('Hello', 'Hell'))),
}),
).toEqual([
{
...block,
children: [{...span, text: 'Hell'}],
},
])
})
test('change text', () => {
expect(
applyPatch([block], {
type: 'diffMatchPatch',
path: [0, 'children', 0, 'text'],
value: stringifyPatches(makePatches(makeDiff('Hello', 'HeLLo'))),
}),
).toEqual([
{
...block,
children: [{...span, text: 'HeLLo'}],
},
])
})
})
})
describe('`insert` before', () => {
describe('root', () => {
test('empty', () => {
expect(
applyPatch([], {
type: 'insert',
path: [0],
position: 'before',
items: [image1],
}),
).toEqual([image1])
})
test('non-empty (indexed path)', () => {
expect(
applyPatch([image1], {
type: 'insert',
path: [0],
position: 'before',
items: [image2],
}),
).toEqual([image2, image1])
})
test('non-empty (keyed path)', () => {
expect(
applyPatch([image1], {
type: 'insert',
path: [{_key: image1._key}],
position: 'before',
items: [image2],
}),
).toEqual([image2, image1])
})
})
describe('block object', () => {
test('indexed path', () => {
expect(
applyPatch([gallery], {
type: 'insert',
path: [0, 'images', 0],
position: 'before',
items: [image2],
}),
).toEqual([
{
...gallery,
images: [image2, image1],
},
])
})
test('keyed path', () => {
expect(
applyPatch([gallery], {
type: 'insert',
path: [{_key: gallery._key}, 'images', {_key: image1._key}],
position: 'before',
items: [image2],
}),
).toEqual([
{
...gallery,
images: [image2, image1],
},
])
})
})
})
describe('`insert` after', () => {
describe('root', () => {
test('empty', () => {
expect(
applyPatch([], {
type: 'insert',
path: [0],
position: 'after',
items: [image1],
}),
).toEqual([image1])
})
test('non-empty (indexed path)', () => {
expect(
applyPatch([image1], {
type: 'insert',
path: [0],
position: 'after',
items: [image2],
}),
).toEqual([image1, image2])
})
test('non-empty (keyed path)', () => {
expect(
applyPatch([image1], {
type: 'insert',
path: [{_key: image1._key}],
position: 'after',
items: [image2],
}),
).toEqual([image1, image2])
})
})
describe('block object', () => {
test('indexed path', () => {
expect(
applyPatch([gallery], {
type: 'insert',
path: [0, 'images', 0],
position: 'after',
items: [image2],
}),
).toEqual([
{
...gallery,
images: [image1, image2],
},
])
})
test('keyed path', () => {
expect(
applyPatch([gallery], {
type: 'insert',
path: [{_key: gallery._key}, 'images', {_key: image1._key}],
position: 'after',
items: [image2],
}),
).toEqual([
{
...gallery,
images: [image1, image2],
},
])
})
})
})
describe('`set`', () => {
describe('root', () => {
test('value to value', () => {
expect(
applyPatch([image1], {
type: 'set',
path: [],
value: [gallery],
}),
).toEqual([gallery])
})
test('value to empty', () => {
expect(
applyPatch([image1], {
type: 'set',
path: [],
value: [],
}),
).toEqual([])
})
test('empty to value', () => {
expect(
applyPatch([], {
type: 'set',
path: [],
value: [gallery],
}),
).toEqual([gallery])
})
test('empty to empty', () => {
expect(
applyPatch([], {
type: 'set',
path: [],
value: [],
}),
).toEqual([])
})
})
describe('block object', () => {
test('indexed path', () => {
expect(
applyPatch([image1], {
type: 'set',
path: [0],
value: gallery,
}),
).toEqual([gallery])
})
test('keyed path', () => {
expect(
applyPatch([image1], {
type: 'set',
path: [{_key: image1._key}],
value: gallery,
}),
).toEqual([gallery])
})
})
describe('block object property', () => {
test('indexed path', () => {
expect(
applyPatch([image1], {
type: 'set',
path: [0, 'alt'],
value: 'Sanity.io is a headless CMS',
}),
).toEqual([
{
...image1,
alt: 'Sanity.io is a headless CMS',
},
])
})
test('keyed path', () => {
expect(
applyPatch([image1], {
type: 'set',
path: [{_key: image1._key}, 'alt'],
value: 'Sanity.io is a headless CMS',
}),
).toEqual([
{
...image1,
alt: 'Sanity.io is a headless CMS',
},
])
})
})
})
describe('`unset`', () => {
test('root', () => {
expect(
applyPatch([image1], {
type: 'unset',
path: [],
}),
).toEqual(undefined)
})
describe('block object', () => {
test('indexed path', () => {
expect(
applyPatch([image1], {
type: 'unset',
path: [0],
}),
).toEqual([])
})
test('keyed path', () => {
expect(
applyPatch([image1], {
type: 'unset',
path: [{_key: image1._key}],
}),
).toEqual([])
})
})
describe('block object property', () => {
test('indexed path', () => {
expect(
applyPatch([image1], {
type: 'unset',
path: [0, 'alt'],
}),
).toEqual([
{
...image1,
alt: undefined,
},
])
})
test('keyed path', () => {
expect(
applyPatch([image1], {
type: 'unset',
path: [{_key: image1._key}, 'alt'],
}),
).toEqual([
{
...image1,
alt: undefined,
},
])
})
})
})
})
function createTestKeyGenerator() {
let index = 0
return function keyGenerator() {
const key = `k${index}`
index++
return key
}
}