From b0d91ba82fa5edf292ee9b38460d1e6707949d0c Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 8 Aug 2024 09:28:12 -0700 Subject: [PATCH] Reusable proptypes (#1189) * Reusable proptypes * Update error catch timeout * Return console errors with callback * Ignore favicon errors * Prevent default browser favicon fetch attempt * Use improved favicon ignore strategy to prevent double fetch * Remove comment in index.html * Update snapshots * Remove unnecessary assertions * Update snapshots * Remove errant variable --- .../DataManagementRow/index.jsx | 33 +- .../MarkBotRunFinishedButton/index.jsx | 3 +- .../RetryCanceledCollectionsButton/index.jsx | 12 +- .../StopRunningCollectionButton/index.jsx | 12 +- .../ManageBotRunDialog/WithButton.jsx | 5 +- .../components/ManageBotRunDialog/index.jsx | 5 +- .../ManageTestQueue/ManageAtVersions.jsx | 16 +- client/components/ManageTestQueue/index.jsx | 18 +- .../Reports/SummarizeTestPlanReport.jsx | 60 +--- .../Reports/SummarizeTestPlanReports.jsx | 22 +- .../Reports/SummarizeTestPlanVersion.jsx | 26 +- .../ReviewConflicts/ReviewConflicts.jsx | 55 +-- .../TestPlanReportStatusDialog/index.jsx | 33 +- client/components/TestQueue/Actions.jsx | 45 +-- client/components/TestQueue/AssignTesters.jsx | 54 +-- .../CompletionStatusListItem/index.jsx | 20 +- .../BotTestCompletionStatus/index.js | 18 +- .../index.js | 11 +- .../TestRenderer/OutputTextArea/index.jsx | 17 +- client/components/TestRenderer/index.jsx | 5 +- .../TestRun/CollectionJobContext.js | 10 +- .../TestRun/ReviewConflictsModal/index.jsx | 11 +- .../common/AssignTesterDropdown/index.jsx | 19 +- .../common/AtAndBrowserDetailsModal/index.jsx | 6 +- client/components/common/BasicModal/index.jsx | 13 +- .../common/BasicThemedModal/index.jsx | 8 +- .../common/ReportStatusSummary/index.jsx | 13 +- .../common/TestPlanResultsTable/index.jsx | 12 +- client/components/common/proptypes/index.js | 322 ++++++++++++++++++ client/static/index.html | 1 + client/tests/e2e/CandidateReview.e2e.test.js | 69 ++-- client/tests/e2e/DataManagement.e2e.test.js | 41 ++- client/tests/e2e/Reports.e2e.test.js | 54 +-- client/tests/e2e/TestPlanVersions.e2e.test.js | 4 +- client/tests/e2e/TestQueue.e2e.test.js | 19 +- client/tests/e2e/TestReview.e2e.test.js | 19 +- client/tests/e2e/TestRun.e2e.test.js | 98 +++--- client/tests/e2e/UserSettings.e2e.test.js | 70 ++-- client/tests/e2e/snapshots/saved/_.html | 1 + client/tests/e2e/snapshots/saved/_404.html | 1 + .../snapshots/saved/_account_settings.html | 1 + .../snapshots/saved/_candidate-review.html | 1 + .../saved/_candidate-test-plan_24_1.html | 1 + .../e2e/snapshots/saved/_data-management.html | 21 +- .../saved/_data-management_meter.html | 1 + .../tests/e2e/snapshots/saved/_reports.html | 1 + client/tests/e2e/snapshots/saved/_run_2.html | 1 + .../snapshots/saved/_signup-instructions.html | 1 + .../snapshots/saved/_test-plan-report_1.html | 1 + .../e2e/snapshots/saved/_test-queue.html | 5 +- .../e2e/snapshots/saved/_test-review_8.html | 1 + client/tests/util/getPage.js | 14 +- 52 files changed, 669 insertions(+), 641 deletions(-) create mode 100644 client/components/common/proptypes/index.js diff --git a/client/components/DataManagement/DataManagementRow/index.jsx b/client/components/DataManagement/DataManagementRow/index.jsx index 40d3cf8cf..981c89e05 100644 --- a/client/components/DataManagement/DataManagementRow/index.jsx +++ b/client/components/DataManagement/DataManagementRow/index.jsx @@ -19,6 +19,11 @@ import VersionString from '../../common/VersionString'; import PhasePill from '../../common/PhasePill'; import { differenceBy, uniq as unique, uniqBy as uniqueBy } from 'lodash'; import { getVersionData } from '../utils'; +import { + AtPropType, + TestPlanPropType, + TestPlanVersionPropType +} from '../../common/proptypes'; const StatusCell = styled.div` display: flex; @@ -1089,32 +1094,16 @@ const DataManagementRow = ({ DataManagementRow.propTypes = { isAdmin: PropTypes.bool, - ats: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string - }) - ), - testPlan: PropTypes.shape({ - id: PropTypes.string, - title: PropTypes.string, - directory: PropTypes.string - }).isRequired, + ats: PropTypes.arrayOf(AtPropType), + testPlan: TestPlanPropType.isRequired, testPlanVersions: PropTypes.arrayOf( PropTypes.shape({ - id: PropTypes.string, + ...TestPlanVersionPropType, + // Optional in this component title: PropTypes.string, - phase: PropTypes.string, - gitSha: PropTypes.string, - testPlan: PropTypes.shape({ - directory: PropTypes.string - }), - updatedAt: PropTypes.string, - draftPhaseReachedAt: PropTypes.string, - candidatePhaseReachedAt: PropTypes.string, - recommendedPhaseReachedAt: PropTypes.string + isRequired: PropTypes.bool }) - ).isRequired, + ), tableRowIndex: PropTypes.number.isRequired, setTestPlanVersions: PropTypes.func }; diff --git a/client/components/ManageBotRunDialog/MarkBotRunFinishedButton/index.jsx b/client/components/ManageBotRunDialog/MarkBotRunFinishedButton/index.jsx index bcec9dd67..6a8fdec5d 100644 --- a/client/components/ManageBotRunDialog/MarkBotRunFinishedButton/index.jsx +++ b/client/components/ManageBotRunDialog/MarkBotRunFinishedButton/index.jsx @@ -10,6 +10,7 @@ import { LoadingStatus, useTriggerLoad } from '../../common/LoadingStatus'; import { useTestPlanRunValidatedAssertionCounts } from '../../../hooks/useTestPlanRunValidatedAssertionCounts'; import BasicModal from '../../common/BasicModal'; import { useTestPlanRunIsFinished } from '../../../hooks/useTestPlanRunIsFinished'; +import { TestPlanRunPropType } from '../../common/proptypes'; const MarkBotRunFinishedButton = ({ testPlanRun, onClick = () => {} }) => { const { @@ -86,7 +87,7 @@ const MarkBotRunFinishedButton = ({ testPlanRun, onClick = () => {} }) => { }; MarkBotRunFinishedButton.propTypes = { - testPlanRun: PropTypes.object.isRequired, + testPlanRun: TestPlanRunPropType.isRequired, onClick: PropTypes.func }; diff --git a/client/components/ManageBotRunDialog/RetryCanceledCollectionsButton/index.jsx b/client/components/ManageBotRunDialog/RetryCanceledCollectionsButton/index.jsx index a842b8142..947b480dd 100644 --- a/client/components/ManageBotRunDialog/RetryCanceledCollectionsButton/index.jsx +++ b/client/components/ManageBotRunDialog/RetryCanceledCollectionsButton/index.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { Button } from 'react-bootstrap'; import { useMutation } from '@apollo/client'; import { RETRY_CANCELED_COLLECTIONS } from '../queries'; +import { CollectionJobPropType } from '../../common/proptypes'; const RetryCanceledCollectionsButton = ({ collectionJob, @@ -33,16 +34,7 @@ const RetryCanceledCollectionsButton = ({ }; RetryCanceledCollectionsButton.propTypes = { - collectionJob: PropTypes.shape({ - id: PropTypes.string, - status: PropTypes.oneOf([ - 'QUEUED', - 'RUNNING', - 'CANCELLED', - 'COMPLETED', - 'ERROR' - ]) - }), + collectionJob: CollectionJobPropType, onClick: PropTypes.func }; diff --git a/client/components/ManageBotRunDialog/StopRunningCollectionButton/index.jsx b/client/components/ManageBotRunDialog/StopRunningCollectionButton/index.jsx index b985996fd..a1fa69c61 100644 --- a/client/components/ManageBotRunDialog/StopRunningCollectionButton/index.jsx +++ b/client/components/ManageBotRunDialog/StopRunningCollectionButton/index.jsx @@ -4,6 +4,7 @@ import { Button } from 'react-bootstrap'; import { useMutation } from '@apollo/client'; import { CANCEL_COLLECTION_JOB } from '../queries'; import { LoadingStatus, useTriggerLoad } from '../../common/LoadingStatus'; +import { CollectionJobPropType } from '../../common/proptypes'; const StopRunningCollectionButton = ({ collectionJob, onClick = () => {} }) => { if (!collectionJob) { @@ -44,16 +45,7 @@ const StopRunningCollectionButton = ({ collectionJob, onClick = () => {} }) => { }; StopRunningCollectionButton.propTypes = { - collectionJob: PropTypes.shape({ - id: PropTypes.string, - status: PropTypes.oneOf([ - 'QUEUED', - 'RUNNING', - 'CANCELLED', - 'COMPLETED', - 'ERROR' - ]).isRequired - }), + collectionJob: CollectionJobPropType, onClick: PropTypes.func }; diff --git a/client/components/ManageBotRunDialog/WithButton.jsx b/client/components/ManageBotRunDialog/WithButton.jsx index ea6f9018a..1eac6318a 100644 --- a/client/components/ManageBotRunDialog/WithButton.jsx +++ b/client/components/ManageBotRunDialog/WithButton.jsx @@ -5,6 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faRobot } from '@fortawesome/free-solid-svg-icons'; import ManageBotRunDialog from '.'; import { useTestPlanRunIsFinished } from '../../hooks/useTestPlanRunIsFinished'; +import { TestPlanRunPropType, UserPropType } from '../common/proptypes'; const ManageBotRunDialogWithButton = ({ testPlanRun, @@ -49,10 +50,10 @@ const ManageBotRunDialogWithButton = ({ }; ManageBotRunDialogWithButton.propTypes = { - testPlanRun: PropTypes.object.isRequired, + testPlanRun: TestPlanRunPropType.isRequired, testPlanReportId: PropTypes.string.isRequired, runnableTestsLength: PropTypes.number.isRequired, - testers: PropTypes.array.isRequired, + testers: PropTypes.arrayOf(UserPropType).isRequired, onChange: PropTypes.func.isRequired }; diff --git a/client/components/ManageBotRunDialog/index.jsx b/client/components/ManageBotRunDialog/index.jsx index 154a8db6b..8915ad55b 100644 --- a/client/components/ManageBotRunDialog/index.jsx +++ b/client/components/ManageBotRunDialog/index.jsx @@ -16,6 +16,7 @@ import MarkBotRunFinishedButton from './MarkBotRunFinishedButton'; import RetryCanceledCollectionsButton from './RetryCanceledCollectionsButton'; import StopRunningCollectionButton from './StopRunningCollectionButton'; import ViewLogsButton from './ViewLogsButton'; +import { TestPlanRunPropType, UserPropType } from '../common/proptypes'; const ManageBotRunDialog = ({ testPlanReportId, @@ -177,10 +178,10 @@ const ManageBotRunDialog = ({ }; ManageBotRunDialog.propTypes = { - testPlanRun: PropTypes.object.isRequired, + testPlanRun: TestPlanRunPropType.isRequired, show: PropTypes.bool.isRequired, setShow: PropTypes.func.isRequired, - testers: PropTypes.array.isRequired, + testers: PropTypes.arrayOf(UserPropType).isRequired, testPlanReportId: PropTypes.string.isRequired, runnableTestsLength: PropTypes.number.isRequired, onChange: PropTypes.func.isRequired diff --git a/client/components/ManageTestQueue/ManageAtVersions.jsx b/client/components/ManageTestQueue/ManageAtVersions.jsx index 0953d51e9..65beea962 100644 --- a/client/components/ManageTestQueue/ManageAtVersions.jsx +++ b/client/components/ManageTestQueue/ManageAtVersions.jsx @@ -15,6 +15,7 @@ import { import { useTriggerLoad } from '@components/common/LoadingStatus'; import { THEMES, useThemedModal } from '@client/hooks/useThemedModal'; import PropTypes from 'prop-types'; +import { AtPropType } from '../common/proptypes'; const ManageAtVersions = ({ ats = [], triggerUpdate = () => {} }) => { const { triggerLoad } = useTriggerLoad(); @@ -410,20 +411,7 @@ const ManageAtVersions = ({ ats = [], triggerUpdate = () => {} }) => { }; ManageAtVersions.propTypes = { - ats: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - key: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - browsers: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - key: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }) - ).isRequired - }) - ).isRequired, + ats: PropTypes.arrayOf(AtPropType).isRequired, triggerUpdate: PropTypes.func }; diff --git a/client/components/ManageTestQueue/index.jsx b/client/components/ManageTestQueue/index.jsx index d5aa795af..3bf82420d 100644 --- a/client/components/ManageTestQueue/index.jsx +++ b/client/components/ManageTestQueue/index.jsx @@ -5,6 +5,7 @@ import { LoadingStatus, useTriggerLoad } from '../common/LoadingStatus'; import DisclosureComponent from '../common/DisclosureComponent'; import ManageAtVersions from '@components/ManageTestQueue/ManageAtVersions'; import AddTestPlans from '@components/ManageTestQueue/AddTestPlans'; +import { AtPropType, TestPlanVersionPropType } from '../common/proptypes'; export const DisclosureContainer = styled.div` // Following directives are related to the ManageTestQueue component @@ -148,21 +149,8 @@ const ManageTestQueue = ({ }; ManageTestQueue.propTypes = { - ats: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - key: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - browsers: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - key: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }) - ).isRequired - }) - ).isRequired, - testPlanVersions: PropTypes.array, + ats: PropTypes.arrayOf(AtPropType).isRequired, + testPlanVersions: PropTypes.arrayOf(TestPlanVersionPropType), triggerUpdate: PropTypes.func }; diff --git a/client/components/Reports/SummarizeTestPlanReport.jsx b/client/components/Reports/SummarizeTestPlanReport.jsx index 6abd3d46c..ac9f2b138 100644 --- a/client/components/Reports/SummarizeTestPlanReport.jsx +++ b/client/components/Reports/SummarizeTestPlanReport.jsx @@ -18,6 +18,10 @@ import TestPlanResultsTable from '../common/TestPlanResultsTable'; import DisclosureComponent from '../common/DisclosureComponent'; import { Link, Navigate, useLocation, useParams } from 'react-router-dom'; import createIssueLink from '../../utils/createIssueLink'; +import { + TestPlanReportPropType, + TestPlanVersionPropType +} from '../common/proptypes'; const ResultsContainer = styled.div` padding: 1em 1.75em; @@ -378,60 +382,8 @@ const SummarizeTestPlanReport = ({ testPlanVersion, testPlanReports }) => { }; SummarizeTestPlanReport.propTypes = { - testPlanVersion: PropTypes.object.isRequired, - testPlanReports: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - runnableTests: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired, - at: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }).isRequired, - browser: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }).isRequired, - finalizedTestResults: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - test: PropTypes.shape({ - title: PropTypes.string.isRequired, - renderedUrl: PropTypes.string.isRequired - }).isRequired, - scenarioResults: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - output: PropTypes.string.isRequired, - assertionResults: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - passed: PropTypes.bool.isRequired, - assertion: PropTypes.shape({ - text: PropTypes.string.isRequired - }).isRequired - }).isRequired - ).isRequired, - unexpectedBehaviors: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - text: PropTypes.string.isRequired, - impact: PropTypes.string.isRequired, - details: PropTypes.string.isRequired - }).isRequired - ).isRequired - }).isRequired - ).isRequired - }).isRequired - ).isRequired, - draftTestPlanRuns: PropTypes.arrayOf( - PropTypes.shape({ - tester: PropTypes.shape({ - username: PropTypes.string.isRequired - }) - }) - ) - }).isRequired - ) + testPlanVersion: TestPlanVersionPropType.isRequired, + testPlanReports: PropTypes.arrayOf(TestPlanReportPropType).isRequired }; export default SummarizeTestPlanReport; diff --git a/client/components/Reports/SummarizeTestPlanReports.jsx b/client/components/Reports/SummarizeTestPlanReports.jsx index 26867cd5a..ee3e4bbf7 100644 --- a/client/components/Reports/SummarizeTestPlanReports.jsx +++ b/client/components/Reports/SummarizeTestPlanReports.jsx @@ -9,6 +9,7 @@ import { derivePhaseName } from '../../utils/aria'; import { none } from './None'; import { getTestPlanTargetTitle, getTestPlanVersionTitle } from './getTitles'; import ClippedProgressBar from '@components/common/ClippedProgressBar'; +import { TestPlanVersionPropType } from '../common/proptypes'; const FullHeightContainer = styled(Container)` min-height: calc(100vh - 64px); @@ -151,26 +152,7 @@ const SummarizeTestPlanReports = ({ testPlanVersions }) => { }; SummarizeTestPlanReports.propTypes = { - testPlanVersions: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - phase: PropTypes.string.isRequired, - gitSha: PropTypes.string, - testPlan: PropTypes.shape({ - directory: PropTypes.string - }), - metadata: PropTypes.object, - testPlanReports: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - metrics: PropTypes.object.isRequired, - at: PropTypes.object.isRequired, - browser: PropTypes.object.isRequired - }) - ) - }) - ).isRequired + testPlanVersions: PropTypes.arrayOf(TestPlanVersionPropType).isRequired }; export default SummarizeTestPlanReports; diff --git a/client/components/Reports/SummarizeTestPlanVersion.jsx b/client/components/Reports/SummarizeTestPlanVersion.jsx index be579b5ba..74005bda1 100644 --- a/client/components/Reports/SummarizeTestPlanVersion.jsx +++ b/client/components/Reports/SummarizeTestPlanVersion.jsx @@ -11,6 +11,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faHome } from '@fortawesome/free-solid-svg-icons'; import styled from '@emotion/styled'; import DisclaimerInfo from '../DisclaimerInfo'; +import { + TestPlanReportPropType, + TestPlanVersionPropType +} from '../common/proptypes'; const FullHeightContainer = styled(Container)` min-height: calc(100vh - 64px); @@ -183,26 +187,8 @@ const SummarizeTestPlanVersion = ({ testPlanVersion, testPlanReports }) => { }; SummarizeTestPlanVersion.propTypes = { - testPlanVersion: PropTypes.shape({ - gitSha: PropTypes.string, - testPlan: PropTypes.object, - directory: PropTypes.string, - versionString: PropTypes.string, - id: PropTypes.string.isRequired, - title: PropTypes.string, - phase: PropTypes.string, - metadata: PropTypes.shape({ - exampleUrl: PropTypes.string.isRequired, - designPatternUrl: PropTypes.string - }).isRequired - }).isRequired, - testPlanReports: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - runnableTests: PropTypes.arrayOf(PropTypes.object).isRequired, - finalizedTestResults: PropTypes.arrayOf(PropTypes.object) - }).isRequired - ).isRequired + testPlanVersion: TestPlanVersionPropType.isRequired, + testPlanReports: PropTypes.arrayOf(TestPlanReportPropType).isRequired }; export default SummarizeTestPlanVersion; diff --git a/client/components/ReviewConflicts/ReviewConflicts.jsx b/client/components/ReviewConflicts/ReviewConflicts.jsx index c97740dc2..f272c5663 100644 --- a/client/components/ReviewConflicts/ReviewConflicts.jsx +++ b/client/components/ReviewConflicts/ReviewConflicts.jsx @@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import styled from '@emotion/styled'; import TurndownService from 'turndown'; +import { TestPlanReportPropType, TestPropType } from '../common/proptypes'; const Wrapper = styled.div` & h2 { @@ -119,58 +120,8 @@ const ReviewConflicts = ({ }; ReviewConflicts.propTypes = { - testPlanReport: PropTypes.shape({ - id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - conflicts: PropTypes.arrayOf( - PropTypes.shape({ - source: PropTypes.shape({ - test: PropTypes.shape({ - id: PropTypes.string.isRequired - }).isRequired, - scenario: PropTypes.shape({ - id: PropTypes.string.isRequired, - commands: PropTypes.arrayOf( - PropTypes.shape({ - text: PropTypes.string.isRequired - }) - ).isRequired - }).isRequired, - assertion: PropTypes.shape({ - id: PropTypes.string.isRequired, - text: PropTypes.string.isRequired - }) - }).isRequired, - conflictingResults: PropTypes.arrayOf( - PropTypes.shape({ - testPlanRun: PropTypes.shape({ - id: PropTypes.string.isRequired, - tester: PropTypes.shape({ - username: PropTypes.string.isRequired - }).isRequired - }).isRequired, - scenarioResult: PropTypes.shape({ - output: PropTypes.string.isRequired, - unexpectedBehaviors: PropTypes.arrayOf( - PropTypes.shape({ - text: PropTypes.string.isRequired, - impact: PropTypes.string.isRequired, - details: PropTypes.string.isRequired - }) - ).isRequired - }), - assertionResult: PropTypes.shape({ - passed: PropTypes.bool.isRequired - }) - }) - ).isRequired - }) - ).isRequired - }), - test: PropTypes.shape({ - id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - rowNumber: PropTypes.number.isRequired - }), + testPlanReport: TestPlanReportPropType.isRequired, + test: TestPropType.isRequired, hideHeadline: PropTypes.bool, conflictMarkdownRef: PropTypes.shape({ current: PropTypes.string diff --git a/client/components/TestPlanReportStatusDialog/index.jsx b/client/components/TestPlanReportStatusDialog/index.jsx index 37d109f0a..7bd981b0b 100644 --- a/client/components/TestPlanReportStatusDialog/index.jsx +++ b/client/components/TestPlanReportStatusDialog/index.jsx @@ -9,6 +9,7 @@ import BasicModal from '../common/BasicModal'; import './TestPlanReportStatusDialog.css'; import ReportStatusSummary from '../common/ReportStatusSummary'; import { AtVersion } from '../common/AtBrowserVersion'; +import { TestPlanVersionPropType } from '../common/proptypes'; const TestPlanReportStatusDialog = ({ testPlanVersion, @@ -147,37 +148,7 @@ const TestPlanReportStatusDialog = ({ }; TestPlanReportStatusDialog.propTypes = { - testPlanVersion: PropTypes.shape({ - id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - phase: PropTypes.string.isRequired, - testPlanReportStatuses: PropTypes.arrayOf( - PropTypes.shape({ - at: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }).isRequired, - browser: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }).isRequired, - minimumAtVersion: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }), - exactAtVersion: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }), - testPlanReport: PropTypes.shape({ - id: PropTypes.string.isRequired, - status: PropTypes.string, - runnableTests: PropTypes.arrayOf(PropTypes.object), - finalizedTestResults: PropTypes.arrayOf(PropTypes.object) - }) - }).isRequired - ).isRequired - }).isRequired, + testPlanVersion: TestPlanVersionPropType.isRequired, handleHide: PropTypes.func.isRequired, triggerUpdate: PropTypes.func, show: PropTypes.bool.isRequired diff --git a/client/components/TestQueue/Actions.jsx b/client/components/TestQueue/Actions.jsx index c9ba177cc..444e244a6 100644 --- a/client/components/TestQueue/Actions.jsx +++ b/client/components/TestQueue/Actions.jsx @@ -22,6 +22,11 @@ import BasicThemedModal from '../common/BasicThemedModal'; import { evaluateAuth } from '../../utils/evaluateAuth'; import { TEST_PLAN_REPORT_STATUS_DIALOG_QUERY } from '../TestPlanReportStatusDialog/queries'; import ManageBotRunDialogWithButton from '@components/ManageBotRunDialog/WithButton'; +import { + TestPlanPropType, + TestPlanReportPropType, + UserPropType +} from '../common/proptypes'; const ActionContainer = styled.div` display: flex; @@ -296,42 +301,10 @@ const Actions = ({ }; Actions.propTypes = { - me: PropTypes.shape({ - id: PropTypes.string.isRequired, - username: PropTypes.string.isRequired - }), - testPlan: PropTypes.shape({ - directory: PropTypes.string.isRequired - }).isRequired, - testPlanReport: PropTypes.shape({ - id: PropTypes.string.isRequired, - runnableTestsLength: PropTypes.number.isRequired, - conflictsLength: PropTypes.number.isRequired, - draftTestPlanRuns: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - testResultsLength: PropTypes.number.isRequired, - tester: PropTypes.shape({ - id: PropTypes.string.isRequired, - username: PropTypes.string.isRequired, - isBot: PropTypes.bool.isRequired - }) - }) - ).isRequired - }).isRequired, - testers: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - username: PropTypes.string.isRequired, - isBot: PropTypes.bool.isRequired, - ats: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - key: PropTypes.string.isRequired - }) - ) - }) - ).isRequired, + me: UserPropType, + testPlan: TestPlanPropType.isRequired, + testPlanReport: TestPlanReportPropType.isRequired, + testers: PropTypes.arrayOf(UserPropType).isRequired, triggerUpdate: PropTypes.func.isRequired }; diff --git a/client/components/TestQueue/AssignTesters.jsx b/client/components/TestQueue/AssignTesters.jsx index 38f50c076..7e2c64c1a 100644 --- a/client/components/TestQueue/AssignTesters.jsx +++ b/client/components/TestQueue/AssignTesters.jsx @@ -19,6 +19,7 @@ import { } from './queries'; import { SCHEDULE_COLLECTION_JOB_MUTATION } from '../AddTestToQueueWithConfirmation/queries'; import { TEST_PLAN_REPORT_STATUS_DIALOG_QUERY } from '../TestPlanReportStatusDialog/queries'; +import { TestPlanReportPropType, UserPropType } from '../common/proptypes'; const AssignTestersContainer = styled.div` display: flex; @@ -328,56 +329,9 @@ const AssignTesters = ({ me, testers, testPlanReport }) => { }; AssignTesters.propTypes = { - me: PropTypes.shape({ - id: PropTypes.string.isRequired - }), - testers: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - username: PropTypes.string.isRequired, - isBot: PropTypes.bool.isRequired, - ats: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - key: PropTypes.string.isRequired - }) - ) - }) - ).isRequired, - testPlanReport: PropTypes.shape({ - id: PropTypes.string.isRequired, - runnableTestsLength: PropTypes.number.isRequired, - draftTestPlanRuns: PropTypes.arrayOf( - PropTypes.shape({ - tester: PropTypes.shape({ id: PropTypes.string.isRequired }).isRequired - }) - ).isRequired, - at: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - key: PropTypes.string.isRequired, - atVersions: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - supportedByAutomation: PropTypes.bool.isRequired - }) - ) - }).isRequired, - browser: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - key: PropTypes.string.isRequired - }).isRequired, - minimumAtVersion: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }), - exactAtVersion: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }) - }).isRequired + me: UserPropType, + testers: PropTypes.arrayOf(UserPropType).isRequired, + testPlanReport: TestPlanReportPropType.isRequired }; export default AssignTesters; diff --git a/client/components/TestQueue/CompletionStatusListItem/index.jsx b/client/components/TestQueue/CompletionStatusListItem/index.jsx index 98ed53eaa..2ba2c1818 100644 --- a/client/components/TestQueue/CompletionStatusListItem/index.jsx +++ b/client/components/TestQueue/CompletionStatusListItem/index.jsx @@ -4,6 +4,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faRobot } from '@fortawesome/free-solid-svg-icons'; import BotTestCompletionStatus from '@components/TestQueueCompletionStatusListItem/BotTestCompletionStatus'; import PreviouslyAutomatedTestCompletionStatus from '@components/TestQueueCompletionStatusListItem/PreviouslyAutomatedTestCompletionStatus'; +import { + TestPlanReportPropType, + TestPlanRunPropType, + UserPropType +} from '../../common/proptypes'; const CompletionStatusListItem = ({ rowId, @@ -67,20 +72,11 @@ const CompletionStatusListItem = ({ ); }; -// TODO: Update shape for testPlanReport and tester CompletionStatusListItem.propTypes = { rowId: PropTypes.string.isRequired, - testPlanReport: PropTypes.object.isRequired, - testPlanRun: PropTypes.shape({ - id: PropTypes.string.isRequired, - testResultsLength: PropTypes.number.isRequired, - initiatedByAutomation: PropTypes.bool.isRequired, - tester: PropTypes.shape({ - username: PropTypes.string.isRequired, - isBot: PropTypes.bool.isRequired - }).isRequired - }).isRequired, - tester: PropTypes.object.isRequired + testPlanReport: TestPlanReportPropType.isRequired, + testPlanRun: TestPlanRunPropType.isRequired, + tester: UserPropType.isRequired }; export default CompletionStatusListItem; diff --git a/client/components/TestQueueCompletionStatusListItem/BotTestCompletionStatus/index.js b/client/components/TestQueueCompletionStatusListItem/BotTestCompletionStatus/index.js index 0368b1165..e7e6f7b2e 100644 --- a/client/components/TestQueueCompletionStatusListItem/BotTestCompletionStatus/index.js +++ b/client/components/TestQueueCompletionStatusListItem/BotTestCompletionStatus/index.js @@ -1,6 +1,7 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { useTestPlanRunValidatedAssertionCounts } from '../../../hooks/useTestPlanRunValidatedAssertionCounts'; +import { TestPlanRunPropType } from '../../common/proptypes'; const BotTestCompletionStatus = ({ testPlanRun, id, runnableTestsLength }) => { const { @@ -31,22 +32,7 @@ const BotTestCompletionStatus = ({ testPlanRun, id, runnableTestsLength }) => { }; BotTestCompletionStatus.propTypes = { - testPlanRun: PropTypes.shape({ - id: PropTypes.string.isRequired, - testResults: PropTypes.arrayOf( - PropTypes.shape({ - scenarioResults: PropTypes.arrayOf( - PropTypes.shape({ - assertionResults: PropTypes.arrayOf( - PropTypes.shape({ - passed: PropTypes.bool - }) - ) - }) - ) - }) - ) - }).isRequired, + testPlanRun: TestPlanRunPropType.isRequired, id: PropTypes.string.isRequired, runnableTestsLength: PropTypes.number.isRequired }; diff --git a/client/components/TestQueueCompletionStatusListItem/index.js b/client/components/TestQueueCompletionStatusListItem/index.js index 165ad5a47..1da90dfba 100644 --- a/client/components/TestQueueCompletionStatusListItem/index.js +++ b/client/components/TestQueueCompletionStatusListItem/index.js @@ -4,6 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faRobot } from '@fortawesome/free-solid-svg-icons'; import BotTestCompletionStatus from './BotTestCompletionStatus'; import PreviouslyAutomatedTestCompletionStatus from './PreviouslyAutomatedTestCompletionStatus'; +import { TestPlanRunPropType } from '../common/proptypes'; const TestQueueCompletionStatusListItem = ({ runnableTestsLength, @@ -77,15 +78,7 @@ const TestQueueCompletionStatusListItem = ({ TestQueueCompletionStatusListItem.propTypes = { runnableTestsLength: PropTypes.number.isRequired, - testPlanRun: PropTypes.shape({ - id: PropTypes.string.isRequired, - testResultsLength: PropTypes.number.isRequired, - initiatedByAutomation: PropTypes.bool.isRequired, - tester: PropTypes.shape({ - username: PropTypes.string.isRequired, - isBot: PropTypes.bool.isRequired - }).isRequired - }).isRequired, + testPlanRun: TestPlanRunPropType.isRequired, id: PropTypes.string.isRequired }; diff --git a/client/components/TestRenderer/OutputTextArea/index.jsx b/client/components/TestRenderer/OutputTextArea/index.jsx index 62b173ab3..79dea9570 100644 --- a/client/components/TestRenderer/OutputTextArea/index.jsx +++ b/client/components/TestRenderer/OutputTextArea/index.jsx @@ -4,6 +4,7 @@ import styled from '@emotion/styled'; import { Feedback } from '..'; import { Form } from 'react-bootstrap'; import { NO_OUTPUT_STRING } from './constants'; +import { AtOutputPropType } from '../../common/proptypes'; const OutputTextAreaWrapper = styled.div` > textarea { @@ -85,21 +86,7 @@ const OutputTextArea = ({ OutputTextArea.propTypes = { commandIndex: PropTypes.number.isRequired, - atOutput: PropTypes.shape({ - description: PropTypes.arrayOf( - PropTypes.oneOfType([ - PropTypes.string, - PropTypes.shape({ - required: PropTypes.bool.isRequired, - highlightRequired: PropTypes.bool.isRequired, - description: PropTypes.string.isRequired - }) - ]) - ).isRequired, - value: PropTypes.string.isRequired, - change: PropTypes.func.isRequired, - focus: PropTypes.bool.isRequired - }).isRequired, + atOutput: AtOutputPropType.isRequired, readOnly: PropTypes.bool, isSubmitted: PropTypes.bool.isRequired }; diff --git a/client/components/TestRenderer/index.jsx b/client/components/TestRenderer/index.jsx index aac75c423..1780eac67 100644 --- a/client/components/TestRenderer/index.jsx +++ b/client/components/TestRenderer/index.jsx @@ -26,6 +26,7 @@ import AssertionsFieldset from './AssertionsFieldset'; import UnexpectedBehaviorsFieldset from './UnexpectedBehaviorsFieldset'; import supportJson from '../../resources/support.json'; import commandsJson from '../../resources/commands.json'; +import { AtPropType, TestResultPropType } from '../common/proptypes/index.js'; const Container = styled.div` width: 100%; @@ -580,8 +581,8 @@ ErrorComponent.propTypes = { }; TestRenderer.propTypes = { - at: PropTypes.object, - testResult: PropTypes.object, + at: AtPropType, + testResult: TestResultPropType, support: PropTypes.object, testPageUrl: PropTypes.string, testFormatVersion: PropTypes.number, diff --git a/client/components/TestRun/CollectionJobContext.js b/client/components/TestRun/CollectionJobContext.js index af16f4f83..2b5b69f9b 100644 --- a/client/components/TestRun/CollectionJobContext.js +++ b/client/components/TestRun/CollectionJobContext.js @@ -3,6 +3,7 @@ import React, { createContext, useState, useEffect } from 'react'; import { useLazyQuery } from '@apollo/client'; import { COLLECTION_JOB_UPDATES_QUERY } from './queries'; import { isJobStatusFinal } from '../../utils/collectionJobStatus'; +import { TestPlanRunPropType } from '../common/proptypes'; const pollInterval = 5000; export const Context = createContext({ @@ -60,12 +61,5 @@ export const Provider = ({ children, testPlanRun }) => { Provider.propTypes = { children: PropTypes.node, - testPlanRun: PropTypes.shape({ - id: PropTypes.string, - collectionJob: PropTypes.shape({ - id: PropTypes.string.isRequired, - status: PropTypes.string.isRequired, - testStatus: PropTypes.arrayOf(PropTypes.object).isRequired - }) - }) + testPlanRun: TestPlanRunPropType }; diff --git a/client/components/TestRun/ReviewConflictsModal/index.jsx b/client/components/TestRun/ReviewConflictsModal/index.jsx index 94dcf5b03..40e0ffd59 100644 --- a/client/components/TestRun/ReviewConflictsModal/index.jsx +++ b/client/components/TestRun/ReviewConflictsModal/index.jsx @@ -3,6 +3,11 @@ import PropTypes from 'prop-types'; import { Button, Modal } from 'react-bootstrap'; import styled from '@emotion/styled'; import ReviewConflicts from '../../ReviewConflicts'; +import { + TestPlanReportPropType, + TestPlanVersionPropType, + TestPropType +} from '../../common/proptypes'; const H2 = styled.h2` margin-top: 0; @@ -57,9 +62,9 @@ const ReviewConflictsModal = ({ ReviewConflictsModal.propTypes = { show: PropTypes.bool, - testPlanVersion: PropTypes.object.isRequired, - testPlanReport: PropTypes.object.isRequired, - test: PropTypes.object.isRequired, + testPlanVersion: TestPlanVersionPropType.isRequired, + testPlanReport: TestPlanReportPropType.isRequired, + test: TestPropType.isRequired, handleClose: PropTypes.func, conflictMarkdown: PropTypes.string, issueLink: PropTypes.string.isRequired diff --git a/client/components/common/AssignTesterDropdown/index.jsx b/client/components/common/AssignTesterDropdown/index.jsx index f576549fd..5d4cd9ceb 100644 --- a/client/components/common/AssignTesterDropdown/index.jsx +++ b/client/components/common/AssignTesterDropdown/index.jsx @@ -19,6 +19,7 @@ import { SCHEDULE_COLLECTION_JOB_MUTATION } from '../../AddTestToQueueWithConfir import { isSupportedByResponseCollector } from '../../../utils/automation'; import './AssignTesterDropdown.css'; +import { TestPlanRunPropType, UserPropType } from '../proptypes'; const AssignTesterDropdown = ({ testPlanReportId, @@ -209,23 +210,11 @@ const AssignTesterDropdown = ({ AssignTesterDropdown.propTypes = { testPlanReportId: PropTypes.string.isRequired, - possibleTesters: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - username: PropTypes.string.isRequired, - isBot: PropTypes.bool.isRequired, - ats: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - key: PropTypes.string.isRequired - }) - ) - }) - ).isRequired, + possibleTesters: PropTypes.arrayOf(UserPropType).isRequired, onChange: PropTypes.func.isRequired, - testPlanRun: PropTypes.object, + testPlanRun: TestPlanRunPropType, label: PropTypes.string, - draftTestPlanRuns: PropTypes.array, + draftTestPlanRuns: PropTypes.arrayOf(TestPlanRunPropType), setAlertMessage: PropTypes.func, dropdownAssignTesterButtonRef: PropTypes.object }; diff --git a/client/components/common/AtAndBrowserDetailsModal/index.jsx b/client/components/common/AtAndBrowserDetailsModal/index.jsx index 1d8894153..e26475e18 100644 --- a/client/components/common/AtAndBrowserDetailsModal/index.jsx +++ b/client/components/common/AtAndBrowserDetailsModal/index.jsx @@ -10,6 +10,7 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { useDetectUa } from '../../../hooks/useDetectUa'; import BasicModal from '../BasicModal'; +import { AtVersionPropType } from '../proptypes'; const ModalInnerSectionContainer = styled.div` display: flex; @@ -596,10 +597,7 @@ AtAndBrowserDetailsModal.propTypes = { browserVersions: PropTypes.arrayOf(PropTypes.string), patternName: PropTypes.string, testerName: PropTypes.string, - exactAtVersion: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }), + exactAtVersion: AtVersionPropType, handleClose: PropTypes.func, handleAction: PropTypes.func }; diff --git a/client/components/common/BasicModal/index.jsx b/client/components/common/BasicModal/index.jsx index fdb015742..1ed363537 100644 --- a/client/components/common/BasicModal/index.jsx +++ b/client/components/common/BasicModal/index.jsx @@ -6,6 +6,7 @@ import FocusTrapper from '../FocusTrapper'; import { uniqueId } from 'lodash'; import './BasicModal.css'; +import { ModalActionPropType } from '../proptypes'; const ModalTitleStyle = styled.h1` border: 0; @@ -133,17 +134,7 @@ BasicModal.propTypes = { handleHide: PropTypes.func, staticBackdrop: PropTypes.bool, useOnHide: PropTypes.bool, - actions: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string, - onClick: PropTypes.func, - variant: PropTypes.string, - className: PropTypes.string, - testId: PropTypes.string, - component: PropTypes.elementType, - props: PropTypes.object - }) - ), + actions: PropTypes.arrayOf(ModalActionPropType), initialFocusRef: PropTypes.shape({ current: PropTypes.any }) diff --git a/client/components/common/BasicThemedModal/index.jsx b/client/components/common/BasicThemedModal/index.jsx index d2dafffb2..5c53c5edb 100644 --- a/client/components/common/BasicThemedModal/index.jsx +++ b/client/components/common/BasicThemedModal/index.jsx @@ -5,6 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; import styled from '@emotion/styled'; import { uniqueId } from 'lodash'; +import { ActionButtonPropType } from '../proptypes'; const ModalTitleStyle = styled.h1` border: 0; @@ -122,12 +123,7 @@ BasicThemedModal.propTypes = { dialogClassName: PropTypes.string, title: PropTypes.node.isRequired, content: PropTypes.node.isRequired, - actionButtons: PropTypes.arrayOf( - PropTypes.shape({ - text: PropTypes.string, - action: PropTypes.func - }) - ), + actionButtons: PropTypes.arrayOf(ActionButtonPropType), closeLabel: PropTypes.string, handleClose: PropTypes.func, showCloseAction: PropTypes.bool diff --git a/client/components/common/ReportStatusSummary/index.jsx b/client/components/common/ReportStatusSummary/index.jsx index df59b4689..aaae6acb8 100644 --- a/client/components/common/ReportStatusSummary/index.jsx +++ b/client/components/common/ReportStatusSummary/index.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import styled from '@emotion/styled'; import { dates } from 'shared'; import { calculatePercentComplete } from '../../../utils/calculatePercentComplete'; +import { TestPlanVersionPropType, TestPlanRunPropType } from '../proptypes'; const IncompleteStatusReport = styled.span` min-width: 5rem; @@ -74,20 +75,12 @@ const ReportStatusSummary = ({ }; ReportStatusSummary.propTypes = { - testPlanVersion: PropTypes.shape({ - id: PropTypes.string.isRequired - }).isRequired, + testPlanVersion: TestPlanVersionPropType.isRequired, testPlanReport: PropTypes.shape({ id: PropTypes.string.isRequired, markedFinalAt: PropTypes.string, metrics: PropTypes.object, - draftTestPlanRuns: PropTypes.arrayOf( - PropTypes.shape({ - tester: PropTypes.shape({ - username: PropTypes.string.isRequired - }).isRequired - }) - ).isRequired + draftTestPlanRuns: PropTypes.arrayOf(TestPlanRunPropType).isRequired }), fromTestQueue: PropTypes.bool }; diff --git a/client/components/common/TestPlanResultsTable/index.jsx b/client/components/common/TestPlanResultsTable/index.jsx index c29bcb688..1cd97a814 100644 --- a/client/components/common/TestPlanResultsTable/index.jsx +++ b/client/components/common/TestPlanResultsTable/index.jsx @@ -4,6 +4,7 @@ import { Table } from 'react-bootstrap'; import nextId from 'react-id-generator'; import { getMetrics } from 'shared'; import './TestPlanResultsTable.css'; +import { TestPropType, TestResultPropType } from '../proptypes'; const getAssertionResultText = (passed, priority) => { if (priority === 'MAY') { @@ -191,15 +192,8 @@ const TestPlanResultsTable = ({ }; TestPlanResultsTable.propTypes = { - test: PropTypes.shape({ - title: PropTypes.string.isRequired, - at: PropTypes.shape({ - name: PropTypes.string.isRequired - }).isRequired - }), - testResult: PropTypes.shape({ - scenarioResults: PropTypes.array.isRequired - }), + test: TestPropType.isRequired, + testResult: TestResultPropType.isRequired, tableClassName: PropTypes.string, optionalHeader: PropTypes.node, commandHeadingLevel: PropTypes.number diff --git a/client/components/common/proptypes/index.js b/client/components/common/proptypes/index.js new file mode 100644 index 000000000..7d98d1d78 --- /dev/null +++ b/client/components/common/proptypes/index.js @@ -0,0 +1,322 @@ +import PropTypes from 'prop-types'; + +export const AtPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + key: PropTypes.string.isRequired, + name: PropTypes.string.isRequired +}); + +export const AtVersionPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + releasedAt: PropTypes.string, + supportedByAutomation: PropTypes.bool +}); + +export const AssertionResultPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + passed: PropTypes.bool.isRequired, + assertion: PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + phrase: PropTypes.string, + priority: PropTypes.string + }).isRequired +}); + +export const BrowserPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + key: PropTypes.string.isRequired, + name: PropTypes.string.isRequired +}); + +export const BrowserVersionPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired +}); + +export const CollectionJobPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + status: PropTypes.oneOf([ + 'QUEUED', + 'RUNNING', + 'CANCELLED', + 'COMPLETED', + 'ERROR' + ]), + externalLogsUrl: PropTypes.string, + testStatus: PropTypes.arrayOf( + PropTypes.shape({ + test: PropTypes.shape({ + id: PropTypes.string.isRequired + }).isRequired, + status: PropTypes.string.isRequired + }) + ) +}); + +export const IssuePropType = PropTypes.shape({ + __typename: PropTypes.string, + link: PropTypes.string.isRequired, + isOpen: PropTypes.bool.isRequired, + feedbackType: PropTypes.string, + isCandidateReview: PropTypes.bool, + title: PropTypes.string, + author: PropTypes.string, + testNumberFilteredByAt: PropTypes.number, + createdAt: PropTypes.string, + closedAt: PropTypes.string +}); + +export const MePropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + username: PropTypes.string.isRequired, + roles: PropTypes.arrayOf(PropTypes.string) +}); + +export const ScenarioResultPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + output: PropTypes.string, + scenario: PropTypes.shape({ + commands: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + atOperatingMode: PropTypes.string + }) + ).isRequired + }).isRequired, + assertionResults: PropTypes.arrayOf(AssertionResultPropType), + mustAssertionResults: PropTypes.arrayOf(AssertionResultPropType), + shouldAssertionResults: PropTypes.arrayOf(AssertionResultPropType), + mayAssertionResults: PropTypes.arrayOf(AssertionResultPropType), + unexpectedBehaviors: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + impact: PropTypes.string, + details: PropTypes.string + }) + ) +}); + +export const TestPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + rowNumber: PropTypes.number, + renderedUrl: PropTypes.string, + testFormatVersion: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + ats: PropTypes.arrayOf(AtPropType), + scenarios: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + at: AtPropType, + commands: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + atOperatingMode: PropTypes.string + }) + ) + }) + ), + assertions: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + phrase: PropTypes.string, + priority: PropTypes.string + }) + ) +}); + +export const TestPlanPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + directory: PropTypes.string +}); + +export const TestPlanReportPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + metrics: PropTypes.object, + isFinal: PropTypes.bool, + createdAt: PropTypes.string, + markedFinalAt: PropTypes.string, + conflictsLength: PropTypes.number, + runnableTestsLength: PropTypes.number +}); + +export const TestPlanReportConflictPropType = PropTypes.shape({ + __typename: PropTypes.string, + source: PropTypes.shape({ + test: PropTypes.shape({ + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + rowNumber: PropTypes.number + }).isRequired, + scenario: PropTypes.shape({ + id: PropTypes.string.isRequired, + commands: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + atOperatingMode: PropTypes.string + }) + ) + }).isRequired, + assertion: PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + phrase: PropTypes.string, + priority: PropTypes.string + }).isRequired + }).isRequired, + conflictingResults: PropTypes.arrayOf( + PropTypes.shape({ + testPlanRun: PropTypes.shape({ + id: PropTypes.string.isRequired, + tester: PropTypes.shape({ + username: PropTypes.string.isRequired + }).isRequired + }).isRequired, + scenarioResult: PropTypes.shape({ + output: PropTypes.string, + unexpectedBehaviors: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + impact: PropTypes.string, + details: PropTypes.string + }) + ) + }), + assertionResult: PropTypes.shape({ + passed: PropTypes.bool.isRequired + }).isRequired + }) + ).isRequired +}); + +export const TestPlanReportStatusPropType = PropTypes.shape({ + __typename: PropTypes.string, + isRequired: PropTypes.bool, + at: AtPropType, + browser: BrowserPropType, + minimumAtVersion: AtVersionPropType, + exactAtVersion: AtVersionPropType, + testPlanReport: PropTypes.shape({ + id: PropTypes.string.isRequired, + metrics: PropTypes.object, + isFinal: PropTypes.bool, + markedFinalAt: PropTypes.string, + issues: PropTypes.arrayOf(IssuePropType), + draftTestPlanRuns: PropTypes.arrayOf( + PropTypes.shape({ + tester: PropTypes.shape({ + username: PropTypes.string.isRequired + }).isRequired, + testPlanReport: PropTypes.shape({ + id: PropTypes.string.isRequired + }).isRequired, + testResults: PropTypes.arrayOf( + PropTypes.shape({ + test: PropTypes.shape({ + id: PropTypes.string.isRequired + }).isRequired, + atVersion: AtVersionPropType, + browserVersion: BrowserVersionPropType, + completedAt: PropTypes.string + }) + ) + }) + ) + }).isRequired +}); + +export const TestPlanRunPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string, + initiatedByAutomation: PropTypes.bool, + tester: PropTypes.shape({ + id: PropTypes.string, + username: PropTypes.string.isRequired, + isBot: PropTypes.bool + }).isRequired +}); + +export const TestPlanVersionPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + phase: PropTypes.string, + gitSha: PropTypes.string, + gitMessage: PropTypes.string, + versionString: PropTypes.string, + updatedAt: PropTypes.string, + draftPhaseReachedAt: PropTypes.string, + candidatePhaseReachedAt: PropTypes.string, + recommendedPhaseReachedAt: PropTypes.string, + recommendedPhaseTargetDate: PropTypes.string, + deprecatedAt: PropTypes.string, + testPageUrl: PropTypes.string, + metadata: PropTypes.object, + testPlan: PropTypes.shape({ + directory: PropTypes.string + }).isRequired +}); + +export const TestResultPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string, + startedAt: PropTypes.string, + completedAt: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]) +}); + +export const UserPropType = PropTypes.shape({ + __typename: PropTypes.string, + id: PropTypes.string.isRequired, + username: PropTypes.string.isRequired, + isBot: PropTypes.bool +}); + +export const ModalActionPropType = PropTypes.shape({ + label: PropTypes.string, + onClick: PropTypes.func, + variant: PropTypes.string, + className: PropTypes.string, + testId: PropTypes.string, + component: PropTypes.elementType, + props: PropTypes.object +}); + +export const ActionButtonPropType = PropTypes.shape({ + label: PropTypes.string, + action: PropTypes.func +}); + +export const AtOutputPropType = PropTypes.shape({ + description: PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.string, + PropTypes.shape({ + required: PropTypes.bool.isRequired, + highlightRequired: PropTypes.bool.isRequired, + description: PropTypes.string.isRequired + }) + ]) + ).isRequired, + value: PropTypes.string.isRequired, + change: PropTypes.func.isRequired, + focus: PropTypes.bool.isRequired +}); diff --git a/client/static/index.html b/client/static/index.html index 057213870..5db6d0959 100644 --- a/client/static/index.html +++ b/client/static/index.html @@ -5,6 +5,7 @@ + ARIA-AT App diff --git a/client/tests/e2e/CandidateReview.e2e.test.js b/client/tests/e2e/CandidateReview.e2e.test.js index 63894da9a..98c7811c1 100644 --- a/client/tests/e2e/CandidateReview.e2e.test.js +++ b/client/tests/e2e/CandidateReview.e2e.test.js @@ -25,38 +25,43 @@ describe('Candidate Review when not signed in or tester', () => { describe('Candidate Review when signed in as vendor', () => { it('renders page if signed in', async () => { - await getPage({ role: 'vendor', url: '/candidate-review' }, async page => { - await page.waitForSelector('h1 ::-p-text(Candidate Review)'); - - // Get section's disclosure titles - await page.waitForSelector('h3 button ::-p-text(JAWS)'); - await page.waitForSelector('h3 button ::-p-text(NVDA)'); - await page.waitForSelector('h3 button ::-p-text(VoiceOver for macOS)'); - - // Check for table headings - await page.waitForSelector('th ::-p-text(Candidate Test Plans)'); - await page.waitForSelector('th ::-p-text(Last Updated)'); - await page.waitForSelector('th ::-p-text(Target Completion Date)'); - await page.waitForSelector('th ::-p-text(Review Status)'); - await page.waitForSelector('th ::-p-text(Results Summary)'); - - await page.waitForSelector('h3 ::-p-text(Review Status Summary)'); - - // Test disclosure collapse interaction - const tableDisclosureContainerSelector = 'div#expand-at-1'; - const initialDisplayForTableDisclosureContainer = await display( - page, - tableDisclosureContainerSelector - ); - await page.click('h3 button ::-p-text(JAWS)'); - const afterClickDisplayForTableDisclosureContainer = await display( - page, - tableDisclosureContainerSelector - ); - - expect(initialDisplayForTableDisclosureContainer).not.toBe('none'); - expect(afterClickDisplayForTableDisclosureContainer).toBe('none'); - }); + await getPage( + { role: 'vendor', url: '/candidate-review' }, + async (page, { consoleErrors }) => { + await page.waitForSelector('h1 ::-p-text(Candidate Review)'); + + // Get section's disclosure titles + await page.waitForSelector('h3 button ::-p-text(JAWS)'); + await page.waitForSelector('h3 button ::-p-text(NVDA)'); + await page.waitForSelector('h3 button ::-p-text(VoiceOver for macOS)'); + + // Check for table headings + await page.waitForSelector('th ::-p-text(Candidate Test Plans)'); + await page.waitForSelector('th ::-p-text(Last Updated)'); + await page.waitForSelector('th ::-p-text(Target Completion Date)'); + await page.waitForSelector('th ::-p-text(Review Status)'); + await page.waitForSelector('th ::-p-text(Results Summary)'); + + await page.waitForSelector('h3 ::-p-text(Review Status Summary)'); + + // Test disclosure collapse interaction + const tableDisclosureContainerSelector = 'div#expand-at-1'; + const initialDisplayForTableDisclosureContainer = await display( + page, + tableDisclosureContainerSelector + ); + await page.click('h3 button ::-p-text(JAWS)'); + const afterClickDisplayForTableDisclosureContainer = await display( + page, + tableDisclosureContainerSelector + ); + + expect(initialDisplayForTableDisclosureContainer).not.toBe('none'); + expect(afterClickDisplayForTableDisclosureContainer).toBe('none'); + + expect(consoleErrors).toHaveLength(0); + } + ); }); it('navigates to candidate test plan run page', async () => { diff --git a/client/tests/e2e/DataManagement.e2e.test.js b/client/tests/e2e/DataManagement.e2e.test.js index 7032bdc1b..043a0263a 100644 --- a/client/tests/e2e/DataManagement.e2e.test.js +++ b/client/tests/e2e/DataManagement.e2e.test.js @@ -10,25 +10,32 @@ describe('Data Management common traits', () => { }); it('renders page with introduction', async () => { - await getPage({ role: false, url: '/data-management' }, async page => { - const introductionHeadingSelector = 'h2 ::-p-text(Introduction)'; - const introductionHeadingText = await text( - page, - introductionHeadingSelector - ); + await getPage( + { role: false, url: '/data-management' }, + async (page, { consoleErrors }) => { + const introductionHeadingSelector = 'h2 ::-p-text(Introduction)'; + const introductionHeadingText = await text( + page, + introductionHeadingSelector + ); + expect(introductionHeadingText).toBe('Introduction'); - const introductionContentSelector = - '[data-testid="data-management-instructions"]'; - const introductionContentText = await text( - page, - introductionContentSelector - ); + expect(consoleErrors).toHaveLength(0); - expect(introductionHeadingText).toBe('Introduction'); - expect(introductionContentText).toMatch( - /This page provides a view of the latest test plan version information, and where they currently are in the ARIA-AT Community Group’s review process\./ - ); - }); + const introductionContentSelector = + '[data-testid="data-management-instructions"]'; + const introductionContentText = await text( + page, + introductionContentSelector + ); + + expect(introductionContentText).toMatch( + /This page provides a view of the latest test plan version information, and where they currently are in the ARIA-AT Community Group’s review process\./ + ); + + expect(consoleErrors).toHaveLength(0); + } + ); }); it('renders page with Test Plan Status Summary heading and table', async () => { diff --git a/client/tests/e2e/Reports.e2e.test.js b/client/tests/e2e/Reports.e2e.test.js index a89961592..92bc8ab04 100644 --- a/client/tests/e2e/Reports.e2e.test.js +++ b/client/tests/e2e/Reports.e2e.test.js @@ -3,30 +3,36 @@ import { text } from './util'; describe('Reports page', () => { it('renders reports page', async () => { - await getPage({ role: false, url: '/reports' }, async page => { - await page.waitForSelector( - 'h1 ::-p-text(Assistive Technology Interoperability Reports)' - ); - await page.waitForSelector('h2 ::-p-text(Introduction)'); - await page.waitForSelector('h2 ::-p-text(Support Levels)'); - - const tableRowsLength = await page.$eval( - 'table[aria-label="Support Levels"]', - el => Array.from(el.rows).length - ); - - // Check that the currently 'required' reports combinations exist; these - // combinations must exist in the table to be on this page - await page.waitForSelector('th ::-p-text(Test Plan)'); - await page.waitForSelector('th ::-p-text(JAWS and Chrome)'); - await page.waitForSelector('th ::-p-text(NVDA and Chrome)'); - await page.waitForSelector( - 'th ::-p-text(VoiceOver for macOS and Safari)' - ); - - // There is more than just the thead row - expect(tableRowsLength).toBeGreaterThan(1); - }); + await getPage( + { role: false, url: '/reports' }, + async (page, { consoleErrors }) => { + await page.waitForSelector( + 'h1 ::-p-text(Assistive Technology Interoperability Reports)' + ); + + await page.waitForSelector('h2 ::-p-text(Introduction)'); + await page.waitForSelector('h2 ::-p-text(Support Levels)'); + + const tableRowsLength = await page.$eval( + 'table[aria-label="Support Levels"]', + el => Array.from(el.rows).length + ); + + // Check that the currently 'required' reports combinations exist; these + // combinations must exist in the table to be on this page + await page.waitForSelector('th ::-p-text(Test Plan)'); + await page.waitForSelector('th ::-p-text(JAWS and Chrome)'); + await page.waitForSelector('th ::-p-text(NVDA and Chrome)'); + await page.waitForSelector( + 'th ::-p-text(VoiceOver for macOS and Safari)' + ); + + // There is more than just the thead row + expect(tableRowsLength).toBeGreaterThan(1); + + expect(consoleErrors).toHaveLength(0); + } + ); }); }); diff --git a/client/tests/e2e/TestPlanVersions.e2e.test.js b/client/tests/e2e/TestPlanVersions.e2e.test.js index 11763657a..958e1d27e 100644 --- a/client/tests/e2e/TestPlanVersions.e2e.test.js +++ b/client/tests/e2e/TestPlanVersions.e2e.test.js @@ -5,11 +5,13 @@ describe('Versions page for pattern with highest report being recommended', () = it('renders page h1', async () => { await getPage( { role: false, url: '/data-management/checkbox-tri-state' }, - async page => { + async (page, { consoleErrors }) => { await text( page, 'h1 ::-p-text(Checkbox Example (Tri State) Test Plan Versions)' ); + + expect(consoleErrors).toHaveLength(0); } ); }); diff --git a/client/tests/e2e/TestQueue.e2e.test.js b/client/tests/e2e/TestQueue.e2e.test.js index 4e9793d69..f8168bed3 100644 --- a/client/tests/e2e/TestQueue.e2e.test.js +++ b/client/tests/e2e/TestQueue.e2e.test.js @@ -19,14 +19,19 @@ describe('Test Queue admin traits when reports exist', () => { }); it('renders page with instructions', async () => { - await getPage({ role: 'admin', url: '/test-queue' }, async page => { - const instructionsSelector = '[data-testid="test-queue-instructions"]'; - const instructionsText = await text(page, instructionsSelector); + await getPage( + { role: 'admin', url: '/test-queue' }, + async (page, { consoleErrors }) => { + const instructionsSelector = '[data-testid="test-queue-instructions"]'; + const instructionsText = await text(page, instructionsSelector); + + expect(instructionsText).toBe( + 'Manage the test plans, assign yourself a test plan or start executing one that is already assigned to you.' + ); - expect(instructionsText).toBe( - 'Manage the test plans, assign yourself a test plan or start executing one that is already assigned to you.' - ); - }); + expect(consoleErrors).toHaveLength(0); + } + ); }); it('renders page with known pattern sections', async () => { diff --git a/client/tests/e2e/TestReview.e2e.test.js b/client/tests/e2e/TestReview.e2e.test.js index de41c77b2..61d979c15 100644 --- a/client/tests/e2e/TestReview.e2e.test.js +++ b/client/tests/e2e/TestReview.e2e.test.js @@ -40,13 +40,18 @@ describe('Test Review page', () => { }; it('renders page for review page before test format v2', async () => { - await getPage({ role: false, url: '/test-review/1' }, async page => { - await text( - page, - 'h1 ::-p-text(Alert Example Test Plan V22.04.14 (Deprecated))' - ); - await getReviewPageElements(page); - }); + await getPage( + { role: false, url: '/test-review/1' }, + async (page, { consoleErrors }) => { + await text( + page, + 'h1 ::-p-text(Alert Example Test Plan V22.04.14 (Deprecated))' + ); + + await getReviewPageElements(page); + expect(consoleErrors).toHaveLength(0); + } + ); }); it('renders page for review page after test format v2', async () => { diff --git a/client/tests/e2e/TestRun.e2e.test.js b/client/tests/e2e/TestRun.e2e.test.js index 13f34dba6..795f78f52 100644 --- a/client/tests/e2e/TestRun.e2e.test.js +++ b/client/tests/e2e/TestRun.e2e.test.js @@ -14,58 +14,58 @@ describe('Test Run when not signed in', () => { it('renders /test-plan-report/:id and can navigate between tests', async () => { // This should be NVDA + Chrome + Modal Dialog Example with 12 tests - await getPage({ role: false, url: '/test-plan-report/19' }, async page => { - const h1Text = await text(page, 'h1'); - const currentUrl = await page.url(); - - await page.waitForSelector('nav#test-navigator-nav ol'); - const testNavigatorListItemsHandle = await page.evaluateHandle(() => { - const testNavigatorListSelector = 'nav#test-navigator-nav ol'; - const testNavigatorList = document.querySelector( - testNavigatorListSelector - ); - return Array.from(testNavigatorList.querySelectorAll('li')); - }); - - const testNavigatorListItemsMap = - await testNavigatorListItemsHandle.getProperties(); - const testNavigatorListItems = Array.from( - testNavigatorListItemsMap.values() - ); - const listItemsLength = testNavigatorListItems.length; - - // Click each navigation item and confirm the h1 on page has changed - for (const [index, li] of testNavigatorListItems.entries()) { - // Randomly navigate using the navigation link or the next button - if (Math.random()) - await li.evaluate(el => el.querySelector('a').click()); - else await page.click('button ::-p-text(Next Test)'); - - await page.waitForSelector(`h1 ::-p-text(Test ${index + 1}:)`); - await page.waitForSelector( - `div[class="info-label"] ::-p-text(Test Plan:)` - ); - await page.waitForSelector(`div[class="info-label"] ::-p-text(AT:)`); - await page.waitForSelector( - `div[class="info-label"] ::-p-text(Browser:)` - ); - await page.waitForSelector( - `div[class="info-label"] ::-p-text(${listItemsLength} tests to view)` - ); - await page.waitForSelector(`h2 ::-p-text(Instructions)`); - await page.waitForSelector(`h2 ::-p-text(Record Results)`); - await page.waitForSelector(`h3 ::-p-text(After)`); + await getPage( + { role: false, url: '/test-plan-report/19' }, + async (page, { consoleErrors }) => { + const h1Text = await text(page, 'h1'); + expect(h1Text.includes('Test 1:')).toBe(true); + + await page.waitForSelector('nav#test-navigator-nav ol'); + const testNavigatorListItemsHandle = await page.evaluateHandle(() => { + const testNavigatorListSelector = 'nav#test-navigator-nav ol'; + const testNavigatorList = document.querySelector( + testNavigatorListSelector + ); + return Array.from(testNavigatorList.querySelectorAll('li')); + }); - const updatedUrl = await page.url(); - expect(updatedUrl).toMatch( - new RegExp(`/test-plan-report/19#${index + 1}$`) + const testNavigatorListItemsMap = + await testNavigatorListItemsHandle.getProperties(); + const testNavigatorListItems = Array.from( + testNavigatorListItemsMap.values() ); + const listItemsLength = testNavigatorListItems.length; + + // Click each navigation item and confirm the h1 on page has changed + for (const [index, li] of testNavigatorListItems.entries()) { + // Randomly navigate using the navigation link or the next button + if (Math.random()) + await li.evaluate(el => el.querySelector('a').click()); + else await page.click('button ::-p-text(Next Test)'); + + await page.waitForSelector(`h1 ::-p-text(Test ${index + 1}:)`); + await page.waitForSelector( + `div[class="info-label"] ::-p-text(Test Plan:)` + ); + await page.waitForSelector(`div[class="info-label"] ::-p-text(AT:)`); + await page.waitForSelector( + `div[class="info-label"] ::-p-text(Browser:)` + ); + await page.waitForSelector( + `div[class="info-label"] ::-p-text(${listItemsLength} tests to view)` + ); + await page.waitForSelector(`h2 ::-p-text(Instructions)`); + await page.waitForSelector(`h2 ::-p-text(Record Results)`); + await page.waitForSelector(`h3 ::-p-text(After)`); + + const updatedUrl = await page.url(); + expect(updatedUrl).toMatch( + new RegExp(`/test-plan-report/19#${index + 1}$`) + ); + } + expect(consoleErrors).toHaveLength(0); } - - expect(h1Text.includes('Test 1:')).toBe(true); - expect(currentUrl.includes('/test-plan-report/19')).toBe(true); - expect(listItemsLength).toBeGreaterThan(1); - }); + ); }); }); diff --git a/client/tests/e2e/UserSettings.e2e.test.js b/client/tests/e2e/UserSettings.e2e.test.js index 49257f7a9..f796b7f4a 100644 --- a/client/tests/e2e/UserSettings.e2e.test.js +++ b/client/tests/e2e/UserSettings.e2e.test.js @@ -44,41 +44,47 @@ describe('User Settings common traits', () => { }); it('renders testable assistive technologies status and update on save', async () => { - await getPage({ role: 'tester', url: '/account/settings' }, async page => { - const testableAtsStatusTextBeforeSave = await text( - page, - 'p[data-testid="testable-ats-status"]' - ); - const jawsOptionSelector = 'input[id="1"][type="checkbox"]'; - const nvdaOptionSelector = 'input[id="2"][type="checkbox"]'; - const saveButtonSelector = 'button[type="submit"]'; - const saveButtonText = await text(page, saveButtonSelector); + await getPage( + { role: 'tester', url: '/account/settings' }, + async (page, { consoleErrors }) => { + const testableAtsStatusTextBeforeSave = await text( + page, + 'p[data-testid="testable-ats-status"]' + ); + expect(testableAtsStatusTextBeforeSave).toBe( + 'You have not yet selected any assistive technologies.' + ); - await page.click(jawsOptionSelector); - await page.click(nvdaOptionSelector); - await page.click(saveButtonSelector); + const jawsOptionSelector = 'input[id="1"][type="checkbox"]'; + const nvdaOptionSelector = 'input[id="2"][type="checkbox"]'; + const saveButtonSelector = 'button[type="submit"]'; + const saveButtonText = await text(page, saveButtonSelector); - await page.waitForNetworkIdle(); + await page.click(jawsOptionSelector); + await page.click(nvdaOptionSelector); + await page.click(saveButtonSelector); - const testableAtsStatusTextAfterSave = await text( - page, - 'p[data-testid="testable-ats-status"]' - ); - const selectedAtsListItems = await page.$eval('ul', el => { - const liElements = el.querySelectorAll('li'); - return Array.from(liElements, li => li.innerText.trim()); - }); + await page.waitForNetworkIdle(); - expect(saveButtonText).toBe('Save'); - expect(testableAtsStatusTextBeforeSave).toBe( - 'You have not yet selected any assistive technologies.' - ); - expect(testableAtsStatusTextAfterSave).toBe( - 'You can currently test the following assistive technologies:' - ); - expect(selectedAtsListItems.length).toBe(2); - expect(selectedAtsListItems.includes('JAWS')).toBe(true); - expect(selectedAtsListItems.includes('NVDA')).toBe(true); - }); + const testableAtsStatusTextAfterSave = await text( + page, + 'p[data-testid="testable-ats-status"]' + ); + const selectedAtsListItems = await page.$eval('ul', el => { + const liElements = el.querySelectorAll('li'); + return Array.from(liElements, li => li.innerText.trim()); + }); + + expect(saveButtonText).toBe('Save'); + expect(testableAtsStatusTextAfterSave).toBe( + 'You can currently test the following assistive technologies:' + ); + expect(selectedAtsListItems.length).toBe(2); + expect(selectedAtsListItems.includes('JAWS')).toBe(true); + expect(selectedAtsListItems.includes('NVDA')).toBe(true); + + expect(consoleErrors).toHaveLength(0); + } + ); }); }); diff --git a/client/tests/e2e/snapshots/saved/_.html b/client/tests/e2e/snapshots/saved/_.html index 731c7809a..1b0fdcadb 100644 --- a/client/tests/e2e/snapshots/saved/_.html +++ b/client/tests/e2e/snapshots/saved/_.html @@ -5,6 +5,7 @@ + Home | ARIA-AT diff --git a/client/tests/e2e/snapshots/saved/_404.html b/client/tests/e2e/snapshots/saved/_404.html index 025770160..3e7edfdea 100644 --- a/client/tests/e2e/snapshots/saved/_404.html +++ b/client/tests/e2e/snapshots/saved/_404.html @@ -5,6 +5,7 @@ + Page Not Found | ARIA-AT diff --git a/client/tests/e2e/snapshots/saved/_account_settings.html b/client/tests/e2e/snapshots/saved/_account_settings.html index dbbc8ef09..460460d0f 100644 --- a/client/tests/e2e/snapshots/saved/_account_settings.html +++ b/client/tests/e2e/snapshots/saved/_account_settings.html @@ -5,6 +5,7 @@ + Settings | ARIA-AT diff --git a/client/tests/e2e/snapshots/saved/_candidate-review.html b/client/tests/e2e/snapshots/saved/_candidate-review.html index 417a14e3d..4fb2ede26 100644 --- a/client/tests/e2e/snapshots/saved/_candidate-review.html +++ b/client/tests/e2e/snapshots/saved/_candidate-review.html @@ -5,6 +5,7 @@ + Candidate Review | ARIA-AT diff --git a/client/tests/e2e/snapshots/saved/_candidate-test-plan_24_1.html b/client/tests/e2e/snapshots/saved/_candidate-test-plan_24_1.html index 7b63ae7a9..a2732a7b2 100644 --- a/client/tests/e2e/snapshots/saved/_candidate-test-plan_24_1.html +++ b/client/tests/e2e/snapshots/saved/_candidate-test-plan_24_1.html @@ -5,6 +5,7 @@ + Candidate Test Run Page | ARIA-AT diff --git a/client/tests/e2e/snapshots/saved/_data-management.html b/client/tests/e2e/snapshots/saved/_data-management.html index 0cc8608bf..0569b4f95 100644 --- a/client/tests/e2e/snapshots/saved/_data-management.html +++ b/client/tests/e2e/snapshots/saved/_data-management.html @@ -5,6 +5,7 @@ + Data Management | ARIA-AT @@ -209,7 +210,7 @@

@@ -622,7 +623,7 @@

Test Plans Status Summary

R&D -

Complete Mar 17, 2022

+

Complete Aug 8, 2024

@@ -1094,7 +1095,7 @@

Test Plans Status Summary

V22.03.17-1V24.08.08