Skip to content
Open
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
43 changes: 26 additions & 17 deletions src/accessibility/utils/generate-individual-opportunities.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function createDirectMystiqueMessage({
url,
opportunityId: opportunity.getId(),
issuesList,
opportunityType: opportunity.getType(),
},
};
}
Expand Down Expand Up @@ -543,8 +544,10 @@ export async function sendMessageToMystiqueForRemediation(
opportunity,
context,
log,
options = {},
) {
try {
const { useCodeFixFlow = true } = options;
// Check if mystique suggestions are enabled for this site
const isMystiqueEnabled = await isAuditEnabledForSite('a11y-mystique-auto-suggest', context.site, context);
if (!isMystiqueEnabled) {
Expand Down Expand Up @@ -581,28 +584,34 @@ export async function sendMessageToMystiqueForRemediation(
});

// Determine if code fix flow should be used
const autoFixEnabled = await isAuditEnabledForSite('a11y-mystique-auto-fix', context.site, context);
let applyCodeFixFlow = false;
let autoFixEnabled = false;
let hasCodeFixEligibleIssues = false;
if (autoFixEnabled) {
for (const suggestion of suggestions) {
const suggestionData = suggestion.getData();
if (isNonEmptyArray(suggestionData.issues)) {
const eligibleIssues = suggestionData.issues
.filter((issue) => issueTypesForCodeFix.includes(issue.type))
.filter((issue) => isNonEmptyArray(issue.htmlWithIssues));
if (eligibleIssues.length > 0) {
hasCodeFixEligibleIssues = true;
break;

if (useCodeFixFlow) {
autoFixEnabled = await isAuditEnabledForSite('a11y-mystique-auto-fix', context.site, context);
if (autoFixEnabled) {
for (const suggestion of suggestions) {
const suggestionData = suggestion.getData();
if (isNonEmptyArray(suggestionData.issues)) {
const eligibleIssues = suggestionData.issues
.filter((issue) => issueTypesForCodeFix.includes(issue.type))
.filter((issue) => isNonEmptyArray(issue.htmlWithIssues));
if (eligibleIssues.length > 0) {
hasCodeFixEligibleIssues = true;
break;
}
}
}
}
applyCodeFixFlow = autoFixEnabled && hasCodeFixEligibleIssues;
}
const useCodeFixFlow = autoFixEnabled && hasCodeFixEligibleIssues;
log.debug(`[A11yIndividual] Code fix flow enabled: ${autoFixEnabled}, has eligible issues: ${hasCodeFixEligibleIssues}, using code fix flow: ${useCodeFixFlow}`);

log.debug(`[A11yIndividual] Code fix flow enabled: ${autoFixEnabled}, has eligible issues: ${hasCodeFixEligibleIssues}, using code fix flow: ${applyCodeFixFlow}`);

// Process the suggestions directly to create Mystique messages
// Pass useCodeFixFlow to determine aggregation strategy
const mystiqueData = processSuggestionsForMystique(suggestions, useCodeFixFlow);
// Pass applyCodeFixFlow to determine aggregation strategy
const mystiqueData = processSuggestionsForMystique(suggestions, applyCodeFixFlow);

log.debug(`[A11yIndividual] Mystique data processed: ${mystiqueData.length} messages to send`);

Expand All @@ -617,7 +626,7 @@ export async function sendMessageToMystiqueForRemediation(
return { success: false, error: 'Missing SQS context or queue configuration' };
}

log.info(`[A11yIndividual] Sending ${mystiqueData.length} messages to Mystique (via ${useCodeFixFlow ? 'code fix' : 'legacy'} flow)`);
log.info(`[A11yIndividual] Sending ${mystiqueData.length} messages to Mystique (via ${applyCodeFixFlow ? 'code fix' : 'legacy'} flow)`);

const messagePromises = mystiqueData.map(({
url, issuesList, aggregationKey,
Expand All @@ -633,7 +642,7 @@ export async function sendMessageToMystiqueForRemediation(
env,
log,
context,
useCodeFixFlow,
useCodeFixFlow: applyCodeFixFlow,
}));
// Wait for all messages to be sent (successfully or with errors)
const results = await Promise.allSettled(messagePromises);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { updateStatusToIgnored } from '../../accessibility/utils/scrape-utils.js
import {
aggregateA11yIssuesByOppType,
createIndividualOpportunitySuggestions,
sendMessageToMystiqueForRemediation,
} from '../../accessibility/utils/generate-individual-opportunities.js';
import { aggregateAccessibilityData, sendRunImportMessage, sendCodeFixMessagesToMystique } from '../../accessibility/utils/data-processing.js';
import { URL_SOURCE_SEPARATOR, A11Y_METRICS_AGGREGATOR_IMPORT_TYPE, WCAG_CRITERIA_COUNTS } from '../../accessibility/utils/constants.js';
Expand Down Expand Up @@ -374,7 +375,13 @@ export default async function handler(message, context) {
} else {
log.info(`[Form Opportunity] [Site Id: ${siteId}] ${opportunity.getType()}-auto-fix is disabled for site, skipping code-fix generation`);
}
// TODO: Send message to mystique for guidance

await sendMessageToMystiqueForRemediation(
opportunity,
context,
log,
{ useCodeFixFlow: false },
);
} catch (error) {
log.error(`[Form Opportunity] [Site Id: ${siteId}] Failed to process a11y opportunity from mystique: ${error.message}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2683,7 +2683,7 @@ describe('createAccessibilityIndividualOpportunities', () => {

describe('createDirectMystiqueMessage', () => {
it('should create a message object with all required fields', () => {
const fakeOpportunity = { getId: () => 'oppty-123' };
const fakeOpportunity = { getId: () => 'oppty-123', getType: () => 'accessibility' };
const issuesList = [{ type: 'color-contrast', description: 'desc' }];
const siteId = 'site-789';
const auditId = 'audit-101';
Expand All @@ -2706,12 +2706,13 @@ describe('createDirectMystiqueMessage', () => {
url: 'https://example.com',
opportunityId: 'oppty-123',
issuesList,
opportunityType: 'accessibility',
});
expect(result.time).to.be.a('string');
});

it('should default siteId and auditId to empty string if not provided', () => {
const fakeOpportunity = { getId: () => 'oppty-123' };
const fakeOpportunity = { getId: () => 'oppty-123', getType: () => 'accessibility' };
const issuesList = [];
const result = generateIndividualOpportunitiesModule.createDirectMystiqueMessage({
url: 'https://example.com',
Expand All @@ -2726,7 +2727,7 @@ describe('createDirectMystiqueMessage', () => {
});

it('should default siteId and auditId to empty string when null', () => {
const fakeOpportunity = { getId: () => 'oppty-456' };
const fakeOpportunity = { getId: () => 'oppty-456', getType: () => 'accessibility' };
const issuesList = [];
const result = generateIndividualOpportunitiesModule.createDirectMystiqueMessage({
url: 'https://example.com',
Expand All @@ -2741,7 +2742,7 @@ describe('createDirectMystiqueMessage', () => {
});

it('should default siteId and auditId to empty string when empty string', () => {
const fakeOpportunity = { getId: () => 'oppty-789' };
const fakeOpportunity = { getId: () => 'oppty-789', getType: () => 'accessibility' };
const issuesList = [];
const result = generateIndividualOpportunitiesModule.createDirectMystiqueMessage({
url: 'https://example.com',
Expand Down Expand Up @@ -2770,6 +2771,7 @@ describe('sendMessageToMystiqueForRemediation', () => {
getId: sandbox.stub().returns('oppty-1'),
getSiteId: sandbox.stub().returns('site-1'),
getAuditId: sandbox.stub().returns('audit-1'),
getType: sandbox.stub().returns('accessibility'),
getSuggestions: sandbox.stub().resolves([]),
};
mockLog = {
Expand Down Expand Up @@ -4376,6 +4378,7 @@ describe('sendMystiqueMessage', () => {

mockOpportunity = {
getId: sandbox.stub().returns('oppty-123'),
getType: sandbox.stub().returns('accessibility'),
};

mockIsAuditEnabledForSite = sandbox.stub();
Expand Down Expand Up @@ -4833,6 +4836,7 @@ describe('sendMystiqueMessage', () => {
url: 'https://example.com/page13',
opportunityId: 'oppty-123',
issuesList: [{ issueName: 'color-contrast', details: 'Low contrast' }],
opportunityType: 'accessibility',
});
});

Expand Down
3 changes: 3 additions & 0 deletions test/audits/forms/accessibility-handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1778,11 +1778,13 @@ describe('Forms Opportunities - Accessibility Handler', () => {
let isAuditEnabledForSiteStub;
let createIndividualOpportunitySuggestionsStub;
let sendCodeFixMessagesToMystiqueStub;
let sendMessageToMystiqueForRemediationStub;

beforeEach(async () => {
isAuditEnabledForSiteStub = sandbox.stub().resolves(false); // Default: auto-fix disabled
createIndividualOpportunitySuggestionsStub = sandbox.stub().resolves();
sendCodeFixMessagesToMystiqueStub = sandbox.stub().resolves();
sendMessageToMystiqueForRemediationStub = sandbox.stub().resolves();
mockOpportunityData = {
accessibility: [{
form: 'https://example.com/form1',
Expand Down Expand Up @@ -1876,6 +1878,7 @@ describe('Forms Opportunities - Accessibility Handler', () => {
},
'../../../src/accessibility/utils/generate-individual-opportunities.js': {
createIndividualOpportunitySuggestions: createIndividualOpportunitySuggestionsStub,
sendMessageToMystiqueForRemediation: sendMessageToMystiqueForRemediationStub,
},
'../../../src/accessibility/utils/data-processing.js': {
sendCodeFixMessagesToMystique: sendCodeFixMessagesToMystiqueStub,
Expand Down