From 7d592865b17197175e23ce1cb6de6d1ce4ea6444 Mon Sep 17 00:00:00 2001 From: Wahaj <32555133+waabid@users.noreply.github.com> Date: Thu, 14 May 2020 14:16:51 -0700 Subject: [PATCH 01/15] feat(nav-bar-content): adding requirement table section (#2681) --- .../left-nav/requirement-table-section.tsx | 86 +++++++++++++++++++ .../requirement-table-section.test.tsx.snap | 64 ++++++++++++++ .../requirement-table-section.test.tsx | 84 ++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 src/DetailsView/components/left-nav/requirement-table-section.tsx create mode 100644 src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/requirement-table-section.test.tsx.snap create mode 100644 src/tests/unit/tests/DetailsView/components/left-nav/requirement-table-section.test.tsx diff --git a/src/DetailsView/components/left-nav/requirement-table-section.tsx b/src/DetailsView/components/left-nav/requirement-table-section.tsx new file mode 100644 index 00000000000..91cd7adfa28 --- /dev/null +++ b/src/DetailsView/components/left-nav/requirement-table-section.tsx @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { AssessmentDefaultMessageGenerator } from 'assessments/assessment-default-message-generator'; +import { AssessmentsProvider } from 'assessments/types/assessments-provider'; +import { Requirement } from 'assessments/types/requirement'; +import { NamedFC } from 'common/react/named-fc'; +import { + AssessmentNavState, + GeneratedAssessmentInstance, + ManualTestStepResult, +} from 'common/types/store-data/assessment-result-data'; +import { FeatureFlagStoreData } from 'common/types/store-data/feature-flag-store-data'; +import { PathSnippetStoreData } from 'common/types/store-data/path-snippet-store-data'; +import { AssessmentInstanceTable } from 'DetailsView/components/assessment-instance-table'; +import { ManualTestStepView } from 'DetailsView/components/manual-test-step-view'; +import { AssessmentInstanceTableHandler } from 'DetailsView/handlers/assessment-instance-table-handler'; +import { Spinner, SpinnerSize } from 'office-ui-fabric-react'; +import * as React from 'react'; +import { DictionaryStringTo } from 'types/common-types'; + +export type RequirementTableSectionProps = { + assessmentNavState: AssessmentNavState; + requirement: Requirement; + instancesMap: DictionaryStringTo; + assessmentInstanceTableHandler: AssessmentInstanceTableHandler; + assessmentsProvider: AssessmentsProvider; + featureFlagStoreData: FeatureFlagStoreData; + pathSnippetStoreData: PathSnippetStoreData; + scanningInProgress: boolean; + manualRequirementResultMap: DictionaryStringTo; + assessmentDefaultMessageGenerator: AssessmentDefaultMessageGenerator; + isRequirementScanned: boolean; + selectedRequirementHasVisualHelper: boolean; +}; + +export const RequirementTableSection = NamedFC( + 'RequirementTableSection', + props => { + if (props.requirement.isManual) { + return ( + + ); + } + + if (props.scanningInProgress) { + return ( + + ); + } + + const renderScanCompleteAlert = () => { + if (!props.requirement.isManual && props.isRequirementScanned) { + return
; + } + }; + + return ( + + {renderScanCompleteAlert()} +

Instances

+ +
+ ); + }, +); diff --git a/src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/requirement-table-section.test.tsx.snap b/src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/requirement-table-section.test.tsx.snap new file mode 100644 index 00000000000..7bc3fac42a5 --- /dev/null +++ b/src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/requirement-table-section.test.tsx.snap @@ -0,0 +1,64 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RequirementTableSection render ManualTestStepView when requirement is manual 1`] = ` + +`; + +exports[`RequirementTableSection render Spinner when scanning in progress 1`] = ` + +`; + +exports[`RequirementTableSection render instance table 1`] = ` + +

+ Instances +

