2023-07-19 10:52:21 +00:00
|
|
|
import test, { expect } from '@playwright/test'
|
2024-02-29 16:06:19 +00:00
|
|
|
import { Editor } from 'tldraw'
|
2023-07-19 10:52:21 +00:00
|
|
|
|
2023-10-04 09:01:48 +00:00
|
|
|
declare const EDITOR_A: Editor
|
|
|
|
declare const EDITOR_B: Editor
|
|
|
|
declare const EDITOR_C: Editor
|
2023-07-19 10:52:21 +00:00
|
|
|
|
|
|
|
// We're just testing the events, not the actual results.
|
|
|
|
|
|
|
|
test.describe('Focus', () => {
|
|
|
|
test('focus events', async ({ page }) => {
|
2024-02-02 17:36:30 +00:00
|
|
|
await page.goto('http://localhost:5420/multiple/full')
|
2023-07-19 10:52:21 +00:00
|
|
|
await page.waitForSelector('.tl-canvas')
|
|
|
|
|
|
|
|
const EditorA = (await page.$(`.A`))!
|
|
|
|
const EditorB = (await page.$(`.B`))!
|
2023-10-04 09:01:48 +00:00
|
|
|
const EditorC = (await page.$(`.C`))!
|
2023-07-19 10:52:21 +00:00
|
|
|
expect(EditorA).toBeTruthy()
|
|
|
|
expect(EditorB).toBeTruthy()
|
2023-10-04 09:01:48 +00:00
|
|
|
expect(EditorC).toBeTruthy()
|
|
|
|
|
|
|
|
async function isOnlyFocused(id: 'A' | 'B' | 'C' | null) {
|
|
|
|
let activeElement: string | null = null
|
|
|
|
const isA = await EditorA.evaluate(
|
|
|
|
(node) => document.activeElement === node || node.contains(document.activeElement)
|
|
|
|
)
|
|
|
|
const isB = await EditorB.evaluate(
|
|
|
|
(node) => document.activeElement === node || node.contains(document.activeElement)
|
|
|
|
)
|
|
|
|
|
|
|
|
const isC = await EditorC.evaluate(
|
|
|
|
(node) => document.activeElement === node || node.contains(document.activeElement)
|
|
|
|
)
|
|
|
|
|
|
|
|
activeElement = isA ? 'A' : isB ? 'B' : isC ? 'C' : null
|
|
|
|
|
|
|
|
expect(
|
|
|
|
activeElement,
|
|
|
|
`Active element should have been ${id}, but was ${activeElement ?? 'null'} instead`
|
|
|
|
).toBe(id)
|
|
|
|
|
|
|
|
await page.evaluate(
|
|
|
|
({ id }) => {
|
|
|
|
if (
|
|
|
|
!(
|
2023-11-13 11:51:22 +00:00
|
|
|
EDITOR_A.getInstanceState().isFocused === (id === 'A') &&
|
|
|
|
EDITOR_B.getInstanceState().isFocused === (id === 'B') &&
|
|
|
|
EDITOR_C.getInstanceState().isFocused === (id === 'C')
|
2023-10-04 09:01:48 +00:00
|
|
|
)
|
|
|
|
) {
|
|
|
|
throw Error('isFocused is not correct')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{ id }
|
|
|
|
)
|
|
|
|
}
|
2023-07-19 10:52:21 +00:00
|
|
|
|
2023-10-04 09:01:48 +00:00
|
|
|
// Component A has autofocus
|
|
|
|
// Component B does not
|
|
|
|
// Component C does not
|
|
|
|
// Component B and C share persistence id
|
2023-07-19 10:52:21 +00:00
|
|
|
|
|
|
|
await (await page.$('body'))?.click()
|
|
|
|
|
2023-10-04 09:01:48 +00:00
|
|
|
await isOnlyFocused('A')
|
2023-07-19 10:52:21 +00:00
|
|
|
|
|
|
|
await EditorA.click()
|
2023-10-04 09:01:48 +00:00
|
|
|
|
|
|
|
await isOnlyFocused('A')
|
2023-07-19 10:52:21 +00:00
|
|
|
|
|
|
|
await EditorA.click()
|
2023-10-04 09:01:48 +00:00
|
|
|
|
|
|
|
await isOnlyFocused('A')
|
2023-07-19 10:52:21 +00:00
|
|
|
|
|
|
|
await EditorB.click()
|
2023-10-04 09:01:48 +00:00
|
|
|
|
|
|
|
await isOnlyFocused('B')
|
2023-07-19 10:52:21 +00:00
|
|
|
|
|
|
|
// Escape does not break focus
|
|
|
|
await page.keyboard.press('Escape')
|
2023-10-04 09:01:48 +00:00
|
|
|
|
|
|
|
await isOnlyFocused('B')
|
|
|
|
})
|
|
|
|
|
|
|
|
test('kbds when not focused', async ({ page }) => {
|
2024-02-02 17:36:30 +00:00
|
|
|
await page.goto('http://localhost:5420/multiple/full')
|
2023-10-04 09:01:48 +00:00
|
|
|
await page.waitForSelector('.tl-canvas')
|
|
|
|
|
|
|
|
// Should not have any shapes on the page
|
2023-11-14 16:32:27 +00:00
|
|
|
expect(await page.evaluate(() => EDITOR_A.getCurrentPageShapes().length)).toBe(0)
|
2023-10-04 09:01:48 +00:00
|
|
|
|
|
|
|
const EditorA = (await page.$(`.A`))!
|
|
|
|
await page.keyboard.press('r')
|
|
|
|
await EditorA.click({ position: { x: 100, y: 100 } })
|
|
|
|
|
|
|
|
// Should not have created a shape
|
2023-11-14 16:32:27 +00:00
|
|
|
expect(await page.evaluate(() => EDITOR_A.getCurrentPageShapes().length)).toBe(1)
|
2023-10-04 09:01:48 +00:00
|
|
|
|
|
|
|
const TextArea = page.getByTestId(`textarea`)
|
|
|
|
await TextArea.focus()
|
|
|
|
await page.keyboard.type('hello world')
|
|
|
|
await page.keyboard.press('Control+A')
|
|
|
|
await page.keyboard.press('Delete')
|
|
|
|
|
|
|
|
// Should not have deleted the page
|
2023-11-14 16:32:27 +00:00
|
|
|
expect(await page.evaluate(() => EDITOR_A.getCurrentPageShapes().length)).toBe(1)
|
2023-07-19 10:52:21 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
test('kbds when focused', async ({ page }) => {
|
2024-02-02 17:36:30 +00:00
|
|
|
await page.goto('http://localhost:5420/multiple/full')
|
2023-07-19 10:52:21 +00:00
|
|
|
await page.waitForSelector('.tl-canvas')
|
|
|
|
|
|
|
|
const EditorA = (await page.$(`.A`))!
|
|
|
|
const EditorB = (await page.$(`.B`))!
|
2023-10-04 09:01:48 +00:00
|
|
|
const EditorC = (await page.$(`.C`))!
|
2023-07-19 10:52:21 +00:00
|
|
|
expect(EditorA).toBeTruthy()
|
|
|
|
expect(EditorB).toBeTruthy()
|
2023-10-04 09:01:48 +00:00
|
|
|
expect(EditorC).toBeTruthy()
|
2023-07-19 10:52:21 +00:00
|
|
|
|
|
|
|
await (await page.$('body'))?.click()
|
|
|
|
|
|
|
|
expect(await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
|
|
|
|
null
|
|
|
|
)
|
|
|
|
expect(await EditorB.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
|
|
|
|
null
|
|
|
|
)
|
|
|
|
|
|
|
|
await page.keyboard.press('d')
|
|
|
|
|
|
|
|
expect(
|
|
|
|
await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
|
|
|
|
).not.toBe(null)
|
|
|
|
expect(await EditorB.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
|
|
|
|
null
|
|
|
|
)
|
|
|
|
|
|
|
|
await EditorB.click()
|
|
|
|
await page.waitForTimeout(100) // takes 30ms or so to focus
|
|
|
|
await page.keyboard.press('d')
|
|
|
|
|
|
|
|
expect(
|
|
|
|
await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
|
|
|
|
).not.toBe(null)
|
|
|
|
expect(
|
|
|
|
await EditorB.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
|
|
|
|
).not.toBe(null)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('kbds after clicking on ui elements', async ({ page }) => {
|
|
|
|
await page.goto('http://localhost:5420/end-to-end')
|
|
|
|
await page.waitForSelector('.tl-canvas')
|
|
|
|
|
|
|
|
const EditorA = (await page.$(`.tl-container`))!
|
|
|
|
expect(EditorA).toBeTruthy()
|
|
|
|
|
|
|
|
const drawButton = await EditorA.$('.tlui-button[data-testid="tools.draw"]')
|
|
|
|
|
|
|
|
// select button should be selected, not the draw button
|
|
|
|
expect(await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
|
|
|
|
null
|
|
|
|
)
|
|
|
|
|
|
|
|
await drawButton?.click()
|
|
|
|
|
|
|
|
// draw button should be selected now
|
|
|
|
expect(
|
|
|
|
await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
|
|
|
|
).not.toBe(null)
|
|
|
|
|
|
|
|
await page.keyboard.press('v')
|
|
|
|
|
|
|
|
// select button should be selected again
|
|
|
|
expect(await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
|
|
|
|
null
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|