chore: publish from main

This commit is contained in:
github-actions[bot]
2026-10-07 22:20:42 +00:00
parent 0b51b6bbaf
commit b0613980fd
107 changed files with 6456 additions and 11 deletions
+44 -5
View File
@@ -36,6 +36,15 @@ const routes = [
// chassis is audited in addition to the Learning Hub landing page.
'/learning-hub/github-copilot-app/',
'/learning-hub/cookbook/',
'/learning-hub/app-for-beginners/',
'/learning-hub/app-for-beginners/00-setup/',
'/learning-hub/app-for-beginners/01-tour-the-app/',
'/learning-hub/app-for-beginners/02-sessions-worktrees-context/',
'/learning-hub/app-for-beginners/03-development-workflows/',
'/learning-hub/app-for-beginners/04-skills-custom-agents/',
'/learning-hub/app-for-beginners/05-mcp-plugins/',
'/learning-hub/app-for-beginners/06-canvases/',
'/learning-hub/app-for-beginners/07-automations/',
// Representative dedicated detail pages (one per resource type) so the audit
// covers the shared detail layout, sidebar, install buttons, and file browser.
'/agent/accessibility/',
@@ -211,6 +220,7 @@ async function auditSite(browser, baseUrl) {
for (const route of routes) {
for (const theme of themes) {
const url = new URL(route, baseUrl).toString();
await page.emulateMedia({ colorScheme: theme });
// 'load' (not 'networkidle') keeps the audit robust: cards are server-rendered
// into the initial HTML, and lazy images / search-index requests can otherwise
@@ -239,14 +249,15 @@ async function auditSite(browser, baseUrl) {
content: '*,*::before,*::after{transition:none!important;animation:none!important;transition-duration:0s!important;animation-duration:0s!important;}',
});
// Force both theme modes so persisted user preference logic cannot hide regressions.
await page.evaluate((selectedTheme) => {
document.documentElement.setAttribute('data-theme', selectedTheme);
localStorage.setItem('awesome-copilot-theme', selectedTheme);
}, theme);
// Primer's auto theme and the page bootstrap both read the OS color scheme.
await page.waitForFunction(
(selectedTheme) => document.documentElement.getAttribute('data-color-mode') === selectedTheme,
theme,
);
// Let the forced theme settle (style recalc / reflow) before sampling colors.
await page.waitForTimeout(150);
await verifyCourseAnchors(page, route);
await page.addScriptTag({ path: axeSourcePath });
@@ -266,6 +277,34 @@ async function auditSite(browser, baseUrl) {
}
}
async function verifyCourseAnchors(page, route) {
if (!route.startsWith('/learning-hub/app-for-beginners/')) return;
const duplicateIds = await page.locator('main [id]').evaluateAll((elements) => {
const ids = elements.map((element) => element.id);
return ids.filter((id, index) => ids.indexOf(id) !== index);
});
if (duplicateIds.length) {
throw new Error(`Duplicate course IDs on ${route}: ${duplicateIds.join(', ')}`);
}
if (route !== '/learning-hub/app-for-beginners/06-canvases/') return;
const viewport = page.viewportSize();
try {
await page.setViewportSize({ width: 1440, height: 960 });
await page.locator('main a[href="#markdown-fallback"]').first().click();
await page.waitForFunction(() => {
const heading = document.getElementById('markdown-fallback');
if (!heading?.closest('details')?.open) return false;
let hero = document.querySelector('main h1');
while (hero && getComputedStyle(hero).position !== 'sticky') hero = hero.parentElement;
const top = heading.getBoundingClientRect().top;
return top >= (hero?.getBoundingClientRect().bottom ?? 0) && top < innerHeight;
});
} finally {
if (viewport) await page.setViewportSize(viewport);
}
}
await page.close();
return violations;
}