Inital code commit
Some checks failed
Build, Test, and Publish (to Private NPM Registry) UI Components Library / publish (push) Failing after 52m26s
Some checks failed
Build, Test, and Publish (to Private NPM Registry) UI Components Library / publish (push) Failing after 52m26s
This commit is contained in:
commit
5024375e20
32 changed files with 5379 additions and 0 deletions
26
test-harness/server.ts
Normal file
26
test-harness/server.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import express from 'express';
|
||||
import type { RequestHandler, Request, Response } from 'express';
|
||||
import baWebComponents from '../dist/index.js';
|
||||
|
||||
const app = express();
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', './test-harness/views');
|
||||
|
||||
// Mount the library using your virtual path strategy
|
||||
app.use(await baWebComponents({ expressApp: app }) as RequestHandler);
|
||||
|
||||
app.get('/', (req: Request, res: Response) => {
|
||||
res.send('Hello from the test server! Navigate to /test/tooltip to see the tooltip component test page.');
|
||||
});
|
||||
|
||||
app.get('/test/tooltip', (req: Request, res: Response) => {
|
||||
res.render('tooltip');
|
||||
});
|
||||
|
||||
app.get('/test/drawer', (req: Request, res: Response) => {
|
||||
res.render('drawer');
|
||||
});
|
||||
|
||||
app.listen(3080, () => {
|
||||
console.log('Test server running on http://localhost:3080');
|
||||
});
|
||||
73
test-harness/tests/drawer.spec.ts
Normal file
73
test-harness/tests/drawer.spec.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { AxeBuilder } from '@axe-core/playwright';
|
||||
|
||||
test.describe('Accessible Drawer Component', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Navigate to the test harness view for the drawer
|
||||
await page.goto('/test/drawer');
|
||||
});
|
||||
|
||||
test('should pass AAA accessibility audits', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const accessibilityScanResults = await new AxeBuilder({ page })
|
||||
.withTags(['wcag2a', 'wcag2aa', 'wcag2aaa', 'best-practice'])
|
||||
.analyze();
|
||||
|
||||
expect(accessibilityScanResults.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test('should toggle content visibility and ARIA states via mouse click', async ({ page }) => {
|
||||
const drawerHeader = page.locator('#example-drawer-drawer-header');
|
||||
const drawerContent = page.locator('#example-drawer-drawer-contents');
|
||||
|
||||
// Assert Initial State
|
||||
await expect(drawerHeader).toHaveAttribute('aria-expanded', 'false');
|
||||
await expect(drawerContent).toHaveClass(/hidden/);
|
||||
|
||||
// Interact (Open)
|
||||
await drawerHeader.click();
|
||||
|
||||
// Assert Open State
|
||||
await expect(drawerHeader).toHaveAttribute('aria-expanded', 'true');
|
||||
await expect(drawerContent).not.toHaveClass(/hidden/);
|
||||
|
||||
// Interact (Close)
|
||||
await drawerHeader.click();
|
||||
|
||||
// Assert Closed State
|
||||
await expect(drawerHeader).toHaveAttribute('aria-expanded', 'false');
|
||||
await expect(drawerContent).toHaveClass(/hidden/);
|
||||
});
|
||||
|
||||
test('should toggle content visibility via keyboard navigation', async ({ page }) => {
|
||||
const drawerHeader = page.locator('#example-drawer-drawer-header');
|
||||
const drawerContent = page.locator('#example-drawer-drawer-contents');
|
||||
|
||||
// Focus the drawer header using the keyboard
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(drawerHeader).toBeFocused();
|
||||
|
||||
// Open with Space
|
||||
await page.keyboard.press(' ');
|
||||
await expect(drawerHeader).toHaveAttribute('aria-expanded', 'true');
|
||||
await expect(drawerContent).not.toHaveClass(/hidden/);
|
||||
|
||||
// Close with Enter
|
||||
await page.keyboard.press('Enter');
|
||||
await expect(drawerHeader).toHaveAttribute('aria-expanded', 'false');
|
||||
await expect(drawerContent).toHaveClass(/hidden/);
|
||||
});
|
||||
|
||||
test('visual regression: component renders correctly', async ({ page }) => {
|
||||
const drawerContainer = page.locator('#example-drawer');
|
||||
const drawerHeader = page.locator('#example-drawer-drawer-header');
|
||||
|
||||
// Snapshot the closed state
|
||||
await expect(drawerContainer).toHaveScreenshot('drawer-closed.png');
|
||||
|
||||
// Snapshot the open state
|
||||
await drawerHeader.click();
|
||||
await expect(drawerContainer).toHaveScreenshot('drawer-open.png');
|
||||
});
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
56
test-harness/tests/tooltip.spec.ts
Normal file
56
test-harness/tests/tooltip.spec.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { AxeBuilder } from '@axe-core/playwright';
|
||||
|
||||
test.describe('Accessible Tooltip Component', () => {
|
||||
// Before each test, navigate to the specific EJS view serving the tooltip
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/test/tooltip'); // Resolves to http://localhost:3080/test/tooltip
|
||||
});
|
||||
|
||||
test('should pass AAA accessibility audits', async ({ page }) => {
|
||||
// Wait for the component to be fully hydrated
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Run the Axe-core engine against the page
|
||||
const accessibilityScanResults = await new AxeBuilder({ page })
|
||||
.withTags(['wcag2a', 'wcag2aa', 'wcag2aaa', 'best-practice'])
|
||||
.analyze();
|
||||
|
||||
// If there are violations, the test fails and prints them in the console
|
||||
expect(accessibilityScanResults.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test('should toggle the popover content natively', async ({ page }) => {
|
||||
// Locate the button and the content div
|
||||
// Notice how we don't care about the shadow boundary, we just use standard CSS selectors
|
||||
const tooltipBtn = page.locator('.popover-btn');
|
||||
const tooltipContent = page.locator('.tool-tip-content');
|
||||
|
||||
// Assert initial state (Popover should be hidden)
|
||||
await expect(tooltipContent).not.toBeVisible();
|
||||
|
||||
// Interact
|
||||
await tooltipBtn.click();
|
||||
|
||||
// Assert new state (Popover should be visible)
|
||||
await expect(tooltipContent).toBeVisible();
|
||||
|
||||
// Test native accessibility behavior (Esc key to dismiss Popover)
|
||||
await page.keyboard.press('Escape');
|
||||
await expect(tooltipContent).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('visual regression: component renders correctly', async ({ page }) => {
|
||||
const tooltipBtn = page.locator('.popover-btn');
|
||||
const tooltipContent = page.locator('.tool-tip-content');
|
||||
|
||||
// Take a snapshot of just the button element
|
||||
await expect(tooltipBtn).toHaveScreenshot('tooltip-button-closed.png');
|
||||
|
||||
// Open it and take a snapshot of the whole component area to catch layout shifts
|
||||
await tooltipBtn.click();
|
||||
await expect(tooltipContent).toBeVisible();
|
||||
|
||||
await expect(page.locator('.tool-tip-icon')).toHaveScreenshot('tooltip-container-open.png');
|
||||
});
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 155 B |
Binary file not shown.
|
After Width: | Height: | Size: 155 B |
39
test-harness/views/drawer.ejs
Normal file
39
test-harness/views/drawer.ejs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drawer Test</title>
|
||||
<link rel="stylesheet" type="text/css" href="<%= componentsStyleHref %>">
|
||||
<script src="<%= componentsScriptSrc %>"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main style="padding: 20px;">
|
||||
<h1>Drawer Test</h1>
|
||||
<p>The following is an example of a drawer component. Click to toggle the visibility of the content.</p>
|
||||
<%- useComponent('drawer', {
|
||||
id: 'example-drawer',
|
||||
label: `
|
||||
<h2>Example Drawer</h2>
|
||||
`,
|
||||
content: `
|
||||
<div>
|
||||
<div class="drawer-content-header">
|
||||
<h3>Hello World!</h3>
|
||||
</div>
|
||||
<div class="drawer-content-contents">
|
||||
<p>This is the body of a drawer</p>
|
||||
<p>It can have multiple lines.</p>
|
||||
<span>
|
||||
<code>Even code snippets</code>,
|
||||
<em>Emphasized</em> or <strong>Strong</strong> text,
|
||||
or even
|
||||
<button>Buttons!</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}) %>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
40
test-harness/views/tooltip.ejs
Normal file
40
test-harness/views/tooltip.ejs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tooltip Test</title>
|
||||
<link rel="stylesheet" type="text/css" href="<%= componentsStyleHref %>">
|
||||
<script src="<%= componentsScriptSrc %>"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main style="margin-top:12rem;margin-left:4rem">
|
||||
<h1>Tooltip Test</h1>
|
||||
<span>
|
||||
I need a bit of a preamble to make sure the tooltip gets positioned correctly.
|
||||
This is a <%- useComponent('tooltip', {
|
||||
id: 'example-tooltip',
|
||||
srText: 'Example Tooltip',
|
||||
content: `
|
||||
<div>
|
||||
<div class="tooltip-content-header">
|
||||
<h2>Hello World!</h2>
|
||||
</div>
|
||||
<div class="tooltip-content-contents">
|
||||
<p>This is the body of a tooltip</p>
|
||||
<p>It can have multiple lines.</p>
|
||||
<span>
|
||||
<code>Even code snippets</code>,
|
||||
<em>Emphasized</em> or <strong>Strong</strong> text,
|
||||
or even
|
||||
<button>Buttons!</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}) %>.
|
||||
Isn't it cool!
|
||||
</span>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue