Skip to content

Commit

Permalink
test(playwright-ct): add range decoration test for PT-input
Browse files Browse the repository at this point in the history
  • Loading branch information
skogsmaskin committed Feb 29, 2024
1 parent 8a41030 commit af4a95e
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {expect, test} from '@playwright/experimental-ct-react'
import {type SanityDocument} from 'sanity'

import {testHelpers} from '../../../utils/testHelpers'
import {type DecorationData, RangeDecorationStory} from './RangeDecorationStory'

const document: SanityDocument = {
_id: '123',
_type: 'test',
_createdAt: new Date().toISOString(),
_updatedAt: new Date().toISOString(),
_rev: '123',
body: [
{
_type: 'block',
_key: 'a',
children: [{_type: 'span', _key: 'a1', text: 'Hello there world'}],
markDefs: [],
},
{
_type: 'block',
_key: 'b',
children: [{_type: 'span', _key: 'b1', text: "It's a beautiful day on planet earth"}],
markDefs: [],
},
],
}

// Since we can't pass React components to our story, we'll just pass the selection data,
// and use a test component inside the Story to render the range decoration.
const decorationData: DecorationData[] = [
{
word: 'there',
selection: {
anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 6},
focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 11},
},
},
]

test.describe('Portable Text Input', () => {
test.describe('Range Decoration', () => {
// test.only('Manual testing can be performed with this test', async ({mount, page}) => {
// await mount(<RangeDecorationStory document={document} decorationData={decorationData} />)
// await page.waitForTimeout(360000)
// })
test(`Draws range decoration around our selection`, async ({mount, page}) => {
await mount(<RangeDecorationStory document={document} decorationData={decorationData} />)
await expect(page.getByTestId('range-decoration')).toHaveText('there')
})

test(`Let's us move the range according to our edits`, async ({mount, page}) => {
const {getFocusedPortableTextEditor, insertPortableText} = testHelpers({page})

await mount(<RangeDecorationStory document={document} decorationData={decorationData} />)

const $pte = await getFocusedPortableTextEditor('field-body')

await insertPortableText('123 ', $pte)
await expect($pte).toHaveText("123 Hello there worldIt's a beautiful day on planet earth")
// Assert that the same word is decorated after the edit
await expect(page.getByTestId('range-decoration')).toHaveText('there')
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* eslint-disable max-nested-callbacks */
import {type EditorSelection, type RangeDecoration} from '@sanity/portable-text-editor'
import {defineArrayMember, defineField, defineType, type SanityDocument} from '@sanity/types'
import {type PropsWithChildren, useEffect, useMemo, useState} from 'react'
import {type InputProps, PortableTextInput, type PortableTextInputProps} from 'sanity'

import {TestForm} from '../../utils/TestForm'
import {TestWrapper} from '../../utils/TestWrapper'

export type DecorationData = {selection: EditorSelection; word: string}

const RangeDecorationTestComponent = (props: PropsWithChildren) => {
return (
<span style={{backgroundColor: 'yellow'}} data-testid="range-decoration">
{props.children}
</span>
)
}

const CustomPortableTextInput = (
props: PortableTextInputProps & {decorationData?: DecorationData[]},
) => {
const {decorationData} = props
const [rangeDecorationsState, setRangeDecorationsState] = useState<RangeDecoration[]>([])

useEffect(() => {
setRangeDecorationsState(
(decorationData?.map((data) => ({
component: RangeDecorationTestComponent,
selection: data.selection,
onMoved: (movedProps) => {
const {newSelection, rangeDecoration} = movedProps
setRangeDecorationsState((prev) =>
prev.map((decoration) =>
data.selection === rangeDecoration.selection
? {...decoration, selection: newSelection}
: decoration,
),
)
},
payload: {word: data.word},
})) || []) as RangeDecoration[],
)
}, [decorationData])

return <PortableTextInput {...props} rangeDecorations={rangeDecorationsState} />
}

export function RangeDecorationStory({
document,
decorationData,
}: {
document?: SanityDocument
decorationData?: DecorationData[]
}) {
const schemaTypes = useMemo(
() => [
defineType({
type: 'document',
name: 'test',
title: 'Test',
fields: [
defineField({
type: 'array',
name: 'body',
of: [
defineArrayMember({
type: 'block',
}),
],
components: {
input: (props: InputProps) => (
<CustomPortableTextInput
{...(props as PortableTextInputProps)}
decorationData={decorationData}
/>
),
},
}),
],
}),
],
[decorationData],
)

return (
<TestWrapper schemaTypes={schemaTypes}>
<TestForm document={document} />
</TestWrapper>
)
}

0 comments on commit af4a95e

Please sign in to comment.