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
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ jobs:
# but skips the actual `pnpm run build`, so pnpm's
# syncInjectedDepsAfterScripts hook never refreshes the injected
# copies created by the scenario install
run: pnpm turbo test --force
# scenarios only vary test-app's dependencies; docs-app tests run
# in the Default Tests job
run: pnpm turbo test --filter test-app --force
env: ${{ matrix.env }}

build_docs:
Expand Down
3 changes: 3 additions & 0 deletions docs-app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ node_modules/
.env*
!.env.example
tmp/

# a11y middleware reporter output (test artifact)
ember-a11y-report/
1 change: 1 addition & 0 deletions docs-app/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/
node_modules/
pnpm-lock.yaml
ember-a11y-report/
13 changes: 12 additions & 1 deletion docs-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
"lint:prettier": "prettier -c .",
"lint:prettier:fix": "prettier -w .",
"lint:types": "ember-tsc --noEmit",
"start": "vite"
"start": "vite",
"build:test": "NODE_ENV=development vite build --mode development",
"test": "pnpm build:test && pnpm test:ci",
"test:ci": "testem ci --port 0"
},
"dependencies": {
"@ember/test-waiters": "^4.1.1",
Expand Down Expand Up @@ -65,6 +68,7 @@
"@babel/plugin-transform-typescript": "^7.29.7",
"@babel/runtime": "^7.29.7",
"@ember/app-tsconfig": "^2.0.0",
"@ember/test-helpers": "^5.4.3",
"@embroider/core": "^4.4.3",
"@embroider/macros": "^1.19.7",
"@embroider/vite": "^1.5.2",
Expand All @@ -74,15 +78,22 @@
"@glint/tsserver-plugin": "^2.5.18",
"@nullvoxpopuli/eslint-configs": "^6.0.0",
"@rollup/plugin-babel": "^7.1.0",
"@types/qunit": "^2.19.14",
"@warp-drive/build-config": "^5.8.2",
"axe-core": "^4.12.1",
"babel-plugin-ember-template-compilation": "^4.0.0",
"concurrently": "^9.2.1",
"decorator-transforms": "^2.3.1",
"ember-a11y-testing": "^8.0.1",
"ember-qunit": "^9.1.0",
"ember-source": "^7.1.0",
"ember-template-lint": "^5.2.0",
"eslint": "^9.22.0",
"prettier": "^3.8.1",
"prettier-plugin-ember-template-tag": "^2.1.3",
"qunit": "^2.26.0",
"qunit-dom": "^3.6.0",
"testem": "^3.20.1",
"typescript": "~6.0.0",
"vite": "^8.1.5"
},
Expand Down
11 changes: 10 additions & 1 deletion docs-app/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ const ENV = {
rootURL: '/',
locationType: 'history',
EmberENV: {},
APP: {} as Record<string, unknown>,
APP: {} as Record<string, unknown> & {
rootElement?: string;
autoboot?: boolean;
},
};

export default ENV;

export function enterTestMode() {
ENV.locationType = 'none';
ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
}
120 changes: 120 additions & 0 deletions docs-app/src/styles/app.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,125 @@
@import './docs-support.css';

/*
* CSS Reset (modern minimal)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}

* {
margin: 0;
}

body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}

img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}

input,
button,
textarea,
select {
font: inherit;
}

p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}

ol,
ul {
list-style: none;
margin: 0;
padding: 0;
}

/*
* Custom properties
*/
:root {
--font-sans:
'InterVariable', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-display: 'Helvetica', 'Arial', sans-serif;
--max-width-8xl: 88rem;
}

body {
font-family: var(--font-sans);
}

/*
* Theme variables
*/
.theme-light {
--color-page-background: white;
--color-foreground: black;
}

.theme-dark {
--color-page-background: #252525;
--color-foreground: white;
}

/*
* Prose overrides
*/
.prose
:where(code):not(
:where([class~='not-prose'], [class~='not-prose'] *)
)::before {
content: '' !important;
}

.prose
:where(code):not(
:where([class~='not-prose'], [class~='not-prose'] *)
)::after {
content: '' !important;
}

.prose .demo details {
border: 0;
margin: 0;
padding: 0;
}

.prose .featured-demo input {
color: black;
}

