mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-28 01:19:52 +02:00
Compare only decorations offsets in MemoizedText. Code highlighting example improvements. (#5271)
* add basePath prop to Range inside slate-react custom types, calculate absolute ranges on passing them into TextComponent * code highlighting example improvements, minor markdown preview refactoring * changeset added * Revert "add basePath prop to Range inside slate-react custom types, calculate absolute ranges on passing them into TextComponent" This reverts commit afa085c289bc67ce3d27dd33b1f074ab8153efe8. * add basePath prop to Point inside slate-react custom types, resolve relative ranges on passing them to TextComponent * Update changeset * linter fixes * remove redundant checks inside renderElement function * custom types fixes for Range and Point in examples * wrap intervals and ranges extractors in useMemo hook for running them only if editor.children is changed * revert basePath changes, compare only offsets for MemoizedText decorations * use an element as a key in decorations ranges map instead of id * simplify code highlighting implementation, make code block nested * fix code-highlighting example, add toolbar code block button * remove redundant code * fix code highlighting playwright integration test
This commit is contained in:
@@ -1,57 +1,122 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
import { test, expect, Page } from '@playwright/test'
|
||||
|
||||
test.describe('code highlighting', () => {
|
||||
const slateEditor = '[data-slate-node="element"]'
|
||||
const leafNode = 'span[data-slate-leaf="true"]'
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
page.goto('http://localhost:3000/examples/code-highlighting')
|
||||
})
|
||||
|
||||
test('highlights HTML tags', async ({ page }) => {
|
||||
const outer = page
|
||||
.locator(slateEditor)
|
||||
.locator('span')
|
||||
.nth(0)
|
||||
.locator(leafNode)
|
||||
.nth(0)
|
||||
await expect(await outer.textContent()).toContain('<h1>')
|
||||
await expect(outer).toHaveCSS('color', 'rgb(153, 0, 85)')
|
||||
})
|
||||
for (const testCase of getTestCases()) {
|
||||
const { language, content, highlights } = testCase
|
||||
|
||||
test('highlights javascript syntax', async ({ page }) => {
|
||||
const JSCode = 'const slateVar = 30;'
|
||||
await page.locator('select').selectOption('JavaScript') // Select the 'JavaScript' option
|
||||
await expect(await page.locator('select').inputValue()).toBe('js') // Confirm value to avoid race condition
|
||||
test(`code highlighting ${language}`, async ({ page }) => {
|
||||
await setText(page, content, language)
|
||||
|
||||
await page.locator(slateEditor).click() // focus on the editor
|
||||
const isMac = await page.evaluate(() => {
|
||||
return /Mac|iPhone|iPod|iPad/i.test(navigator.platform)
|
||||
const tokens = await page
|
||||
.locator('[data-slate-editor] [data-slate-string]')
|
||||
.all()
|
||||
|
||||
for (const [index, token] of tokens.entries()) {
|
||||
const highlight = highlights[index]
|
||||
const textContent = await token.textContent()
|
||||
|
||||
await expect(textContent).toEqual(highlight[0])
|
||||
await expect(token).toHaveCSS('color', highlight[1])
|
||||
}
|
||||
})
|
||||
if (isMac) {
|
||||
await page.keyboard.press('Meta+A')
|
||||
} else {
|
||||
await page.keyboard.press('Control+A')
|
||||
}
|
||||
await page.keyboard.type(JSCode) // Type JavaScript code
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
expect(
|
||||
await page
|
||||
.locator(slateEditor)
|
||||
.locator('span')
|
||||
.nth(0)
|
||||
.locator(leafNode)
|
||||
.nth(0)
|
||||
.textContent()
|
||||
).toContain('const')
|
||||
await expect(
|
||||
page
|
||||
.locator(slateEditor)
|
||||
.locator('span')
|
||||
.nth(0)
|
||||
.locator(leafNode)
|
||||
.nth(0)
|
||||
).toHaveCSS('color', 'rgb(0, 119, 170)')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// it also tests if select and code block button works the right way
|
||||
async function setText(page: Page, text: string, language: string) {
|
||||
await page.locator('[data-slate-editor]').fill('') // clear editor
|
||||
await page.getByTestId('code-block-button').click() // convert first and the only one paragraph to code block
|
||||
await page.getByTestId('language-select').selectOption({ value: language }) // select the language option
|
||||
|
||||
await page.keyboard.type(text) // type text
|
||||
}
|
||||
|
||||
function getTestCases() {
|
||||
const testCases: {
|
||||
language: string
|
||||
content: string
|
||||
highlights: [string, string][]
|
||||
}[] = [
|
||||
{
|
||||
language: 'css',
|
||||
content: `body {
|
||||
background-color: lightblue;
|
||||
}`,
|
||||
highlights: [
|
||||
['body', 'rgb(102, 153, 0)'],
|
||||
[' ', 'rgb(0, 0, 0)'],
|
||||
['{', 'rgb(153, 153, 153)'],
|
||||
[' ', 'rgb(0, 0, 0)'],
|
||||
['background-color', 'rgb(153, 0, 85)'],
|
||||
[':', 'rgb(153, 153, 153)'],
|
||||
[' lightblue', 'rgb(0, 0, 0)'],
|
||||
[';', 'rgb(153, 153, 153)'],
|
||||
['}', 'rgb(153, 153, 153)'],
|
||||
],
|
||||
},
|
||||
{
|
||||
language: 'html',
|
||||
content: `<body>
|
||||
<h1 class="title">Testing html</h1>
|
||||
</body>`,
|
||||
highlights: [
|
||||
['<', 'rgb(153, 0, 85)'],
|
||||
['body', 'rgb(153, 0, 85)'],
|
||||
['>', 'rgb(153, 0, 85)'],
|
||||
[' ', 'rgb(0, 0, 0)'],
|
||||
['<', 'rgb(153, 0, 85)'],
|
||||
['h1', 'rgb(153, 0, 85)'],
|
||||
[' ', 'rgb(153, 0, 85)'],
|
||||
['class', 'rgb(102, 153, 0)'],
|
||||
['=', 'rgb(0, 119, 170)'],
|
||||
['"', 'rgb(0, 119, 170)'],
|
||||
['title', 'rgb(0, 119, 170)'],
|
||||
['"', 'rgb(0, 119, 170)'],
|
||||
['>', 'rgb(153, 0, 85)'],
|
||||
['Testing html', 'rgb(0, 0, 0)'],
|
||||
['</', 'rgb(153, 0, 85)'],
|
||||
['h1', 'rgb(153, 0, 85)'],
|
||||
['>', 'rgb(153, 0, 85)'],
|
||||
['</', 'rgb(153, 0, 85)'],
|
||||
['body', 'rgb(153, 0, 85)'],
|
||||
['>', 'rgb(153, 0, 85)'],
|
||||
],
|
||||
},
|
||||
{
|
||||
language: 'jsx',
|
||||
content: `<Title title="title" renderIcon={() => <Icon />} />`,
|
||||
highlights: [
|
||||
['<', 'rgb(153, 0, 85)'],
|
||||
['Title', 'rgb(221, 74, 104)'],
|
||||
[' ', 'rgb(153, 0, 85)'],
|
||||
['title', 'rgb(102, 153, 0)'],
|
||||
['=', 'rgb(0, 119, 170)'],
|
||||
['"', 'rgb(0, 119, 170)'],
|
||||
['title', 'rgb(0, 119, 170)'],
|
||||
['"', 'rgb(0, 119, 170)'],
|
||||
[' ', 'rgb(153, 0, 85)'],
|
||||
['renderIcon', 'rgb(102, 153, 0)'],
|
||||
['=', 'rgb(153, 0, 85)'],
|
||||
['{', 'rgb(153, 0, 85)'],
|
||||
['(', 'rgb(153, 0, 85)'],
|
||||
[')', 'rgb(153, 0, 85)'],
|
||||
[' ', 'rgb(153, 0, 85)'],
|
||||
['=>', 'rgb(154, 110, 58)'],
|
||||
[' ', 'rgb(153, 0, 85)'],
|
||||
['<', 'rgb(153, 0, 85)'],
|
||||
['Icon', 'rgb(221, 74, 104)'],
|
||||
[' ', 'rgb(153, 0, 85)'],
|
||||
['/>', 'rgb(153, 0, 85)'],
|
||||
['}', 'rgb(153, 0, 85)'],
|
||||
[' ', 'rgb(153, 0, 85)'],
|
||||
['/>', 'rgb(153, 0, 85)'],
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return testCases
|
||||
}
|
||||
|
Reference in New Issue
Block a user