8000 [MWPW-171403][Preflight][Due diligence] Integrate full accessibility report in Preflight by skumar09 · Pull Request #3968 · adobecom/milo · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[MWPW-171403][Preflight][Due diligence] Integrate full accessibility report in Preflight #3968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Jul 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4502b2c
initial commit
Apr 14, 2025
1e35ee5
update review comments
Apr 16, 2025
cd65ade
update review comment-2
Apr 16, 2025
341927e
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
Apr 16, 2025
d6d616a
update review comments-3
Apr 17, 2025
2084082
add tags for color-contrast
Apr 17, 2025
65f32f8
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
Apr 17, 2025
23f8ada
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
May 29, 2025
1f9fa15
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
Jun 4, 2025
f7fc239
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
skumar09 Jun 18, 2025
edfb7a9
consider alt= as decorative images
skumar09 Jun 19, 2025
403619b
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
skumar09 Jun 19, 2025
6c83588
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
skumar09 Jun 20, 2025
e5b094b
merge existing img alt feature into new accessibility tab
skumar09 Jun 23, 2025
89bffe6
adust the preflight-full-width css
skumar09 Jun 23, 2025
4f46724
adust violation-column css bottom padding
skumar09 Jun 23, 2025
71f0530
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
skumar09 Jun 23, 2025
6ede750
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
skumar09 Jun 26, 2025
253e753
updated the tags
skumar09 Jun 26, 2025
551aedf
update the tags
skumar09 Jun 26, 2025
937ca08
rm color-contrast
skumar09 Jun 26, 2025
2f05883
remove console log
skumar09 Jun 26, 2025
5631172
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
skumar09 Jun 26, 2025
203e11f
include wcag22a and wcag22aa support
skumar09 Jun 27, 2025
d7ae5ab
Merge remote-tracking branch 'upstream/stage' into accessibility-pref…
skumar09 Jul 8, 2025
47ee0e0
comment update
skumar09 Jul 8, 2025
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
8000
14 changes: 14 additions & 0 deletions libs/blocks/preflight/accessibility/accessibility-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const AXE_CORE_CONFIG = {
include: [['body']],
exclude: [['.preflight'], ['aem-sidekick'], ['header'], ['.global-navigation'], ['footer'], ['.global-footer'], ['.mep-preview-overlay'], ['preflight-decoration']],
runOnly: {
type: 'tag',
values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22a', 'wcag22aa'],
},
};

