Skip to content

Commit 1812f84

Browse files
authored
Merge pull request #1178 from w3c/development
Create July 29, Release Includes the following changes: * #1172, to address #1173 and #1174 * #1170, to address #1171
2 parents 1fc0de3 + 9c73ab5 commit 1812f84

File tree

16 files changed

+3572
-32
lines changed

16 files changed

+3572
-32
lines changed

client/components/AddTestToQueueWithConfirmation/index.jsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ function AddTestToQueueWithConfirmation({
166166
} catch (e) {
167167
console.error(e);
168168
}
169-
}
169+
},
170+
testId: 'add-run-later'
170171
});
171172

172173
if (!alreadyHasBotInTestPlanReport) {
@@ -186,7 +187,8 @@ function AddTestToQueueWithConfirmation({
186187
} catch (e) {
187188
console.error(e);
188189
}
189-
}
190+
},
191+
testId: 'add-run-bot'
190192
});
191193
}
192194
}

client/components/CandidateReview/TestPlans/index.jsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import ClippedProgressBar from '@components/common/ClippedProgressBar';
2121
import { convertDateToString } from '@client/utils/formatter';
2222
import './TestPlans.css';
23+
import { calculations } from 'shared';
2324

2425
const FullHeightContainer = styled(Container)`
2526
min-height: calc(100vh - 64px);
@@ -486,13 +487,12 @@ const TestPlans = ({ testPlanVersions }) => {
486487
obj.mustAssertionsFailedCount,
487488
0
488489
),
489-
totalSupportPercent:
490-
Math.round(
491-
allMetrics.reduce(
492-
(acc, obj) => acc + obj.supportPercent,
493-
0
494-
) / allMetrics.length
495-
) || 0
490+
totalSupportPercent: calculations.trimDecimals(
491+
allMetrics.reduce(
492+
(acc, obj) => acc + obj.supportPercent,
493+
0
494+
) / allMetrics.length
495+
)
496496
};
497497

498498
// Make sure issues are unique
@@ -550,10 +550,10 @@ const TestPlans = ({ testPlanVersions }) => {
550550
<CenteredTd>
551551
<Link
552552
to={`/candidate-test-plan/${testPlanVersion.id}/${atId}`}
553+
aria-label={`${metrics.totalSupportPercent}%`}
553554
>
554555
<ClippedProgressBar
555556
progress={metrics.totalSupportPercent}
556-
label={`${metrics.totalSupportPercent}% completed`}
557557
clipped
558558
/>
559559
</Link>

client/components/Reports/SummarizeTestPlanReports.jsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,10 @@ const SummarizeTestPlanReports = ({ testPlanVersions }) => {
132132
`/report/${testPlanVersion.id}` +
133133
`/targets/${testPlanReport.id}`
134134
}
135+
aria-label={`${metrics.supportPercent}%`}
135136
>
136137
<ClippedProgressBar
137138
progress={metrics.supportPercent}
138-
label={`${getTestPlanTargetTitle(
139-
testPlanTarget
140-
)}, ${metrics.supportPercent}% completed`}
141139
/>
142140
</Link>
143141
</td>

client/components/common/BasicModal/index.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const BasicModal = ({
6161
variant={action.variant ?? 'primary'}
6262
onClick={action.onClick}
6363
className={action.className ?? ''}
64+
data-testid={action.testId ?? ''}
6465
>
6566
{action.label ?? 'Continue'}
6667
</Button>
@@ -138,6 +139,7 @@ BasicModal.propTypes = {
138139
onClick: PropTypes.func,
139140
variant: PropTypes.string,
140141
className: PropTypes.string,
142+
testId: PropTypes.string,
141143
component: PropTypes.elementType,
142144
props: PropTypes.object
143145
})

client/components/common/ClippedProgressBar/index.jsx

+3-9
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import './ClippedProgressBar.css';
44

5-
const ProgressBar = ({
6-
progress = 0,
7-
label = '',
8-
clipped = true,
9-
decorative
10-
}) => {
5+
const ProgressBar = ({ progress = 0, clipped = true, decorative }) => {
116
return (
127
<>
138
{clipped ? (
14-
<div className="progress clipped" aria-label={label}>
9+
<div className="progress clipped">
1510
<div
1611
className="front"
1712
style={{
@@ -23,7 +18,7 @@ const ProgressBar = ({
2318
<div className="back">{decorative ? null : `${progress}%`}</div>
2419
</div>
2520
) : (
26-
<div className="progress" aria-label={label}>
21+
<div className="progress">
2722
<div
2823
className="progress-bar bg-info"
2924
style={{
@@ -40,7 +35,6 @@ const ProgressBar = ({
4035

4136
ProgressBar.propTypes = {
4237
progress: PropTypes.number,
43-
label: PropTypes.string,
4438
clipped: PropTypes.bool,
4539
decorative: PropTypes.bool
4640
};

client/tests/AddTestToQueueWithConfirmation.test.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ describe('AddTestToQueueWithConfirmation', () => {
111111

112112
test('calls mutation on button click with correct variables', async () => {
113113
fireEvent.click(getByTestId('add-button'));
114+
fireEvent.click(await getByTestId('add-run-later'));
114115

115116
await waitFor(() => {
116117
expect(mutationMock).toHaveBeenCalled();

client/utils/automation.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ export const isSupportedByResponseCollector = ctx => {
1919
// Check if the AT and browser are supported by the automation
2020
const isNvdaWithSupportedBrowser =
2121
atKey === 'nvda' && (browserKey === 'chrome' || browserKey === 'firefox');
22-
const isVoiceOverMacWithSafari =
23-
atKey === 'voiceover_macos' && browserKey === 'safari_macos';
22+
const isVoiceOverMacWithSupportedBrowser =
23+
atKey === 'voiceover_macos' &&
24+
(browserKey === 'safari_macos' ||
25+
browserKey === 'chrome' ||
26+
browserKey === 'firefox');
2427

25-
if (!isNvdaWithSupportedBrowser && !isVoiceOverMacWithSafari) {
28+
if (!isNvdaWithSupportedBrowser && !isVoiceOverMacWithSupportedBrowser) {
2629
return false;
2730
}
2831

@@ -89,7 +92,12 @@ export const getBotUsernameFromAtBrowser = (at, browser) => {
8992
) {
9093
return 'NVDA Bot';
9194
}
92-
if (at?.key === 'voiceover_macos' && browser?.key === 'safari_macos') {
95+
if (
96+
at?.key === 'voiceover_macos' &&
97+
(browser?.key === 'safari_macos' ||
98+
browser?.key === 'chrome' ||
99+
browser?.key === 'firefox')
100+
) {
93101
return 'VoiceOver Bot';
94102
}
95103
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use strict';
2+
3+
const { getMetrics } = require('shared');
4+
const populateData = require('../services/PopulatedData/populateData');
5+
const runnableTestsResolver = require('../resolvers/TestPlanReport/runnableTestsResolver');
6+
const finalizedTestResultsResolver = require('../resolvers/TestPlanReport/finalizedTestResultsResolver');
7+
const {
8+
updateTestPlanReportById
9+
} = require('../models/services/TestPlanReportService');
10+
const getGraphQLContext = require('../graphql-context');
11+
12+
/** @type {import('sequelize-cli').Migration} */
13+
module.exports = {
14+
async up(queryInterface, Sequelize) {
15+
return queryInterface.sequelize.transaction(async transaction => {
16+
const context = getGraphQLContext({ req: { transaction } });
17+
18+
const testPlanReports = await queryInterface.sequelize.query(
19+
`select distinct on ("TestPlanReport".id) "TestPlanReport".id, metrics
20+
from "TestPlanReport"
21+
join public."TestPlanRun" testPlanRun on "TestPlanReport".id = testPlanRun."testPlanReportId"
22+
where jsonb_array_length(testPlanRun."testResults") > 0;`,
23+
{
24+
type: Sequelize.QueryTypes.SELECT,
25+
transaction
26+
}
27+
);
28+
29+
for (const testPlanReport of testPlanReports) {
30+
const { testPlanReport: testPlanReportPopulated } = await populateData(
31+
{ testPlanReportId: testPlanReport.id },
32+
{ context }
33+
);
34+
const runnableTests = runnableTestsResolver(
35+
testPlanReportPopulated,
36+
null,
37+
context
38+
);
39+
const finalizedTestResults = await finalizedTestResultsResolver(
40+
testPlanReportPopulated,
41+
null,
42+
context
43+
);
44+
const metrics = getMetrics({
45+
testPlanReport: {
46+
...testPlanReportPopulated,
47+
finalizedTestResults,
48+
runnableTests
49+
}
50+
});
51+
await updateTestPlanReportById({
52+
id: testPlanReportPopulated.id,
53+
values: {
54+
metrics: {
55+
...testPlanReportPopulated.metrics,
56+
...metrics
57+
}
58+
},
59+
transaction
60+
});
61+
}
62+
});
63+
}
64+
};

server/resolvers/TestPlanReport/finalizedTestResultsResolver.js

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const finalizedTestResultsResolver = async (testPlanReport, _, context) => {
88
// Return the primary test plan run, otherwise pick the first TestPlanRun found.
99
const testPlanRun =
1010
testPlanReport.testPlanRuns.find(({ isPrimary }) => isPrimary) ||
11+
testPlanReport.testPlanRuns.find(testPlanRun =>
12+
testPlanRun.testResults?.some(testResult => !!testResult.completedAt)
13+
) ||
1114
testPlanReport.testPlanRuns[0];
1215

1316
return testResultsResolver(

server/services/GithubWorkflowService.js

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ const createGithubWorkflow = async ({ job, directory, gitSha, atVersion }) => {
154154
// due to limitations on Github workflow runners
155155
// See https://github.com/w3c/aria-at-app/issues/1143 for more info
156156
inputs.macos_version = atVersion?.name?.split('.')[0];
157+
inputs.browser = browser;
157158
}
158159
const axiosConfig = {
159160
method: 'POST',

shared/calculations.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @param {number} value
3+
* @param {number} total
4+
* @param {boolean} ignoreError - to account for cases where having a NaN is "expected"
5+
* @returns {number}
6+
*/
7+
const calculatePercentage = (value, total, { ignoreError = true } = {}) => {
8+
if (!ignoreError && total === 0) {
9+
throw new Error("Unable to divide. 'total' cannot be 0.");
10+
}
11+
return (value / total) * 100;
12+
};
13+
14+
const trimDecimals = (number, decimals = 0) => {
15+
if (decimals === undefined || decimals <= 0) {
16+
return Math.floor(number);
17+
} else {
18+
let factor = Math.pow(10, decimals);
19+
return Math.floor(number * factor) / factor;
20+
}
21+
};
22+
23+
module.exports = {
24+
calculatePercentage,
25+
trimDecimals
26+
};

shared/getMetrics.js

+29-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const convertAssertionPriority = require('./convertAssertionPriority');
2+
const { calculatePercentage, trimDecimals } = require('./calculations');
23

34
const sum = arr => arr?.reduce((total, item) => total + item, 0) || 0;
45

@@ -46,11 +47,32 @@ const countAssertions = ({
4647
if (isClient) {
4748
all = scenarioResult?.[`${priority.toLowerCase()}AssertionResults`] || [];
4849
} else {
49-
all = scenarioResult.assertionResults.filter(
50-
a =>
50+
all = scenarioResult.assertionResults.filter(a => {
51+
// Same as `server/resolvers/ScenarioResult/assertionResultsResolver.js`
52+
if (a.assertion?.assertionExceptions?.length) {
53+
const scenarioSettings = scenarioResult.scenario.settings;
54+
const scenarioCommandId =
55+
scenarioResult.scenario.commandIds.join(' ');
56+
57+
const foundException = a.assertion.assertionExceptions.find(
58+
exception =>
59+
exception.settings === scenarioSettings &&
60+
exception.commandId === scenarioCommandId
61+
);
62+
63+
if (foundException) {
64+
return (
65+
convertAssertionPriority(foundException.priority) ===
66+
convertAssertionPriority(priority)
67+
);
68+
}
69+
}
70+
71+
return (
5172
convertAssertionPriority(a.assertion.priority) ===
5273
convertAssertionPriority(priority)
53-
);
74+
);
75+
});
5476
}
5577
if (passedOnly) return all.filter(each => each.passed).length;
5678
return all.length;
@@ -236,9 +258,11 @@ const getMetrics = ({
236258
supportLevel = 'FULL';
237259
}
238260

239-
const supportPercent = Math.round(
240-
(mustAssertionsPassedCount / mustAssertionsCount) * 100
261+
const percentage = calculatePercentage(
262+
mustAssertionsPassedCount + shouldAssertionsPassedCount,
263+
mustAssertionsCount + shouldAssertionsCount
241264
);
265+
const supportPercent = trimDecimals(percentage);
242266

243267
const assertionsPassedCount =
244268
mustAssertionsPassedCount +

shared/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const calculations = require('./calculations');
12
const convertAssertionPriority = require('./convertAssertionPriority');
23
const getMetrics = require('./getMetrics');
3-
module.exports = { convertAssertionPriority, getMetrics };
4+
5+
module.exports = { calculations, convertAssertionPriority, getMetrics };

0 commit comments

Comments
 (0)