Skip to content

Commit 90fbe81

Browse files
authored
test: add e2e tests for splitter, clipboard and file-upload (#2374)
* test: add clipboard e2e tests * test: add splitter e2e tests * test: add file-upload e2e tests * fix: test wording
1 parent 9dbbd84 commit 90fbe81

File tree

7 files changed

+193
-5
lines changed

7 files changed

+193
-5
lines changed

e2e/clipboard.e2e.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { test } from "@playwright/test"
2+
import { ClipboardModel } from "./models/clipboard.model"
3+
4+
let I: ClipboardModel
5+
6+
test.describe("clipboard", () => {
7+
test.beforeEach(async ({ page }) => {
8+
I = new ClipboardModel(page)
9+
await I.goto()
10+
})
11+
12+
test("should have no accessibility violations", async () => {
13+
await I.checkAccessibility()
14+
})
15+
16+
test("should copy content to clipboard", async () => {
17+
await I.clickTrigger()
18+
await I.seeContent("Copied!")
19+
await I.dontSeeContent("Copy")
20+
})
21+
22+
test("should focus on trigger", async () => {
23+
await I.focusTrigger()
24+
await I.seeTriggerIsFocused()
25+
})
26+
})

e2e/file-upload.e2e.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { test, expect } from "@playwright/test"
2+
import { a11y, part, controls, testid } from "./_utils"
3+
import path from "node:path"
4+
5+
const root = part("root")
6+
const trigger = part("trigger")
7+
const dropzone = part("dropzone")
8+
9+
test.describe("file-upload", () => {
10+
test.beforeEach(async ({ page }) => {
11+
await page.goto("/file-upload")
12+
})
13+
14+
// TBD: fix a11y complaints
15+
test.skip("should have no accessibility violations", async ({ page }) => {
16+
await a11y(page)
17+
})
18+
19+
test("should be focused when page is tabbed", async ({ page }) => {
20+
const dropzone = part("dropzone")
21+
22+
await page.click("main")
23+
await page.keyboard.press("Tab")
24+
25+
await expect(page.locator(dropzone)).toBeFocused()
26+
})
27+
28+
test("should open file picker on trigger click", async ({ page }) => {
29+
const fileChooserPromise = page.waitForEvent("filechooser")
30+
31+
await page.locator(trigger).click()
32+
33+
const prom = await fileChooserPromise
34+
35+
expect(prom).toBeDefined()
36+
})
37+
38+
test("should display chosen file", async ({ page }) => {
39+
const fileChooserPromise = page.waitForEvent("filechooser")
40+
await page.locator(trigger).click()
41+
const fileChooser = await fileChooserPromise
42+
await fileChooser.setFiles(path.join(__dirname, "fixtures/text.txt"))
43+
44+
const item = page.locator(part("item"))
45+
const deleteTrigger = page.locator(part("item-delete-trigger"))
46+
47+
expect(item).toBeVisible()
48+
expect(await item.innerText()).toContain("text.txt")
49+
expect(deleteTrigger).toBeVisible()
50+
})
51+
52+
test("should have disabled attributes when disabled", async ({ page }) => {
53+
await controls(page).bool("disabled")
54+
await expect(page.locator(root)).toHaveAttribute("data-disabled", "")
55+
await expect(page.locator(dropzone)).toHaveAttribute("data-disabled", "")
56+
await expect(page.locator(trigger)).toHaveAttribute("data-disabled", "")
57+
await expect(page.locator(trigger)).toBeDisabled()
58+
await expect(page.locator(testid("input"))).toBeDisabled()
59+
})
60+
})

e2e/fixtures/text.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
zag

e2e/models/clipboard.model.ts

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { expect, type Page } from "@playwright/test"
2+
import { a11y, part } from "../_utils"
3+
import { Model } from "./model"
4+
5+
export class ClipboardModel extends Model {
6+
constructor(public page: Page) {
7+
super(page)
8+
}
9+
10+
goto() {
11+
return this.page.goto("/clipboard")
12+
}
13+
14+
checkAccessibility(selector?: string): Promise<void> {
15+
return a11y(this.page, selector)
16+
}
17+
18+
getTrigger() {
19+
return this.page.locator(part("trigger"))
20+
}
21+
22+
getContent(text: string) {
23+
return this.page.locator(part("indicator")).getByText(text)
24+
}
25+
26+
async focusTrigger() {
27+
await this.getTrigger().focus()
28+
}
29+
30+
async clickTrigger() {
31+
await this.getTrigger().click()
32+
}
33+
34+
async seeTriggerIsFocused() {
35+
await expect(this.getTrigger()).toBeFocused()
36+
}
37+
38+
async seeContent(text: string) {
39+
const content = this.getContent(text)
40+
const hidden = await content.isHidden()
41+
42+
expect(hidden).not.toBe(true)
43+
}
44+
45+
async dontSeeContent(text: string) {
46+
const content = this.getContent(text)
47+
const hidden = await content.isHidden()
48+
49+
expect(hidden).toBe(true)
50+
}
51+
}

e2e/splitter.e2e.ts

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { test, expect } from "@playwright/test"
2+
import { a11y, controls, testid, part } from "./_utils"
3+
4+
test.describe("splitter", () => {
5+
test.beforeEach(async ({ page }) => {
6+
await page.goto("/splitter")
7+
})
8+
9+
test("should have no accessibility violations", async ({ page }) => {
10+
await a11y(page)
11+
})
12+
13+
test("should be focused on next splitter when tabbed", async ({ page }) => {
14+
await page.click(part("root"))
15+
await page.keyboard.press("Tab")
16+
17+
expect(page.locator(testid("trigger-b:c"))).toHaveAttribute("data-focus", "")
18+
})
19+
20+
test("should increase panel when arrow right pressed", async ({ page }) => {
21+
await page.click("main")
22+
23+
await page.keyboard.press("Tab")
24+
await page.keyboard.press("ArrowRight")
25+
await page.keyboard.press("ArrowRight")
26+
await page.keyboard.press("ArrowRight")
27+
28+
expect(page.locator(part("resize-trigger")).nth(1)).toHaveAttribute("aria-valuenow", "36")
29+
})
30+
31+
test("should decrease panel when arrow left pressed", async ({ page }) => {
32+
await page.click("main")
33+
34+
await page.keyboard.press("Tab")
35+
await page.keyboard.press("ArrowLeft")
36+
await page.keyboard.press("ArrowLeft")
37+
await page.keyboard.press("ArrowLeft")
38+
39+
expect(page.locator(part("resize-trigger")).nth(1)).toHaveAttribute("aria-valuenow", "30")
40+
})
41+
42+
test("should manage splitter panels when vertical orientation", async ({ page }) => {
43+
await controls(page).select("orientation", "vertical")
44+
45+
expect(page.locator(part("root"))).toHaveAttribute("data-orientation", "vertical")
46+
expect(page.locator(part("panel")).first()).toHaveAttribute("data-orientation", "vertical")
47+
expect(page.locator(part("resize-trigger")).first()).toHaveAttribute("data-orientation", "vertical")
48+
})
49+
})

examples/next-ts/pages/file-upload.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { useControls } from "../hooks/use-controls"
99
export default function Page() {
1010
const controls = useControls(fileUploadControls)
1111

12-
const service = useMachine(fileUpload.machine, { id: useId() })
12+
const service = useMachine(fileUpload.machine, { id: useId(), ...controls.context })
1313

1414
const api = fileUpload.connect(service, normalizeProps)
1515

@@ -18,7 +18,7 @@ export default function Page() {
1818
<main className="file-upload">
1919
<div {...api.getRootProps()}>
2020
<div {...api.getDropzoneProps()}>
21-
<input {...api.getHiddenInputProps()} />
21+
<input data-testid="input" {...api.getHiddenInputProps()} />
2222
Drag your files here
2323
</div>
2424

@@ -41,7 +41,7 @@ export default function Page() {
4141
</div>
4242
</main>
4343

44-
<Toolbar controls={controls.ui} viz>
44+
<Toolbar controls={controls.ui}>
4545
<StateVisualizer state={service} />
4646
</Toolbar>
4747
</>

examples/next-ts/pages/splitter.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default function Page() {
1212
const service = useMachine(splitter.machine, {
1313
id: useId(),
1414
panels: [{ id: "a" }, { id: "b" }, { id: "c" }],
15+
...controls.context,
1516
})
1617

1718
const api = splitter.connect(service, normalizeProps)
@@ -24,11 +25,11 @@ export default function Page() {
2425
<div {...api.getPanelProps({ id: "a" })}>
2526
<p>Left</p>
2627
</div>
27-
<div {...api.getResizeTriggerProps({ id: "a:b" })} />
28+
<div data-testid="trigger-a:b" {...api.getResizeTriggerProps({ id: "a:b" })} />
2829
<div {...api.getPanelProps({ id: "b" })}>
2930
<p>Middle</p>
3031
</div>
31-
<div {...api.getResizeTriggerProps({ id: "b:c" })} />
32+
<div data-testid="trigger-b:c" {...api.getResizeTriggerProps({ id: "b:c" })} />
3233
<div {...api.getPanelProps({ id: "c" })}>
3334
<p>Right</p>
3435
</div>

0 commit comments

Comments
 (0)