/*
* TypeDoc overrides
*/
.typedoc__declaration-children {
max-width: 800px;
}

.typedoc__component-signature__block
> .typedoc__property
> .typedoc__declaration
.typedoc__declaration-children {
display: block;
}

/*
* Small utility set used by the doc pages' demos
* (kept intentionally tiny -- this app does not use tailwind)
Expand Down
34 changes: 34 additions & 0 deletions docs-app/testem.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

if (typeof module !== 'undefined') {
const { a11yMiddleware } = require('ember-a11y-testing/middleware');

module.exports = {
test_page: 'tests/index.html?hidepassed',
cwd: 'dist',
middleware: [a11yMiddleware],
disable_watching: true,
launch_in_ci: ['Chrome'],
launch_in_dev: ['Chrome'],
browser_start_timeout: 120,
// The Pages a11y test walks every docs page and runs axe-core
// three times per page (default/dark/light theme); give the
// disconnect timeout enough headroom that a slow audit isn't
// mistaken for a dead browser.
browser_disconnect_timeout: 240,
browser_args: {
Chrome: {
ci: [
// --no-sandbox is needed when running Chrome inside a container
process.env.CI ? '--no-sandbox' : null,
'--headless=new',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--mute-audio',
'--remote-debugging-port=0',
'--window-size=1440,900',
].filter(Boolean),
},
},
};
}
108 changes: 108 additions & 0 deletions docs-app/tests/application/pages-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { findAll, settled, visit, waitUntil } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';

import { colorScheme } from 'ember-primitives/color-scheme';
import { docsManager } from 'kolay';

import { a11yAudit } from 'ember-a11y-testing/test-support';

/**
* per-page a11y rule overrides
*/
const a11yChecks: {
[url: string]: {
[checkName: string]: Record<string, unknown>;
};
} = {};

/**
* a11yAudit halts tests, this gets around that
*/
async function checkA11y(
assert: Assert,
path: string,
theme: string,
settings: object,
) {
await settled();

try {
await a11yAudit({
rules: {
// TODO: find a syntax highlighting theme
// with better contrast
'color-contrast': {
enabled: false,
},
...settings,
},
});
assert.ok(
true,
`no a11y errors found for ${path} using the ${theme} theme`,
);
} catch (e) {
let errorText = '';

if (typeof e === 'object') {
if (e && 'message' in e && typeof e.message === 'string') {
errorText = e.message;
}
}

const message =
`${path}: no a11y errors found using the ${theme} theme` +
`\n\n` +
errorText;

if (window.location.search.includes('debugA11yAudit')) {
console.error(errorText);
}

assert.ok(false, message);
}
}

module('Application | Pages', function (hooks) {
setupApplicationTest(hooks);

test('Pages all render and fit a11y criteria', async function (assert) {
// every page is visited and audited three times
// (default / dark / light theme)
assert.timeout(600_000);

await visit('/');

const pages: { path: string }[] = [];

const docsService = docsManager(this);
const groups = docsService.manifest.groups;

for (const group of groups) {
for (const page of group.list) {
pages.push(page);
}
}

assert.ok(pages.length > 10, `There are at least a few pages`);

for (const page of pages) {
const path = page.path.replace('.gjs.md', '').replace('.md', '');
const settings: object = a11yChecks[page.path] ?? {};

await visit(path);
await waitUntil(() => findAll('nav a').length !== 0);

for (const theme of ['default', 'dark', 'light'] as const) {
if (theme === 'dark') colorScheme.update('dark');
if (theme === 'light') colorScheme.update('light');
await checkA11y(assert, path, theme, settings);
}

assert
.dom('[data-page-error]')
.doesNotExist(`${page.path}: does not contain [data-page-error]`);
}
});
});
27 changes: 27 additions & 0 deletions docs-app/tests/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>docs-app Tests</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture">
<div id="ember-testing-container">
<div id="ember-testing"></div>
</div>
</div>

<script src="/testem.js" integrity="" data-embroider-ignore></script>
<script type="module">
import 'ember-testing';
</script>

<script type="module">
import { start } from './test-helper';
import.meta.glob('./**/*-test.{js,ts,gjs,gts}', { eager: true });
start();
</script>
</body>
</html>
Loading
Loading