Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions e2e/a11y.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
// SPDX-License-Identifier: AGPL-3.0-or-later

import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

test.describe("axe", () => {
test.beforeEach(async ({page}) => {
await page.goto("/");
await page.getByRole("button", {name: "Load sample PDF"}).click();
await expect(page.locator("canvas").first()).toBeVisible();
await page.getByRole("button", {name: "Add Signature"}).click();
await expect(page.getByRole("button", {name: "Click to place"})).toBeVisible();
await page.locator(".overlay").first().click({position: {x:100,y:100}});
await expect(page.locator(".resize-handle").first()).toBeVisible();
})

test("has no accessibility violations", async({page})=>{
const results = await new AxeBuilder({page}).analyze();
const summary = results.violations.map(v => `${v.id} (${v.impact}): ${v.nodes.length} nodes`);
expect(summary).toEqual([]);
expect(results.violations).toEqual([]);
})
})

test.describe("keyboard", () => {
test("toolbar buttons can be opened with the keyboard", async({page})=>{
await page.goto("/");
const btn = page.getByRole("button", { name: "Load sample PDF" });
await btn.focus();
await expect(btn).toBeFocused();
await page.keyboard.press("Enter");
await expect(page.locator("canvas").first()).toBeVisible();

})
test("focus is visible on toolbar buttons", async ({ page }) => {
await page.goto("/");
const btn = page.getByRole("button", { name: "Load sample PDF" });
const focusStyles = () => btn.evaluate(el => {
const style = getComputedStyle(el);
return [style.outlineStyle, style.outlineWidth, style.outlineColor, style.boxShadow].join(" | ");
});
const unfocused = await focusStyles();
await page.keyboard.press("Tab");
await expect(btn).toBeFocused();
const focused = await focusStyles();
expect(focused).not.toBe(unfocused);
})
})
3 changes: 3 additions & 0 deletions examples/basic/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-or-later
-->

<template>
<main>
<h1>PDF Elements Demo</h1>
<div class="app-shell">
<AppToolbar
:loading="loading"
Expand Down Expand Up @@ -54,6 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
@close="showElementsViewer = false"
/>
</div>
</main>
</template>

<script lang="ts">
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/components/DocumentsList.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<section v-if="documents.length" class="docs-list">
<h3>Documents ({{ documents.length }})</h3>
<h2>Documents ({{ documents.length }})</h2>
<ul>
<li v-for="(doc, idx) in documents" :key="idx">
{{ doc }}
Expand Down
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"vue": "^3.5.28"
},
"devDependencies": {
"@axe-core/playwright": "^4.13.0",
"@eslint/js": "^10.0.1",
"@nextcloud/browserslist-config": "^3.1.2",
"@playwright/test": "^1.63.0",
Expand Down
2 changes: 2 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export default defineConfig({
testDir: "e2e",
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
// All tests share one dev server, parallel workers make the suite flaky
workers: 1,
reporter: [['html', { open: 'never' }], ['list']],
use: {
baseURL: "http://localhost:5173/",
Expand Down
1 change: 1 addition & 0 deletions src/components/DraggableElement.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
class="resize-handle"
:class="`handle-${dir}`"
type="button"
:aria-label="`Resize ${dir}`"
@mousedown.stop.prevent="startResize(dir, $event)"
@touchstart.stop.prevent="startResize(dir, $event)"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/PDFElements.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
class="overlay"
:role="isAddingMode ? 'button' : undefined"
:tabindex="isAddingMode ? 0 : -1"
:aria-label="getOverlayAriaLabel(docIndex, pIndex)"
:aria-label="isAddingMode ? getOverlayAriaLabel(docIndex, pIndex) : undefined"
@mousemove="handleMouseMove"
@touchmove="handleMouseMove"
@click="handleOverlayClick(docIndex, pIndex, $event)"
Expand Down
Loading