+ +
+`; diff --git a/src/tests/unit/tests/DetailsView/components/left-nav/requirement-table-section.test.tsx b/src/tests/unit/tests/DetailsView/components/left-nav/requirement-table-section.test.tsx new file mode 100644 index 00000000000..4be15f5f700 --- /dev/null +++ b/src/tests/unit/tests/DetailsView/components/left-nav/requirement-table-section.test.tsx @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { AssessmentsProvider } from 'assessments/types/assessments-provider'; +import { Requirement } from 'assessments/types/requirement'; +import { ManualTestStepResult } from 'common/types/store-data/assessment-result-data'; +import { FeatureFlagStoreData } from 'common/types/store-data/feature-flag-store-data'; +import { PathSnippetStoreData } from 'common/types/store-data/path-snippet-store-data'; +import { + RequirementTableSection, + RequirementTableSectionProps, +} from 'DetailsView/components/left-nav/requirement-table-section'; +import { AssessmentInstanceTableHandler } from 'DetailsView/handlers/assessment-instance-table-handler'; +import { shallow } from 'enzyme'; +import * as React from 'react'; +import { DictionaryStringTo } from 'types/common-types'; + +describe('RequirementTableSection', () => { + let props: RequirementTableSectionProps; + let manualRequirementResultMapStub: DictionaryStringTo; + let assessmentInstanceTableHandlerStub: AssessmentInstanceTableHandler; + let assessmentProviderStub: AssessmentsProvider; + let featureFlagStoreDataStub: FeatureFlagStoreData; + let pathSnippetStoreDataStub: PathSnippetStoreData; + + beforeEach(() => { + assessmentInstanceTableHandlerStub = { + changeRequirementStatus: null, + } as AssessmentInstanceTableHandler; + manualRequirementResultMapStub = { + 'some manual test step result id': null, + }; + assessmentProviderStub = { + all: null, + } as AssessmentsProvider; + featureFlagStoreDataStub = { + 'some feature flag': true, + }; + pathSnippetStoreDataStub = { + path: null, + } as PathSnippetStoreData; + + props = { + assessmentNavState: { + selectedTestSubview: 'some test view', + selectedTestType: -1, + }, + manualRequirementResultMap: manualRequirementResultMapStub, + assessmentInstanceTableHandler: assessmentInstanceTableHandlerStub, + assessmentsProvider: assessmentProviderStub, + featureFlagStoreData: featureFlagStoreDataStub, + pathSnippetStoreData: pathSnippetStoreDataStub, + requirement: { + isManual: false, + getDefaultMessage: _ => null, + renderInstanceTableHeader: (_, a) => null, + }, + } as RequirementTableSectionProps; + }); + + test('render ManualTestStepView when requirement is manual', () => { + props.requirement = { + isManual: true, + } as Requirement; + + const testObject = shallow(); + + expect(testObject.getElement()).toMatchSnapshot(); + }); + + test('render Spinner when scanning in progress', () => { + props.scanningInProgress = true; + + const testObject = shallow(); + + expect(testObject.getElement()).toMatchSnapshot(); + }); + + test('render instance table', () => { + const testObject = shallow(); + + expect(testObject.getElement()).toMatchSnapshot(); + }); +}); From 010f34e1d2936e2415f530f928d99caaf4860837 Mon Sep 17 00:00:00 2001 From: Dan Bjorge Date: Thu, 14 May 2020 14:58:34 -0700 Subject: [PATCH 02/15] fix: auto-pass main landmark requirements for no-landmark pages (#2644) #### Description of changes #2521 tracks an issue where it wasn't clear what the expectations on a user were for testing the Landmarks "primary content" and "no repeating content" requirements on pages with no landmarks. The proposed fix for that was a text update + making the requirements pass automatically on pages that have no landmarks. This fix involves a significant bit of new behavior. We wanted to *keep* the 2 requirements in question as manual requirements, not assisted requirements, since it's possible for a page to have no main landmarks and for a user to need to manually enter a failure not associated with any instance we might show in an instance list. However, this is the first time we're assigning auto-pass behavior to a manual test; in all other cases where we support auto-pass, it works by looking for an assisted requirement with no matching instances. This new behavior is especially challenging because the set of instances required for auto-passing ("are there **any** landmarks on the page?") is different from the set of instances required for visualization ("what are all the **main** landmarks on the page?"). To support this, I've added 2 new features to `AssessmentStore`'s `Requirement` processing: * A new `isVisualizationSupportedForResult` property which `Requirement`s can use to indicate that certain results returned by their analyzers should not support being visualized (by default, all results support visualization) * A new `getInitialManualTestStatus` property which manual `Requirement`s can use to infer an initial pass/fail state after scanning for results (by default, a manual requirement is put in the UNKNOWN state regardless of analysis results) These are used by the updated requirements by updating their analyzers to use the `unique-landmark` rule to look for *all* landmarks instead of the old behavior of looking only for main landmarks, use `isVisualizationSupportedForResult` to only visualize the main landmarks (like before), and use `getInitialManualTestStatus` to set a "PASS" status if the scan completes and there are no instances with the landmark role data from the `unique-landmark` rule. New behavior: **no landmarks: "Primary content" and "No repeating content" automatically pass** ![screen recording of no-landmarks interactions](https://user-images.githubusercontent.com/376284/81753659-1ef3ea00-9469-11ea-8646-e394ffff61de.gif) **only non-main landmarks: "Primary content" and "No repeating content" don't auto-pass and show no matching instances to visualize** ![screen recording of banner-landmark-only interactions](https://user-images.githubusercontent.com/376284/81753648-1ac7cc80-9469-11ea-9c90-05f8d7243088.gif) **Mix of main and non-main landmarks: "Primary content" and "No repeating content" don't auto-pass and visualize only the main landmark** ![screen recording of mixed-landmarks interactions](https://user-images.githubusercontent.com/376284/81753619-0a175680-9469-11ea-9d6e-40131889cf46.gif) #### Pull request checklist - [x] Addresses an existing issue: #2521 - [x] Ran `yarn fastpass` - [x] Added/updated relevant unit test(s) (and ran `yarn test`) - [x] Verified code coverage for the changes made. Check coverage report at: `/test-results/unit/coverage` - [x] PR title *AND* final merge commit title both start with a semantic tag (`fix:`, `chore:`, `feat(feature-name):`, `refactor:`). See `CONTRIBUTING.md`. - [x] (UI changes only) Added screenshots/GIFs to description above - [x] (UI changes only) Verified usability with NVDA/JAWS --- ...ssessment-visualization-enabled-toggle.tsx | 17 +- src/assessments/assessment-builder.tsx | 20 + .../landmarks/auto-pass-if-no-landmarks.ts | 14 + .../landmarks/does-result-have-main-role.ts | 13 + .../test-steps/no-repeating-content.tsx | 38 +- .../landmarks/test-steps/primary-content.tsx | 42 +- src/assessments/types/requirement.ts | 8 + src/background/assessment-data-converter.ts | 7 + src/background/stores/assessment-store.ts | 58 +- .../store-data/assessment-result-data.ts | 1 + src/scanner/custom-rule-configurations.ts | 2 - src/scanner/custom-rules/landmark-rule.ts | 15 - .../visual-helper-toggle-config-builder.ts | 32 +- ...ment-visualization-enabled-toggle.test.tsx | 324 ++++++----- .../auto-pass-if-no-landmarks.test.ts | 40 ++ .../does-result-have-main-role.test.ts | 71 +++ .../assessment-data-converter.test.ts | 543 +++++++++--------- .../assessment-store.test.ts.snap | 4 +- .../stores/assessment-store.test.ts | 316 ++++++++-- .../custom-rules/landmark-role.test.ts | 14 - 20 files changed, 1049 insertions(+), 530 deletions(-) create mode 100644 src/assessments/landmarks/auto-pass-if-no-landmarks.ts create mode 100644 src/assessments/landmarks/does-result-have-main-role.ts delete mode 100644 src/scanner/custom-rules/landmark-rule.ts create mode 100644 src/tests/unit/tests/assessments/landmarks/auto-pass-if-no-landmarks.test.ts create mode 100644 src/tests/unit/tests/assessments/landmarks/does-result-have-main-role.test.ts delete mode 100644 src/tests/unit/tests/scanner/custom-rules/landmark-role.test.ts diff --git a/src/DetailsView/components/assessment-visualization-enabled-toggle.tsx b/src/DetailsView/components/assessment-visualization-enabled-toggle.tsx index d3ef06bcf53..461e78ad1c3 100644 --- a/src/DetailsView/components/assessment-visualization-enabled-toggle.tsx +++ b/src/DetailsView/components/assessment-visualization-enabled-toggle.tsx @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { GeneratedAssessmentInstance } from 'common/types/store-data/assessment-result-data'; -import { isEmpty } from 'lodash'; import { BaseVisualHelperToggle } from './base-visual-helper-toggle'; export class AssessmentVisualizationEnabledToggle extends BaseVisualHelperToggle { - protected isDisabled(filteredInstances: GeneratedAssessmentInstance<{}, {}>[]): boolean { - return isEmpty(filteredInstances); + protected isDisabled(instances: GeneratedAssessmentInstance<{}, {}>[]): boolean { + return !this.isAnyInstanceVisualizable(instances); } protected isChecked(instances: GeneratedAssessmentInstance<{}, {}>[]): boolean { @@ -28,10 +27,16 @@ export class AssessmentVisualizationEnabledToggle extends BaseVisualHelperToggle }; private isAnyInstanceVisible(instances: GeneratedAssessmentInstance<{}, {}>[]): boolean { + const testStep = this.props.assessmentNavState.selectedTestSubview; return instances.some( - instance => - instance.testStepResults[this.props.assessmentNavState.selectedTestSubview] - .isVisualizationEnabled, + instance => instance.testStepResults[testStep].isVisualizationEnabled, + ); + } + + private isAnyInstanceVisualizable(instances: GeneratedAssessmentInstance<{}, {}>[]): boolean { + const testStep = this.props.assessmentNavState.selectedTestSubview; + return instances.some( + instance => instance.testStepResults[testStep].isVisualizationSupported, ); } } diff --git a/src/assessments/assessment-builder.tsx b/src/assessments/assessment-builder.tsx index b150d41e3b5..a01c3f3bed5 100644 --- a/src/assessments/assessment-builder.tsx +++ b/src/assessments/assessment-builder.tsx @@ -10,6 +10,7 @@ import { RequirementComparer } from 'common/assessment/requirement-comparer'; import { AssessmentVisualizationConfiguration } from 'common/configs/assessment-visualization-configuration'; import { Messages } from 'common/messages'; import { ManualTestStatus } from 'common/types/manual-test-status'; +import { InstanceIdToInstanceDataMap } from 'common/types/store-data/assessment-result-data'; import { FeatureFlagStoreData } from 'common/types/store-data/feature-flag-store-data'; import { AssessmentScanData, ScanData } from 'common/types/store-data/visualization-store-data'; import { @@ -52,6 +53,15 @@ export class AssessmentBuilder { requirement.getInstanceStatus = AssessmentBuilder.getInstanceStatus; } + if (!requirement.getInitialManualTestStatus) { + requirement.getInitialManualTestStatus = AssessmentBuilder.getInitialManualTestStatus; + } + + if (!requirement.isVisualizationSupportedForResult) { + requirement.isVisualizationSupportedForResult = + AssessmentBuilder.isVisualizationSupportedForResult; + } + if (!requirement.getInstanceStatusColumns) { requirement.getInstanceStatusColumns = AssessmentBuilder.getInstanceStatusColumns; } @@ -75,6 +85,16 @@ export class AssessmentBuilder { return ManualTestStatus.UNKNOWN; } + private static getInitialManualTestStatus( + instances: InstanceIdToInstanceDataMap, + ): ManualTestStatus { + return ManualTestStatus.UNKNOWN; + } + + private static isVisualizationSupportedForResult(result: DecoratedAxeNodeResult): boolean { + return true; + } + private static getInstanceStatusColumns(): Readonly[] { return [ { diff --git a/src/assessments/landmarks/auto-pass-if-no-landmarks.ts b/src/assessments/landmarks/auto-pass-if-no-landmarks.ts new file mode 100644 index 00000000000..4a2d28673a8 --- /dev/null +++ b/src/assessments/landmarks/auto-pass-if-no-landmarks.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { ManualTestStatus } from 'common/types/manual-test-status'; +import { InstanceIdToInstanceDataMap } from 'common/types/store-data/assessment-result-data'; +import { some } from 'lodash'; + +export function autoPassIfNoLandmarks(instanceData: InstanceIdToInstanceDataMap): ManualTestStatus { + const someInstanceHasLandmarkRole = some( + Object.values(instanceData), + instance => instance.propertyBag != null && instance.propertyBag['role'] != null, + ); + + return someInstanceHasLandmarkRole ? ManualTestStatus.UNKNOWN : ManualTestStatus.PASS; +} diff --git a/src/assessments/landmarks/does-result-have-main-role.ts b/src/assessments/landmarks/does-result-have-main-role.ts new file mode 100644 index 00000000000..5a99b888217 --- /dev/null +++ b/src/assessments/landmarks/does-result-have-main-role.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { DecoratedAxeNodeResult } from 'injected/scanner-utils'; +import { some } from 'lodash'; + +export function doesResultHaveMainRole(result: DecoratedAxeNodeResult): boolean { + // This 'role' data is populated by the unique-landmark rule, which considers + // both explicit role attributes and implicit roles based on tag name + return ( + some(result.any, checkResult => checkResult.data['role'] === 'main') || + some(result.all, checkResult => checkResult.data['role'] === 'main') + ); +} diff --git a/src/assessments/landmarks/test-steps/no-repeating-content.tsx b/src/assessments/landmarks/test-steps/no-repeating-content.tsx index 9a0a84860b5..f10f2c03485 100644 --- a/src/assessments/landmarks/test-steps/no-repeating-content.tsx +++ b/src/assessments/landmarks/test-steps/no-repeating-content.tsx @@ -2,6 +2,7 @@ // Licensed under the MIT License. import * as React from 'react'; +import { doesResultHaveMainRole } from 'assessments/landmarks/does-result-have-main-role'; import { VisualizationType } from 'common/types/visualization-type'; import { link } from 'content/link'; import * as content from 'content/test/landmarks/no-repeating-content'; @@ -10,10 +11,14 @@ import { AnalyzerConfigurationFactory } from '../../common/analyzer-configuratio import { ManualTestRecordYourResults } from '../../common/manual-test-record-your-results'; import * as Markup from '../../markup'; import { Requirement } from '../../types/requirement'; +import { autoPassIfNoLandmarks } from '../auto-pass-if-no-landmarks'; import { LandmarkTestStep } from './test-steps'; const description: JSX.Element = ( - The main landmark must not contain any blocks of content that repeat across pages. + + The main landmark must not contain any blocks of content + that repeat across pages. + ); const howToTest: JSX.Element = ( @@ -22,10 +27,33 @@ const howToTest: JSX.Element = ( The visual helper for this requirement highlights the page's{' '} main landmark.

+

+ + Note: If no landmarks are found, this requirement will automatically be marked as + pass. + +

  1. - In the target page, examine the main landmark to verify that it does not contain any - blocks of content that repeat across pages (e.g., site-wide navigation links). +

    Examine the target page to verify that all of the following are true:

    +
      +
    1. + The page has exactly one main landmark, + and +
    2. +
    3. + The main landmark does not contain any + blocks of content that repeat across pages (such as site-wide navigation + links). +
    4. +
    +

    + Exception: If a page has nested document or{' '} + application roles (typically applied to{' '} + or elements), + each nested document or application may also{' '} + have one main landmark. +

@@ -38,11 +66,13 @@ export const NoRepeatingContent: Requirement = { description, howToTest, isManual: true, + getInitialManualTestStatus: autoPassIfNoLandmarks, + isVisualizationSupportedForResult: doesResultHaveMainRole, guidanceLinks: [link.WCAG_1_3_1, link.WCAG_2_4_1], getAnalyzer: provider => provider.createRuleAnalyzer( AnalyzerConfigurationFactory.forScanner({ - rules: ['main-landmark'], + rules: ['unique-landmark'], key: LandmarkTestStep.noRepeatingContent, testType: VisualizationType.LandmarksAssessment, }), diff --git a/src/assessments/landmarks/test-steps/primary-content.tsx b/src/assessments/landmarks/test-steps/primary-content.tsx index 6f13b711e4f..f76a938feac 100644 --- a/src/assessments/landmarks/test-steps/primary-content.tsx +++ b/src/assessments/landmarks/test-steps/primary-content.tsx @@ -2,6 +2,7 @@ // Licensed under the MIT License. import * as React from 'react'; +import { doesResultHaveMainRole } from 'assessments/landmarks/does-result-have-main-role'; import { VisualizationType } from 'common/types/visualization-type'; import { link } from 'content/link'; import * as content from 'content/test/landmarks/primary-content'; @@ -10,19 +11,48 @@ import { AnalyzerConfigurationFactory } from '../../common/analyzer-configuratio import { ManualTestRecordYourResults } from '../../common/manual-test-record-your-results'; import * as Markup from '../../markup'; import { Requirement } from '../../types/requirement'; +import { autoPassIfNoLandmarks } from '../auto-pass-if-no-landmarks'; import { LandmarkTestStep } from './test-steps'; const description: JSX.Element = ( - The main landmark must contain all of the page's primary content. + + The main landmark must contain all of the page's primary + content. + ); const howToTest: JSX.Element = (
-

The visual helper for this requirement highlights the page's main landmark.

+

+ The visual helper for this requirement highlights the page's{' '} + main landmark. +

+

+ + Note: If no landmarks are found, this requirement will automatically be marked as + pass. + +

  1. - In the target page, examine the main landmark to - verify that it contains all of the page's primary content. +

    Examine the target page to verify that all of the following are true:

    +
      +
    1. + The page has exactly one main landmark, + and +
    2. +
    3. + The main landmark contains all of the + page's primary content. +
    4. +
    +

    + Exception: If a page has nested document or{' '} + application roles (typically applied to{' '} + or elements), + each nested document or application may also{' '} + have one main landmark. +

@@ -35,11 +65,13 @@ export const PrimaryContent: Requirement = { description, howToTest, isManual: true, + getInitialManualTestStatus: autoPassIfNoLandmarks, + isVisualizationSupportedForResult: doesResultHaveMainRole, guidanceLinks: [link.WCAG_1_3_1, link.WCAG_2_4_1], getAnalyzer: provider => provider.createRuleAnalyzer( AnalyzerConfigurationFactory.forScanner({ - rules: ['main-landmark'], + rules: ['unique-landmark'], key: LandmarkTestStep.primaryContent, testType: VisualizationType.LandmarksAssessment, }), diff --git a/src/assessments/types/requirement.ts b/src/assessments/types/requirement.ts index 2656094ff08..8ccb7fc4560 100644 --- a/src/assessments/types/requirement.ts +++ b/src/assessments/types/requirement.ts @@ -5,6 +5,7 @@ import { ManualTestStatus } from 'common/types/manual-test-status'; import { AssessmentNavState, GeneratedAssessmentInstance, + InstanceIdToInstanceDataMap, } from 'common/types/store-data/assessment-result-data'; import { FeatureFlagStoreData } from 'common/types/store-data/feature-flag-store-data'; import { DetailsViewActionMessageCreator } from 'DetailsView/actions/details-view-action-message-creator'; @@ -39,10 +40,17 @@ export interface Requirement { addFailureInstruction?: string; infoAndExamples?: ContentPageComponent; isManual: boolean; + // This is for semi-manual cases where we can't present a list of instances like an assisted + // test would, but can infer a PASS or FAIL state. If not specified, acts like () => UNKNOWN. + getInitialManualTestStatus?: (instances: InstanceIdToInstanceDataMap) => ManualTestStatus; guidanceLinks: HyperlinkDefinition[]; columnsConfig?: InstanceTableColumn[]; getAnalyzer?: (provider: AnalyzerProvider) => Analyzer; getVisualHelperToggle?: (props: VisualHelperToggleConfig) => JSX.Element; + // Any results this returns false for will be omitted from visual helper displays, but still + // present for the purposes of instance lists or getInitialManualTestStatus. By default, all + // results support visualization. + isVisualizationSupportedForResult?: (result: DecoratedAxeNodeResult) => boolean; visualizationInstanceProcessor?: VisualizationInstanceProcessorCallback< PropertyBags, PropertyBags diff --git a/src/background/assessment-data-converter.ts b/src/background/assessment-data-converter.ts index 0c5c7d24522..edc68817be1 100644 --- a/src/background/assessment-data-converter.ts +++ b/src/background/assessment-data-converter.ts @@ -29,6 +29,7 @@ export class AssessmentDataConverter { stepName: string, generateInstanceIdentifier: (instance: UniquelyIdentifiableInstances) => string, getInstanceStatus: (result: DecoratedAxeNodeResult) => ManualTestStatus, + isVisualizationSupported: (result: DecoratedAxeNodeResult) => boolean, ): AssessmentInstancesMap { let instancesMap: AssessmentInstancesMap = {}; @@ -51,6 +52,7 @@ export class AssessmentDataConverter { stepName, ruleResult, getInstanceStatus, + isVisualizationSupported, ); } }); @@ -98,6 +100,7 @@ export class AssessmentDataConverter { testStep: string, ruleResult: DecoratedAxeNodeResult, getInstanceStatus: (result: DecoratedAxeNodeResult) => ManualTestStatus, + isVisualizationSupported: (result: DecoratedAxeNodeResult) => boolean, ): GeneratedAssessmentInstance { const target: string[] = elementAxeResult.target; let testStepResults = {}; @@ -114,6 +117,7 @@ export class AssessmentDataConverter { ruleResult, elementAxeResult, getInstanceStatus, + isVisualizationSupported, ); let actualPropertyBag = { @@ -163,6 +167,7 @@ export class AssessmentDataConverter { status: ManualTestStatus.UNKNOWN, isCapturedByUser: false, failureSummary: null, + isVisualizationSupported: true, isVisualizationEnabled: true, isVisible: true, }; @@ -172,12 +177,14 @@ export class AssessmentDataConverter { ruleResult: DecoratedAxeNodeResult, elementAxeResult: HtmlElementAxeResults, getInstanceStatus: (result: DecoratedAxeNodeResult) => ManualTestStatus, + isVisualizationSupported: (result: DecoratedAxeNodeResult) => boolean, ): TestStepResult { return { id: ruleResult.id, status: getInstanceStatus(ruleResult), isCapturedByUser: false, failureSummary: ruleResult.failureSummary, + isVisualizationSupported: isVisualizationSupported(ruleResult), isVisualizationEnabled: false, isVisible: true, }; diff --git a/src/background/stores/assessment-store.ts b/src/background/stores/assessment-store.ts index e8f9e7d7ce9..a2a5e4108d8 100644 --- a/src/background/stores/assessment-store.ts +++ b/src/background/stores/assessment-store.ts @@ -11,6 +11,7 @@ import { AssessmentData, AssessmentStoreData, GeneratedAssessmentInstance, + InstanceIdToInstanceDataMap, TestStepResult, UserCapturedInstance, } from 'common/types/store-data/assessment-result-data'; @@ -272,16 +273,17 @@ export class AssessmentStore extends BaseStoreImpl { private onChangeAssessmentVisualizationStateForAll = ( payload: ChangeInstanceSelectionPayload, ): void => { - const config = this.assessmentsProvider - .forType(payload.test) - .getVisualizationConfiguration(); + const { test, requirement } = payload; + const config = this.assessmentsProvider.forType(test).getVisualizationConfiguration(); const assessmentDataMap = config.getAssessmentData(this.state) .generatedAssessmentInstancesMap; + forEach(assessmentDataMap, val => { - const stepResult = val.testStepResults[payload.requirement]; + const stepResult = val.testStepResults[requirement]; if (stepResult != null) { - stepResult.isVisualizationEnabled = payload.isVisualizationEnabled; + stepResult.isVisualizationEnabled = + stepResult.isVisualizationSupported && payload.isVisualizationEnabled; } }); @@ -318,15 +320,14 @@ export class AssessmentStore extends BaseStoreImpl { private onChangeAssessmentVisualizationState = ( payload: ChangeInstanceSelectionPayload, ): void => { - const config = this.assessmentsProvider - .forType(payload.test) - .getVisualizationConfiguration(); + const { test, requirement } = payload; + const config = this.assessmentsProvider.forType(test).getVisualizationConfiguration(); const assessmentData = config.getAssessmentData(this.state); - const stepResult: TestStepResult = - assessmentData.generatedAssessmentInstancesMap[payload.selector].testStepResults[ - payload.requirement - ]; - stepResult.isVisualizationEnabled = payload.isVisualizationEnabled; + const instance = assessmentData.generatedAssessmentInstancesMap[payload.selector]; + const stepResult: TestStepResult = instance.testStepResults[requirement]; + + stepResult.isVisualizationEnabled = + stepResult.isVisualizationSupported && payload.isVisualizationEnabled; this.emitChanged(); }; @@ -382,6 +383,7 @@ export class AssessmentStore extends BaseStoreImpl { step, config.getInstanceIdentiferGenerator(step), stepConfig.getInstanceStatus, + stepConfig.isVisualizationSupportedForResult, ); assessmentData.generatedAssessmentInstancesMap = generatedAssessmentInstancesMap; assessmentData.testStepStatus[step].isStepScanned = true; @@ -432,12 +434,38 @@ export class AssessmentStore extends BaseStoreImpl { testStepName: string, testType: VisualizationType, ): void { - const isManual = this.assessmentsProvider.getStep(testType, testStepName).isManual; - if (isManual !== true) { + const step = this.assessmentsProvider.getStep(testType, testStepName); + const { isManual, getInitialManualTestStatus } = step; + + if (isManual) { + this.applyInitialManualTestStatus( + assessmentData, + testStepName, + testType, + getInitialManualTestStatus, + ); + } else { this.updateTestStepStatusForGeneratedInstances(assessmentData, testStepName); } } + private applyInitialManualTestStatus( + assessmentData: AssessmentData, + testStepName: string, + testType: VisualizationType, + getInitialManualTestStatus: (InstanceIdToInstanceDataMap) => ManualTestStatus, + ): void { + const originalStatus = assessmentData.manualTestStepResultMap[testStepName].status; + if (originalStatus !== ManualTestStatus.UNKNOWN) { + return; // Never override an explicitly set status + } + + const instanceMap = assessmentData.generatedAssessmentInstancesMap; + const status = getInitialManualTestStatus(instanceMap); + assessmentData.manualTestStepResultMap[testStepName].status = status; + this.updateManualTestStepStatus(assessmentData, testStepName, testType); + } + private getGroupResult( instanceMap: DictionaryStringTo, testStepName: string, diff --git a/src/common/types/store-data/assessment-result-data.ts b/src/common/types/store-data/assessment-result-data.ts index a44c441affa..f90213f4da2 100644 --- a/src/common/types/store-data/assessment-result-data.ts +++ b/src/common/types/store-data/assessment-result-data.ts @@ -61,6 +61,7 @@ export interface TestStepResult { status: ManualTestStatus; isCapturedByUser: boolean; failureSummary: string; + isVisualizationSupported: boolean; isVisualizationEnabled: boolean; isVisible: boolean; originalStatus?: ManualTestStatus; diff --git a/src/scanner/custom-rule-configurations.ts b/src/scanner/custom-rule-configurations.ts index 4791b40d7c2..481f380563f 100644 --- a/src/scanner/custom-rule-configurations.ts +++ b/src/scanner/custom-rule-configurations.ts @@ -10,7 +10,6 @@ import { frameTitleConfiguration } from './custom-rules/frame-title'; import { headerRuleConfiguration } from './custom-rules/header-rule'; import { headingConfiguration } from './custom-rules/heading-rule'; import { imageConfiguration } from './custom-rules/image-rule'; -import { landmarkConfiguration } from './custom-rules/landmark-rule'; import { linkFunctionConfiguration } from './custom-rules/link-function'; import { linkPurposeConfiguration } from './custom-rules/link-purpose'; import { nativeWidgetsDefaultConfiguration } from './custom-rules/native-widgets-default'; @@ -24,7 +23,6 @@ import { RuleConfiguration } from './iruleresults'; export const configuration: RuleConfiguration[] = [ headingConfiguration, colorConfiguration, - landmarkConfiguration, uniqueLandmarkConfiguration, imageConfiguration, textAlternativeConfiguration, diff --git a/src/scanner/custom-rules/landmark-rule.ts b/src/scanner/custom-rules/landmark-rule.ts deleted file mode 100644 index 778f201e4a1..00000000000 --- a/src/scanner/custom-rules/landmark-rule.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -import { RuleConfiguration } from '../iruleresults'; - -const landmarkCheckId: string = 'unique-landmark'; - -export const landmarkConfiguration: RuleConfiguration = { - checks: [], - rule: { - id: 'main-landmark', - selector: '[role=main], main', - any: [landmarkCheckId], - enabled: false, - }, -}; diff --git a/src/tests/unit/common/visual-helper-toggle-config-builder.ts b/src/tests/unit/common/visual-helper-toggle-config-builder.ts index 23a86eb2aec..065653bf9b5 100644 --- a/src/tests/unit/common/visual-helper-toggle-config-builder.ts +++ b/src/tests/unit/common/visual-helper-toggle-config-builder.ts @@ -52,6 +52,7 @@ export class VisualHelperToggleConfigBuilder extends BaseDataBuilder, } as GeneratedAssessmentInstance, @@ -68,7 +70,8 @@ export class VisualHelperToggleConfigBuilder extends BaseDataBuilder, } as GeneratedAssessmentInstance, @@ -102,4 +105,29 @@ export class VisualHelperToggleConfigBuilder extends BaseDataBuilder, + } as GeneratedAssessmentInstance, + 'selector-2': { + testStepResults: { + [this.stepKey]: { + id: 'id1', + status: ManualTestStatus.PASS, + isVisualizationEnabled: false, + isVisualizationSupported: false, + } as TestStepResult, + } as AssessmentResultType, + } as GeneratedAssessmentInstance, + }; + return this; + } } diff --git a/src/tests/unit/tests/DetailsView/components/assessment-visualization-enabled-toggle.test.tsx b/src/tests/unit/tests/DetailsView/components/assessment-visualization-enabled-toggle.test.tsx index e9b8e86d8a1..99a457b0984 100644 --- a/src/tests/unit/tests/DetailsView/components/assessment-visualization-enabled-toggle.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/assessment-visualization-enabled-toggle.test.tsx @@ -1,200 +1,234 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import * as Enzyme from 'enzyme'; -import * as React from 'react'; -import { IMock, Mock, Times } from 'typemoq'; import { VisualizationToggle, VisualizationToggleProps, -} from '../../../../../common/components/visualization-toggle'; -import { DetailsViewActionMessageCreator } from '../../../../../DetailsView/actions/details-view-action-message-creator'; -import { AssessmentVisualizationEnabledToggle } from '../../../../../DetailsView/components/assessment-visualization-enabled-toggle'; -import { visualHelperText } from '../../../../../DetailsView/components/base-visual-helper-toggle'; -import { VisualHelperToggleConfigBuilder } from '../../../common/visual-helper-toggle-config-builder'; -import { VisualizationTogglePropsBuilder } from '../../../common/visualization-toggle-props-builder'; +} from 'common/components/visualization-toggle'; +import { DetailsViewActionMessageCreator } from 'DetailsView/actions/details-view-action-message-creator'; +import { AssessmentVisualizationEnabledToggle } from 'DetailsView/components/assessment-visualization-enabled-toggle'; +import { visualHelperText } from 'DetailsView/components/base-visual-helper-toggle'; +import * as Enzyme from 'enzyme'; +import * as React from 'react'; +import { VisualHelperToggleConfigBuilder } from 'tests/unit/common/visual-helper-toggle-config-builder'; +import { VisualizationTogglePropsBuilder } from 'tests/unit/common/visualization-toggle-props-builder'; +import { IMock, Mock, Times } from 'typemoq'; describe('AssessmentVisualizationEnabledToggle', () => { const actionMessageCreatorMock: IMock = Mock.ofType( DetailsViewActionMessageCreator, ); - it('render with disabled message', () => { - const props = new VisualHelperToggleConfigBuilder() - .withToggleStepEnabled(true) - .withToggleStepScanned(false) - .withActionMessageCreator(actionMessageCreatorMock.object) - .withEmptyFilteredMap() - .build(); + describe('render', () => { + it('is disabled when no instances exist', () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(true) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .withEmptyFilteredMap() + .build(); - const wrapper = Enzyme.shallow(); + const testSubject = Enzyme.shallow(); - const visualHelperClass = 'visual-helper'; - const toggleDiv = wrapper.find(`.${visualHelperClass}`); + expectDisabledTextLayout(testSubject); - expect(toggleDiv.exists()).toBeTruthy(); + const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() + .with('checked', false) + .with('disabled', true) + .build(); - const textDiv = toggleDiv.find(`.${visualHelperClass}-text`); + expectChildVisualizationToggleWith(expectedToggleProps, testSubject); + }); - expect(textDiv.exists()).toBeTruthy(); - expect(textDiv.childAt(0).text()).toEqual(visualHelperText); + it("is disabled when only instances that don't support visualization exist", () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(true) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .withNonEmptyFilteredMap(false, false) + .build(); - const noMatchesWarningClass = 'no-matching-elements'; - expect(wrapper.find(`.${noMatchesWarningClass}`).exists()).toBeTruthy(); + const testSubject = Enzyme.shallow(); - const toggle = wrapper.find(VisualizationToggle); + expectDisabledTextLayout(testSubject); - const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() - .with('checked', false) - .with('disabled', true) - .build(); + const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() + .with('checked', false) + .with('disabled', true) + .build(); - assertVisualizationToggle(expectedToggleProps, toggle); - }); + expectChildVisualizationToggleWith(expectedToggleProps, testSubject); + }); - it('render: toggle not disabled', () => { - const props = new VisualHelperToggleConfigBuilder() - .withToggleStepEnabled(true) - .withToggleStepScanned(false) - .withActionMessageCreator(actionMessageCreatorMock.object) - .withNonEmptyFilteredMap() - .build(); + it('is enabled but unchecked if step is enabled but all instance visualizations are disabled', () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(true) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .withNonEmptyFilteredMap(false) + .build(); - const wrapper = Enzyme.shallow(); + const testSubject = Enzyme.shallow(); - const visualHelperClass = 'visual-helper'; - const toggleDiv = wrapper.find(`.${visualHelperClass}`); + expectEnabledTextLayout(testSubject); - expect(toggleDiv.exists()).toBeTruthy(); + const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() + .with('checked', false) + .with('disabled', false) + .build(); - const textDiv = toggleDiv.find(`.${visualHelperClass}-text`); + expectChildVisualizationToggleWith(expectedToggleProps, testSubject); + }); - expect(textDiv.exists()).toBeTruthy(); - expect(textDiv.childAt(0).text()).toEqual(visualHelperText); - expect(wrapper.find('strong').exists()).toBeFalsy(); - const toggle = wrapper.find(VisualizationToggle); + it('is enabled and checked if step and instance visualizations are both enabled', () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(false) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .withNonEmptyFilteredMap(true) + .build(); - const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() - .with('checked', false) - .with('disabled', false) - .build(); + const testSubject = Enzyme.shallow(); - assertVisualizationToggle(expectedToggleProps, toggle); - }); + expectEnabledTextLayout(testSubject); - it('render: have non empty instance map with a visible instance', () => { - const props = new VisualHelperToggleConfigBuilder() - .withToggleStepEnabled(false) - .withToggleStepScanned(false) - .withActionMessageCreator(actionMessageCreatorMock.object) - .withNonEmptyFilteredMap(true) - .build(); + const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() + .with('checked', true) + .with('disabled', false) + .build(); - const wrapper = Enzyme.shallow(); + expectChildVisualizationToggleWith(expectedToggleProps, testSubject); + }); - const visualHelperClass = 'visual-helper'; - const toggleDiv = wrapper.find(`.${visualHelperClass}`); + it("is enabled and checked if some instances support visualization and some don't", () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(false) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .withMixedVisualizationSupportFilteredMap() + .build(); - expect(toggleDiv.exists()).toBeTruthy(); + const testSubject = Enzyme.shallow(); - const textDiv = toggleDiv.find(`.${visualHelperClass}-text`); + expectEnabledTextLayout(testSubject); - expect(textDiv.exists()).toBeTruthy(); - expect(textDiv.childAt(0).text()).toEqual(visualHelperText); - expect(wrapper.find('strong').exists()).toBeFalsy(); + const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() + .with('checked', true) + .with('disabled', false) + .build(); - const toggle = wrapper.find(VisualizationToggle); + expectChildVisualizationToggleWith(expectedToggleProps, testSubject); + }); - const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() - .with('checked', true) - .with('disabled', false) - .build(); + it('is enabled and unchecked if step and instance visualizations are both disabled', () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(false) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .withNonEmptyFilteredMap(false) + .build(); - assertVisualizationToggle(expectedToggleProps, toggle); - }); + const testSubject = Enzyme.shallow(); - it('render: have non empty instance map without a visible instance', () => { - const props = new VisualHelperToggleConfigBuilder() - .withToggleStepEnabled(false) - .withToggleStepScanned(false) - .withActionMessageCreator(actionMessageCreatorMock.object) - .withNonEmptyFilteredMap() - .build(); + expectEnabledTextLayout(testSubject); - const wrapper = Enzyme.shallow(); + const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() + .with('checked', false) + .with('disabled', false) + .build(); - const visualHelperClass = 'visual-helper'; - const toggleDiv = wrapper.find(`.${visualHelperClass}`); + expectChildVisualizationToggleWith(expectedToggleProps, testSubject); + }); - expect(toggleDiv.exists()).toBeTruthy(); + function expectEnabledTextLayout( + testSubject: Enzyme.ShallowWrapper, + ): void { + const visualHelperClass = 'visual-helper'; + const toggleDiv = testSubject.find(`.${visualHelperClass}`); - const textDiv = toggleDiv.find(`.${visualHelperClass}-text`); + expect(toggleDiv.exists()).toBeTruthy(); - expect(textDiv.exists()).toBeTruthy(); - expect(textDiv.childAt(0).text()).toEqual(visualHelperText); - expect(wrapper.find('strong').exists()).toBeFalsy(); - const toggle = wrapper.find(VisualizationToggle); + const textDiv = toggleDiv.find(`.${visualHelperClass}-text`); - const expectedToggleProps = getDefaultVisualizationTogglePropsBuilder() - .with('checked', false) - .with('disabled', false) - .build(); + expect(textDiv.exists()).toBeTruthy(); + expect(textDiv.childAt(0).text()).toEqual(visualHelperText); + expect(testSubject.find('strong').exists()).toBeFalsy(); + } - assertVisualizationToggle(expectedToggleProps, toggle); - }); + function expectDisabledTextLayout( + testSubject: Enzyme.ShallowWrapper, + ): void { + const visualHelperClass = 'visual-helper'; + const toggleDiv = testSubject.find(`.${visualHelperClass}`); + + expect(toggleDiv.exists()).toBeTruthy(); - it('enables all visualizations when none are shown', () => { - const props = new VisualHelperToggleConfigBuilder() - .withToggleStepEnabled(true) - .withToggleStepScanned(false) - .withActionMessageCreator(actionMessageCreatorMock.object) - .build(); - - const wrapper = Enzyme.shallow(); - actionMessageCreatorMock.reset(); - actionMessageCreatorMock - .setup(acm => - acm.changeAssessmentVisualizationStateForAll( - true, - props.assessmentNavState.selectedTestType, - props.assessmentNavState.selectedTestSubview, - ), - ) - .verifiable(Times.once()); - - wrapper.find(VisualizationToggle).simulate('click'); - - actionMessageCreatorMock.verifyAll(); + const textDiv = toggleDiv.find(`.${visualHelperClass}-text`); + + expect(textDiv.exists()).toBeTruthy(); + expect(textDiv.childAt(0).text()).toEqual(visualHelperText); + + const noMatchesWarningClass = 'no-matching-elements'; + expect(testSubject.find(`.${noMatchesWarningClass}`).exists()).toBeTruthy(); + } }); - it('disables all visualizations when some are shown', () => { - const props = new VisualHelperToggleConfigBuilder() - .withToggleStepEnabled(true) - .withToggleStepScanned(false) - .withActionMessageCreator(actionMessageCreatorMock.object) - .withNonEmptyFilteredMap(true) - .build(); - - const wrapper = Enzyme.shallow(); - actionMessageCreatorMock.reset(); - actionMessageCreatorMock - .setup(acm => - acm.changeAssessmentVisualizationStateForAll( - false, - props.assessmentNavState.selectedTestType, - props.assessmentNavState.selectedTestSubview, - ), - ) - .verifiable(Times.once()); - - wrapper.find(VisualizationToggle).simulate('click'); - - actionMessageCreatorMock.verifyAll(); + describe('toggle behavior', () => { + it('enables all visualizations when none are shown', () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(true) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .build(); + + const wrapper = Enzyme.shallow(); + actionMessageCreatorMock.reset(); + actionMessageCreatorMock + .setup(acm => + acm.changeAssessmentVisualizationStateForAll( + true, + props.assessmentNavState.selectedTestType, + props.assessmentNavState.selectedTestSubview, + ), + ) + .verifiable(Times.once()); + + wrapper.find(VisualizationToggle).simulate('click'); + + actionMessageCreatorMock.verifyAll(); + }); + + it('disables all visualizations when some are shown', () => { + const props = new VisualHelperToggleConfigBuilder() + .withToggleStepEnabled(true) + .withToggleStepScanned(false) + .withActionMessageCreator(actionMessageCreatorMock.object) + .withNonEmptyFilteredMap(true) + .build(); + + const wrapper = Enzyme.shallow(); + actionMessageCreatorMock.reset(); + actionMessageCreatorMock + .setup(acm => + acm.changeAssessmentVisualizationStateForAll( + false, + props.assessmentNavState.selectedTestType, + props.assessmentNavState.selectedTestSubview, + ), + ) + .verifiable(Times.once()); + + wrapper.find(VisualizationToggle).simulate('click'); + + actionMessageCreatorMock.verifyAll(); + }); }); - function assertVisualizationToggle( + function expectChildVisualizationToggleWith( expectedProps: VisualizationToggleProps, - visualizationToggle: Enzyme.ShallowWrapper, + testSubject: Enzyme.ShallowWrapper, ): void { + const visualizationToggle = testSubject.find(VisualizationToggle); + expect(visualizationToggle.exists()).toBeTruthy(); const actualProps = visualizationToggle.props(); diff --git a/src/tests/unit/tests/assessments/landmarks/auto-pass-if-no-landmarks.test.ts b/src/tests/unit/tests/assessments/landmarks/auto-pass-if-no-landmarks.test.ts new file mode 100644 index 00000000000..ece051ee4ac --- /dev/null +++ b/src/tests/unit/tests/assessments/landmarks/auto-pass-if-no-landmarks.test.ts @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { autoPassIfNoLandmarks } from 'assessments/landmarks/auto-pass-if-no-landmarks'; +import { ManualTestStatus } from 'common/types/manual-test-status'; +import { InstanceIdToInstanceDataMap } from 'common/types/store-data/assessment-result-data'; + +describe('autoPassIfNoLandmarks', () => { + it('returns PASS for instance data with no landmarks', () => { + const input = makeInputDataWithLandmarkRoles([]); + expect(autoPassIfNoLandmarks(input)).toBe(ManualTestStatus.PASS); + }); + + it.each(['main', 'complementary'])( + 'returns UNKNOWN for instance data with one %s landmark', + (landmarkRole: string) => { + const input = makeInputDataWithLandmarkRoles([landmarkRole]); + expect(autoPassIfNoLandmarks(input)).toBe(ManualTestStatus.UNKNOWN); + }, + ); + + it('returns UNKNOWN for instance data with multiple landmarks', () => { + const input = makeInputDataWithLandmarkRoles(['main', 'complementary', 'header']); + expect(autoPassIfNoLandmarks(input)).toBe(ManualTestStatus.UNKNOWN); + }); + + function makeInputDataWithLandmarkRoles(landmarkRoles: string[]): InstanceIdToInstanceDataMap { + const data: InstanceIdToInstanceDataMap = {}; + for (const landmarkRole of landmarkRoles) { + data[`#element-with-${landmarkRole}`] = { + target: [`#element-with-${landmarkRole}`], + html: `
`, + propertyBag: { + role: landmarkRole, + }, + testStepResults: {}, + }; + } + return data; + } +}); diff --git a/src/tests/unit/tests/assessments/landmarks/does-result-have-main-role.test.ts b/src/tests/unit/tests/assessments/landmarks/does-result-have-main-role.test.ts new file mode 100644 index 00000000000..83295474935 --- /dev/null +++ b/src/tests/unit/tests/assessments/landmarks/does-result-have-main-role.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { doesResultHaveMainRole } from 'assessments/landmarks/does-result-have-main-role'; +import { DecoratedAxeNodeResult } from 'injected/scanner-utils'; + +describe('doesResultHaveMainRole', () => { + it('returns false for results with no check results', () => { + const input = { any: [], all: [] } as DecoratedAxeNodeResult; + + expect(doesResultHaveMainRole(input)).toBe(false); + }); + + it('returns false for results with check results without role data', () => { + const input = { + any: [makeCheckResultWithRole(undefined)], + all: [makeCheckResultWithRole(undefined)], + } as DecoratedAxeNodeResult; + + expect(doesResultHaveMainRole(input)).toBe(false); + }); + + it('returns false for results with check results with only non-main role data', () => { + const input = { + any: [makeCheckResultWithRole('complementary')], + all: [makeCheckResultWithRole('banner')], + } as DecoratedAxeNodeResult; + + expect(doesResultHaveMainRole(input)).toBe(false); + }); + + it('returns true for results with an "any" check result with "main" role data', () => { + const input = { + any: [makeCheckResultWithRole('main')], + all: [], + } as DecoratedAxeNodeResult; + + expect(doesResultHaveMainRole(input)).toBe(true); + }); + + it('returns true for results with an "all" check result with "main" role data', () => { + const input = { + any: [], + all: [makeCheckResultWithRole('main')], + } as DecoratedAxeNodeResult; + + expect(doesResultHaveMainRole(input)).toBe(true); + }); + + it('returns true for results with mixed check results', () => { + const input = { + any: [makeCheckResultWithRole('banner'), makeCheckResultWithRole(undefined)], + all: [ + makeCheckResultWithRole('main'), + makeCheckResultWithRole('banner'), + makeCheckResultWithRole(undefined), + ], + } as DecoratedAxeNodeResult; + + expect(doesResultHaveMainRole(input)).toBe(true); + }); + + function makeCheckResultWithRole(role: string): FormattedCheckResult { + return { + id: 'test-check-id', + message: 'test check message', + data: { + role, + }, + }; + } +}); diff --git a/src/tests/unit/tests/background/assessment-data-converter.test.ts b/src/tests/unit/tests/background/assessment-data-converter.test.ts index c87b86145f7..911c9c97f5f 100644 --- a/src/tests/unit/tests/background/assessment-data-converter.test.ts +++ b/src/tests/unit/tests/background/assessment-data-converter.test.ts @@ -13,7 +13,7 @@ import { DecoratedAxeNodeResult, HtmlElementAxeResults } from '../../../../injec import { TabStopEvent } from '../../../../injected/tab-stops-listener'; import { DictionaryStringTo } from '../../../../types/common-types'; -describe('AssessmentDataConverterTest', () => { +describe('AssessmentDataConverter', () => { let testSubject: AssessmentDataConverter; const uid: string = 'uid123'; let testStep: string; @@ -22,6 +22,7 @@ describe('AssessmentDataConverterTest', () => { status: ManualTestStatus.UNKNOWN, isCapturedByUser: false, failureSummary: null, + isVisualizationSupported: true, isVisualizationEnabled: true, isVisible: true, }; @@ -39,305 +40,285 @@ describe('AssessmentDataConverterTest', () => { htmlStub = 'some html'; }); - test('generateAssessmentInstancesMap: property bag from any checks', () => { - const expectedPropertyBag = { - someProperty: 1, - }; - - const selectorMap: DictionaryStringTo = { - [selectorStub]: { - ruleResults: { - rule1: { - any: [ - { - id: 'rule1', - data: expectedPropertyBag, - }, - ], - html: htmlStub, - id: 'id1', - status: true, - } as DecoratedAxeNodeResult, + describe('generateAssessmentInstancesMap', () => { + it('should ignore selectors with no rule results.', () => { + const selectorMap: DictionaryStringTo = { + [selectorStub]: { + ruleResults: {}, + target: [selectorStub], }, - target: [selectorStub], - }, - }; - - setupGenerateInstanceIdentifierMock( - { target: [selectorStub], html: htmlStub }, - identifierStub, - ); - const instanceMap = testSubject.generateAssessmentInstancesMap( - null, - selectorMap, - testStep, - generateInstanceIdentifierMock.object, - () => ManualTestStatus.UNKNOWN, - ); - - expect(instanceMap[identifierStub].propertyBag).toEqual(expectedPropertyBag); - }); - - test(`generateAssessmentInstancesMap: previouslyGeneratedInstances is null, - new rule result is not false and any data is there.`, () => { - const selectorMap: DictionaryStringTo = { - [selectorStub]: { - ruleResults: { - rule1: { - any: [ - { - id: 'rule1', - data: { someProperty: 1 }, - }, - ], - html: htmlStub, - id: 'id1', - status: true, - } as DecoratedAxeNodeResult, + }; + const previouslyGeneratedInstances = {}; + const instanceMap = testSubject.generateAssessmentInstancesMap( + previouslyGeneratedInstances, + selectorMap, + testStep, + undefined, + null, + null, + ); + + expect(instanceMap).toEqual(previouslyGeneratedInstances); + }); + + it('should produce an empty map (not null) if previouslyGeneratedInstances is null and there are no rule results to add', () => { + const selectorMap: DictionaryStringTo = { + [selectorStub]: { + ruleResults: {}, + target: [selectorStub], }, - target: [selectorStub], - }, - }; - const expectedResult = { - [identifierStub]: { - html: htmlStub, - propertyBag: { someProperty: 1 }, - target: [selectorStub], - testStepResults: { - [testStep]: { - id: 'id1', - status: ManualTestStatus.UNKNOWN, - isCapturedByUser: false, - failureSummary: undefined, - isVisible: true, - isVisualizationEnabled: false, + }; + const expectedResult = {}; + const instanceMap = testSubject.generateAssessmentInstancesMap( + null, + selectorMap, + testStep, + undefined, + null, + null, + ); + + expect(instanceMap).toEqual(expectedResult); + }); + + it('should create a new instance wrapping the generated result if there is no existing instance matching the selector', () => { + const selectorMap: DictionaryStringTo = { + [selectorStub]: { + ruleResults: { + rule1: { + html: htmlStub, + id: 'id1', + status: false, + } as DecoratedAxeNodeResult, }, + target: [selectorStub], }, - }, - }; - - setupGenerateInstanceIdentifierMock( - { target: [selectorStub], html: htmlStub }, - identifierStub, - ); - const instanceMap = testSubject.generateAssessmentInstancesMap( - null, - selectorMap, - testStep, - generateInstanceIdentifierMock.object, - () => ManualTestStatus.UNKNOWN, - ); - - expect(instanceMap).toEqual(expectedResult); - }); - - test(`generateAssessmentInstancesMap: previouslyGeneratedInstances is null, - new rule result is null (shouldn't happen but covered).`, () => { - const selectorMap: DictionaryStringTo = { - [selectorStub]: { - ruleResults: {}, - target: [selectorStub], - }, - }; - const expectedResult = {}; - const instanceMap = testSubject.generateAssessmentInstancesMap( - null, - selectorMap, - testStep, - undefined, - null, - ); - - expect(instanceMap).toEqual(expectedResult); - }); - - test(`generateAssessmentInstancesMap: previouslyGeneratedInstances is not null, - new rule result is null (shouldn't happen but covered).`, () => { - const selectorMap: DictionaryStringTo = { - [selectorStub]: { - ruleResults: {}, - target: [selectorStub], - }, - }; - const previouslyGeneratedInstances = {}; - const instanceMap = testSubject.generateAssessmentInstancesMap( - previouslyGeneratedInstances, - selectorMap, - testStep, - undefined, - null, - ); - - expect(instanceMap).toEqual(previouslyGeneratedInstances); - }); - - test(`generateAssessmentInstancesMap: previouslyGeneratedInstances is - empty/does not match any new instances and any data is not there`, () => { - const selectorMap: DictionaryStringTo = { - [selectorStub]: { - ruleResults: { - rule1: { - html: htmlStub, - id: 'id1', - status: false, - } as DecoratedAxeNodeResult, + }; + const expectedResult = { + [identifierStub]: { + html: htmlStub, + propertyBag: null, + target: [selectorStub], + testStepResults: { + [testStep]: { + id: 'id1', + status: ManualTestStatus.UNKNOWN, + isCapturedByUser: false, + failureSummary: undefined, + isVisible: true, + isVisualizationEnabled: false, + isVisualizationSupported: true, + }, + }, }, - target: [selectorStub], - }, - }; - const expectedResult = { - [identifierStub]: { - html: htmlStub, - propertyBag: null, - target: [selectorStub], - testStepResults: { - [testStep]: { - id: 'id1', - status: ManualTestStatus.UNKNOWN, - isCapturedByUser: false, - failureSummary: undefined, - isVisible: true, - isVisualizationEnabled: false, + }; + setupGenerateInstanceIdentifierMock( + { target: [selectorStub], html: htmlStub }, + identifierStub, + ); + const instanceMap = testSubject.generateAssessmentInstancesMap( + {}, + selectorMap, + testStep, + generateInstanceIdentifierMock.object, + () => ManualTestStatus.UNKNOWN, + () => true, + ); + + expect(instanceMap).toEqual(expectedResult); + }); + + it("should merge check results' data into the instance's propertyBag", () => { + const expectedPropertyBag = { + someProperty: 1, + }; + + const selectorMap: DictionaryStringTo = { + [selectorStub]: { + ruleResults: { + rule1: { + any: [ + { + id: 'rule1', + data: expectedPropertyBag, + }, + ], + html: htmlStub, + id: 'id1', + status: true, + } as DecoratedAxeNodeResult, }, + target: [selectorStub], }, + }; + + setupGenerateInstanceIdentifierMock( + { target: [selectorStub], html: htmlStub }, + identifierStub, + ); + const instanceMap = testSubject.generateAssessmentInstancesMap( + null, + selectorMap, + testStep, + generateInstanceIdentifierMock.object, + () => ManualTestStatus.UNKNOWN, + () => true, + ); + + expect(instanceMap[identifierStub].propertyBag).toEqual(expectedPropertyBag); + }); + + it.each([ManualTestStatus.FAIL, ManualTestStatus.UNKNOWN, ManualTestStatus.PASS])( + 'should use getInstanceStatus to determine the status of the generated step result', + (getInstanceStatusResult: ManualTestStatus) => { + const selectorMap: DictionaryStringTo = { + [selectorStub]: { + ruleResults: { + rule1: { + html: htmlStub, + id: 'id1', + status: false, + } as DecoratedAxeNodeResult, + }, + target: [selectorStub], + }, + }; + + setupGenerateInstanceIdentifierMock( + { target: [selectorStub], html: htmlStub }, + identifierStub, + ); + const instanceMap = testSubject.generateAssessmentInstancesMap( + {}, + selectorMap, + testStep, + generateInstanceIdentifierMock.object, + () => getInstanceStatusResult, + () => true, + ); + + expect(instanceMap[identifierStub].testStepResults[testStep].status).toEqual( + getInstanceStatusResult, + ); }, - }; - setupGenerateInstanceIdentifierMock( - { target: [selectorStub], html: htmlStub }, - identifierStub, - ); - const instanceMap = testSubject.generateAssessmentInstancesMap( - {}, - selectorMap, - testStep, - generateInstanceIdentifierMock.object, - () => ManualTestStatus.UNKNOWN, ); - expect(instanceMap).toEqual(expectedResult); - }); - - test('generateAssessmentInstancesMap: automated check status should be FAIL', () => { - const selectorMap: DictionaryStringTo = { - [selectorStub]: { - ruleResults: { - rule1: { - html: htmlStub, - id: 'id1', - status: false, - } as DecoratedAxeNodeResult, - }, - target: [selectorStub], - }, - }; - const expectedResult = { - [identifierStub]: { - html: htmlStub, - propertyBag: null, - target: [selectorStub], - testStepResults: { - [testStep]: { - id: 'id1', - status: ManualTestStatus.FAIL, - isCapturedByUser: false, - failureSummary: undefined, - isVisible: true, - isVisualizationEnabled: false, + it.each([true, false])( + 'should use isVisualizationSupported to determine the corresponding property of the generated step result', + (isVisualizationSupportedResult: boolean) => { + const selectorMap: DictionaryStringTo = { + [selectorStub]: { + ruleResults: { + rule1: { + html: htmlStub, + id: 'id1', + status: false, + } as DecoratedAxeNodeResult, + }, + target: [selectorStub], }, - }, + }; + + setupGenerateInstanceIdentifierMock( + { target: [selectorStub], html: htmlStub }, + identifierStub, + ); + const instanceMap = testSubject.generateAssessmentInstancesMap( + {}, + selectorMap, + testStep, + generateInstanceIdentifierMock.object, + () => ManualTestStatus.UNKNOWN, + () => isVisualizationSupportedResult, + ); + + expect( + instanceMap[identifierStub].testStepResults[testStep].isVisualizationSupported, + ).toEqual(isVisualizationSupportedResult); }, - }; - setupGenerateInstanceIdentifierMock( - { target: [selectorStub], html: htmlStub }, - identifierStub, ); - const instanceMap = testSubject.generateAssessmentInstancesMap( - {}, - selectorMap, - testStep, - generateInstanceIdentifierMock.object, - () => ManualTestStatus.FAIL, - ); - - expect(instanceMap).toEqual(expectedResult); - }); - test('generateAssessmentInstancesMap: previouslyGeneratedInstances contains matching instance', () => { - const anotherTestStep = 'another test step'; - const selectorMap: DictionaryStringTo = { - [selectorStub]: { - ruleResults: { - rule1: { - any: [ - { - id: 'rule1', - data: { someProperty: 1 }, - }, - ], - html: htmlStub, - id: 'id1', - status: false, - } as DecoratedAxeNodeResult, - }, - target: [selectorStub], - }, - }; - const previouslyGeneratedInstances: AssessmentInstancesMap = { - [identifierStub]: { - html: htmlStub, - propertyBag: { someProperty: 3 }, - target: [selectorStub], - testStepResults: { - [anotherTestStep]: { - id: 'id2', - status: ManualTestStatus.UNKNOWN, - isCapturedByUser: false, - failureSummary: undefined, - isVisible: true, - isVisualizationEnabled: true, + it('should merge results for a previously seen selector into the existing instance data', () => { + const anotherTestStep = 'another test step'; + const selectorMap: DictionaryStringTo = { + [selectorStub]: { + ruleResults: { + rule1: { + any: [ + { + id: 'rule1', + data: { someProperty: 1 }, + }, + ], + html: htmlStub, + id: 'id1', + status: false, + } as DecoratedAxeNodeResult, }, + target: [selectorStub], }, - }, - }; - const expectedResult = { - [identifierStub]: { - html: htmlStub, - propertyBag: { someProperty: 3 }, - target: [selectorStub], - testStepResults: { - [testStep]: { - id: 'id1', - status: ManualTestStatus.UNKNOWN, - isCapturedByUser: false, - failureSummary: undefined, - isVisible: true, - isVisualizationEnabled: false, + }; + const previouslyGeneratedInstances: AssessmentInstancesMap = { + [identifierStub]: { + html: htmlStub, + propertyBag: { someProperty: 3 }, + target: [selectorStub], + testStepResults: { + [anotherTestStep]: { + id: 'id2', + status: ManualTestStatus.UNKNOWN, + isCapturedByUser: false, + failureSummary: undefined, + isVisible: true, + isVisualizationEnabled: true, + isVisualizationSupported: true, + }, }, - [anotherTestStep]: { - id: 'id2', - status: ManualTestStatus.UNKNOWN, - isCapturedByUser: false, - failureSummary: undefined, - isVisible: true, - isVisualizationEnabled: true, + }, + }; + const expectedResult = { + [identifierStub]: { + html: htmlStub, + propertyBag: { someProperty: 3 }, + target: [selectorStub], + testStepResults: { + [testStep]: { + id: 'id1', + status: ManualTestStatus.UNKNOWN, + isCapturedByUser: false, + failureSummary: undefined, + isVisible: true, + isVisualizationEnabled: false, + isVisualizationSupported: true, + }, + [anotherTestStep]: { + id: 'id2', + status: ManualTestStatus.UNKNOWN, + isCapturedByUser: false, + failureSummary: undefined, + isVisible: true, + isVisualizationEnabled: true, + isVisualizationSupported: true, + }, }, }, - }, - }; - - setupGenerateInstanceIdentifierMock( - { target: [selectorStub], html: htmlStub }, - identifierStub, - ); - const instanceMap = testSubject.generateAssessmentInstancesMap( - previouslyGeneratedInstances, - selectorMap, - testStep, - generateInstanceIdentifierMock.object, - () => ManualTestStatus.UNKNOWN, - ); - - expect(instanceMap).toEqual(expectedResult); + }; + + setupGenerateInstanceIdentifierMock( + { target: [selectorStub], html: htmlStub }, + identifierStub, + ); + const instanceMap = testSubject.generateAssessmentInstancesMap( + previouslyGeneratedInstances, + selectorMap, + testStep, + generateInstanceIdentifierMock.object, + () => ManualTestStatus.UNKNOWN, + () => true, + ); + + expect(instanceMap).toEqual(expectedResult); + }); }); test('generateAssessmentInstancesMapForEvents: previouslyGeneratedInstances is null', () => { diff --git a/src/tests/unit/tests/background/stores/__snapshots__/assessment-store.test.ts.snap b/src/tests/unit/tests/background/stores/__snapshots__/assessment-store.test.ts.snap index 7c92b440b56..217f5139508 100644 --- a/src/tests/unit/tests/background/stores/__snapshots__/assessment-store.test.ts.snap +++ b/src/tests/unit/tests/background/stores/__snapshots__/assessment-store.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`AssessmentStoreTest onResetAllAssessmentsData 1`] = `"tab with Id 1000 not found"`; +exports[`AssessmentStore onResetAllAssessmentsData 1`] = `"tab with Id 1000 not found"`; -exports[`AssessmentStoreTest onUpdateTargetTabId 1`] = `"tab with Id 1000 not found"`; +exports[`AssessmentStore onUpdateTargetTabId 1`] = `"tab with Id 1000 not found"`; diff --git a/src/tests/unit/tests/background/stores/assessment-store.test.ts b/src/tests/unit/tests/background/stores/assessment-store.test.ts index f87c17fad8a..39776f31617 100644 --- a/src/tests/unit/tests/background/stores/assessment-store.test.ts +++ b/src/tests/unit/tests/background/stores/assessment-store.test.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { AssessmentsProvider } from 'assessments/types/assessments-provider'; import { Assessment } from 'assessments/types/iassessment'; +import { Requirement } from 'assessments/types/requirement'; import { AddFailureInstancePayload, AddResultDescriptionPayload, @@ -59,7 +60,7 @@ const assessmentKey: string = 'assessment-1'; const requirementKey: string = 'assessment-1-step-1'; const assessmentType = -1 as VisualizationType; -describe('AssessmentStoreTest', () => { +describe('AssessmentStore', () => { let browserMock: IMock; let assessmentDataConverterMock: IMock; let assessmentDataRemoverMock: IMock; @@ -470,7 +471,7 @@ describe('AssessmentStoreTest', () => { .testListenerToBeCalledOnce(initialState, finalState); }); - test('onScanCompleted', () => { + test('onScanCompleted with an assisted requirement', () => { const initialAssessmentData = new AssessmentDataBuilder() .with('testStepStatus', { ['assessment-1-step-1']: getDefaultTestStepData(), @@ -490,16 +491,121 @@ describe('AssessmentStoreTest', () => { const expectedInstanceMap = {}; const stepMapStub = assessmentsProvider.getStepMap(assessmentType); - const stepConfig = assessmentsProvider.getStep(assessmentType, 'assessment-1-step-1'); + const stepConfig: Readonly = { + ...assessmentsProvider.getStep(assessmentType, 'assessment-1-step-1'), + isManual: false, + }; const assessmentData = new AssessmentDataBuilder() .with('generatedAssessmentInstancesMap', expectedInstanceMap) .with('testStepStatus', { + // should PASS because it is a non-manual test with no associated instances ['assessment-1-step-1']: generateTestStepData(ManualTestStatus.PASS, true), + // should stay unchanged because the event/payload is requirement-specific + ['assessment-1-step-2']: getDefaultTestStepData(), + ['assessment-1-step-3']: getDefaultTestStepData(), + }) + .with('scanIncompleteWarnings', []) + .build(); + + const finalState = getStateWithAssessment(assessmentData); + + assessmentsProviderMock + .setup(provider => provider.all()) + .returns(() => assessmentsProvider.all()); + + assessmentsProviderMock + .setup(provider => provider.getStepMap(assessmentType)) + .returns(() => stepMapStub); + + assessmentsProviderMock + .setup(provider => provider.getStep(assessmentType, 'assessment-1-step-1')) + .returns(() => stepConfig); + + assessmentsProviderMock + .setup(provider => provider.forType(payload.testType)) + .returns(() => assessmentMock.object); + + assessmentMock.setup(am => am.getVisualizationConfiguration()).returns(() => configStub); + + getInstanceIdentiferGeneratorMock + .setup(idGetter => idGetter(requirementKey)) + .returns(() => instanceIdentifierGeneratorStub); + + assessmentDataConverterMock + .setup(a => + a.generateAssessmentInstancesMap( + initialAssessmentData.generatedAssessmentInstancesMap, + payload.selectorMap, + requirementKey, + instanceIdentifierGeneratorStub, + stepConfig.getInstanceStatus, + stepConfig.isVisualizationSupportedForResult, + ), + ) + .returns(() => expectedInstanceMap); + + createStoreTesterForAssessmentActions('scanCompleted') + .withActionParam(payload) + .testListenerToBeCalledOnce(initialState, finalState); + }); + + test('onScanCompleted with a manual requirement uses getInitialManualTestStatus to set status', () => { + const initialManualTestStepResult = { + status: ManualTestStatus.UNKNOWN, + id: requirementKey, + instances: [ + { + id: '1', + description: 'aaa', + }, + ], + }; + const initialAssessmentData = new AssessmentDataBuilder() + .with('testStepStatus', { + ['assessment-1-step-1']: getDefaultTestStepData(), + ['assessment-1-step-2']: getDefaultTestStepData(), + ['assessment-1-step-3']: getDefaultTestStepData(), + }) + .with('manualTestStepResultMap', { + [requirementKey]: initialManualTestStepResult, + }) + .build(); + const initialState = getStateWithAssessment(initialAssessmentData); + + const payload: ScanCompletedPayload = { + selectorMap: {}, + scanResult: {} as ScanResults, + testType: assessmentType, + key: requirementKey, + scanIncompleteWarnings: [], + }; + + const expectedInstanceMap = {}; + const stepMapStub = assessmentsProvider.getStepMap(assessmentType); + const stepConfig: Readonly = { + ...assessmentsProvider.getStep(assessmentType, 'assessment-1-step-1'), + isManual: true, + getInitialManualTestStatus: () => ManualTestStatus.FAIL, + }; + + const assessmentData = new AssessmentDataBuilder() + .with('generatedAssessmentInstancesMap', expectedInstanceMap) + .with('testStepStatus', { + // should FAIL based on getInitialManualTestStatus + ['assessment-1-step-1']: generateTestStepData(ManualTestStatus.FAIL, true), + // should stay unchanged because the event/payload is requirement-specific ['assessment-1-step-2']: getDefaultTestStepData(), ['assessment-1-step-3']: getDefaultTestStepData(), }) .with('scanIncompleteWarnings', []) + .with('manualTestStepResultMap', { + [requirementKey]: { + ...initialManualTestStepResult, + // should FAIL based on getInitialManualTestStatus + status: ManualTestStatus.FAIL, + }, + }) .build(); const finalState = getStateWithAssessment(assessmentData); @@ -533,7 +639,108 @@ describe('AssessmentStoreTest', () => { payload.selectorMap, requirementKey, instanceIdentifierGeneratorStub, - It.isAny(), + stepConfig.getInstanceStatus, + stepConfig.isVisualizationSupportedForResult, + ), + ) + .returns(() => expectedInstanceMap); + + createStoreTesterForAssessmentActions('scanCompleted') + .withActionParam(payload) + .testListenerToBeCalledOnce(initialState, finalState); + }); + + test('onScanCompleted with a manual requirement skips getInitialManualTestStatus for requirements that already have a status', () => { + const initialManualTestStepResult = { + status: ManualTestStatus.PASS, + id: requirementKey, + instances: [ + { + id: '1', + description: 'aaa', + }, + ], + }; + const initialAssessmentData = new AssessmentDataBuilder() + .with('testStepStatus', { + ['assessment-1-step-1']: generateTestStepData(ManualTestStatus.PASS, true), + ['assessment-1-step-2']: getDefaultTestStepData(), + ['assessment-1-step-3']: getDefaultTestStepData(), + }) + .with('manualTestStepResultMap', { + [requirementKey]: initialManualTestStepResult, + }) + .build(); + const initialState = getStateWithAssessment(initialAssessmentData); + + const payload: ScanCompletedPayload = { + selectorMap: {}, + scanResult: {} as ScanResults, + testType: assessmentType, + key: requirementKey, + scanIncompleteWarnings: [], + }; + + const expectedInstanceMap = {}; + const stepMapStub = assessmentsProvider.getStepMap(assessmentType); + const stepConfig: Readonly = { + ...assessmentsProvider.getStep(assessmentType, 'assessment-1-step-1'), + isManual: true, + getInitialManualTestStatus: () => ManualTestStatus.FAIL, + }; + + const assessmentData = new AssessmentDataBuilder() + .with('generatedAssessmentInstancesMap', expectedInstanceMap) + .with('testStepStatus', { + // should ignore getInitialManualTestStatus because the original state was not UNKNOWN + ['assessment-1-step-1']: generateTestStepData(ManualTestStatus.PASS, true), + // should stay unchanged because the event/payload is requirement-specific + ['assessment-1-step-2']: getDefaultTestStepData(), + ['assessment-1-step-3']: getDefaultTestStepData(), + }) + .with('scanIncompleteWarnings', []) + .with('manualTestStepResultMap', { + [requirementKey]: { + ...initialManualTestStepResult, + // should ignore getInitialManualTestStatus because the original state was not UNKNOWN + status: ManualTestStatus.PASS, + }, + }) + .build(); + + const finalState = getStateWithAssessment(assessmentData); + + assessmentsProviderMock + .setup(provider => provider.all()) + .returns(() => assessmentsProvider.all()); + + assessmentsProviderMock + .setup(provider => provider.getStepMap(assessmentType)) + .returns(() => stepMapStub); + + assessmentsProviderMock + .setup(provider => provider.getStep(assessmentType, 'assessment-1-step-1')) + .returns(() => stepConfig); + + assessmentsProviderMock + .setup(provider => provider.forType(payload.testType)) + .returns(() => assessmentMock.object); + + assessmentMock.setup(am => am.getVisualizationConfiguration()).returns(() => configStub); + + getInstanceIdentiferGeneratorMock + .setup(idGetter => idGetter(requirementKey)) + .returns(() => instanceIdentifierGeneratorStub); + + assessmentDataConverterMock + .setup(a => + a.generateAssessmentInstancesMap( + initialAssessmentData.generatedAssessmentInstancesMap, + payload.selectorMap, + requirementKey, + instanceIdentifierGeneratorStub, + stepConfig.getInstanceStatus, + stepConfig.isVisualizationSupportedForResult, ), ) .returns(() => expectedInstanceMap); @@ -893,56 +1100,73 @@ describe('AssessmentStoreTest', () => { .testListenerToBeCalledOnce(initialState, finalState); }); - test('on changeAssessmentVisualizationState', () => { - const generatedAssessmentInstancesMap: DictionaryStringTo = { - selector: { - testStepResults: { - [requirementKey]: { - isVisualizationEnabled: true, + test.each` + supportsVisualization | startsEnabled | payloadEnabled | expectedFinalEnabled + ${false} | ${false} | ${true} | ${false} + ${true} | ${false} | ${true} | ${true} + ${true} | ${true} | ${false} | ${false} + ${true} | ${true} | ${true} | ${true} + ${true} | ${false} | ${false} | ${false} + `( + 'on changeAssessmentVisualizationState: supportsVisualization:$supportsVisualization, ' + + 'startsEnabled:$startsEnabled, payloadEnabled:$payloadEnabled -> finalEnabled:$expectedFinalEnabled', + ({ supportsVisualization, startsEnabled, payloadEnabled, expectedFinalEnabled }) => { + const generatedAssessmentInstancesMap: DictionaryStringTo = { + selector: { + testStepResults: { + [requirementKey]: { + isVisualizationEnabled: startsEnabled, + isVisualizationSupported: supportsVisualization, + }, }, - }, - } as any, - }; + } as any, + }; - const assessmentData = new AssessmentDataBuilder() - .with('generatedAssessmentInstancesMap', generatedAssessmentInstancesMap) - .build(); + const assessmentData = new AssessmentDataBuilder() + .with('generatedAssessmentInstancesMap', generatedAssessmentInstancesMap) + .build(); - const initialState = getStateWithAssessment(assessmentData); + const initialState = getStateWithAssessment(assessmentData); - const payload: ChangeInstanceSelectionPayload = { - test: assessmentType, - requirement: requirementKey, - isVisualizationEnabled: true, - selector: 'selector', - }; + const payload: ChangeInstanceSelectionPayload = { + test: assessmentType, + requirement: requirementKey, + isVisualizationEnabled: payloadEnabled, + selector: 'selector', + }; - assessmentsProviderMock - .setup(apm => apm.forType(payload.test)) - .returns(() => assessmentMock.object); + assessmentsProviderMock + .setup(apm => apm.forType(payload.test)) + .returns(() => assessmentMock.object); - assessmentMock.setup(am => am.getVisualizationConfiguration()).returns(() => configStub); + assessmentMock + .setup(am => am.getVisualizationConfiguration()) + .returns(() => configStub); - const expectedInstancesMap = cloneDeep(generatedAssessmentInstancesMap); - expectedInstancesMap.selector.testStepResults[requirementKey].isVisualizationEnabled = true; + const expectedInstancesMap = cloneDeep(generatedAssessmentInstancesMap); + expectedInstancesMap.selector.testStepResults[ + requirementKey + ].isVisualizationEnabled = expectedFinalEnabled; - const expectedAssessment = new AssessmentDataBuilder() - .with('generatedAssessmentInstancesMap', expectedInstancesMap) - .build(); + const expectedAssessment = new AssessmentDataBuilder() + .with('generatedAssessmentInstancesMap', expectedInstancesMap) + .build(); - const finalState = getStateWithAssessment(expectedAssessment); + const finalState = getStateWithAssessment(expectedAssessment); - createStoreTesterForAssessmentActions('changeAssessmentVisualizationState') - .withActionParam(payload) - .testListenerToBeCalledOnce(initialState, finalState); - }); + createStoreTesterForAssessmentActions('changeAssessmentVisualizationState') + .withActionParam(payload) + .testListenerToBeCalledOnce(initialState, finalState); + }, + ); - test('on changeAssessmentVisualizationStateForAll', () => { + test('changeAssessmentVisualizationStateForAll enables all visualizations that support it', () => { const generatedAssessmentInstancesMap: DictionaryStringTo = { selector1: { testStepResults: { [requirementKey]: { isVisualizationEnabled: true, + isVisualizationSupported: true, }, }, } as any, @@ -950,12 +1174,21 @@ describe('AssessmentStoreTest', () => { testStepResults: { [requirementKey]: { isVisualizationEnabled: false, + isVisualizationSupported: false, }, }, } as any, selector3: { testStepResults: {}, } as any, + selector4: { + testStepResults: { + [requirementKey]: { + isVisualizationEnabled: false, + isVisualizationSupported: true, + }, + }, + } as any, }; const assessmentData = new AssessmentDataBuilder() @@ -978,7 +1211,12 @@ describe('AssessmentStoreTest', () => { assessmentMock.setup(am => am.getVisualizationConfiguration()).returns(() => configStub); const expectedInstancesMap = cloneDeep(generatedAssessmentInstancesMap); - expectedInstancesMap.selector2.testStepResults[ + + // Selector 1 shouldn't change because it's already enabled + // Selector 2 shouldn't change because it doesn't support visualizations + // Selector 3 shouldn't change because it has no test step results + // Selector 4 should toggle from disabled to enabled: + expectedInstancesMap.selector4.testStepResults[ requirementKey ].isVisualizationEnabled = true; diff --git a/src/tests/unit/tests/scanner/custom-rules/landmark-role.test.ts b/src/tests/unit/tests/scanner/custom-rules/landmark-role.test.ts deleted file mode 100644 index 12e0a14e3a7..00000000000 --- a/src/tests/unit/tests/scanner/custom-rules/landmark-role.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -import { landmarkConfiguration } from '../../../../../scanner/custom-rules/landmark-rule'; - -describe('landmarkRule', () => { - describe('verify landmark configs', () => { - it('should have correct props', () => { - expect(landmarkConfiguration.rule.id).toBe('main-landmark'); - expect(landmarkConfiguration.rule.selector).toBe('[role=main], main'); - expect(landmarkConfiguration.rule.any[0]).toBe('unique-landmark'); - expect(landmarkConfiguration.checks.length).toBe(0); - }); - }); -}); From 335ab1dbe1acbe3be858ecfbfdcf1c509597edb7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 22:12:54 +0000 Subject: [PATCH 03/15] chore(deps-dev): bump typescript from 3.8.3 to 3.9.2 (#2674) --- package.json | 2 +- .../images/test-steps/text-alternative.tsx | 4 +-- .../semantics/test-steps/css-content.tsx | 4 +-- .../test-steps/headers-attribute.tsx | 4 +-- .../semantics/test-steps/table-semantics.tsx | 4 +-- .../sequence/test-steps/css-positioning.tsx | 4 +-- .../sequence/test-steps/layout-tables.tsx | 7 +++-- .../test-steps/high-contrast-mode.tsx | 6 ++-- .../test-steps/resize-text.tsx | 6 ++-- .../details-view-command-bar.test.tsx | 17 ++++++----- .../left-nav/details-view-left-nav.test.tsx | 12 +++++--- .../DetailsView/details-view-body.test.tsx | 29 ++++++++++++------- yarn.lock | 8 ++--- 13 files changed, 62 insertions(+), 45 deletions(-) diff --git a/package.json b/package.json index f3892e53030..836ca9ca459 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "tslint-microsoft-contrib": "6.2.0", "typed-scss-modules": "^1.3.0", "typemoq": "^2.1.0", - "typescript": "^3.8.3", + "typescript": "^3.9.2", "webdriverio": "^4.13.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11", diff --git a/src/assessments/images/test-steps/text-alternative.tsx b/src/assessments/images/test-steps/text-alternative.tsx index f49f7de0aad..88a0d996c2b 100644 --- a/src/assessments/images/test-steps/text-alternative.tsx +++ b/src/assessments/images/test-steps/text-alternative.tsx @@ -76,8 +76,8 @@ const howToTest: JSX.Element = ( If a CSS background image is coded as meaningful:
  1. - Use the Web Developer browser extension (CSS >{' '} - Disable All Styles) to turn off CSS. + Use the Web Developer browser extension (CSS{' '} + {'>'} Disable All Styles) to turn off CSS.
  2. Verify that the information conveyed by the image is visible when CSS is diff --git a/src/assessments/semantics/test-steps/css-content.tsx b/src/assessments/semantics/test-steps/css-content.tsx index 42ced03fbb5..22bf2ea54b1 100644 --- a/src/assessments/semantics/test-steps/css-content.tsx +++ b/src/assessments/semantics/test-steps/css-content.tsx @@ -70,8 +70,8 @@ const cssContentHowToTest: JSX.Element = (
    • Use the Web Developer browser extension{' '} - (CSS > Disable All Styles) to turn off - CSS. + (CSS {'>'} Disable All Styles) to turn + off CSS.
    • Verify that any information conveyed by the inserted content is diff --git a/src/assessments/semantics/test-steps/headers-attribute.tsx b/src/assessments/semantics/test-steps/headers-attribute.tsx index 9c9902f0d2b..95b9ffae4c8 100644 --- a/src/assessments/semantics/test-steps/headers-attribute.tsx +++ b/src/assessments/semantics/test-steps/headers-attribute.tsx @@ -29,8 +29,8 @@ const headersAttributeHowToTest: JSX.Element = (
      1. Use the Web Developer browser extension ( - Information > Display table information) to reveal any{' '} - headers attributes on the page. Note: The{' '} + Information {'>'} Display table information) to reveal + any headers attributes on the page. Note: The{' '} headers attributes are displayed on the data cells, and not on the cells they reference.
      2. diff --git a/src/assessments/semantics/test-steps/table-semantics.tsx b/src/assessments/semantics/test-steps/table-semantics.tsx index f0fcfb0de59..a3d5cea1e37 100644 --- a/src/assessments/semantics/test-steps/table-semantics.tsx +++ b/src/assessments/semantics/test-steps/table-semantics.tsx @@ -25,7 +25,7 @@ const tableSemanticsHowToTest: JSX.Element = (
        1. Use the Web Developer browser extension ( - Outline > Outline tables) to outline{' '} + Outline {'>'} Outline tables) to outline{' '} elements on the page.
        2. @@ -43,7 +43,7 @@ const tableSemanticsHowToTest: JSX.Element = (
        3. Use the Web Developer browser extension to reveal elements with ARIA roles ( - Information > Display ARIA Roles). + Information {'>'} Display ARIA Roles).
        4. Verify that each table is coded correctly for its type: diff --git a/src/assessments/sequence/test-steps/css-positioning.tsx b/src/assessments/sequence/test-steps/css-positioning.tsx index b0d9eb0360c..543d992f83a 100644 --- a/src/assessments/sequence/test-steps/css-positioning.tsx +++ b/src/assessments/sequence/test-steps/css-positioning.tsx @@ -50,8 +50,8 @@ const howToTest: JSX.Element = (
        5. If the page does have meaningful positioned content, use the Web Developer browser - extension (Miscellaneous > Linearize page) to show the - page in DOM order. + extension (Miscellaneous {'>'} Linearize page) to show + the page in DOM order.
        6. Verify that the positioned content retains its meaning when the page is linearized. diff --git a/src/assessments/sequence/test-steps/layout-tables.tsx b/src/assessments/sequence/test-steps/layout-tables.tsx index a87c5ba0fcc..c0caebb3d74 100644 --- a/src/assessments/sequence/test-steps/layout-tables.tsx +++ b/src/assessments/sequence/test-steps/layout-tables.tsx @@ -24,7 +24,8 @@ const howToTest: JSX.Element = (

          1. - Use the Web Developer extension (Outline > Outline Tables + Use the Web Developer extension ( + Outline {'>'} Outline Tables ) to identify any elements in the target page.
          2. @@ -43,8 +44,8 @@ const howToTest: JSX.Element = (
          3. If you find a layout table, use the Web Developer browser extension ( - Miscellaneous > Linearize page) to show the page in DOM - order. + Miscellaneous {'>'} Linearize page) to show the page in + DOM order.
          4. Verify that content in layout tables still has the correct reading order when the diff --git a/src/assessments/text-legibility/test-steps/high-contrast-mode.tsx b/src/assessments/text-legibility/test-steps/high-contrast-mode.tsx index 332e11bd417..0fba224f94c 100644 --- a/src/assessments/text-legibility/test-steps/high-contrast-mode.tsx +++ b/src/assessments/text-legibility/test-steps/high-contrast-mode.tsx @@ -18,9 +18,9 @@ const highContrastModeHowToTest: JSX.Element = (
            1. Open the target page in the new Microsoft Edge or Microsoft Edge Legacy.
            2. - Use Windows Settings >{' '} - Ease of Access > High contrast{' '} - to apply a high contrast theme. + Use Windows Settings {'>'}{' '} + Ease of Access {'>'}{' '} + High contrast to apply a high contrast theme.
            3. Verify that the target page adopts the colors specified for the theme.
            4. diff --git a/src/assessments/text-legibility/test-steps/resize-text.tsx b/src/assessments/text-legibility/test-steps/resize-text.tsx index 69cf604dfac..3501b8aa384 100644 --- a/src/assessments/text-legibility/test-steps/resize-text.tsx +++ b/src/assessments/text-legibility/test-steps/resize-text.tsx @@ -28,9 +28,9 @@ const resizeTextHowToTest: JSX.Element = (  
              1. - Use Windows Settings > System{' '} - > Display > Scale and layout{' '} - to + Use Windows Settings {'>'}{' '} + System {'>'} Display {'>'}{' '} + Scale and layout to
                1. Set the resolution to 1920x1080, and
                2. Set scaling to 100%.
                3. diff --git a/src/tests/unit/tests/DetailsView/components/details-view-command-bar.test.tsx b/src/tests/unit/tests/DetailsView/components/details-view-command-bar.test.tsx index 3928b97a231..8f590932b32 100644 --- a/src/tests/unit/tests/DetailsView/components/details-view-command-bar.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/details-view-command-bar.test.tsx @@ -3,8 +3,10 @@ import { NamedFC, ReactFCWithDisplayName } from 'common/react/named-fc'; import { ScanMetadata } from 'common/types/store-data/unified-data-interface'; import { DetailsViewActionMessageCreator } from 'DetailsView/actions/details-view-action-message-creator'; -import { DetailsViewSwitcherNavConfiguration } from 'DetailsView/components/details-view-switcher-nav'; -import { DetailsViewBodyProps } from 'DetailsView/details-view-body'; +import { + DetailsViewSwitcherNavConfiguration, + LeftNavProps, +} from 'DetailsView/components/details-view-switcher-nav'; import { shallow } from 'enzyme'; import { ActionButton } from 'office-ui-fabric-react'; import * as React from 'react'; @@ -38,12 +40,13 @@ describe('DetailsViewCommandBar', () => { }); function getProps(): DetailsViewCommandBarProps { - const CommandBarStub: Readonly> = NamedFC< - DetailsViewBodyProps - >('test', _ => null); - const LeftNavStub: Readonly> = NamedFC< - DetailsViewBodyProps + const CommandBarStub: ReactFCWithDisplayName = NamedFC< + DetailsViewCommandBarProps >('test', _ => null); + const LeftNavStub: ReactFCWithDisplayName = NamedFC( + 'test', + _ => null, + ); const switcherNavConfiguration: DetailsViewSwitcherNavConfiguration = { CommandBar: CommandBarStub, ReportExportComponentFactory: p => reportExportComponent, diff --git a/src/tests/unit/tests/DetailsView/components/left-nav/details-view-left-nav.test.tsx b/src/tests/unit/tests/DetailsView/components/left-nav/details-view-left-nav.test.tsx index 8847dc47128..85bab38586f 100644 --- a/src/tests/unit/tests/DetailsView/components/left-nav/details-view-left-nav.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/left-nav/details-view-left-nav.test.tsx @@ -13,7 +13,10 @@ import { import { FeatureFlagStoreData } from '../../../../../../common/types/store-data/feature-flag-store-data'; import { VisualizationType } from '../../../../../../common/types/visualization-type'; import { DetailsRightPanelConfiguration } from '../../../../../../DetailsView/components/details-view-right-panel'; -import { DetailsViewSwitcherNavConfiguration } from '../../../../../../DetailsView/components/details-view-switcher-nav'; +import { + DetailsViewSwitcherNavConfiguration, + LeftNavProps, +} from '../../../../../../DetailsView/components/details-view-switcher-nav'; import { DetailsViewLeftNav, DetailsViewLeftNavDeps, @@ -36,9 +39,10 @@ describe('DetailsViewLeftNav', () => { (theProps: GetLeftNavSelectedKeyProps) => null, MockBehavior.Strict, ); - const LeftNavStub: Readonly> = NamedFC< - DetailsViewLeftNavProps - >('test', _ => null); + const LeftNavStub: Readonly> = NamedFC( + 'test', + _ => null, + ); const assessmentDataStub: { [key: string]: AssessmentData } = { x: { testStepStatus: {} } as AssessmentData, }; diff --git a/src/tests/unit/tests/DetailsView/details-view-body.test.tsx b/src/tests/unit/tests/DetailsView/details-view-body.test.tsx index 18ab5a78240..9f7ee72b5a3 100644 --- a/src/tests/unit/tests/DetailsView/details-view-body.test.tsx +++ b/src/tests/unit/tests/DetailsView/details-view-body.test.tsx @@ -5,7 +5,10 @@ import { IMock, Mock, MockBehavior } from 'typemoq'; import { getDefaultFeatureFlagsWeb } from 'common/feature-flags'; import { ScanMetadata, TargetAppData } from 'common/types/store-data/unified-data-interface'; -import { DetailsViewCommandBarDeps } from 'DetailsView/components/details-view-command-bar'; +import { + DetailsViewCommandBarDeps, + DetailsViewCommandBarProps, +} from 'DetailsView/components/details-view-command-bar'; import { VisualizationConfiguration } from '../../../../common/configs/visualization-configuration'; import { VisualizationConfigurationFactory } from '../../../../common/configs/visualization-configuration-factory'; import { NamedFC, ReactFCWithDisplayName } from '../../../../common/react/named-fc'; @@ -22,8 +25,14 @@ import { } from '../../../../common/types/store-data/visualization-store-data'; import { VisualizationType } from '../../../../common/types/visualization-type'; import { DetailsViewActionMessageCreator } from '../../../../DetailsView/actions/details-view-action-message-creator'; -import { DetailsRightPanelConfiguration } from '../../../../DetailsView/components/details-view-right-panel'; -import { DetailsViewSwitcherNavConfiguration } from '../../../../DetailsView/components/details-view-switcher-nav'; +import { + DetailsRightPanelConfiguration, + RightPanelProps, +} from '../../../../DetailsView/components/details-view-right-panel'; +import { + DetailsViewSwitcherNavConfiguration, + LeftNavProps, +} from '../../../../DetailsView/components/details-view-switcher-nav'; import { DetailsViewLeftNav } from '../../../../DetailsView/components/left-nav/details-view-left-nav'; import { TargetPageHiddenBar } from '../../../../DetailsView/components/target-page-hidden-bar'; import { DetailsViewBody, DetailsViewBodyProps } from '../../../../DetailsView/details-view-body'; @@ -49,14 +58,14 @@ describe('DetailsViewBody', () => { describe('render', () => { beforeEach(() => { selectedTest = -1; - const RightPanelStub: Readonly> = NamedFC< - DetailsViewBodyProps - >('test', _ => null); - const CommandBarStub: Readonly> = NamedFC< - DetailsViewBodyProps + const RightPanelStub: Readonly> = NamedFC< + RightPanelProps >('test', _ => null); - const LeftNavStub: Readonly> = NamedFC< - DetailsViewBodyProps + const CommandBarStub: Readonly> = NamedFC('test', _ => null); + const LeftNavStub: Readonly> = NamedFC< + LeftNavProps >('test', _ => null); rightPanelConfig = { RightPanel: RightPanelStub, diff --git a/yarn.lock b/yarn.lock index 25921a41b45..09b12c33f17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10131,10 +10131,10 @@ typemoq@^2.1.0: lodash "^4.17.4" postinstall-build "^5.0.1" -typescript@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" + integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw== typeson-registry@^1.0.0-alpha.20: version "1.0.0-alpha.29" From b86905208ba3736fff96b730b150654c4bff6e0e Mon Sep 17 00:00:00 2001 From: Liu Haonan Date: Thu, 14 May 2020 15:21:19 -0700 Subject: [PATCH 04/15] feat(mobile-rules-guidance): add rule link (#2682) * add rule link * update test name * fix a url * share base url --- .../android/rule-information-provider.ts | 7 ++++- .../platform/android/rule-information.ts | 1 + .../android/scan-results-to-unified-rules.ts | 2 +- ...scan-results-to-unified-rules.test.ts.snap | 10 +++---- .../android/rule-information-provider.test.ts | 2 +- .../platform/android/rule-information.test.ts | 29 +++++++++++++++++-- .../platform/android/scan-results-helpers.ts | 2 ++ .../scan-results-to-unified-results.test.ts | 7 ++++- .../scan-results-to-unified-rules.test.ts | 5 +++- 9 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/electron/platform/android/rule-information-provider.ts b/src/electron/platform/android/rule-information-provider.ts index 81236c64b39..2838a19ccbc 100644 --- a/src/electron/platform/android/rule-information-provider.ts +++ b/src/electron/platform/android/rule-information-provider.ts @@ -9,11 +9,12 @@ import { RuleInformation } from './rule-information'; export class RuleInformationProvider { private supportedRules: DictionaryStringTo; - + private readonly ruleLinkBaseUrl = 'https://accessibilityinsights.io/info-examples/android'; constructor() { this.supportedRules = { ColorContrast: new RuleInformation( 'ColorContrast', + `${this.ruleLinkBaseUrl}/color-contrast/`, 'Text elements must have sufficient contrast against the background.', [link.WCAG_1_4_3], this.getColorContrastUnifiedFormattableResolution, @@ -21,6 +22,7 @@ export class RuleInformationProvider { ), TouchSizeWcag: new RuleInformation( 'TouchSizeWcag', + `${this.ruleLinkBaseUrl}/touch-size-wcag/`, 'Touch inputs must have a sufficient target size.', [link.WCAG_1_3_1, link.WCAG_3_3_2], this.getTouchSizeUnifiedFormattableResolution, @@ -28,6 +30,7 @@ export class RuleInformationProvider { ), ActiveViewName: new RuleInformation( 'ActiveViewName', + `${this.ruleLinkBaseUrl}/active-view-name/`, "Active views must have a name that's available to assistive technologies.", [link.WCAG_2_5_5], () => @@ -39,6 +42,7 @@ export class RuleInformationProvider { ), ImageViewName: new RuleInformation( 'ImageViewName', + `${this.ruleLinkBaseUrl}/image-view-name/`, 'Meaningful images must have alternate text.', [link.WCAG_1_1_1], () => @@ -50,6 +54,7 @@ export class RuleInformationProvider { ), EditTextValue: new RuleInformation( 'EditTextValue', + `${this.ruleLinkBaseUrl}/edit-text-value/`, 'EditText elements must expose their entered text value to assistive technologies', [link.WCAG_4_1_2], () => diff --git a/src/electron/platform/android/rule-information.ts b/src/electron/platform/android/rule-information.ts index 2e8827e1610..2082d8c6d21 100644 --- a/src/electron/platform/android/rule-information.ts +++ b/src/electron/platform/android/rule-information.ts @@ -14,6 +14,7 @@ export type IncludeThisResultDelegate = (ruleResultsData: RuleResultsData) => bo export class RuleInformation { constructor( readonly ruleId: string, + readonly ruleLink: string, readonly ruleDescription: string, readonly guidance: GuidanceLink[], readonly getUnifiedFormattableResolutionDelegate: GetUnifiedFormattableResolutionDelegate, diff --git a/src/electron/platform/android/scan-results-to-unified-rules.ts b/src/electron/platform/android/scan-results-to-unified-rules.ts index bdafe26cfa2..4a74b483599 100644 --- a/src/electron/platform/android/scan-results-to-unified-rules.ts +++ b/src/electron/platform/android/scan-results-to-unified-rules.ts @@ -48,7 +48,7 @@ function createUnifiedRuleFromRuleResult( uid: uuidGenerator(), id: ruleInformation.ruleId, description: ruleInformation.ruleDescription, - url: null, + url: ruleInformation.ruleLink, guidance: ruleInformation.guidance, }; } diff --git a/src/tests/unit/tests/electron/platform/android/__snapshots__/scan-results-to-unified-rules.test.ts.snap b/src/tests/unit/tests/electron/platform/android/__snapshots__/scan-results-to-unified-rules.test.ts.snap index fb46dc9fa68..5c7e5bb09a4 100644 --- a/src/tests/unit/tests/electron/platform/android/__snapshots__/scan-results-to-unified-rules.test.ts.snap +++ b/src/tests/unit/tests/electron/platform/android/__snapshots__/scan-results-to-unified-rules.test.ts.snap @@ -9,7 +9,7 @@ Array [ "guidance": Array [], "id": "Rule #1", "uid": "gguid-mock-stub", - "url": null, + "url": "rule-link", }, ] `; @@ -21,7 +21,7 @@ Array [ "guidance": Array [], "id": "Rule #1", "uid": "gguid-mock-stub", - "url": null, + "url": "rule-link", }, ] `; @@ -39,21 +39,21 @@ Array [ ], "id": "Rule #3", "uid": "gguid-mock-stub", - "url": null, + "url": "rule-link-3", }, Object { "description": "This describes Rule #1", "guidance": Array [], "id": "Rule #1", "uid": "gguid-mock-stub", - "url": null, + "url": "rule-link", }, Object { "description": "This describes Rule #2", "guidance": Array [], "id": "Rule #2", "uid": "gguid-mock-stub", - "url": null, + "url": "rule-link", }, ] `; diff --git a/src/tests/unit/tests/electron/platform/android/rule-information-provider.test.ts b/src/tests/unit/tests/electron/platform/android/rule-information-provider.test.ts index 0d03fabca68..e763199a0cf 100644 --- a/src/tests/unit/tests/electron/platform/android/rule-information-provider.test.ts +++ b/src/tests/unit/tests/electron/platform/android/rule-information-provider.test.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. - import { UnifiedFormattableResolution } from 'common/types/store-data/unified-data-interface'; import { RuleResultsData } from 'electron/platform/android/android-scan-results'; import { RuleInformation } from 'electron/platform/android/rule-information'; import { RuleInformationProvider } from 'electron/platform/android/rule-information-provider'; + import { buildRuleResultObject } from './scan-results-helpers'; describe('RuleInformationProvider', () => { diff --git a/src/tests/unit/tests/electron/platform/android/rule-information.test.ts b/src/tests/unit/tests/electron/platform/android/rule-information.test.ts index a1e3cbce780..26f12156181 100644 --- a/src/tests/unit/tests/electron/platform/android/rule-information.test.ts +++ b/src/tests/unit/tests/electron/platform/android/rule-information.test.ts @@ -20,7 +20,14 @@ describe('RuleInformation', () => { test('RuleId works correctly', () => { for (const ruleId of testInputs) { - const ruleInformation = new RuleInformation(ruleId, null, null, null, failIfCalled); + const ruleInformation = new RuleInformation( + ruleId, + null, + null, + null, + null, + failIfCalled, + ); expect(ruleId === ruleInformation.ruleId); } }); @@ -28,6 +35,7 @@ describe('RuleInformation', () => { test('RuleDescription works correctly', () => { for (const ruleDescription of testInputs) { const ruleInformation = new RuleInformation( + null, null, ruleDescription, null, @@ -38,12 +46,25 @@ describe('RuleInformation', () => { } }); - test('guidance works correctly', () => { + test('rule link works correctly', () => { const guidance = [link.WCAG_1_1_1]; - const ruleInformation = new RuleInformation(null, null, guidance, null, failIfCalled); + const ruleInformation = new RuleInformation(null, null, null, guidance, null, failIfCalled); expect(ruleInformation.guidance).toEqual(guidance); }); + test('guidance works correctly', () => { + const url = 'rule-link'; + const ruleInformation = new RuleInformation( + null, + 'rule-link', + null, + null, + null, + failIfCalled, + ); + expect(ruleInformation.ruleLink).toEqual(url); + }); + test('GetUnifiedResolution works correctly', () => { const testData: RuleResultsData = { axeViewId: 'test', @@ -68,6 +89,7 @@ describe('RuleInformation', () => { null, null, null, + null, getUnifiedFormattableResolutionDelegateMock.object, failIfCalled, ); @@ -99,6 +121,7 @@ describe('RuleInformation', () => { null, null, null, + null, includeThisResultMock.object, ); diff --git a/src/tests/unit/tests/electron/platform/android/scan-results-helpers.ts b/src/tests/unit/tests/electron/platform/android/scan-results-helpers.ts index f39d74f883c..37ba4de2b05 100644 --- a/src/tests/unit/tests/electron/platform/android/scan-results-helpers.ts +++ b/src/tests/unit/tests/electron/platform/android/scan-results-helpers.ts @@ -112,12 +112,14 @@ export function buildViewElement( export function buildRuleInformation( ruleId: string, + ruleLink = 'rule-link', guidance: GuidanceLink[] = [], includeResults: boolean = true, ): RuleInformation { return { ruleId: ruleId, ruleDescription: 'This describes ' + ruleId, + ruleLink, guidance, getUnifiedFormattableResolutionDelegate: r => { expect('getUnifiedResolution').toBe('This code should never execute'); diff --git a/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-results.test.ts b/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-results.test.ts index 4ba578dc4f7..f764276aaa3 100644 --- a/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-results.test.ts +++ b/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-results.test.ts @@ -36,7 +36,12 @@ describe('ScanResultsToUnifiedResults', () => { const ruleInformation1: RuleInformation = buildRuleInformation(ruleId1); const ruleInformation2: RuleInformation = buildRuleInformation(ruleId2); const ruleInformation3: RuleInformation = buildRuleInformation(ruleId3); - const ruleInformation4: RuleInformation = buildRuleInformation(ruleId4, [], false); + const ruleInformation4: RuleInformation = buildRuleInformation( + ruleId4, + 'rule-link-4', + [], + false, + ); ruleInformationProviderMock = Mock.ofType(); ruleInformationProviderMock diff --git a/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-rules.test.ts b/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-rules.test.ts index d032581d6d9..657f2947589 100644 --- a/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-rules.test.ts +++ b/src/tests/unit/tests/electron/platform/android/scan-results-to-unified-rules.test.ts @@ -73,9 +73,12 @@ describe('ScanResultsToUnifiedRules', () => { const ruleInformation1: RuleInformation = buildRuleInformation(ruleId1); const ruleInformation2: RuleInformation = buildRuleInformation(ruleId2); - const ruleInformation3: RuleInformation = buildRuleInformation(ruleId3, [link.WCAG_1_1_1]); + const ruleInformation3: RuleInformation = buildRuleInformation(ruleId3, 'rule-link-3', [ + link.WCAG_1_1_1, + ]); const ruleInformation4: RuleInformation = buildRuleInformation( ruleId4, + 'rule-link-4', [link.WCAG_1_2_1], false, ); From 505427b4b294c4c040121da2d95257b5961c7f2e Mon Sep 17 00:00:00 2001 From: lisli1 <48259897+lisli1@users.noreply.github.com> Date: Thu, 14 May 2020 16:50:52 -0700 Subject: [PATCH 05/15] feat(nav-bar-content): add visual helper toggle to requirement view (#2676) --- .../components/requirement-view.scss | 11 ++++++ .../components/requirement-view.tsx | 37 ++++++++++++++++++- .../requirement-view.test.tsx.snap | 3 ++ .../components/requirement-view.test.tsx | 29 +++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/DetailsView/components/requirement-view.scss b/src/DetailsView/components/requirement-view.scss index f46a9352d85..60b13c92b13 100644 --- a/src/DetailsView/components/requirement-view.scss +++ b/src/DetailsView/components/requirement-view.scss @@ -7,3 +7,14 @@ padding-left: 6px; padding-top: 1vh; } + +:global(.visual-helper) { + display: flex; + padding-top: 1.5vh; + &-text { + padding-right: 0.9vh; + font-family: $fontFamily; + font-size: 14px; + line-height: 20px; + } +} diff --git a/src/DetailsView/components/requirement-view.tsx b/src/DetailsView/components/requirement-view.tsx index 355acd5a9bd..077684baa98 100644 --- a/src/DetailsView/components/requirement-view.tsx +++ b/src/DetailsView/components/requirement-view.tsx @@ -1,22 +1,54 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { Requirement } from 'assessments/types/requirement'; +import { AssessmentsProvider } from 'assessments/types/assessments-provider'; +import { Requirement, VisualHelperToggleConfig } from 'assessments/types/requirement'; import { NamedFC } from 'common/react/named-fc'; +import { + AssessmentNavState, + GeneratedAssessmentInstance, +} from 'common/types/store-data/assessment-result-data'; +import { DetailsViewActionMessageCreator } from 'DetailsView/actions/details-view-action-message-creator'; import { RequirementInstructions } from 'DetailsView/components/requirement-instructions'; import { RequirementViewTitle, RequirementViewTitleDeps, } from 'DetailsView/components/requirement-view-title'; import * as React from 'react'; +import { DictionaryStringTo } from 'types/common-types'; import * as styles from './requirement-view.scss'; -export type RequirementViewDeps = RequirementViewTitleDeps; +export type RequirementViewDeps = { + detailsViewActionMessageCreator: DetailsViewActionMessageCreator; +} & RequirementViewTitleDeps; + export interface RequirementViewProps { deps: RequirementViewDeps; requirement: Requirement; + assessmentsProvider: AssessmentsProvider; + assessmentNavState: AssessmentNavState; + instancesMap: DictionaryStringTo; + isStepEnabled: boolean; + isStepScanned: boolean; } export const RequirementView = NamedFC('RequirementView', props => { + const requirement: Readonly = props.assessmentsProvider.getStep( + props.assessmentNavState.selectedTestType, + props.assessmentNavState.selectedTestSubview, + ); + + const visualHelperToggleConfig: VisualHelperToggleConfig = { + deps: props.deps, + assessmentNavState: props.assessmentNavState, + instancesMap: props.instancesMap, + isStepEnabled: props.isStepEnabled, + isStepScanned: props.isStepScanned, + }; + + const visualHelperToggle = requirement.getVisualHelperToggle + ? requirement.getVisualHelperToggle(visualHelperToggleConfig) + : null; + return (
                  ('RequirementView', infoAndExamples={props.requirement.infoAndExamples} /> {props.requirement.description} + {visualHelperToggle}
                  ); diff --git a/src/tests/unit/tests/DetailsView/components/__snapshots__/requirement-view.test.tsx.snap b/src/tests/unit/tests/DetailsView/components/__snapshots__/requirement-view.test.tsx.snap index 7ad439b8c99..bb6e800d911 100644 --- a/src/tests/unit/tests/DetailsView/components/__snapshots__/requirement-view.test.tsx.snap +++ b/src/tests/unit/tests/DetailsView/components/__snapshots__/requirement-view.test.tsx.snap @@ -11,6 +11,9 @@ exports[`RequirementViewTest renders with content from props 1`] = `
                  test-description
                  +
                  + test-visual-helper-toggle +
                  diff --git a/src/tests/unit/tests/DetailsView/components/requirement-view.test.tsx b/src/tests/unit/tests/DetailsView/components/requirement-view.test.tsx index 7f252622f88..0c8b36b3204 100644 --- a/src/tests/unit/tests/DetailsView/components/requirement-view.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/requirement-view.test.tsx @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { AssessmentsProviderImpl } from 'assessments/assessments-provider'; import { Requirement } from 'assessments/types/requirement'; +import { GeneratedAssessmentInstance } from 'common/types/store-data/assessment-result-data'; +import { VisualizationType } from 'common/types/visualization-type'; import { RequirementView, RequirementViewDeps, @@ -8,6 +11,8 @@ import { } from 'DetailsView/components/requirement-view'; import { shallow } from 'enzyme'; import * as React from 'react'; +import { Mock } from 'typemoq'; +import { DictionaryStringTo } from 'types/common-types'; describe('RequirementViewTest', () => { it('renders with content from props', () => { @@ -17,9 +22,33 @@ describe('RequirementViewTest', () => { howToTest:

                  how-to-test-stub

                  , } as Requirement; + const assessmentNavState = { + selectedTestType: VisualizationType.Headings, + selectedTestSubview: 'test-requirement-name', + }; + + const selectedRequirementStub = { + getVisualHelperToggle: ({}) =>
                  test-visual-helper-toggle
                  , + } as Readonly; + + const assessmentsProviderMock = Mock.ofType(AssessmentsProviderImpl); + assessmentsProviderMock + .setup(ap => + ap.getStep( + assessmentNavState.selectedTestType, + assessmentNavState.selectedTestSubview, + ), + ) + .returns(() => selectedRequirementStub); + const props: RequirementViewProps = { deps: {} as RequirementViewDeps, requirement: requirementStub, + assessmentsProvider: assessmentsProviderMock.object, + assessmentNavState: assessmentNavState, + instancesMap: {} as DictionaryStringTo, + isStepEnabled: true, + isStepScanned: true, }; const rendered = shallow(); From 08529b99d0196230f6b18fa9559facabbb3b9383 Mon Sep 17 00:00:00 2001 From: Wahaj <32555133+waabid@users.noreply.github.com> Date: Thu, 14 May 2020 18:31:11 -0700 Subject: [PATCH 06/15] feat(nav-bar-content): nav link handler uses requirement key explicitly (#2684) * feat(nav-bar-content): nav link handler uses requirement key explicitly * re-added removed line --- .../left-nav/assessment-left-nav.tsx | 1 + .../left-nav/left-nav-link-builder.tsx | 1 + .../components/left-nav/nav-link-handler.ts | 6 ++- .../left-nav-link-builder.test.tsx.snap | 54 +++++++++++-------- .../left-nav/left-nav-link-builder.test.tsx | 1 + .../handlers/nav-link-handler.test.ts | 8 ++- 6 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/DetailsView/components/left-nav/assessment-left-nav.tsx b/src/DetailsView/components/left-nav/assessment-left-nav.tsx index 0ed067d4668..2e51322f2c2 100644 --- a/src/DetailsView/components/left-nav/assessment-left-nav.tsx +++ b/src/DetailsView/components/left-nav/assessment-left-nav.tsx @@ -41,6 +41,7 @@ export type TestGettingStartedNavLink = { export type TestRequirementLeftNavLink = { displayedIndex: string; testType: VisualizationType; + requirementKey: string; } & AssessmentLeftNavLink; export type onTestRequirementClick = ( diff --git a/src/DetailsView/components/left-nav/left-nav-link-builder.tsx b/src/DetailsView/components/left-nav/left-nav-link-builder.tsx index 7a2fbcd28a0..558e2e72795 100644 --- a/src/DetailsView/components/left-nav/left-nav-link-builder.tsx +++ b/src/DetailsView/components/left-nav/left-nav-link-builder.tsx @@ -226,6 +226,7 @@ export class LeftNavLinkBuilder { title: `${displayedIndex}: ${name} (${narratorRequirementStatus})`, displayedIndex, testType: test, + requirementKey: requirement.key, }; } diff --git a/src/DetailsView/components/left-nav/nav-link-handler.ts b/src/DetailsView/components/left-nav/nav-link-handler.ts index c9505682ca0..27b9ceee676 100644 --- a/src/DetailsView/components/left-nav/nav-link-handler.ts +++ b/src/DetailsView/components/left-nav/nav-link-handler.ts @@ -41,7 +41,11 @@ export class NavLinkHandler { event: React.MouseEvent, item: TestRequirementLeftNavLink, ) => { - this.detailsViewActionMessageCreator.selectRequirement(event, item.key, item.testType); + this.detailsViewActionMessageCreator.selectRequirement( + event, + item.requirementKey, + item.testType, + ); this.detailsViewActionMessageCreator.changeRightContentPanel('TestView'); }; diff --git a/src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/left-nav-link-builder.test.tsx.snap b/src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/left-nav-link-builder.test.tsx.snap index 12051a7943c..0a757a3257a 100644 --- a/src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/left-nav-link-builder.test.tsx.snap +++ b/src/tests/unit/tests/DetailsView/components/left-nav/__snapshots__/left-nav-link-builder.test.tsx.snap @@ -86,6 +86,27 @@ exports[`LeftNavBuilder buildAssessmentTestLinks should build links for assessme /> `; +exports[`LeftNavBuilder buildOverviewLink should build overview link 1`] = ` + +`; + exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for assessments: getting started nav link render 1`] = ``; exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for assessments: getting started nav link render 2`] = ``; @@ -104,6 +125,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "-1.1: requirement-name-1 (passed)", @@ -128,6 +150,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "0.1: requirement-name-1 (passed)", @@ -154,6 +177,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "-1.1: requirement-name-1 (passed)", @@ -182,6 +206,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "0.1: requirement-name-1 (passed)", @@ -230,6 +255,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "-1.1: requirement-name-1 (passed)", @@ -246,6 +272,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-2", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-2", "status": -2, "testType": 1, "title": "-1.2: requirement-name-2 (passed)", @@ -300,6 +327,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "0.1: requirement-name-1 (passed)", @@ -316,6 +344,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-2", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-2", "status": -2, "testType": 1, "title": "0.2: requirement-name-2 (passed)", @@ -370,6 +399,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "-1.1: requirement-name-1 (passed)", @@ -386,6 +416,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-2", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-2", "status": -2, "testType": 1, "title": "-1.2: requirement-name-2 (passed)", @@ -439,6 +470,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-1", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-1", "status": -2, "testType": 1, "title": "0.1: requirement-name-1 (passed)", @@ -455,6 +487,7 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as "name": "requirement-name-2", "onClickNavLink": [Function], "onRenderNavLink": [Function], + "requirementKey": "requirement-key-2", "status": -2, "testType": 1, "title": "0.2: requirement-name-2 (passed)", @@ -472,27 +505,6 @@ exports[`LeftNavBuilder buildReflowAssessmentTestLinks should build links for as /> `; -exports[`LeftNavBuilder buildOverviewLink should build overview link 1`] = ` - -`; - exports[`LeftNavBuilder buildVisualizationConfigurationLink should build link using configuration 1`] = ` { }, testType: test, status, + requirementKey: requirement.key, } as TestRequirementLeftNavLink; } }); diff --git a/src/tests/unit/tests/DetailsView/handlers/nav-link-handler.test.ts b/src/tests/unit/tests/DetailsView/handlers/nav-link-handler.test.ts index d24fb24e579..d6bebe7a516 100644 --- a/src/tests/unit/tests/DetailsView/handlers/nav-link-handler.test.ts +++ b/src/tests/unit/tests/DetailsView/handlers/nav-link-handler.test.ts @@ -81,12 +81,16 @@ describe('NavLinkHandler', () => { describe('onRequirementClick', () => { it('should call selectRequirement and changeRightContentPanel with appropriate params', () => { const requirementLink = { - key: 'some requirement', + requirementKey: 'some requirement', testType: -1, } as TestRequirementLeftNavLink; detailsViewActionMessageCreatorMock .setup(amc => - amc.selectRequirement(eventStub, requirementLink.key, requirementLink.testType), + amc.selectRequirement( + eventStub, + requirementLink.requirementKey, + requirementLink.testType, + ), ) .verifiable(); From 4c7d0e50eee25a26cd71886b9118b58a8030d165 Mon Sep 17 00:00:00 2001 From: Liu Haonan Date: Fri, 15 May 2020 08:15:37 -0700 Subject: [PATCH 07/15] feat(mobile-rules-guidance): update common components to use LinkComponent (#2686) * using optional link component * uts * update all guidance link usage * fix report-html-generator deps * revert a change * update snapshots --- src/DetailsView/details-view-initializer.ts | 3 + .../components/cards/rule-resources.tsx | 14 ++- src/common/components/guidance-links.tsx | 9 +- src/injected/components/details-dialog.tsx | 5 +- .../assessment-report-step-header.tsx | 3 + .../report-sections/full-rule-header.tsx | 5 +- src/reports/report-html-generator.tsx | 4 +- .../guidance-links.test.tsx.snap | 16 ++- .../rule-resources.test.tsx.snap | 111 +++++++++++++----- .../components/cards/rule-resources.test.tsx | 29 +++-- .../common/components/guidance-links.test.tsx | 20 ++++ ...ssessment-report-step-header.test.tsx.snap | 2 + .../assessment-report-step-header.test.tsx | 9 +- .../reports/report-html-generator.test.tsx | 3 + 14 files changed, 179 insertions(+), 54 deletions(-) diff --git a/src/DetailsView/details-view-initializer.ts b/src/DetailsView/details-view-initializer.ts index 0fe0aba8b54..802774fe5b7 100644 --- a/src/DetailsView/details-view-initializer.ts +++ b/src/DetailsView/details-view-initializer.ts @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + import { AssessmentDefaultMessageGenerator } from 'assessments/assessment-default-message-generator'; import { Assessments } from 'assessments/assessments'; import { assessmentsProviderWithFeaturesEnabled } from 'assessments/assessments-feature-flag-filter'; @@ -39,6 +40,7 @@ import { ReactStaticRenderer } from 'reports/react-static-renderer'; import { ReportGenerator } from 'reports/report-generator'; import { ReportHtmlGenerator } from 'reports/report-html-generator'; import { WebReportNameGenerator } from 'reports/report-name-generator'; + import { A11YSelfValidator } from '../common/a11y-self-validator'; import { AutoChecker } from '../common/auto-checker'; import { AxeInfo } from '../common/axe-info'; @@ -310,6 +312,7 @@ if (isNaN(tabId) === false) { const assessmentReportHtmlGeneratorDeps = { outcomeTypeSemanticsFromTestStatus, getGuidanceTagsFromGuidanceLinks: GetGuidanceTagsFromGuidanceLinks, + LinkComponent: NewTabLink, }; const assessmentReportHtmlGenerator = new AssessmentReportHtmlGenerator( assessmentReportHtmlGeneratorDeps, diff --git a/src/common/components/cards/rule-resources.tsx b/src/common/components/cards/rule-resources.tsx index 02a1fbb5258..52c348ad6f5 100644 --- a/src/common/components/cards/rule-resources.tsx +++ b/src/common/components/cards/rule-resources.tsx @@ -2,15 +2,17 @@ // Licensed under the MIT License. import { GuidanceLinks } from 'common/components/guidance-links'; import { GuidanceTags, GuidanceTagsDeps } from 'common/components/guidance-tags'; -import { NewTabLink } from 'common/components/new-tab-link'; import { NamedFC } from 'common/react/named-fc'; +import { LinkComponentType } from 'common/types/link-component-type'; import { UnifiedRule } from 'common/types/store-data/unified-data-interface'; import { isEmpty } from 'lodash'; import * as React from 'react'; import * as styles from './rule-resources.scss'; -export type RuleResourcesDeps = GuidanceTagsDeps; +export type RuleResourcesDeps = GuidanceTagsDeps & { + LinkComponent: LinkComponentType; +}; export type RuleResourcesProps = { deps: RuleResourcesDeps; @@ -35,12 +37,16 @@ export const RuleResources = NamedFC('RuleResources', ({ dep const ruleUrl = rule.url; return ( - More information about {ruleId} + + More information about {ruleId} + ); }; - const renderGuidanceLinks = () => ; + const renderGuidanceLinks = () => ( + + ); const renderGuidanceTags = () => ; return ( diff --git a/src/common/components/guidance-links.tsx b/src/common/components/guidance-links.tsx index ac28b1f2cbf..fcee38aceb7 100644 --- a/src/common/components/guidance-links.tsx +++ b/src/common/components/guidance-links.tsx @@ -1,14 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { LinkComponentType } from 'common/types/link-component-type'; import { isEmpty } from 'lodash'; import * as React from 'react'; import { HyperlinkDefinition } from 'views/content/content-page'; + import { NamedFC } from '../react/named-fc'; -import { NewTabLink } from './new-tab-link'; export interface GuidanceLinksProps { links: HyperlinkDefinition[]; classNameForDiv?: string; + LinkComponent: LinkComponentType; } export const GuidanceLinks = NamedFC('GuidanceLinks', (props: GuidanceLinksProps) => { @@ -27,11 +29,12 @@ export const GuidanceLinks = NamedFC('GuidanceLinks', (props: GuidanceLinksProps const renderLink = (link: HyperlinkDefinition, index: number, length: number): JSX.Element => { const addComma: boolean = index !== length - 1; const comma = addComma ? : null; + const LinkComponent: LinkComponentType = props.LinkComponent; return ( - event.stopPropagation()}> + event.stopPropagation()}> {link.text.toUpperCase()} - + {comma} ); diff --git a/src/injected/components/details-dialog.tsx b/src/injected/components/details-dialog.tsx index 86b7f68bcd8..db8a5594912 100644 --- a/src/injected/components/details-dialog.tsx +++ b/src/injected/components/details-dialog.tsx @@ -213,7 +213,10 @@ export class DetailsDialog extends React.Component {this.renderSectionTitle(sectionTitle, successTitleId)}
                  - +
                  ); diff --git a/src/reports/components/assessment-report-step-header.tsx b/src/reports/components/assessment-report-step-header.tsx index 5b87003c94c..2c2a57bdea4 100644 --- a/src/reports/components/assessment-report-step-header.tsx +++ b/src/reports/components/assessment-report-step-header.tsx @@ -4,6 +4,7 @@ import { DefaultMessageInterface } from 'assessments/assessment-default-message- import { GuidanceLinks } from 'common/components/guidance-links'; import { GuidanceTags, GuidanceTagsDeps } from 'common/components/guidance-tags'; import { NamedFC } from 'common/react/named-fc'; +import { LinkComponentType } from 'common/types/link-component-type'; import { ManualTestStatus } from 'common/types/manual-test-status'; import * as React from 'react'; @@ -14,6 +15,7 @@ import { allRequirementOutcomeTypes } from './requirement-outcome-type'; export type AssessmentReportStepHeaderDeps = GuidanceTagsDeps & { outcomeTypeSemanticsFromTestStatus: (testStatus: ManualTestStatus) => OutcomeTypeSemantic; + LinkComponent: LinkComponentType; }; export interface AssessmentReportStepHeaderProps { @@ -53,6 +55,7 @@ export const AssessmentReportStepHeader = NamedFC diff --git a/src/reports/components/report-sections/full-rule-header.tsx b/src/reports/components/report-sections/full-rule-header.tsx index a6c3cfd10a9..77de37345c7 100644 --- a/src/reports/components/report-sections/full-rule-header.tsx +++ b/src/reports/components/report-sections/full-rule-header.tsx @@ -5,15 +5,18 @@ import { GuidanceTags } from 'common/components/guidance-tags'; import { NewTabLink } from 'common/components/new-tab-link'; import { GetGuidanceTagsFromGuidanceLinks } from 'common/get-guidance-tags-from-guidance-links'; import { NamedFC } from 'common/react/named-fc'; +import { LinkComponentType } from 'common/types/link-component-type'; import { CardRuleResult } from 'common/types/store-data/card-view-model'; import { isEmpty, kebabCase } from 'lodash'; import * as React from 'react'; + import { InstanceOutcomeType } from '../instance-outcome-type'; import { OutcomeChip } from '../outcome-chip'; import { outcomeTypeSemantics } from '../outcome-type'; export type FullRuleHeaderDeps = { getGuidanceTagsFromGuidanceLinks: GetGuidanceTagsFromGuidanceLinks; + LinkComponent: LinkComponentType; }; export type FullRuleHeaderProps = { @@ -63,7 +66,7 @@ export const FullRuleHeader = NamedFC('FullRuleHeader', pro } return ( <> - () + () ); }; diff --git a/src/reports/report-html-generator.tsx b/src/reports/report-html-generator.tsx index 930bdc00ff6..3aaf6661750 100644 --- a/src/reports/report-html-generator.tsx +++ b/src/reports/report-html-generator.tsx @@ -2,13 +2,14 @@ // Licensed under the MIT License. import { noCardInteractionsSupported } from 'common/components/cards/card-interaction-support'; import { FixInstructionProcessor } from 'common/components/fix-instruction-processor'; +import { NewTabLink } from 'common/components/new-tab-link'; import { NullComponent } from 'common/components/null-component'; import { PropertyConfiguration } from 'common/configs/unified-result-property-configurations'; import { GetGuidanceTagsFromGuidanceLinks } from 'common/get-guidance-tags-from-guidance-links'; import { CardsViewModel } from 'common/types/store-data/card-view-model'; +import { ScanMetadata } from 'common/types/store-data/unified-data-interface'; import * as React from 'react'; -import { ScanMetadata } from 'common/types/store-data/unified-data-interface'; import { ReportBody, ReportBodyProps } from './components/report-sections/report-body'; import { ReportCollapsibleContainerControl } from './components/report-sections/report-collapsible-container'; import { @@ -48,6 +49,7 @@ export class ReportHtmlGenerator { getPropertyConfigById: this.getPropertyConfiguration, cardInteractionSupport: noCardInteractionsSupported, cardsVisualizationModifierButtons: NullComponent, + LinkComponent: NewTabLink, } as SectionDeps, cardsViewData: cardsViewData, toUtcString: this.utcDateConverter, diff --git a/src/tests/unit/tests/common/components/__snapshots__/guidance-links.test.tsx.snap b/src/tests/unit/tests/common/components/__snapshots__/guidance-links.test.tsx.snap index 4b35414b218..d914e079ab9 100644 --- a/src/tests/unit/tests/common/components/__snapshots__/guidance-links.test.tsx.snap +++ b/src/tests/unit/tests/common/components/__snapshots__/guidance-links.test.tsx.snap @@ -1,18 +1,26 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`GuidanceLinksTest linkComponentType is defined as ElectronExternalLink 1`] = ` +" + + TEXT1 + +" +`; + exports[`GuidanceLinksTest links is empty 1`] = `""`; exports[`GuidanceLinksTest links is not null 1`] = ` " - + TEXT1 - + ,  - + TEXT2 - + " `; diff --git a/src/tests/unit/tests/common/components/cards/__snapshots__/rule-resources.test.tsx.snap b/src/tests/unit/tests/common/components/cards/__snapshots__/rule-resources.test.tsx.snap index c6a3120627c..1c6d716e43d 100644 --- a/src/tests/unit/tests/common/components/cards/__snapshots__/rule-resources.test.tsx.snap +++ b/src/tests/unit/tests/common/components/cards/__snapshots__/rule-resources.test.tsx.snap @@ -2,7 +2,12 @@ exports[`RuleResources renders with { url: 'test-url', - guidanceLinks: [ { href: 'test-href' }, [length]: 1 ] + guidanceLinks: [ [length]: 0 ], + linkComponent: [Function] { + [length]: 1, + [name]: '', + displayName: 'ElectronExternalLink' + } } 1`] = `
                  - More information about some-rule - +
                  `; -exports[`RuleResources renders with { url: 'test-url', guidanceLinks: [ [length]: 0 ] } 1`] = ` +exports[`RuleResources renders with { + url: 'test-url', + guidanceLinks: [ { href: 'test-href' }, [length]: 1 ], + linkComponent: [Function] { + [length]: 1, + [name]: '', + displayName: 'ElectronExternalLink' + } +} 1`] = `
                  @@ -58,26 +64,47 @@ exports[`RuleResources renders with { url: 'test-url', guidanceLinks: [ [length] - More information about some-rule - +
                  `; -exports[`RuleResources renders with { url: 'test-url', guidanceLinks: null } 1`] = ` +exports[`RuleResources renders with { + url: 'test-url', + guidanceLinks: null, + linkComponent: [Function] { [length]: 1, [name]: '', displayName: 'NewTabLink' } +} 1`] = `
                  @@ -98,19 +125,36 @@ exports[`RuleResources renders with { url: 'test-url', guidanceLinks: null } 1`]
                  `; -exports[`RuleResources renders with { url: null, guidanceLinks: [ [length]: 0 ] } 1`] = `null`; +exports[`RuleResources renders with { + url: null, + guidanceLinks: [ [length]: 0 ], + linkComponent: [Function] { + [length]: 1, + [name]: '', + displayName: 'ElectronExternalLink' + } +} 1`] = `null`; -exports[`RuleResources renders with { url: null, guidanceLinks: [ { href: 'test-href' }, [length]: 1 ] } 1`] = ` +exports[`RuleResources renders with { + url: null, + guidanceLinks: [ { href: 'test-href' }, [length]: 1 ], + linkComponent: [Function] { [length]: 1, [name]: '', displayName: 'NewTabLink' } +} 1`] = `
                  @@ -121,6 +165,7 @@ exports[`RuleResources renders with { url: null, guidanceLinks: [ { href: 'test-
                  `; -exports[`RuleResources renders with { url: null, guidanceLinks: null } 1`] = `null`; +exports[`RuleResources renders with { + url: null, + guidanceLinks: null, + linkComponent: [Function] { [length]: 1, [name]: '', displayName: 'NewTabLink' } +} 1`] = `null`; diff --git a/src/tests/unit/tests/common/components/cards/rule-resources.test.tsx b/src/tests/unit/tests/common/components/cards/rule-resources.test.tsx index aadf46eaf13..148b456084a 100644 --- a/src/tests/unit/tests/common/components/cards/rule-resources.test.tsx +++ b/src/tests/unit/tests/common/components/cards/rule-resources.test.tsx @@ -5,10 +5,14 @@ import { RuleResourcesDeps, RuleResourcesProps, } from 'common/components/cards/rule-resources'; +import { NewTabLink } from 'common/components/new-tab-link'; +import { LinkComponentType } from 'common/types/link-component-type'; +import { ElectronExternalLink } from 'electron/views/device-connect-view/components/electron-external-link'; import { shallow } from 'enzyme'; import { cloneDeep } from 'lodash'; import * as React from 'react'; import { GuidanceLink } from 'scanner/rule-to-links-mappings'; + import { exampleUnifiedRuleResult } from './sample-view-model-data'; describe('RuleResources', () => { @@ -16,15 +20,24 @@ describe('RuleResources', () => { type TestCases = { url: string; guidanceLinks: GuidanceLink[]; + linkComponent: LinkComponentType; }; const testCases: TestCases[] = [ - { url: 'test-url', guidanceLinks: [{ href: 'test-href' } as GuidanceLink] }, - { url: null, guidanceLinks: [{ href: 'test-href' } as GuidanceLink] }, - { url: 'test-url', guidanceLinks: [] }, - { url: 'test-url', guidanceLinks: null }, - { url: null, guidanceLinks: [] }, - { url: null, guidanceLinks: null }, + { + url: 'test-url', + guidanceLinks: [{ href: 'test-href' } as GuidanceLink], + linkComponent: ElectronExternalLink, + }, + { + url: null, + guidanceLinks: [{ href: 'test-href' } as GuidanceLink], + linkComponent: NewTabLink, + }, + { url: 'test-url', guidanceLinks: [], linkComponent: ElectronExternalLink }, + { url: 'test-url', guidanceLinks: null, linkComponent: NewTabLink }, + { url: null, guidanceLinks: [], linkComponent: ElectronExternalLink }, + { url: null, guidanceLinks: null, linkComponent: NewTabLink }, ]; it.each(testCases)('with %o', testCase => { @@ -34,7 +47,9 @@ describe('RuleResources', () => { const props: RuleResourcesProps = { rule, - deps: {} as RuleResourcesDeps, + deps: { + LinkComponent: testCase.linkComponent, + } as RuleResourcesDeps, }; const wrapper = shallow(); diff --git a/src/tests/unit/tests/common/components/guidance-links.test.tsx b/src/tests/unit/tests/common/components/guidance-links.test.tsx index bbf4c47cfe3..5b03debf9b9 100644 --- a/src/tests/unit/tests/common/components/guidance-links.test.tsx +++ b/src/tests/unit/tests/common/components/guidance-links.test.tsx @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { ElectronExternalLink } from 'electron/views/device-connect-view/components/electron-external-link'; import { shallow } from 'enzyme'; import * as React from 'react'; @@ -11,6 +12,7 @@ describe('GuidanceLinksTest', () => { const props: GuidanceLinksProps = { links: null, classNameForDiv: null, + LinkComponent: NewTabLink, }; const rendered = shallow(); @@ -21,6 +23,7 @@ describe('GuidanceLinksTest', () => { const props: GuidanceLinksProps = { links: [], classNameForDiv: null, + LinkComponent: NewTabLink, }; const rendered = shallow(); @@ -40,6 +43,22 @@ describe('GuidanceLinksTest', () => { }, ], classNameForDiv: 'className', + LinkComponent: ElectronExternalLink, + }; + + const rendered = shallow(); + expect(rendered.debug()).toMatchSnapshot(); + }); + + test('linkComponentType is defined as ElectronExternalLink', () => { + const props: GuidanceLinksProps = { + links: [ + { + text: 'text1', + href: 'https://url1', + }, + ], + LinkComponent: ElectronExternalLink, }; const rendered = shallow(); @@ -55,6 +74,7 @@ describe('GuidanceLinksTest', () => { }, ], classNameForDiv: 'className', + LinkComponent: NewTabLink, }; const rendered = shallow(); diff --git a/src/tests/unit/tests/reports/components/__snapshots__/assessment-report-step-header.test.tsx.snap b/src/tests/unit/tests/reports/components/__snapshots__/assessment-report-step-header.test.tsx.snap index ed588c0f299..e056a0d3cc7 100644 --- a/src/tests/unit/tests/reports/components/__snapshots__/assessment-report-step-header.test.tsx.snap +++ b/src/tests/unit/tests/reports/components/__snapshots__/assessment-report-step-header.test.tsx.snap @@ -24,6 +24,7 @@ exports[`AssessmentReportStepHeader matches snapshot 1`] = ` - { function genHeader(requirementType: RequirementType): RequirementHeaderReportModel { @@ -31,6 +31,7 @@ describe('AssessmentReportStepHeader', () => { return { pastTense: ManualTestStatus[testStatus] + '-tested' }; }, getGuidanceTagsFromGuidanceLinks: Mock.ofInstance(GetGuidanceTagsFromGuidanceLinks).object, + LinkComponent: NewTabLink, }; test('matches snapshot', () => { diff --git a/src/tests/unit/tests/reports/report-html-generator.test.tsx b/src/tests/unit/tests/reports/report-html-generator.test.tsx index 833c789d4cd..69deea098e6 100644 --- a/src/tests/unit/tests/reports/report-html-generator.test.tsx +++ b/src/tests/unit/tests/reports/report-html-generator.test.tsx @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { noCardInteractionsSupported } from 'common/components/cards/card-interaction-support'; import { FixInstructionProcessor } from 'common/components/fix-instruction-processor'; +import { NewTabLink } from 'common/components/new-tab-link'; import { NullComponent } from 'common/components/null-component'; import { DateProvider } from 'common/date-provider'; import { GetGuidanceTagsFromGuidanceLinks } from 'common/get-guidance-tags-from-guidance-links'; @@ -20,6 +21,7 @@ import { import { ReactStaticRenderer } from 'reports/react-static-renderer'; import { ReportHtmlGenerator } from 'reports/report-html-generator'; import { It, Mock, MockBehavior, Times } from 'typemoq'; + import { exampleUnifiedStatusResults } from '../common/components/cards/sample-view-model-data'; describe('ReportHtmlGenerator', () => { @@ -69,6 +71,7 @@ describe('ReportHtmlGenerator', () => { collapsibleControl: ReportCollapsibleContainerControl, cardInteractionSupport: cardInteractionSupport, cardsVisualizationModifierButtons: NullComponent, + LinkComponent: NewTabLink, } as SectionDeps, fixInstructionProcessor: fixInstructionProcessorMock.object, sectionFactory: sectionFactoryMock.object as ReportBodySectionFactory, From a6f1985d4e9025a377686fbaba4b8a28ec48a2b1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 15 May 2020 17:41:25 +0000 Subject: [PATCH 08/15] chore(deps-dev): bump @types/lodash from 4.14.150 to 4.14.151 (#2691) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 836ca9ca459..36fbcb4a3c8 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@types/enzyme-adapter-react-16": "^1.0.6", "@types/jest": "^25.2.2", "@types/jsdom": "^16.2.1", - "@types/lodash": "^4.14.150", + "@types/lodash": "^4.14.151", "@types/make-dir": "^2.1.0", "@types/moment": "^2.13.0", "@types/puppeteer": "^2.1.0", diff --git a/yarn.lock b/yarn.lock index 09b12c33f17..7e021b174bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -800,10 +800,10 @@ "@types/parse5" "*" "@types/tough-cookie" "*" -"@types/lodash@^4.14.150": - version "4.14.150" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.150.tgz#649fe44684c3f1fcb6164d943c5a61977e8cf0bd" - integrity sha512-kMNLM5JBcasgYscD9x/Gvr6lTAv2NVgsKtet/hm93qMyf/D1pt+7jeEZklKJKxMVmXjxbRVQQGfqDSfipYCO6w== +"@types/lodash@^4.14.151": + version "4.14.151" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.151.tgz#7d58cac32bedb0ec37cb7f99094a167d6176c9d5" + integrity sha512-Zst90IcBX5wnwSu7CAS0vvJkTjTELY4ssKbHiTnGcJgi170uiS8yQDdc3v6S77bRqYQIN1App5a1Pc2lceE5/g== "@types/make-dir@^2.1.0": version "2.1.0" From 02f6ae48b4e12ba5a994f3b225abdbb44e2d994f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 15 May 2020 17:41:49 +0000 Subject: [PATCH 09/15] chore(deps-dev): bump @types/chrome from 0.0.110 to 0.0.112 (#2694) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 36fbcb4a3c8..24438f3bc49 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "7zip-bin": "^5.0.3", "@electron/get": "^1.12.2", "@types/applicationinsights-js": "^1.0.7", - "@types/chrome": "0.0.110", + "@types/chrome": "0.0.112", "@types/enzyme": "^3.10.5", "@types/enzyme-adapter-react-16": "^1.0.6", "@types/jest": "^25.2.2", diff --git a/yarn.lock b/yarn.lock index 7e021b174bf..3e36158987d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -672,10 +672,10 @@ dependencies: "@types/node" "*" -"@types/chrome@0.0.110": - version "0.0.110" - resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.110.tgz#e1179fc5e286615308b44ecfc806fe0b81c8708a" - integrity sha512-oUCGfina2v3eFgCA05vEL6ZlUZcoWaLQCmVRMYeqiDR4RcV9db8WrOQtSypwknathvcdmiatXGK9AiDO9lVDCg== +"@types/chrome@0.0.112": + version "0.0.112" + resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.112.tgz#fd2a8fd9a410435c79eca2a52ddacddc5bdf9a14" + integrity sha512-VJjHiDuF4Xmcn1DuOnGcrMDiGBvoJnaIE6u3ZkhsSz2L16HhnfqIuuM8EAvgQa0ODbNpotHqtPRTKpYoNfpAqQ== dependencies: "@types/filesystem" "*" "@types/har-format" "*" From a62094f85f5d3f7c7fad852be5af8b6ebefae239 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 15 May 2020 17:41:56 +0000 Subject: [PATCH 10/15] chore(deps-dev): bump @types/q from 1.5.2 to 1.5.3 (#2693) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 24438f3bc49..309b21c1e94 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "@types/make-dir": "^2.1.0", "@types/moment": "^2.13.0", "@types/puppeteer": "^2.1.0", - "@types/q": "^1.5.2", + "@types/q": "^1.5.3", "@types/react": "^16.9.35", "@types/react-copy-to-clipboard": "^4.3.0", "@types/react-dom": "^16.9.8", diff --git a/yarn.lock b/yarn.lock index 3e36158987d..93b9d6a3da4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -866,10 +866,10 @@ dependencies: "@types/node" "*" -"@types/q@^1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" - integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== +"@types/q@^1.5.3": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.3.tgz#69047ef831f0e5849a3855a25e019850413dc922" + integrity sha512-I3wR8FNrk9ny4zJzSB1FBpPHw8kv+eVapS3Hkw+QAF7WCIF7foiEj0GcWFR5mwzw/HUMrLBD+rO/OKJcLf/v+w== "@types/range-parser@*": version "1.2.3" From 89d37c4d5fe3acfd0db52347b7c9eece2b458998 Mon Sep 17 00:00:00 2001 From: AhmedAbdoOrtiga <45858632+AhmedAbdoOrtiga@users.noreply.github.com> Date: Fri, 15 May 2020 11:17:33 -0700 Subject: [PATCH 11/15] Increase report package version to be published (#2696) --- src/reports/package/root/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reports/package/root/package.json b/src/reports/package/root/package.json index 2427a74b87b..d82f9063afb 100644 --- a/src/reports/package/root/package.json +++ b/src/reports/package/root/package.json @@ -1,6 +1,6 @@ { "name": "accessibility-insights-report", - "version": "1.0.2", + "version": "1.0.3", "description": "Accessibility Insights Report", "license": "MIT", "repository": { From bc521a74dddb1d96450268713424f7433559b9ca Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 15 May 2020 18:21:53 +0000 Subject: [PATCH 12/15] chore(deps-dev): bump @types/jsdom from 16.2.1 to 16.2.2 (#2692) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 309b21c1e94..4940915f41a 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@types/enzyme": "^3.10.5", "@types/enzyme-adapter-react-16": "^1.0.6", "@types/jest": "^25.2.2", - "@types/jsdom": "^16.2.1", + "@types/jsdom": "^16.2.2", "@types/lodash": "^4.14.151", "@types/make-dir": "^2.1.0", "@types/moment": "^2.13.0", diff --git a/yarn.lock b/yarn.lock index 93b9d6a3da4..f08e3fa1746 100644 --- a/yarn.lock +++ b/yarn.lock @@ -791,10 +791,10 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" -"@types/jsdom@^16.2.1": - version "16.2.1" - resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.1.tgz#9e6eee6a578f74eed5997558ab430dbc11aac753" - integrity sha512-KCEq427OsWfpX7FRyEMb3i2XIuz8Pt3XPls4nmX0iMTDJWsHD4Kzoa3v4Uv9c9IDf11ALeHUtPcyAjTz/HV03Q== +"@types/jsdom@^16.2.2": + version "16.2.2" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.2.tgz#5d820a9578ccb8ac20afecdc141479aa77167dd0" + integrity sha512-QP2IQ5d65WtIMfQwttqFVFgMNikqeWO8mwUCfLrHDI4ijwb5qGhzPEm2ajWr2rlcCnjWeoYeb7Jx3+mtZGWMBw== dependencies: "@types/node" "*" "@types/parse5" "*" From 3acb8abe4acd8dd2a841b3d01583375012f90b33 Mon Sep 17 00:00:00 2001 From: Karan Date: Fri, 15 May 2020 12:05:48 -0700 Subject: [PATCH 13/15] fix: revert 63145e4 to fix stuck assessment > automated checks scanning --- .../components/assessment-test-view.tsx | 1 + .../assessment-view-update-handler.ts | 8 +- .../components/assessment-view.tsx | 13 +++- .../components/reflow-assessment-view.tsx | 15 +++- src/DetailsView/components/test-step-view.tsx | 47 +---------- .../assessment-test-view.test.tsx.snap | 2 + .../assessment-view.test.tsx.snap | 2 +- .../reflow-assessment-view.test.tsx.snap | 8 +- .../test-step-view.test.tsx.snap | 8 +- .../assessment-view-update-handler.test.ts | 8 +- .../components/assessment-view.test.tsx | 21 +++++ .../reflow-assessment-view.test.tsx | 44 ++++++++++- .../components/test-step-view.test.tsx | 77 +------------------ 13 files changed, 115 insertions(+), 139 deletions(-) diff --git a/src/DetailsView/components/assessment-test-view.tsx b/src/DetailsView/components/assessment-test-view.tsx index deb01996af2..ae0cb51944e 100644 --- a/src/DetailsView/components/assessment-test-view.tsx +++ b/src/DetailsView/components/assessment-test-view.tsx @@ -73,6 +73,7 @@ export const AssessmentTestView = NamedFC( currentTarget={currentTarget} prevTarget={prevTarget} assessmentTestResult={assessmentTestResult} + selectedRequirementIsEnabled={selectedRequirementIsEnabled} /> ); }; diff --git a/src/DetailsView/components/assessment-view-update-handler.ts b/src/DetailsView/components/assessment-view-update-handler.ts index 83af945ff5b..4cf0eeb7db6 100644 --- a/src/DetailsView/components/assessment-view-update-handler.ts +++ b/src/DetailsView/components/assessment-view-update-handler.ts @@ -26,7 +26,7 @@ export interface AssessmentViewUpdateHandlerProps { deps: AssessmentViewUpdateHandlerDeps; assessmentNavState: AssessmentNavState; assessmentData: AssessmentData; - isRequirementEnabled: boolean; + selectedRequirementIsEnabled: boolean; currentTarget: Tab; prevTarget: PersistedTabInfo; } @@ -65,12 +65,12 @@ export class AssessmentViewUpdateHandler { return; } - const isRequirementNotScanned = !props.assessmentData.testStepStatus[step].isStepScanned; - if (props.isRequirementEnabled === false || isRequirementNotScanned) { + const isStepNotScanned = !props.assessmentData.testStepStatus[step].isStepScanned; + if (props.selectedRequirementIsEnabled === false || isStepNotScanned) { props.deps.detailsViewActionMessageCreator.enableVisualHelper( test, step, - isRequirementNotScanned, + isStepNotScanned, sendTelemetry, ); } diff --git a/src/DetailsView/components/assessment-view.tsx b/src/DetailsView/components/assessment-view.tsx index 2eb75223b61..aaf9b9bc8eb 100644 --- a/src/DetailsView/components/assessment-view.tsx +++ b/src/DetailsView/components/assessment-view.tsx @@ -92,13 +92,23 @@ export class AssessmentView extends React.Component { ); } + public componentDidMount(): void { + this.deps.assessmentViewUpdateHandler.onMount(this.props); + } + public componentDidUpdate(prevProps: AssessmentViewProps): void { + this.deps.assessmentViewUpdateHandler.update(prevProps, this.props); + const { assessmentTestResult } = this.props; this.deps.detailsViewExtensionPoint .apply(assessmentTestResult.definition.extensions) .onAssessmentViewUpdate(prevProps, this.props); } + public componentWillUnmount(): void { + this.deps.assessmentViewUpdateHandler.onUnmount(this.props); + } + private renderTargetChangeDialog(): JSX.Element { return ( { } featureFlagStoreData={this.props.featureFlagStoreData} pathSnippetStoreData={this.props.pathSnippetStoreData} - assessmentData={this.props.assessmentData} - currentTarget={this.props.currentTarget} - prevTarget={this.props.prevTarget} />
diff --git a/src/DetailsView/components/reflow-assessment-view.tsx b/src/DetailsView/components/reflow-assessment-view.tsx index a9773f3342b..5d08ef3f14a 100644 --- a/src/DetailsView/components/reflow-assessment-view.tsx +++ b/src/DetailsView/components/reflow-assessment-view.tsx @@ -5,6 +5,7 @@ import * as React from 'react'; import { AssessmentViewUpdateHandler, AssessmentViewUpdateHandlerDeps, + AssessmentViewUpdateHandlerProps, } from 'DetailsView/components/assessment-view-update-handler'; import { AssessmentTestResult } from '../../common/assessment/assessment-test-result'; import { Tab } from '../../common/itab'; @@ -28,7 +29,7 @@ export type ReflowAssessmentViewProps = { currentTarget: Tab; prevTarget: PersistedTabInfo; assessmentTestResult: AssessmentTestResult; -}; +} & AssessmentViewUpdateHandlerProps; export class ReflowAssessmentView extends React.Component { public render(): JSX.Element { @@ -46,6 +47,18 @@ export class ReflowAssessmentView extends React.Component { public render(): JSX.Element { @@ -90,34 +77,6 @@ export class TestStepView extends React.Component { ); } - public componentDidMount(): void { - this.props.deps.assessmentViewUpdateHandler.onMount(this.getUpdateHandlerProps(this.props)); - } - - public componentDidUpdate(prevProps: TestStepViewProps): void { - this.props.deps.assessmentViewUpdateHandler.update( - this.getUpdateHandlerProps(prevProps), - this.getUpdateHandlerProps(this.props), - ); - } - - public componentWillUnmount(): void { - this.props.deps.assessmentViewUpdateHandler.onUnmount( - this.getUpdateHandlerProps(this.props), - ); - } - - private getUpdateHandlerProps(props: TestStepViewProps): AssessmentViewUpdateHandlerProps { - return { - deps: props.deps, - isRequirementEnabled: props.isStepEnabled, - assessmentNavState: props.assessmentNavState, - assessmentData: props.assessmentData, - prevTarget: props.prevTarget, - currentTarget: props.currentTarget, - }; - } - private renderTable(): JSX.Element { if (this.props.testStep.isManual) { return ( diff --git a/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-test-view.test.tsx.snap b/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-test-view.test.tsx.snap index 97681ff846c..54f8691ab4f 100644 --- a/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-test-view.test.tsx.snap +++ b/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-test-view.test.tsx.snap @@ -88,6 +88,7 @@ exports[`AssessmentTestView assessment view, isScanning is false 1`] = ` "detailsViewActionMessageCreator": Object {}, } } + selectedRequirementIsEnabled={false} /> } featureFlag="reflowUI" @@ -184,6 +185,7 @@ exports[`AssessmentTestView assessment view, isScanning is true 1`] = ` "detailsViewActionMessageCreator": Object {}, } } + selectedRequirementIsEnabled={false} /> } featureFlag="reflowUI" diff --git a/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-view.test.tsx.snap b/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-view.test.tsx.snap index 77b9fc5f24a..50c6f293a2a 100644 --- a/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-view.test.tsx.snap +++ b/src/tests/unit/tests/DetailsView/components/__snapshots__/assessment-view.test.tsx.snap @@ -22,7 +22,7 @@ exports[`AssessmentViewTest render 1`] = `
- +
diff --git a/src/tests/unit/tests/DetailsView/components/__snapshots__/reflow-assessment-view.test.tsx.snap b/src/tests/unit/tests/DetailsView/components/__snapshots__/reflow-assessment-view.test.tsx.snap index f02d039d031..f47530cf044 100644 --- a/src/tests/unit/tests/DetailsView/components/__snapshots__/reflow-assessment-view.test.tsx.snap +++ b/src/tests/unit/tests/DetailsView/components/__snapshots__/reflow-assessment-view.test.tsx.snap @@ -3,7 +3,13 @@ exports[`AssessmentViewTest render for gettting started 1`] = `

Test Step Test Name - +

- + Info & examples
@@ -25,9 +25,9 @@ exports[`TestStepViewTest render, variable part for assisted test 1`] = `

Test Step Test Name - +

- + Info & examples
diff --git a/src/tests/unit/tests/DetailsView/components/assessment-view-update-handler.test.ts b/src/tests/unit/tests/DetailsView/components/assessment-view-update-handler.test.ts index 4bd723439c8..abf77fe9bb8 100644 --- a/src/tests/unit/tests/DetailsView/components/assessment-view-update-handler.test.ts +++ b/src/tests/unit/tests/DetailsView/components/assessment-view-update-handler.test.ts @@ -18,12 +18,12 @@ describe('AssessmentViewTest', () => { const firstAssessment = assessmentsProvider.all()[0]; const stepName = firstAssessment.requirements[0].key; let detailsViewActionMessageCreatorMock: IMock; - let isRequirementEnabled: boolean; + let selectedRequirementIsEnabled: boolean; let testObject: AssessmentViewUpdateHandler; beforeEach(() => { - isRequirementEnabled = false; + selectedRequirementIsEnabled = false; detailsViewActionMessageCreatorMock = Mock.ofType(); testObject = new AssessmentViewUpdateHandler(); }); @@ -71,7 +71,7 @@ describe('AssessmentViewTest', () => { a.enableVisualHelper(firstAssessment.visualizationType, stepName, false), ) .verifiable(Times.never()); - isRequirementEnabled = true; + selectedRequirementIsEnabled = true; const props = buildProps({ selector: {} }); testObject.onMount(props); @@ -218,7 +218,7 @@ describe('AssessmentViewTest', () => { deps, prevTarget, currentTarget: isTargetChanged ? anotherTarget : prevTarget, - isRequirementEnabled: isRequirementEnabled, + selectedRequirementIsEnabled: selectedRequirementIsEnabled, assessmentNavState, assessmentData, }; diff --git a/src/tests/unit/tests/DetailsView/components/assessment-view.test.tsx b/src/tests/unit/tests/DetailsView/components/assessment-view.test.tsx index f9599aee17f..eb216520c1c 100644 --- a/src/tests/unit/tests/DetailsView/components/assessment-view.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/assessment-view.test.tsx @@ -37,6 +37,16 @@ describe('AssessmentViewTest', () => { expect(rendered.debug()).toMatchSnapshot(); }); + test('componentDidMount', () => { + const props = builder.buildProps(); + builder.updateHandlerMock.setup(u => u.onMount(props)).verifiable(Times.once()); + + const testObject = new AssessmentView(props); + + testObject.componentDidMount(); + builder.verifyAll(); + }); + test('componentDidUpdate', () => { const prevProps = buildPrevProps(); const props = builder.buildProps(); @@ -44,6 +54,7 @@ describe('AssessmentViewTest', () => { (previousProps: AssessmentViewProps, currentProps: AssessmentViewProps) => {}, ); + builder.updateHandlerMock.setup(u => u.update(prevProps, props)).verifiable(Times.once()); builder.detailsViewExtensionPointMock .setup(d => d.apply(props.assessmentTestResult.definition.extensions)) .returns(() => { @@ -60,6 +71,16 @@ describe('AssessmentViewTest', () => { onAssessmentViewUpdateMock.verifyAll(); }); + test('componentWillUnmount', () => { + const props = builder.buildProps(); + builder.updateHandlerMock.setup(u => u.onUnmount(props)).verifiable(Times.once()); + + const testObject = new AssessmentView(props); + + testObject.componentWillUnmount(); + builder.verifyAll(); + }); + function buildPrevProps(): AssessmentViewProps { const prevStep = 'prevStep'; const prevTest = -100 as VisualizationType; diff --git a/src/tests/unit/tests/DetailsView/components/reflow-assessment-view.test.tsx b/src/tests/unit/tests/DetailsView/components/reflow-assessment-view.test.tsx index 46f087b5911..d54c8c89a5b 100644 --- a/src/tests/unit/tests/DetailsView/components/reflow-assessment-view.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/reflow-assessment-view.test.tsx @@ -4,8 +4,9 @@ import { AssessmentTestResult } from 'common/assessment/assessment-test-result'; import { AssessmentData } from 'common/types/store-data/assessment-result-data'; import { shallow } from 'enzyme'; import * as React from 'react'; -import { Mock } from 'typemoq'; +import { IMock, Mock, Times } from 'typemoq'; +import { AssessmentViewUpdateHandler } from 'DetailsView/components/assessment-view-update-handler'; import { ReflowAssessmentView, ReflowAssessmentViewDeps, @@ -13,6 +14,12 @@ import { } from '../../../../../DetailsView/components/reflow-assessment-view'; describe('AssessmentViewTest', () => { + let updateHandlerMock: IMock; + + beforeEach(() => { + updateHandlerMock = Mock.ofType(AssessmentViewUpdateHandler); + }); + test('render for requirement', () => { const props = generateProps('requirement'); const rendered = shallow(); @@ -25,6 +32,37 @@ describe('AssessmentViewTest', () => { expect(rendered.getElement()).toMatchSnapshot(); }); + test('componentDidMount', () => { + const props = generateProps('requirement'); + updateHandlerMock.setup(u => u.onMount(props)).verifiable(Times.once()); + const testObject = new ReflowAssessmentView(props); + + testObject.componentDidMount(); + + updateHandlerMock.verifyAll(); + }); + + test('componentWillUnmount', () => { + const props = generateProps('requirement'); + updateHandlerMock.setup(u => u.onUnmount(props)).verifiable(Times.once()); + const testObject = new ReflowAssessmentView(props); + + testObject.componentWillUnmount(); + + updateHandlerMock.verifyAll(); + }); + + test('componentDidUpdate', () => { + const prevProps = generateProps('requirement1'); + const props = generateProps('requirement2'); + updateHandlerMock.setup(u => u.update(prevProps, props)).verifiable(Times.once()); + const testObject = new ReflowAssessmentView(props); + + testObject.componentDidUpdate(prevProps); + + updateHandlerMock.verifyAll(); + }); + function generateProps(subview: string): ReflowAssessmentViewProps { const assessmentDataMock = Mock.ofType(); @@ -35,7 +73,9 @@ describe('AssessmentViewTest', () => { } as AssessmentTestResult; const reflowProps = { - deps: {} as ReflowAssessmentViewDeps, + deps: { + assessmentViewUpdateHandler: updateHandlerMock.object, + } as ReflowAssessmentViewDeps, prevTarget: { id: 4 }, currentTarget: { id: 5 }, assessmentNavState: { diff --git a/src/tests/unit/tests/DetailsView/components/test-step-view.test.tsx b/src/tests/unit/tests/DetailsView/components/test-step-view.test.tsx index 4fb62edcd41..46b7f927fbe 100644 --- a/src/tests/unit/tests/DetailsView/components/test-step-view.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/test-step-view.test.tsx @@ -6,17 +6,9 @@ import { CollapsibleComponent } from 'common/components/collapsible-component'; import { ManualTestStatus } from 'common/types/manual-test-status'; import { VisualizationType } from 'common/types/visualization-type'; import { AssessmentInstanceTable } from 'DetailsView/components/assessment-instance-table'; -import { - AssessmentViewUpdateHandler, - AssessmentViewUpdateHandlerProps, -} from 'DetailsView/components/assessment-view-update-handler'; import { AssessmentVisualizationEnabledToggle } from 'DetailsView/components/assessment-visualization-enabled-toggle'; import { ManualTestStepView } from 'DetailsView/components/manual-test-step-view'; -import { - TestStepView, - TestStepViewDeps, - TestStepViewProps, -} from 'DetailsView/components/test-step-view'; +import { TestStepView, TestStepViewProps } from 'DetailsView/components/test-step-view'; import * as styles from 'DetailsView/components/test-step-view.scss'; import { AssessmentInstanceTableHandler } from 'DetailsView/handlers/assessment-instance-table-handler'; import * as Enzyme from 'enzyme'; @@ -25,14 +17,12 @@ import { BaseDataBuilder } from 'tests/unit/common/base-data-builder'; import { IMock, It, Mock, MockBehavior, Times } from 'typemoq'; let getVisualHelperToggleMock: IMock<(provider, props) => {}>; -let updateHandlerMock: IMock; describe('TestStepViewTest', () => { beforeEach(() => { getVisualHelperToggleMock = Mock.ofInstance((provider, props) => { return null; }); - updateHandlerMock = Mock.ofType(); }); test('constructor, no side effects', () => { @@ -145,55 +135,6 @@ describe('TestStepViewTest', () => { expect(wrapper.debug()).toMatchSnapshot(); }); - test('componentDidUpdate', () => { - const props = TestStepViewPropsBuilder.defaultProps( - getVisualHelperToggleMock.object, - ).build(); - const prevProps = TestStepViewPropsBuilder.defaultProps( - getVisualHelperToggleMock.object, - ).build(); - prevProps.assessmentNavState.selectedTestSubview = 'prevTestStep'; - updateHandlerMock - .setup(u => u.update(getUpdateHandlerProps(prevProps), getUpdateHandlerProps(props))) - .verifiable(Times.once()); - - const testObject = new TestStepView(props); - - testObject.componentDidUpdate(prevProps); - - updateHandlerMock.verifyAll(); - }); - - test('componentDidMount', () => { - const props = TestStepViewPropsBuilder.defaultProps( - getVisualHelperToggleMock.object, - ).build(); - updateHandlerMock - .setup(u => u.onMount(getUpdateHandlerProps(props))) - .verifiable(Times.once()); - - const testObject = new TestStepView(props); - - testObject.componentDidMount(); - - updateHandlerMock.verifyAll(); - }); - - test('componentWillUnmount', () => { - const props = TestStepViewPropsBuilder.defaultProps( - getVisualHelperToggleMock.object, - ).build(); - updateHandlerMock - .setup(u => u.onUnmount(getUpdateHandlerProps(props))) - .verifiable(Times.once()); - - const testObject = new TestStepView(props); - - testObject.componentWillUnmount(); - - updateHandlerMock.verifyAll(); - }); - function validateManualTestStepView( wrapper: Enzyme.ShallowWrapper, props: TestStepViewProps, @@ -208,17 +149,6 @@ describe('TestStepViewTest', () => { ); expect(props.assessmentsProvider).toEqual(view.prop('assessmentsProvider')); } - - function getUpdateHandlerProps(props: TestStepViewProps): AssessmentViewUpdateHandlerProps { - return { - deps: props.deps, - isRequirementEnabled: props.isStepEnabled, - assessmentNavState: props.assessmentNavState, - assessmentData: props.assessmentData, - prevTarget: props.prevTarget, - currentTarget: props.currentTarget, - }; - } }); class TestStepViewPropsBuilder extends BaseDataBuilder { @@ -289,10 +219,7 @@ class TestStepViewPropsBuilder extends BaseDataBuilder { howToTest:

Instructions

, isManual: false, guidanceLinks: [], - }) - .with('deps', { - assessmentViewUpdateHandler: updateHandlerMock.object, - } as TestStepViewDeps); + }); } public withNoGetToggleConfig(): TestStepViewPropsBuilder { From 13eb1b56f737867fdd8be3687eaa853c76da738f Mon Sep 17 00:00:00 2001 From: Dan Bjorge Date: Fri, 15 May 2020 12:19:02 -0700 Subject: [PATCH 14/15] test: add e2e tests for new Landmarks auto-pass behavior (#2685) #### Description of changes Adds new end to end tests that verify the auto-pass-on-no-landmarks behavior introduced in #2644. Updates the product code to add a new data-automation-id, no UI impact. #### Pull request checklist - [x] Addresses an existing issue: e2e test for behavior in #2521 - [x] Ran `yarn fastpass` - [x] Added/updated relevant unit test(s) (and ran `yarn test`) - [x] Verified code coverage for the changes made. Check coverage report at: `/test-results/unit/coverage` - [x] PR title *AND* final merge commit title both start with a semantic tag (`fix:`, `chore:`, `feat(feature-name):`, `refactor:`). See `CONTRIBUTING.md`. - [n/a] (UI changes only) Added screenshots/GIFs to description above - [n/a] (UI changes only) Verified usability with NVDA/JAWS --- .../components/base-visual-helper-toggle.tsx | 2 + .../components/cards/visual-helper-toggle.tsx | 2 - .../components/visualization-toggle.tsx | 2 + src/tests/end-to-end/common/browser.ts | 12 +++++ .../details-view-selectors.ts | 11 +++- .../page-controllers/details-view-page.ts | 37 ++++++++++++++ .../landmarks/mixed-landmarks.html | 16 ++++++ .../landmarks/no-landmarks.html | 15 ++++++ .../tests/details-view/headings.test.ts | 29 +++-------- .../tests/details-view/landmarks.test.ts | 50 +++++++++++++++++++ ...rt-scan-visual-helper-toggle.test.tsx.snap | 3 ++ ...-checks-visualization-toggle.test.tsx.snap | 3 ++ .../components/visualization-toggle.test.tsx | 12 +++++ 13 files changed, 169 insertions(+), 25 deletions(-) create mode 100644 src/tests/end-to-end/test-resources/landmarks/mixed-landmarks.html create mode 100644 src/tests/end-to-end/test-resources/landmarks/no-landmarks.html create mode 100644 src/tests/end-to-end/tests/details-view/landmarks.test.ts diff --git a/src/DetailsView/components/base-visual-helper-toggle.tsx b/src/DetailsView/components/base-visual-helper-toggle.tsx index e2da2b5bc5c..db0580e2fb2 100644 --- a/src/DetailsView/components/base-visual-helper-toggle.tsx +++ b/src/DetailsView/components/base-visual-helper-toggle.tsx @@ -7,6 +7,7 @@ import { VisualizationToggle } from '../../common/components/visualization-toggl import { GeneratedAssessmentInstance } from '../../common/types/store-data/assessment-result-data'; import { DictionaryStringTo } from '../../types/common-types'; +export const visualHelperToggleAutomationId = 'visual-helper-toggle'; export const visualHelperText = 'Visual helper'; export abstract class BaseVisualHelperToggle extends React.Component { @@ -30,6 +31,7 @@ export abstract class BaseVisualHelperToggle extends React.Component {disabledMessage} diff --git a/src/common/components/cards/visual-helper-toggle.tsx b/src/common/components/cards/visual-helper-toggle.tsx index 374766a56fd..6c534260b96 100644 --- a/src/common/components/cards/visual-helper-toggle.tsx +++ b/src/common/components/cards/visual-helper-toggle.tsx @@ -6,8 +6,6 @@ import { css, Toggle } from 'office-ui-fabric-react'; import * as React from 'react'; import * as styles from './visual-helper-toggle.scss'; -export const visualHelperToggleAutomationId = 'visual-helper-toggle'; - export type VisualHelperToggleDeps = { cardSelectionMessageCreator: CardSelectionMessageCreator; }; diff --git a/src/common/components/visualization-toggle.tsx b/src/common/components/visualization-toggle.tsx index 78ce3eba537..2df34ad0965 100644 --- a/src/common/components/visualization-toggle.tsx +++ b/src/common/components/visualization-toggle.tsx @@ -13,6 +13,7 @@ export interface VisualizationToggleProps { componentRef?: React.RefObject; onBlur?: (ev) => void; onFocus?: (ev) => void; + 'data-automation-id'?: string; } export class VisualizationToggle extends React.Component { @@ -29,6 +30,7 @@ export class VisualizationToggle extends React.Component; diff --git a/src/tests/end-to-end/common/browser.ts b/src/tests/end-to-end/common/browser.ts index fb1bfa1a3e2..c4cf4df4764 100644 --- a/src/tests/end-to-end/common/browser.ts +++ b/src/tests/end-to-end/common/browser.ts @@ -83,6 +83,18 @@ export class Browser { return page; } + public async newAssessment( + targetPageUrlOptions?: TargetPageUrlOptions, + ): Promise<{ detailsViewPage: DetailsViewPage; targetPage: TargetPage }> { + const targetPage = await this.newTargetPage(targetPageUrlOptions); + await this.newPopupPage(targetPage); // Required for the details view to register as having permissions/being open + + const detailsViewPage = await this.newDetailsViewPage(targetPage); + await detailsViewPage.switchToAssessment(); + + return { detailsViewPage, targetPage }; + } + public async waitForDetailsViewPage(targetPage: TargetPage): Promise { const expectedUrl = await this.getExtensionUrl(detailsViewRelativeUrl(targetPage.tabId)); const underlyingTarget = await this.underlyingBrowser.waitForTarget( diff --git a/src/tests/end-to-end/common/element-identifiers/details-view-selectors.ts b/src/tests/end-to-end/common/element-identifiers/details-view-selectors.ts index 1e9b0a6c5b1..935ff28f650 100644 --- a/src/tests/end-to-end/common/element-identifiers/details-view-selectors.ts +++ b/src/tests/end-to-end/common/element-identifiers/details-view-selectors.ts @@ -3,6 +3,7 @@ import { resultSectionAutomationId } from 'common/components/cards/result-section'; import { ruleDetailsGroupAutomationId } from 'common/components/cards/rules-with-instances'; import { instanceTableTextContentAutomationId } from 'DetailsView/components/assessment-instance-details-column'; +import { visualHelperToggleAutomationId } from 'DetailsView/components/base-visual-helper-toggle'; import { settingsPanelAutomationId } from 'DetailsView/components/details-view-overlay/settings-panel/settings-panel'; import { IframeWarningContainerAutomationId } from 'DetailsView/components/iframe-warning'; import { overviewHeadingAutomationId } from 'DetailsView/components/overview-content/overview-heading'; @@ -17,7 +18,15 @@ import { getAutomationIdSelector } from 'tests/common/get-automation-id-selector export const detailsViewSelectors = { previewFeaturesPanel: '.preview-features-panel', - testNavLink: (testName: string): string => `nav [name=${testName}] a`, + testNavLink: (testName: string): string => `nav [name="${testName}"] a`, + requirementNavLink: (requirementName: string): string => `div [name="${requirementName}"] a`, + + visualHelperToggle: getAutomationIdSelector(visualHelperToggleAutomationId), + + requirementWithStatus: ( + requirementName: string, + status: 'Passed' | 'Failed' | 'Incomplete', + ): string => `div[name="${requirementName}"][title^="${requirementName}. ${status}."]`, mainContent: '[role=main]', instanceTableTextContent: getAutomationIdSelector(instanceTableTextContentAutomationId), diff --git a/src/tests/end-to-end/common/page-controllers/details-view-page.ts b/src/tests/end-to-end/common/page-controllers/details-view-page.ts index b785a7cc422..57d22c7979d 100644 --- a/src/tests/end-to-end/common/page-controllers/details-view-page.ts +++ b/src/tests/end-to-end/common/page-controllers/details-view-page.ts @@ -31,6 +31,43 @@ export class DetailsViewPage extends Page { await this.clickSelector('button[title="Assessment"]'); } + public async navigateToTest(testName: string): Promise { + await this.clickSelector(detailsViewSelectors.testNavLink(testName)); + await this.waitForSelectorXPath(`//h1[text()="${testName}"]`); + } + + public async navigateToRequirement(requirementName: string): Promise { + await this.clickSelector(detailsViewSelectors.requirementNavLink(requirementName)); + await this.waitForSelectorXPath(`//h3[text()="${requirementName}"]`); + } + + public async waitForVisualHelperState( + state: 'On' | 'Off' | 'disabled', + waitOptions?: Puppeteer.WaitForSelectorOptions, + ): Promise { + const selectorStateSuffix = { + On: ':not([disabled])[aria-checked="true"]', + Off: ':not([disabled])[aria-checked="false"]', + disabled: '[disabled]', + }[state]; + + await this.waitForSelector( + detailsViewSelectors.visualHelperToggle + selectorStateSuffix, + waitOptions, + ); + } + + public async waitForRequirementStatus( + requirementName: string, + status: 'Passed' | 'Failed' | 'Incomplete', + waitOptions?: Puppeteer.WaitForSelectorOptions, + ): Promise { + await this.waitForSelector( + detailsViewSelectors.requirementWithStatus(requirementName, status), + waitOptions, + ); + } + public async openSettingsPanel(): Promise { await this.ensureNoModals(); diff --git a/src/tests/end-to-end/test-resources/landmarks/mixed-landmarks.html b/src/tests/end-to-end/test-resources/landmarks/mixed-landmarks.html new file mode 100644 index 00000000000..d45a75ef275 --- /dev/null +++ b/src/tests/end-to-end/test-resources/landmarks/mixed-landmarks.html @@ -0,0 +1,16 @@ + + + + + + Landmarks - Mixed + + + +
Banner landmark content
+
Main landmark content
+ + diff --git a/src/tests/end-to-end/test-resources/landmarks/no-landmarks.html b/src/tests/end-to-end/test-resources/landmarks/no-landmarks.html new file mode 100644 index 00000000000..611259c4d12 --- /dev/null +++ b/src/tests/end-to-end/test-resources/landmarks/no-landmarks.html @@ -0,0 +1,15 @@ + + + + + + Landmarks - None + + + +

No landmarks on this page

+ + diff --git a/src/tests/end-to-end/tests/details-view/headings.test.ts b/src/tests/end-to-end/tests/details-view/headings.test.ts index fcbe28a7db2..d36b1d4a7ea 100644 --- a/src/tests/end-to-end/tests/details-view/headings.test.ts +++ b/src/tests/end-to-end/tests/details-view/headings.test.ts @@ -4,13 +4,11 @@ import { Browser } from '../../common/browser'; import { launchBrowser } from '../../common/browser-factory'; import { detailsViewSelectors } from '../../common/element-identifiers/details-view-selectors'; import { DetailsViewPage } from '../../common/page-controllers/details-view-page'; -import { TargetPage } from '../../common/page-controllers/target-page'; import { scanForAccessibilityIssues } from '../../common/scan-for-accessibility-issues'; import { DEFAULT_TARGET_PAGE_SCAN_TIMEOUT_MS } from '../../common/timeouts'; describe('Details View -> Assessment -> Headings', () => { let browser: Browser; - let targetPage: TargetPage; let headingsPage: DetailsViewPage; beforeAll(async () => { @@ -18,9 +16,13 @@ describe('Details View -> Assessment -> Headings', () => { suppressFirstTimeDialog: true, addExtraPermissionsToManifest: 'fake-activeTab', }); - targetPage = await browser.newTargetPage(); - await browser.newPopupPage(targetPage); // Required for the details view to register as having permissions/being open - headingsPage = await openHeadingsPage(browser, targetPage); + + headingsPage = (await browser.newAssessment()).detailsViewPage; + + await headingsPage.navigateToTest('Headings'); + await headingsPage.waitForVisualHelperState('Off', { + timeout: DEFAULT_TARGET_PAGE_SCAN_TIMEOUT_MS, + }); }); afterAll(async () => { @@ -44,20 +46,3 @@ describe('Details View -> Assessment -> Headings', () => { }, ); }); - -async function openHeadingsPage( - browser: Browser, - targetPage: TargetPage, -): Promise { - const detailsViewPage = await browser.newDetailsViewPage(targetPage); - await detailsViewPage.switchToAssessment(); - - await detailsViewPage.clickSelector(detailsViewSelectors.testNavLink('Headings')); - - // Populating the instance table requires scanning the target page - await detailsViewPage.waitForSelector(detailsViewSelectors.instanceTableTextContent, { - timeout: DEFAULT_TARGET_PAGE_SCAN_TIMEOUT_MS, - }); - - return detailsViewPage; -} diff --git a/src/tests/end-to-end/tests/details-view/landmarks.test.ts b/src/tests/end-to-end/tests/details-view/landmarks.test.ts new file mode 100644 index 00000000000..12175553c23 --- /dev/null +++ b/src/tests/end-to-end/tests/details-view/landmarks.test.ts @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { Browser } from 'tests/end-to-end/common/browser'; +import { launchBrowser } from 'tests/end-to-end/common/browser-factory'; +import { DEFAULT_TARGET_PAGE_SCAN_TIMEOUT_MS } from 'tests/end-to-end/common/timeouts'; + +describe('Details View -> Assessment -> Landmarks', () => { + let browser: Browser; + + beforeEach(async () => { + browser = await launchBrowser({ + suppressFirstTimeDialog: true, + addExtraPermissionsToManifest: 'fake-activeTab', + }); + }); + + afterEach(async () => { + if (browser) { + await browser.close(); + browser = undefined; + } + }); + + describe('Primary content', () => { + it('should automatically pass against a target page with no landmarks', async () => { + const { detailsViewPage } = await browser.newAssessment({ + testResourcePath: 'landmarks/no-landmarks.html', + }); + await detailsViewPage.navigateToTest('Landmarks'); + await detailsViewPage.navigateToRequirement('Primary content'); + + await detailsViewPage.waitForRequirementStatus('Primary content', 'Passed', { + timeout: DEFAULT_TARGET_PAGE_SCAN_TIMEOUT_MS, + }); + }); + + it('should not automatically pass against a target page with any landmarks', async () => { + const { detailsViewPage } = await browser.newAssessment({ + testResourcePath: 'landmarks/mixed-landmarks.html', + }); + await detailsViewPage.navigateToTest('Landmarks'); + await detailsViewPage.navigateToRequirement('Primary content'); + + await detailsViewPage.waitForVisualHelperState('Off', { + timeout: DEFAULT_TARGET_PAGE_SCAN_TIMEOUT_MS, + }); + await detailsViewPage.waitForRequirementStatus('Primary content', 'Incomplete'); + }); + }); +}); diff --git a/src/tests/unit/tests/DetailsView/components/__snapshots__/restart-scan-visual-helper-toggle.test.tsx.snap b/src/tests/unit/tests/DetailsView/components/__snapshots__/restart-scan-visual-helper-toggle.test.tsx.snap index e0cc82c1f75..a2f1aa15eb5 100644 --- a/src/tests/unit/tests/DetailsView/components/__snapshots__/restart-scan-visual-helper-toggle.test.tsx.snap +++ b/src/tests/unit/tests/DetailsView/components/__snapshots__/restart-scan-visual-helper-toggle.test.tsx.snap @@ -15,6 +15,7 @@ exports[`RestartScanVisualHelperToggleTest onClick: step enabled = false 1`] = ` { .setLabel('my test label') .setClassName('my test class') .setDisabled(true) + .setDataAutomationId('test-automation-id') .build(); const wrapper = Enzyme.shallow(); @@ -77,6 +78,7 @@ describe('VisualizationToggleTest', () => { componentRef: props.componentRef, onFocus: props.onFocus, onBlur: props.onBlur, + 'data-automation-id': props['data-automation-id'], }; return result; @@ -89,6 +91,7 @@ class VisualizationTogglePropsBuilder { private disabled: boolean; private label: string; private className: string; + private dataAutomationId: string; private visualizationName: string = 'visualizationName'; private componentRefStub: React.RefObject = {} as React.RefObject; private onBlurMock: IMock<(event) => void> = Mock.ofInstance(event => {}); @@ -99,6 +102,11 @@ class VisualizationTogglePropsBuilder { return this; } + public setDataAutomationId(dataAutomationId: string): VisualizationTogglePropsBuilder { + this.dataAutomationId = dataAutomationId; + return this; + } + public setLabel(label: string): VisualizationTogglePropsBuilder { this.label = label; return this; @@ -138,6 +146,10 @@ class VisualizationTogglePropsBuilder { props.className = this.className; } + if (this.dataAutomationId != null) { + props['data-automation-id'] = this.dataAutomationId; + } + return props; } } From 6aaffb3e539e31b38b89b4fe85af9c8e5105ea6b Mon Sep 17 00:00:00 2001 From: AhmedAbdoOrtiga <45858632+AhmedAbdoOrtiga@users.noreply.github.com> Date: Fri, 15 May 2020 12:32:16 -0700 Subject: [PATCH 15/15] Use toolData instead of enviroment provider for issue filing (#2689) --- src/DetailsView/details-view-initializer.ts | 12 +++++++- src/background/background-init.ts | 12 +++++++- src/background/global-context-factory.ts | 4 ++- .../issue-details-text-generator.ts | 6 ++-- src/common/application-properties-provider.ts | 23 +++++++++++++++ .../common/application-properties-provider.ts | 20 +++++-------- src/electron/views/renderer-initializer.ts | 7 ++++- src/injected/dialog-renderer.tsx | 2 +- src/injected/main-window-context.ts | 8 +++++ src/injected/main-window-initializer.ts | 11 +++++++ .../common/create-file-issue-handler.ts | 6 ++-- .../common/create-issue-details-builder.ts | 11 ++++--- .../common/issue-details-builder.ts | 7 ++--- .../common/issue-filing-controller-impl.ts | 6 ++-- .../create-azure-boards-issue-filing-url.ts | 6 ++-- .../github/create-github-issue-filing-url.ts | 6 ++-- .../types/issue-filing-service.ts | 6 ++-- .../application-properties-provider.test.ts | 29 +++++++++++++++++++ .../background/global-context-factory.test.ts | 4 +++ .../issue-details-text-generator.test.ts | 27 +++++++++-------- .../application-properties-provider.test.ts | 11 +++---- .../tests/injected/dialog-renderer.test.tsx | 4 +++ .../injected/main-window-context.test.ts | 9 ++++++ .../issue-details-builder.test.ts.snap | 8 ++--- .../common/create-file-issue-handler.test.ts | 22 +++++++++----- .../common/issue-details-builder.test.ts | 19 ++++++++---- .../issue-filing-controller-impl.test.ts | 20 ++++++++----- ...eate-azure-boards-issue-filing-url.test.ts | 28 +++++++++++------- .../create-github-issue-filing-url.test.ts | 22 +++++++++----- 29 files changed, 248 insertions(+), 108 deletions(-) create mode 100644 src/common/application-properties-provider.ts create mode 100644 src/tests/unit/common/application-properties-provider.test.ts diff --git a/src/DetailsView/details-view-initializer.ts b/src/DetailsView/details-view-initializer.ts index 802774fe5b7..48fdea721f1 100644 --- a/src/DetailsView/details-view-initializer.ts +++ b/src/DetailsView/details-view-initializer.ts @@ -7,6 +7,7 @@ import { assessmentsProviderWithFeaturesEnabled } from 'assessments/assessments- import { UserConfigurationActions } from 'background/actions/user-configuration-actions'; import { IssueDetailsTextGenerator } from 'background/issue-details-text-generator'; import { UserConfigurationStore } from 'background/stores/global/user-configuration-store'; +import { createToolData } from 'common/application-properties-provider'; import { ExpandCollapseVisualHelperModifierButtons } from 'common/components/cards/cards-visualization-modifier-buttons'; import { ThemeInnerState } from 'common/components/theme'; import { getCardSelectionViewData } from 'common/get-card-selection-view-data'; @@ -14,6 +15,7 @@ import { isResultHighlightUnavailableWeb } from 'common/is-result-highlight-unav import { createDefaultLogger } from 'common/logging/default-logger'; import { CardSelectionMessageCreator } from 'common/message-creators/card-selection-message-creator'; import { CardSelectionStoreData } from 'common/types/store-data/card-selection-store-data'; +import { toolName } from 'content/strings/application'; import { textContent } from 'content/strings/text-content'; import { AssessmentViewUpdateHandler } from 'DetailsView/components/assessment-view-update-handler'; import { NoContentAvailableViewDeps } from 'DetailsView/components/no-content-available/no-content-available-view'; @@ -294,6 +296,14 @@ if (isNaN(tabId) === false) { AxeInfo.Default.version, ); + const toolData = createToolData( + toolName, + browserAdapter.getVersion(), + 'axe-core', + AxeInfo.Default.version, + browserSpec, + ); + const reactStaticRenderer = new ReactStaticRenderer(); const reportNameGenerator = new WebReportNameGenerator(); @@ -343,7 +353,7 @@ if (isNaN(tabId) === false) { const issueDetailsTextGenerator = new IssueDetailsTextGenerator( IssueFilingUrlStringUtils, - environmentInfoProvider, + toolData, createIssueDetailsBuilder(PlainTextFormatter), ); diff --git a/src/background/background-init.ts b/src/background/background-init.ts index a96b49e0a71..152099ebe9c 100644 --- a/src/background/background-init.ts +++ b/src/background/background-init.ts @@ -4,6 +4,7 @@ import { AppInsights } from 'applicationinsights-js'; import { Assessments } from 'assessments/assessments'; import { ConsoleTelemetryClient } from 'background/telemetry/console-telemetry-client'; import { DebugToolsTelemetryClient } from 'background/telemetry/debug-tools-telemetry-client'; +import { createToolData } from 'common/application-properties-provider'; import { AxeInfo } from '../common/axe-info'; import { ChromeAdapter } from '../common/browser-adapters/chrome-adapter'; import { VisualizationConfigurationFactory } from '../common/configs/visualization-configuration-factory'; @@ -18,7 +19,7 @@ import { NotificationCreator } from '../common/notification-creator'; import { createDefaultPromiseFactory } from '../common/promises/promise-factory'; import { TelemetryDataFactory } from '../common/telemetry-data-factory'; import { UrlValidator } from '../common/url-validator'; -import { title } from '../content/strings/application'; +import { title, toolName } from '../content/strings/application'; import { IssueFilingServiceProviderImpl } from '../issue-filing/issue-filing-service-provider-impl'; import { BrowserMessageBroadcasterFactory } from './browser-message-broadcaster-factory'; import { DevToolsListener } from './dev-tools-listener'; @@ -109,6 +110,14 @@ async function initialize(): Promise { AxeInfo.Default.version, ); + const toolData = createToolData( + toolName, + browserAdapter.getVersion(), + 'axe-core', + AxeInfo.Default.version, + browserSpec, + ); + const globalContext = await GlobalContextFactory.createContext( browserAdapter, telemetryEventHandler, @@ -119,6 +128,7 @@ async function initialize(): Promise { persistedData, IssueFilingServiceProviderImpl, environmentInfoProvider.getEnvironmentInfo(), + toolData, browserAdapter, browserAdapter, logger, diff --git a/src/background/global-context-factory.ts b/src/background/global-context-factory.ts index 3d68026ec58..7182e2ba490 100644 --- a/src/background/global-context-factory.ts +++ b/src/background/global-context-factory.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { BrowserPermissionsTracker } from 'background/browser-permissions-tracker'; import { Logger } from 'common/logging/logger'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { DebugToolsActionCreator } from 'debug-tools/action-creators/debug-tools-action-creator'; import { DebugToolsController } from 'debug-tools/controllers/debug-tools-controller'; import { BrowserAdapter } from '../common/browser-adapters/browser-adapter'; @@ -45,6 +46,7 @@ export class GlobalContextFactory { persistedData: PersistedData, issueFilingServiceProvider: IssueFilingServiceProvider, environmentInfo: EnvironmentInfo, + toolData: ToolData, storageAdapter: StorageAdapter, commandsAdapter: CommandsAdapter, logger: Logger, @@ -74,7 +76,7 @@ export class GlobalContextFactory { const issueFilingController = new IssueFilingControllerImpl( issueFilingServiceProvider, browserAdapter, - environmentInfo, + toolData, globalStoreHub.userConfigurationStore, ); diff --git a/src/background/issue-details-text-generator.ts b/src/background/issue-details-text-generator.ts index d227fe25aa0..3fdace18a12 100644 --- a/src/background/issue-details-text-generator.ts +++ b/src/background/issue-details-text-generator.ts @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { EnvironmentInfoProvider } from '../common/environment-info-provider'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { CreateIssueDetailsTextData } from '../common/types/create-issue-details-text-data'; import { IssueDetailsBuilder } from '../issue-filing/common/issue-details-builder'; import { IssueUrlCreationUtils } from '../issue-filing/common/issue-filing-url-string-utils'; @@ -8,7 +8,7 @@ import { IssueUrlCreationUtils } from '../issue-filing/common/issue-filing-url-s export class IssueDetailsTextGenerator { constructor( private issueFilingUrlStringUtils: IssueUrlCreationUtils, - private environmentInfoProvider: EnvironmentInfoProvider, + private toolData: ToolData, private issueDetailsBuilder: IssueDetailsBuilder, ) {} @@ -19,7 +19,7 @@ export class IssueDetailsTextGenerator { `Title: ${this.issueFilingUrlStringUtils.getTitle(data)}`, `Tags: ${this.buildTags(data, standardTags)}`, ``, - this.issueDetailsBuilder(this.environmentInfoProvider.getEnvironmentInfo(), data), + this.issueDetailsBuilder(this.toolData, data), ].join('\n'); return text; diff --git a/src/common/application-properties-provider.ts b/src/common/application-properties-provider.ts new file mode 100644 index 00000000000..c00cffb6d32 --- /dev/null +++ b/src/common/application-properties-provider.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { ToolData } from './types/store-data/unified-data-interface'; + +export const createToolData = ( + toolName: string, + toolVersion: string, + scanEngineName: string, + scanEngineVersion: string, + environmentName?: string, +): ToolData => { + return { + scanEngineProperties: { + name: scanEngineName, + version: scanEngineVersion, + }, + applicationProperties: { + name: toolName, + version: toolVersion, + environmentName: environmentName, + }, + }; +}; diff --git a/src/electron/common/application-properties-provider.ts b/src/electron/common/application-properties-provider.ts index e86ba11c85c..f65a2009dd5 100644 --- a/src/electron/common/application-properties-provider.ts +++ b/src/electron/common/application-properties-provider.ts @@ -1,23 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { AppDataAdapter } from 'common/browser-adapters/app-data-adapter'; +import { createToolData } from 'common/application-properties-provider'; import { ToolData } from 'common/types/store-data/unified-data-interface'; -import { androidAppTitle } from 'content/strings/application'; import { AndroidScanResults } from 'electron/platform/android/android-scan-results'; export type ToolDataDelegate = (scanResults: AndroidScanResults) => ToolData; -export const createGetToolDataDelegate = (appDataAdapter: AppDataAdapter): ToolDataDelegate => { +export const createGetToolDataDelegate = ( + toolName: string, + toolVersion: string, + scanEngineName: string, +): ToolDataDelegate => { return scanResults => { - return { - scanEngineProperties: { - name: 'axe-android', - version: scanResults.axeVersion, - }, - applicationProperties: { - name: androidAppTitle, - version: appDataAdapter.getVersion(), - }, - }; + return createToolData(toolName, toolVersion, scanEngineName, scanResults.axeVersion); }; }; diff --git a/src/electron/views/renderer-initializer.ts b/src/electron/views/renderer-initializer.ts index 72a89447046..38b7ffbd0c1 100644 --- a/src/electron/views/renderer-initializer.ts +++ b/src/electron/views/renderer-initializer.ts @@ -303,7 +303,12 @@ getPersistedData(indexedDBInstance, indexedDBDataKeysToFetch).then( ); windowFrameListener.initialize(); - const getToolData = createGetToolDataDelegate(appDataAdapter); + const getToolData = createGetToolDataDelegate( + androidAppTitle, + appDataAdapter.getVersion(), + 'axe-android', + ); + const unifiedResultsBuilder = createDefaultBuilder(getToolData); const scanController = new ScanController( scanActions, diff --git a/src/injected/dialog-renderer.tsx b/src/injected/dialog-renderer.tsx index 4ce18762bc9..5464ef5ece7 100644 --- a/src/injected/dialog-renderer.tsx +++ b/src/injected/dialog-renderer.tsx @@ -83,7 +83,7 @@ export class DialogRenderer { const issueDetailsTextGenerator = new IssueDetailsTextGenerator( IssueFilingUrlStringUtils, - mainWindowContext.getEnvironmentInfoProvider(), + mainWindowContext.getToolData(), createIssueDetailsBuilder(PlainTextFormatter), ); diff --git a/src/injected/main-window-context.ts b/src/injected/main-window-context.ts index 33d02892440..01f95df0950 100644 --- a/src/injected/main-window-context.ts +++ b/src/injected/main-window-context.ts @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { BaseStore } from '../common/base-store'; import { DevToolActionMessageCreator } from '../common/message-creators/dev-tool-action-message-creator'; import { IssueFilingActionMessageCreator } from '../common/message-creators/issue-filing-action-message-creator'; @@ -19,6 +20,7 @@ export class MainWindowContext { private issueFilingActionMessageCreator: IssueFilingActionMessageCreator, private userConfigMessageCreator: UserConfigMessageCreator, private environmentInfoProvider: EnvironmentInfoProvider, + private toolData: ToolData, private issueFilingServiceProvider: IssueFilingServiceProvider, ) {} @@ -50,6 +52,10 @@ export class MainWindowContext { return this.environmentInfoProvider; } + public getToolData(): ToolData { + return this.toolData; + } + public getIssueFilingServiceProvider(): IssueFilingServiceProvider { return this.issueFilingServiceProvider; } @@ -62,6 +68,7 @@ export class MainWindowContext { issueFilingActionMessageCreator: IssueFilingActionMessageCreator, userConfigMessageCreator: UserConfigMessageCreator, environmentInfoProvider: EnvironmentInfoProvider, + toolData: ToolData, issueFilingServiceProvider: IssueFilingServiceProvider, ): void { window.mainWindowContext = new MainWindowContext( @@ -72,6 +79,7 @@ export class MainWindowContext { issueFilingActionMessageCreator, userConfigMessageCreator, environmentInfoProvider, + toolData, issueFilingServiceProvider, ); } diff --git a/src/injected/main-window-initializer.ts b/src/injected/main-window-initializer.ts index b7bd994a877..d32d79aa085 100644 --- a/src/injected/main-window-initializer.ts +++ b/src/injected/main-window-initializer.ts @@ -21,6 +21,8 @@ import { TargetPageVisualizationUpdater } from 'injected/target-page-visualizati import { visualizationNeedsUpdate } from 'injected/visualization-needs-update'; import { VisualizationStateChangeHandler } from 'injected/visualization-state-change-handler'; +import { createToolData } from 'common/application-properties-provider'; +import { toolName } from 'content/strings/application'; import { AxeInfo } from '../common/axe-info'; import { InspectConfigurationFactory } from '../common/configs/inspect-configuration-factory'; import { DateProvider } from '../common/date-provider'; @@ -205,6 +207,14 @@ export class MainWindowInitializer extends WindowInitializer { AxeInfo.Default.version, ); + const toolData = createToolData( + toolName, + this.appDataAdapter.getVersion(), + 'axe-core', + AxeInfo.Default.version, + browserSpec, + ); + MainWindowContext.initialize( this.devToolStoreProxy, this.userConfigStoreProxy, @@ -213,6 +223,7 @@ export class MainWindowInitializer extends WindowInitializer { issueFilingActionMessageCreator, userConfigMessageCreator, environmentInfoProvider, + toolData, IssueFilingServiceProviderImpl, ); diff --git a/src/issue-filing/common/create-file-issue-handler.ts b/src/issue-filing/common/create-file-issue-handler.ts index 7522161ca1f..211af036fd6 100644 --- a/src/issue-filing/common/create-file-issue-handler.ts +++ b/src/issue-filing/common/create-file-issue-handler.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { BrowserAdapter } from 'common/browser-adapters/browser-adapter'; -import { EnvironmentInfo } from 'common/environment-info-provider'; import { CreateIssueDetailsTextData } from 'common/types/create-issue-details-text-data'; import { IssueFilingServicePropertiesMap } from 'common/types/store-data/user-configuration-store'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { IssueFilingUrlProvider } from '../types/issue-filing-service'; export const createFileIssueHandler = ( @@ -15,11 +15,11 @@ export const createFileIssueHandler = ( browserAdapter: BrowserAdapter, servicePropertiesMap: IssueFilingServicePropertiesMap, issueData: CreateIssueDetailsTextData, - environmentInfo: EnvironmentInfo, + toolData: ToolData, ): Promise => { const serviceConfig = getSettings(servicePropertiesMap); - const url = getUrl(serviceConfig, issueData, environmentInfo); + const url = getUrl(serviceConfig, issueData, toolData); await browserAdapter.createActiveTab(url); }; }; diff --git a/src/issue-filing/common/create-issue-details-builder.ts b/src/issue-filing/common/create-issue-details-builder.ts index 0b94720d68d..1b346ade8cc 100644 --- a/src/issue-filing/common/create-issue-details-builder.ts +++ b/src/issue-filing/common/create-issue-details-builder.ts @@ -1,14 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { title } from 'content/strings/application'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { compact } from 'lodash'; -import { EnvironmentInfo } from '../../common/environment-info-provider'; import { CreateIssueDetailsTextData } from '../../common/types/create-issue-details-text-data'; import { IssueDetailsBuilder } from './issue-details-builder'; import { MarkupFormatter } from './markup/markup-formatter'; export const createIssueDetailsBuilder = (markup: MarkupFormatter): IssueDetailsBuilder => { - const getter = (environmentInfo: EnvironmentInfo, data: CreateIssueDetailsTextData): string => { + const getter = (toolData: ToolData, data: CreateIssueDetailsTextData): string => { const { howToFixSection, link, @@ -57,13 +56,13 @@ export const createIssueDetailsBuilder = (markup: MarkupFormatter): IssueDetails sectionHeader('Environment'), sectionHeaderSeparator(), - environmentInfo.browserSpec, + toolData.applicationProperties.environmentName, sectionSeparator(), footerSeparator(), - `This accessibility issue was found using ${title} ` + - `${environmentInfo.extensionVersion} (axe-core ${environmentInfo.axeCoreVersion}), ` + + `This accessibility issue was found using ${toolData.applicationProperties.name} ` + + `${toolData.applicationProperties.version} (${toolData.scanEngineProperties.name} ${toolData.scanEngineProperties.version}), ` + 'a tool that helps find and fix accessibility issues. Get more information & download ' + `this tool at ${link('http://aka.ms/AccessibilityInsights')}.`, ]; diff --git a/src/issue-filing/common/issue-details-builder.ts b/src/issue-filing/common/issue-details-builder.ts index cdbf48d70ad..bb3e075507c 100644 --- a/src/issue-filing/common/issue-details-builder.ts +++ b/src/issue-filing/common/issue-details-builder.ts @@ -1,8 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { EnvironmentInfo } from '../../common/environment-info-provider'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { CreateIssueDetailsTextData } from '../../common/types/create-issue-details-text-data'; -export type IssueDetailsBuilder = ( - environmentInfo: EnvironmentInfo, - data: CreateIssueDetailsTextData, -) => string; +export type IssueDetailsBuilder = (toolData: ToolData, data: CreateIssueDetailsTextData) => string; diff --git a/src/issue-filing/common/issue-filing-controller-impl.ts b/src/issue-filing/common/issue-filing-controller-impl.ts index 51fb9203172..e40ff907c03 100644 --- a/src/issue-filing/common/issue-filing-controller-impl.ts +++ b/src/issue-filing/common/issue-filing-controller-impl.ts @@ -2,10 +2,10 @@ // Licensed under the MIT License. import { BaseStore } from 'common/base-store'; import { BrowserAdapter } from 'common/browser-adapters/browser-adapter'; -import { EnvironmentInfo } from 'common/environment-info-provider'; import { CreateIssueDetailsTextData } from 'common/types/create-issue-details-text-data'; import { UserConfigurationStoreData } from 'common/types/store-data/user-configuration-store'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { IssueFilingServiceProvider } from '../issue-filing-service-provider'; export type IssueFilingController = { @@ -16,7 +16,7 @@ export class IssueFilingControllerImpl implements IssueFilingController { constructor( private readonly provider: IssueFilingServiceProvider, private readonly browserAdapter: BrowserAdapter, - private readonly environmentInfo: EnvironmentInfo, + private readonly toolData: ToolData, private readonly userConfigurationStore: BaseStore, ) {} @@ -31,7 +31,7 @@ export class IssueFilingControllerImpl implements IssueFilingController { this.browserAdapter, userConfigurationStoreData.bugServicePropertiesMap, issueData, - this.environmentInfo, + this.toolData, ); }; } diff --git a/src/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.ts b/src/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.ts index da0af9fc2b1..fb4e67591ed 100644 --- a/src/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.ts +++ b/src/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { title } from 'content/strings/application'; -import { EnvironmentInfo } from '../../../common/environment-info-provider'; import { CreateIssueDetailsTextData } from '../../../common/types/create-issue-details-text-data'; import { createIssueDetailsBuilder } from '../../common/create-issue-details-builder'; import { HTTPQueryBuilder } from '../../common/http-query-builder'; @@ -29,12 +29,12 @@ export const createAzureBoardsIssueFilingUrlProvider = ( return ( settingsData: AzureBoardsIssueFilingSettings, issueData: CreateIssueDetailsTextData, - environmentInfo: EnvironmentInfo, + toolData: ToolData, ) => { const titleField = stringUtils.getTitle(issueData); const standardTags = stringUtils.standardizeTags(issueData); const tags = buildTags(issueData, standardTags); - const body = issueDetailsBuilder(environmentInfo, issueData); + const body = issueDetailsBuilder(toolData, issueData); let bodyField: string = '[Microsoft.VSTS.TCM.ReproSteps]'; let workItemType: AzureBoardsWorkItemType = 'Bug'; diff --git a/src/issue-filing/services/github/create-github-issue-filing-url.ts b/src/issue-filing/services/github/create-github-issue-filing-url.ts index 796aa3a091b..838239ec963 100644 --- a/src/issue-filing/services/github/create-github-issue-filing-url.ts +++ b/src/issue-filing/services/github/create-github-issue-filing-url.ts @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { EnvironmentInfo } from '../../../common/environment-info-provider'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { CreateIssueDetailsTextData } from '../../../common/types/create-issue-details-text-data'; import { createIssueDetailsBuilder } from '../../common/create-issue-details-builder'; import { HTTPQueryBuilder } from '../../common/http-query-builder'; @@ -22,10 +22,10 @@ export const createGitHubIssueFilingUrlProvider = ( return ( settingsData: GitHubIssueFilingSettings, issueData: CreateIssueDetailsTextData, - environmentInfo: EnvironmentInfo, + toolData: ToolData, ): string => { const title = stringUtils.getTitle(issueData); - const body = issueDetailsBuilder(environmentInfo, issueData); + const body = issueDetailsBuilder(toolData, issueData); const baseUrl = rectifier(settingsData.repository); diff --git a/src/issue-filing/types/issue-filing-service.ts b/src/issue-filing/types/issue-filing-service.ts index 34b5eb70c71..f65e5e11527 100644 --- a/src/issue-filing/types/issue-filing-service.ts +++ b/src/issue-filing/types/issue-filing-service.ts @@ -1,16 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { BrowserAdapter } from '../../common/browser-adapters/browser-adapter'; import { ReactFCWithDisplayName } from '../../common/react/named-fc'; import { IssueFilingServicePropertiesMap } from '../../common/types/store-data/user-configuration-store'; -import { EnvironmentInfo } from './../../common/environment-info-provider'; import { CreateIssueDetailsTextData } from './../../common/types/create-issue-details-text-data'; import { SettingsFormProps } from './settings-form-props'; export type IssueFilingUrlProvider = ( data: Settings, issueData: CreateIssueDetailsTextData, - environmentInfo: EnvironmentInfo, + toolData: ToolData, ) => string; export interface IssueFilingService { @@ -25,7 +25,7 @@ export interface IssueFilingService { browserAdapter: BrowserAdapter, servicePropertiesMap: IssueFilingServicePropertiesMap, issueData: CreateIssueDetailsTextData, - environmentInfo: EnvironmentInfo, + toolData: ToolData, ) => Promise; } diff --git a/src/tests/unit/common/application-properties-provider.test.ts b/src/tests/unit/common/application-properties-provider.test.ts new file mode 100644 index 00000000000..6f764d4a9ed --- /dev/null +++ b/src/tests/unit/common/application-properties-provider.test.ts @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { createToolData } from 'common/application-properties-provider'; + +describe('createToolData', () => { + it('returns proper tool data', () => { + const result = createToolData( + 'test-tool-name', + 'test-tool-version', + 'test-engine-name', + 'test-engine-version', + 'test-environment-name', + ); + + expect(result).toMatchInlineSnapshot(` + Object { + "applicationProperties": Object { + "environmentName": "test-environment-name", + "name": "test-tool-name", + "version": "test-tool-version", + }, + "scanEngineProperties": Object { + "name": "test-engine-name", + "version": "test-engine-version", + }, + } + `); + }); +}); diff --git a/src/tests/unit/tests/background/global-context-factory.test.ts b/src/tests/unit/tests/background/global-context-factory.test.ts index 96b8ea1b764..000a086dede 100644 --- a/src/tests/unit/tests/background/global-context-factory.test.ts +++ b/src/tests/unit/tests/background/global-context-factory.test.ts @@ -10,6 +10,7 @@ import { FeatureFlagStore } from 'background/stores/global/feature-flag-store'; import { LaunchPanelStore } from 'background/stores/global/launch-panel-store'; import { TelemetryEventHandler } from 'background/telemetry/telemetry-event-handler'; import { Logger } from 'common/logging/logger'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { IMock, It, Mock } from 'typemoq'; import { BrowserAdapter } from '../../../../common/browser-adapters/browser-adapter'; import { CommandsAdapter } from '../../../../common/browser-adapters/commands-adapter'; @@ -30,6 +31,7 @@ describe('GlobalContextFactoryTest', () => { let loggerMock: IMock; let environmentInfoStub: EnvironmentInfo; + let toolData: ToolData; let userDataStub: LocalStorageData; let idbInstance: IndexedDBAPI; let persistedDataStub: PersistedData; @@ -51,6 +53,7 @@ describe('GlobalContextFactoryTest', () => { userDataStub = {}; environmentInfoStub = {} as EnvironmentInfo; + toolData = {} as ToolData; persistedDataStub = {} as PersistedData; idbInstance = {} as IndexedDBAPI; }); @@ -66,6 +69,7 @@ describe('GlobalContextFactoryTest', () => { persistedDataStub, issueFilingServiceProviderMock.object, environmentInfoStub, + toolData, storageAdapterMock.object, commandsAdapterMock.object, loggerMock.object, diff --git a/src/tests/unit/tests/background/issue-details-text-generator.test.ts b/src/tests/unit/tests/background/issue-details-text-generator.test.ts index 9560c6bd9e7..fd523010e68 100644 --- a/src/tests/unit/tests/background/issue-details-text-generator.test.ts +++ b/src/tests/unit/tests/background/issue-details-text-generator.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { IssueDetailsTextGenerator } from 'background/issue-details-text-generator'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { IMock, Mock, MockBehavior } from 'typemoq'; -import { EnvironmentInfoProvider } from '../../../../common/environment-info-provider'; import { CreateIssueDetailsTextData } from '../../../../common/types/create-issue-details-text-data'; import { IssueDetailsBuilder } from '../../../../issue-filing/common/issue-details-builder'; import { IssueUrlCreationUtils } from '../../../../issue-filing/common/issue-filing-url-string-utils'; @@ -11,13 +11,24 @@ describe('Issue details text builder', () => { let testSubject: IssueDetailsTextGenerator; let sampleIssueDetailsData: CreateIssueDetailsTextData; let issueUrlCreationUtilsMock: IMock; - let envInfoProviderMock: IMock; let issueDetailsBuilderMock: IMock; const wcagTags = ['WCAG-1.4.1', 'WCAG-2.8.2']; const title = `${wcagTags.join(',')}: RR-help (RR-selector)`; const selector = 'RR-selector'; + const toolData: ToolData = { + scanEngineProperties: { + name: 'engine-name', + version: 'engine-version', + }, + applicationProperties: { + name: 'app-name', + version: 'app-version', + environmentName: 'environmentName', + }, + }; + beforeEach(() => { sampleIssueDetailsData = { rule: { @@ -52,22 +63,14 @@ describe('Issue details text builder', () => { .setup(utils => utils.standardizeTags(sampleIssueDetailsData)) .returns(() => wcagTags); - const envInfo = { - axeCoreVersion: 'AXE.CORE.VER', - browserSpec: 'BROWSER.SPEC', - extensionVersion: 'MY.EXT.VER', - }; - envInfoProviderMock = Mock.ofType(undefined, MockBehavior.Strict); - envInfoProviderMock.setup(provider => provider.getEnvironmentInfo()).returns(() => envInfo); - issueDetailsBuilderMock = Mock.ofType(undefined, MockBehavior.Strict); issueDetailsBuilderMock - .setup(builder => builder(envInfo, sampleIssueDetailsData)) + .setup(builder => builder(toolData, sampleIssueDetailsData)) .returns(() => 'test-issue-details-builder'); testSubject = new IssueDetailsTextGenerator( issueUrlCreationUtilsMock.object, - envInfoProviderMock.object, + toolData, issueDetailsBuilderMock.object, ); }); diff --git a/src/tests/unit/tests/electron/common/application-properties-provider.test.ts b/src/tests/unit/tests/electron/common/application-properties-provider.test.ts index 15a0e6fbb3a..ae8330919ec 100644 --- a/src/tests/unit/tests/electron/common/application-properties-provider.test.ts +++ b/src/tests/unit/tests/electron/common/application-properties-provider.test.ts @@ -1,25 +1,26 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { AppDataAdapter } from 'common/browser-adapters/app-data-adapter'; import { createGetToolDataDelegate } from 'electron/common/application-properties-provider'; import { AndroidScanResults } from 'electron/platform/android/android-scan-results'; import { Mock } from 'typemoq'; describe('ToolDataDelegate', () => { it('returns proper tool data', () => { - const appDataAdapterMock = Mock.ofType(); - appDataAdapterMock.setup(adapter => adapter.getVersion()).returns(() => 'test-version'); - const scanResultsMock = Mock.ofType(); scanResultsMock.setup(results => results.axeVersion).returns(() => 'test-axe-version'); - const testSubject = createGetToolDataDelegate(appDataAdapterMock.object); + const testSubject = createGetToolDataDelegate( + 'Accessibility Insights for Android', + 'test-version', + 'axe-android', + ); const result = testSubject(scanResultsMock.object); expect(result).toMatchInlineSnapshot(` Object { "applicationProperties": Object { + "environmentName": undefined, "name": "Accessibility Insights for Android", "version": "test-version", }, diff --git a/src/tests/unit/tests/injected/dialog-renderer.test.tsx b/src/tests/unit/tests/injected/dialog-renderer.test.tsx index 88eaa06609f..66aa002cadc 100644 --- a/src/tests/unit/tests/injected/dialog-renderer.test.tsx +++ b/src/tests/unit/tests/injected/dialog-renderer.test.tsx @@ -16,6 +16,7 @@ import { import { DevToolStore } from 'background/stores/dev-tools-store'; import { UserConfigurationStore } from 'background/stores/global/user-configuration-store'; import { NavigatorUtils } from 'common/navigator-utils'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { BrowserAdapter } from '../../../../common/browser-adapters/browser-adapter'; import { EnvironmentInfoProvider } from '../../../../common/environment-info-provider'; import { FeatureFlags, getDefaultFeatureFlagsWeb } from '../../../../common/feature-flags'; @@ -65,6 +66,8 @@ describe('DialogRendererTests', () => { let getMainWindoContextMock: IGlobalMock<() => MainWindowContext>; let rootContainerMock: IMock; + const toolData = {} as ToolData; + beforeEach(() => { htmlElementUtilsMock = Mock.ofType(HTMLElementUtils); windowUtilsMock = Mock.ofType(WindowUtils); @@ -120,6 +123,7 @@ describe('DialogRendererTests', () => { issueFilingActionMessageCreatorMock.object, userConfigMessageCreatorMock.object, environmentInfoProviderMock.object, + toolData, issueFilingServiceProviderMock.object, ); }); diff --git a/src/tests/unit/tests/injected/main-window-context.test.ts b/src/tests/unit/tests/injected/main-window-context.test.ts index f9a9218d06b..cbb03fc4ff6 100644 --- a/src/tests/unit/tests/injected/main-window-context.test.ts +++ b/src/tests/unit/tests/injected/main-window-context.test.ts @@ -9,6 +9,7 @@ describe('MainWindowContextTest', () => { const targetPageActionMessageCreator: any = { name: 'targetPageActionMessageCreator' }; const issueFilingActionMessageCreator: any = { name: 'targetPageActionMessageCreator' }; const environmentInfoProvider: any = { name: 'environmentInfoProvider' }; + const toolData: any = { name: 'toolData' }; const issueFilingServiceProvider: any = { name: 'issueFilingServiceProvider' }; const userConfigMessageCreator: any = { name: 'userConfigMessageCreator' }; @@ -21,6 +22,7 @@ describe('MainWindowContextTest', () => { issueFilingActionMessageCreator, userConfigMessageCreator, environmentInfoProvider, + toolData, issueFilingServiceProvider, ); @@ -41,6 +43,7 @@ describe('MainWindowContextTest', () => { issueFilingActionMessageCreator, userConfigMessageCreator, environmentInfoProvider, + toolData, issueFilingServiceProvider, ); @@ -60,6 +63,7 @@ describe('MainWindowContextTest', () => { expect(MainWindowContext.getMainWindowContext().getEnvironmentInfoProvider()).toEqual( environmentInfoProvider, ); + expect(MainWindowContext.getMainWindowContext().getToolData()).toEqual(toolData); expect(MainWindowContext.getMainWindowContext().getIssueFilingServiceProvider()).toEqual( issueFilingServiceProvider, ); @@ -74,6 +78,7 @@ describe('MainWindowContextTest', () => { issueFilingActionMessageCreator, userConfigMessageCreator, environmentInfoProvider, + toolData, issueFilingServiceProvider, ); @@ -81,6 +86,7 @@ describe('MainWindowContextTest', () => { const userConfigStoreLocal: any = { name: 'userConfigStoreLocal' }; const devToolActionMessageCreatorLocal: any = { name: 'devToolActionMessageCreatorLocal' }; const environmentInfoProviderLocal: any = { name: 'environmentInfoProviderLocal' }; + const toolDataLocal: any = { name: 'toolDataLocal' }; const issueFilingServiceProviderLocal: any = { name: 'issueFilingServiceProviderLocal' }; const userConfigMessageCreatorLocal: any = { name: 'userConfigMessageCreatorLocal' }; @@ -92,6 +98,7 @@ describe('MainWindowContextTest', () => { issueFilingActionMessageCreator, userConfigMessageCreatorLocal, environmentInfoProviderLocal, + toolDataLocal, issueFilingServiceProviderLocal, ); @@ -110,6 +117,7 @@ describe('MainWindowContextTest', () => { expect(mainWindowContextGiven.getEnvironmentInfoProvider()).toEqual( environmentInfoProviderLocal, ); + expect(mainWindowContextGiven.getToolData()).toEqual(toolDataLocal); expect(mainWindowContextGiven.getIssueFilingServiceProvider()).toEqual( issueFilingServiceProviderLocal, ); @@ -129,6 +137,7 @@ describe('MainWindowContextTest', () => { expect(mainWindowContextNotGiven.getEnvironmentInfoProvider()).toEqual( environmentInfoProvider, ); + expect(mainWindowContextNotGiven.getToolData()).toEqual(toolData); expect(mainWindowContextNotGiven.getIssueFilingServiceProvider()).toEqual( issueFilingServiceProvider, ); diff --git a/src/tests/unit/tests/issue-filing/common/__snapshots__/issue-details-builder.test.ts.snap b/src/tests/unit/tests/issue-filing/common/__snapshots__/issue-details-builder.test.ts.snap index 030911549dc..e437ec81807 100644 --- a/src/tests/unit/tests/issue-filing/common/__snapshots__/issue-details-builder.test.ts.snap +++ b/src/tests/unit/tests/issue-filing/common/__snapshots__/issue-details-builder.test.ts.snap @@ -6,8 +6,8 @@ h-Target application-h--s-h-s--pageTitle h-Element path-h--s-h-s--RR-selector h-Snippet-h--s-h-s--s-RR-snippet space-s h-How to fix-h--s-h-s--h-t--RR-failureSummary--h-t -h-Environment-h--s-h-s--test spec ---f-s--This accessibility issue was found using Accessibility Insights for Web 1.1.1 (axe-core 2.2.2), a tool that helps find and fix accessibility issues. Get more information & download this tool at l-http://aka.ms/AccessibilityInsights-l." +h-Environment-h--s-h-s--environmentName +--f-s--This accessibility issue was found using app-name app-version (engine-name engine-version), a tool that helps find and fix accessibility issues. Get more information & download this tool at l-http://aka.ms/AccessibilityInsights-l." `; exports[`Name of the group build issue details when targetApp.url is pageUrl 1`] = ` @@ -16,6 +16,6 @@ h-Target application-h--s-h-s--l-pageUrl-pageTitle-l h-Element path-h--s-h-s--RR-selector h-Snippet-h--s-h-s--s-RR-snippet space-s h-How to fix-h--s-h-s--h-t--RR-failureSummary--h-t -h-Environment-h--s-h-s--test spec ---f-s--This accessibility issue was found using Accessibility Insights for Web 1.1.1 (axe-core 2.2.2), a tool that helps find and fix accessibility issues. Get more information & download this tool at l-http://aka.ms/AccessibilityInsights-l." +h-Environment-h--s-h-s--environmentName +--f-s--This accessibility issue was found using app-name app-version (engine-name engine-version), a tool that helps find and fix accessibility issues. Get more information & download this tool at l-http://aka.ms/AccessibilityInsights-l." `; diff --git a/src/tests/unit/tests/issue-filing/common/create-file-issue-handler.test.ts b/src/tests/unit/tests/issue-filing/common/create-file-issue-handler.test.ts index 7cdfe6d8e71..376416a49ab 100644 --- a/src/tests/unit/tests/issue-filing/common/create-file-issue-handler.test.ts +++ b/src/tests/unit/tests/issue-filing/common/create-file-issue-handler.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { BrowserAdapter } from 'common/browser-adapters/browser-adapter'; -import { EnvironmentInfo } from 'common/environment-info-provider'; import { CreateIssueDetailsTextData } from 'common/types/create-issue-details-text-data'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { IssueFilingServicePropertiesMap } from 'common/types/store-data/user-configuration-store'; import { createFileIssueHandler } from 'issue-filing/common/create-file-issue-handler'; import { IssueFilingUrlProvider } from 'issue-filing/types/issue-filing-service'; @@ -16,10 +16,16 @@ describe('createFileIssueHandler', () => { name: 'pageTitle', }, } as CreateIssueDetailsTextData; - const environmentInfoStub: EnvironmentInfo = { - axeCoreVersion: 'test axe version', - browserSpec: 'test browser spec', - extensionVersion: 'test extension version', + const toolData: ToolData = { + scanEngineProperties: { + name: 'engine-name', + version: 'engine-version', + }, + applicationProperties: { + name: 'app-name', + version: 'app-version', + environmentName: 'environmentName', + }, }; const settingsStub = { repo: 'test-repo', @@ -39,7 +45,7 @@ describe('createFileIssueHandler', () => { urlProviderMock = Mock.ofType>(undefined, MockBehavior.Strict); urlProviderMock - .setup(provider => provider(settingsStub, issueData, environmentInfoStub)) + .setup(provider => provider(settingsStub, issueData, toolData)) .returns(() => urlStub); browserAdapterMock = Mock.ofType(undefined, MockBehavior.Strict); @@ -57,7 +63,7 @@ describe('createFileIssueHandler', () => { ); await expect( - testSubject(browserAdapterMock.object, serviceMap, issueData, environmentInfoStub), + testSubject(browserAdapterMock.object, serviceMap, issueData, toolData), ).resolves.toBe(undefined); browserAdapterMock.verifyAll(); @@ -76,7 +82,7 @@ describe('createFileIssueHandler', () => { ); await expect( - testSubject(browserAdapterMock.object, serviceMap, issueData, environmentInfoStub), + testSubject(browserAdapterMock.object, serviceMap, issueData, toolData), ).rejects.toEqual(errorMessage); }); }); diff --git a/src/tests/unit/tests/issue-filing/common/issue-details-builder.test.ts b/src/tests/unit/tests/issue-filing/common/issue-details-builder.test.ts index 54cfdf4fbd2..4c4d6153adc 100644 --- a/src/tests/unit/tests/issue-filing/common/issue-details-builder.test.ts +++ b/src/tests/unit/tests/issue-filing/common/issue-details-builder.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { IMock, It, Mock, MockBehavior } from 'typemoq'; -import { EnvironmentInfo } from '../../../../../common/environment-info-provider'; import { createIssueDetailsBuilder } from '../../../../../issue-filing/common/create-issue-details-builder'; import { MarkupFormatter } from '../../../../../issue-filing/common/markup/markup-formatter'; @@ -24,10 +24,17 @@ describe('Name of the group', () => { howToFixSummary: 'RR-failureSummary', snippet: 'RR-snippet space', }; - const environmentInfo: EnvironmentInfo = { - extensionVersion: '1.1.1', - axeCoreVersion: '2.2.2', - browserSpec: 'test spec', + + const toolData: ToolData = { + scanEngineProperties: { + name: 'engine-name', + version: 'engine-version', + }, + applicationProperties: { + name: 'app-name', + version: 'app-version', + environmentName: 'environmentName', + }, }; let markupMock: IMock; @@ -57,7 +64,7 @@ describe('Name of the group', () => { sampleIssueDetailsData.targetApp.url = targetAppUrl; const testSubject = createIssueDetailsBuilder(markupMock.object); - const result = testSubject(environmentInfo, sampleIssueDetailsData); + const result = testSubject(toolData, sampleIssueDetailsData); expect(result).toMatchSnapshot(); }); diff --git a/src/tests/unit/tests/issue-filing/common/issue-filing-controller-impl.test.ts b/src/tests/unit/tests/issue-filing/common/issue-filing-controller-impl.test.ts index 49dfc0be99d..b2e275e97e0 100644 --- a/src/tests/unit/tests/issue-filing/common/issue-filing-controller-impl.test.ts +++ b/src/tests/unit/tests/issue-filing/common/issue-filing-controller-impl.test.ts @@ -2,8 +2,8 @@ // Licensed under the MIT License. import { BaseStore } from 'common/base-store'; import { BrowserAdapter } from 'common/browser-adapters/browser-adapter'; -import { EnvironmentInfo } from 'common/environment-info-provider'; import { CreateIssueDetailsTextData } from 'common/types/create-issue-details-text-data'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { IssueFilingServicePropertiesMap, UserConfigurationStoreData, @@ -19,10 +19,16 @@ describe('IssueFilingControllerImpl', () => { const issueData = { targetApp: {}, } as CreateIssueDetailsTextData; - const environmentInfoStub: EnvironmentInfo = { - axeCoreVersion: 'test axe version', - browserSpec: 'test browser spec', - extensionVersion: 'test extension version', + const toolData: ToolData = { + scanEngineProperties: { + name: 'engine-name', + version: 'engine-version', + }, + applicationProperties: { + name: 'app-name', + version: 'app-version', + environmentName: 'environmentName', + }, }; const testUrl = 'test-url'; const map: IssueFilingServicePropertiesMap = { @@ -36,7 +42,7 @@ describe('IssueFilingControllerImpl', () => { const issueFilingServiceMock = Mock.ofType(); issueFilingServiceMock .setup(service => - service.fileIssue(browserAdapterMock.object, map, issueData, environmentInfoStub), + service.fileIssue(browserAdapterMock.object, map, issueData, toolData), ) .returns(() => Promise.resolve()); @@ -51,7 +57,7 @@ describe('IssueFilingControllerImpl', () => { const testSubject = new IssueFilingControllerImpl( providerMock.object, browserAdapterMock.object, - environmentInfoStub, + toolData, storeMock.object, ); diff --git a/src/tests/unit/tests/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.test.ts b/src/tests/unit/tests/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.test.ts index ac22af7c43f..8e34599985c 100644 --- a/src/tests/unit/tests/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.test.ts +++ b/src/tests/unit/tests/issue-filing/services/azure-boards/create-azure-boards-issue-filing-url.test.ts @@ -2,8 +2,8 @@ // Licensed under the MIT License. import { IMock, Mock } from 'typemoq'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { title } from 'content/strings/application'; -import { EnvironmentInfo } from '../../../../../../common/environment-info-provider'; import { CreateIssueDetailsTextData } from '../../../../../../common/types/create-issue-details-text-data'; import { HTTPQueryBuilder } from '../../../../../../issue-filing/common/http-query-builder'; import { IssueDetailsBuilder } from '../../../../../../issue-filing/common/issue-details-builder'; @@ -16,7 +16,7 @@ describe('createAzureBoardsIssueFilingUrl', () => { const testIssueDetails = 'html issue details'; let baseTags: string; - let environmentInfo: EnvironmentInfo; + let toolData: ToolData; let sampleIssueDetailsData: CreateIssueDetailsTextData; let settingsData: AzureBoardsIssueFilingSettings; let stringUtilsMock: IMock; @@ -26,10 +26,16 @@ describe('createAzureBoardsIssueFilingUrl', () => { let testSubject: IssueFilingUrlProvider; beforeEach(() => { - environmentInfo = { - extensionVersion: '1.1.1', - axeCoreVersion: '2.2.2', - browserSpec: 'test spec', + toolData = { + scanEngineProperties: { + name: 'engine-name', + version: 'engine-version', + }, + applicationProperties: { + name: 'app-name', + version: 'app-version', + environmentName: 'environmentName', + }, }; sampleIssueDetailsData = { rule: { @@ -64,7 +70,7 @@ describe('createAzureBoardsIssueFilingUrl', () => { issueDetailsGetterMock = Mock.ofType(); issueDetailsGetterMock - .setup(getter => getter(environmentInfo, sampleIssueDetailsData)) + .setup(getter => getter(toolData, sampleIssueDetailsData)) .returns(() => testIssueDetails); queryBuilderMock = Mock.ofType(); @@ -104,7 +110,7 @@ describe('createAzureBoardsIssueFilingUrl', () => { .setup(builder => builder.withParam('[System.Description]', testIssueDetails)) .returns(() => queryBuilderMock.object); - const result = testSubject(settingsData, sampleIssueDetailsData, environmentInfo); + const result = testSubject(settingsData, sampleIssueDetailsData, toolData); expect(result).toMatchSnapshot(); }); @@ -128,7 +134,7 @@ describe('createAzureBoardsIssueFilingUrl', () => { .setup(builder => builder.withParam('[System.Description]', testIssueDetails)) .returns(() => queryBuilderMock.object); - const result = testSubject(settingsData, sampleIssueDetailsData, environmentInfo); + const result = testSubject(settingsData, sampleIssueDetailsData, toolData); expect(result).toMatchSnapshot(); }); @@ -154,7 +160,7 @@ describe('createAzureBoardsIssueFilingUrl', () => { ) .returns(() => queryBuilderMock.object); - const result = testSubject(settingsData, sampleIssueDetailsData, environmentInfo); + const result = testSubject(settingsData, sampleIssueDetailsData, toolData); expect(result).toMatchSnapshot(); }); @@ -181,7 +187,7 @@ describe('createAzureBoardsIssueFilingUrl', () => { ) .returns(() => queryBuilderMock.object); - const result = testSubject(settingsData, sampleIssueDetailsData, environmentInfo); + const result = testSubject(settingsData, sampleIssueDetailsData, toolData); expect(result).toMatchSnapshot(); }); diff --git a/src/tests/unit/tests/issue-filing/services/github/create-github-issue-filing-url.test.ts b/src/tests/unit/tests/issue-filing/services/github/create-github-issue-filing-url.test.ts index dfd9ce6cbfc..f4adeffdf20 100644 --- a/src/tests/unit/tests/issue-filing/services/github/create-github-issue-filing-url.test.ts +++ b/src/tests/unit/tests/issue-filing/services/github/create-github-issue-filing-url.test.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { IMock, Mock } from 'typemoq'; -import { EnvironmentInfo } from '../../../../../../common/environment-info-provider'; +import { ToolData } from 'common/types/store-data/unified-data-interface'; import { HTTPQueryBuilder } from '../../../../../../issue-filing/common/http-query-builder'; import { IssueDetailsBuilder } from '../../../../../../issue-filing/common/issue-details-builder'; import { IssueUrlCreationUtils } from '../../../../../../issue-filing/common/issue-filing-url-string-utils'; @@ -13,7 +13,7 @@ import { IssueFilingUrlProvider } from '../../../../../../issue-filing/types/iss const buildedUrl = 'https://builded-url'; describe('createGitHubIssueFilingUrlTest', () => { - let environmentInfo: EnvironmentInfo; + let toolData: ToolData; let sampleIssueDetailsData; let settingsData: GitHubIssueFilingSettings; let stringUtilsMock: IMock; @@ -23,10 +23,16 @@ describe('createGitHubIssueFilingUrlTest', () => { let rectifyMock: IMock; beforeEach(() => { - environmentInfo = { - extensionVersion: '1.1.1', - axeCoreVersion: '2.2.2', - browserSpec: 'test spec', + toolData = { + scanEngineProperties: { + name: 'engine-name', + version: 'engine-version', + }, + applicationProperties: { + name: 'app-name', + version: 'app-version', + environmentName: 'environmentName', + }, }; sampleIssueDetailsData = { pageTitle: 'pageTitle', @@ -56,7 +62,7 @@ describe('createGitHubIssueFilingUrlTest', () => { issueDetailsGetter = Mock.ofType(); const testIssueDetails = 'test issue details'; issueDetailsGetter - .setup(getter => getter(environmentInfo, sampleIssueDetailsData)) + .setup(getter => getter(toolData, sampleIssueDetailsData)) .returns(() => testIssueDetails); const rectifiedUrl = 'rectified-url'; @@ -89,7 +95,7 @@ describe('createGitHubIssueFilingUrlTest', () => { }); it('creates url', () => { - const result = testObject(settingsData, sampleIssueDetailsData, environmentInfo); + const result = testObject(settingsData, sampleIssueDetailsData, toolData); expect(result).toEqual(buildedUrl); });