export const CUSTOM_CHECKS_CONFIG = {
checks: ['altText', 'color-contrast'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is deliberate that you're not adding the keyboard checks as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is deliberate that you're not adding the keyboard checks as well?

@vhargrave: Yes, it’s deliberate. Still exploring the use cases where axe-core doesn’t fully capture keyboard navigation issues when triggerred from browser/dom, will enable in subsequent pr's

include: [['body']],
exclude: [['.preflight'], ['aem-sidekick'], ['header'], ['.global-navigation'], ['footer'], ['.global-footer'], ['.mep-preview-overlay'], ['preflight-decoration']],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getFilteredElements } from './helper.js';
import checkImageAltText from './check-image-alt-text.js';
import checkKeyboardNavigation from './check-keyboard-navigation.js';

const checkFunctions = [
checkImageAltText,
checkKeyboardNavigation,
];

/**
* Runs custom accessibility checks on filtered elements.
* @param {Object} config - custom check config (checks, include, exclude).
* @returns {Array} Violations from all custom checks.
*/
async function customAccessibilityChecks(config = {}) {
try {
// Filter DOM elements based on include/exclude
const elements = getFilteredElements(config.include, config.exclude);
if (!elements.length) return [];
return checkFunctions.flatMap((checkFn) => checkFn(elements, config));
} catch (error) {
window.lana.log(`Error running custom accessibility checks: ${error.message}`);
return [];
}
}

export default customAccessibilityChecks;
200 changes: 200 additions & 0 deletions libs/blocks/preflight/accessibility/accessibility.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import { html, useState, useEffect } from '../../../deps/htm-preact.js';
import '../../../deps/axe.min.js';
import { AXE_CORE_CONFIG, CUSTOM_CHECKS_CONFIG } from './accessibility-config.js';
import customAccessibilityChecks from './accessibility-custom-checks.js';
import AuditImageAltText from './audit-image-alt-text.js';

/**
* Runs the accessibility test using axe-core and custom checks.
* @returns {Promise<Object>} Test results object (pass/fail + violations) or error.
*/
async function runAccessibilityTest() {
try {
const results = await window.axe.run(AXE_CORE_CONFIG);
const customViolations = await customAccessibilityChecks(CUSTOM_CHECKS_CONFIG);
results.violations.push(...customViolations);
return {
pass: !results.violations.length,
violations: results.violations,
};
} catch (error) {
window.lana.log(`Error running accessiblity test:, ${error}`);
return { error: `Error running accessibility test: ${error.message}` };
}
}

/**
* Preflight Accessibility Tab/Panel.
*/
export default function Accessibility() {
const [pageURL, setPageURL] = useState(window.location.href);
const [testResults, setTestResults] = useState(null);
const [loading, setLoading] = useState(false);
const [expandedViolations, setExpandedViolations] = useState([]);

useEffect(() => {
const runTest = async () => {
setLoading(true);
setTestResults(null);
setExpandedViolations([]);
setPageURL(window.location.href);
const results = await runAccessibilityTest();
setTestResults(results);
setLoading(false);
};
runTest();
}, []);
const toggleViolation = (index) => {
setExpandedViolations((prev) => {
const isExpanded = prev.includes(index);
return isExpanded ? prev.filter((i) => i !== index) : [...prev, index];
});
};
// Loading markup
const loadingMarkup = () => html`
<div class="preflight-columns">
<div class="preflight-column">
<p>Running Accessibility Test...</p>
</div>
</div>
`;
// Error markup
const errorMarkup = (errorMsg) => html`
<div class="preflight-columns">
<div class="preflight-column">
<div class="preflight-content-group">
<p class="preflight-item-title">Error</p>
<p class="preflight-item-description">${errorMsg}</p>
</div>
</div>
</div>
`;
// Results summary markup
const resultsSummary = (results, url) => {
if (!results) {
return html`
<div class="preflight-column">
<p>No accessibility results available.</p>
</div>
`;
}
return html`
<div class="preflight-column">
<div class="preflight-content-group">
<div class="preflight-accessibility-item">
<div class="result-icon ${results.pass ? 'green' : 'red'}"></div>
<div class="preflight-item-text">
<p class="preflight-item-title">
${results.pass
? 'Accessibility Test Passed'
: 'Accessibility Test Failed'}
</p>
<p class="preflight-item-description">
${results.pass
? 'No accessibility issues found.'
: `${results.violations.length} accessibility violations detected.`}
</p>
<ul class="summary-list">
<li><strong>Page:</strong> <a href="${url}" target="_blank">${url}</a></li>
<li><strong>Test Scope:</strong> body</li>
<li><strong>WCAG Tags:</strong> ${AXE_CORE_CONFIG.runOnly?.values?.join(', ') || 'NONE'}</li>
</ul>
<p class="preflight-accessibility-note">
<strong>Note:</strong> This test does not include screen reader behavior, focus order, or voice navigation checks.
</p>
</div>
</div>
</div>
</div>
`;
};
// Violations markup
const violationsList = (violations = []) => {
if (!violations.length) {
return html`
<div class="preflight-column">
<p>No violations found.</p>
</div>
`;
}
return html`
<div class="preflight-column">
<div class="preflight-content-group violations-section">
<div class="preflight-accessibility-item">
<div class="result-icon red"></div>
<div class="preflight-item-text">
<p class="preflight-item-title">Accessibility Violations</p>
<p class="preflight-item-description">
Click each violation to view details
</p>
</div>
</div>

<div class="violation-list">
${violations.map((violation, index) => {
const isExpanded = expandedViolations.includes(index);
return html`
<div class="violation-item">
<div
class="violation-summary ${isExpanded ? 'expanded' : ''}"
=> toggleViolation(index)}
>
<div class="violation-expand"></div>
<div class="preflight-content-heading">
<span class="violation-index">${index + 1}.</span>
Violation [
<span class="severity ${violation.impact}">${violation.impact}</span>
]: ${violation.description}
</div>
</div>

${isExpanded && html`
<div class="violation-details">
<ul class="violation-details-list">
<li><strong>Rule ID:</strong> ${violation.id}</li>
<li><strong>Severity:</strong> <span class="severity ${violation.impact}">${violation.impact}</span></li>
<li><strong>Fix: </strong>
<a class="violation-link" href="${violation.helpUrl}" target="_blank">
More Info
</a>
</li>
<li><strong>Affected Elements:</strong>
<ul class="affected-elements">
${violation.nodes.map((node) => html`<li><code>${node.html}</code></li>`)}
</ul>
</li>
</ul>
</div>
`}
</div>
`;
})}
</div>
</div>
</div>
`;
};
// Conditional rendering based on state
if (loading) return loadingMarkup();
if (testResults?.error) return errorMarkup(testResults.error);
if (!testResults) {
return html`
<div class="preflight-columns">
<div class="preflight-column">
<p>No accessibility test has been run yet.</p>
</div>
</div>
`;
}
return html`
<div class="preflight-columns accessibility-columns">
${resultsSummary(testResults, pageURL)}
<div class="preflight-column violations-column">
${!testResults.pass && violationsList(testResults.violations)}
</div>
</div>
<div class="preflight-full-width">
<${AuditImageAltText} />
</div>
`;
}
Loading
Loading
0