diff --git a/src/DetailsView/components/requirement-view.tsx b/src/DetailsView/components/requirement-view.tsx index 077684baa98..5f93b641ee9 100644 --- a/src/DetailsView/components/requirement-view.tsx +++ b/src/DetailsView/components/requirement-view.tsx @@ -1,25 +1,40 @@ // 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, VisualHelperToggleConfig } from 'assessments/types/requirement'; -import { NamedFC } from 'common/react/named-fc'; +import { Tab } from 'common/itab'; import { + AssessmentData, AssessmentNavState, GeneratedAssessmentInstance, + ManualTestStepResult, + PersistedTabInfo, } 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 { DetailsViewActionMessageCreator } from 'DetailsView/actions/details-view-action-message-creator'; +import { + AssessmentViewUpdateHandler, + AssessmentViewUpdateHandlerDeps, + AssessmentViewUpdateHandlerProps, +} from 'DetailsView/components/assessment-view-update-handler'; +import { RequirementTableSection } from 'DetailsView/components/left-nav/requirement-table-section'; import { RequirementInstructions } from 'DetailsView/components/requirement-instructions'; import { RequirementViewTitle, RequirementViewTitleDeps, } from 'DetailsView/components/requirement-view-title'; +import { AssessmentInstanceTableHandler } from 'DetailsView/handlers/assessment-instance-table-handler'; import * as React from 'react'; import { DictionaryStringTo } from 'types/common-types'; import * as styles from './requirement-view.scss'; export type RequirementViewDeps = { detailsViewActionMessageCreator: DetailsViewActionMessageCreator; -} & RequirementViewTitleDeps; + assessmentViewUpdateHandler: AssessmentViewUpdateHandler; +} & RequirementViewTitleDeps & + AssessmentViewUpdateHandlerDeps; export interface RequirementViewProps { deps: RequirementViewDeps; @@ -27,39 +42,93 @@ export interface RequirementViewProps { assessmentsProvider: AssessmentsProvider; assessmentNavState: AssessmentNavState; instancesMap: DictionaryStringTo; - isStepEnabled: boolean; - isStepScanned: boolean; + isRequirementEnabled: boolean; + isRequirementScanned: boolean; + assessmentInstanceTableHandler: AssessmentInstanceTableHandler; + featureFlagStoreData: FeatureFlagStoreData; + pathSnippetStoreData: PathSnippetStoreData; + scanningInProgress: boolean; + manualRequirementResultMap: DictionaryStringTo; + assessmentDefaultMessageGenerator: AssessmentDefaultMessageGenerator; + assessmentData: AssessmentData; + currentTarget: Tab; + prevTarget: PersistedTabInfo; } -export const RequirementView = NamedFC('RequirementView', props => { - const requirement: Readonly = props.assessmentsProvider.getStep( - props.assessmentNavState.selectedTestType, - props.assessmentNavState.selectedTestSubview, - ); +export class RequirementView extends React.Component { + public componentDidMount(): void { + this.props.deps.assessmentViewUpdateHandler.onMount(this.getUpdateHandlerProps(this.props)); + } + + public componentDidUpdate(prevProps: RequirementViewProps): 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), + ); + } - const visualHelperToggleConfig: VisualHelperToggleConfig = { - deps: props.deps, - assessmentNavState: props.assessmentNavState, - instancesMap: props.instancesMap, - isStepEnabled: props.isStepEnabled, - isStepScanned: props.isStepScanned, - }; + private getUpdateHandlerProps(props: RequirementViewProps): AssessmentViewUpdateHandlerProps { + return { + deps: props.deps, + isRequirementEnabled: props.isRequirementEnabled, + assessmentNavState: props.assessmentNavState, + assessmentData: props.assessmentData, + prevTarget: props.prevTarget, + currentTarget: props.currentTarget, + }; + } - const visualHelperToggle = requirement.getVisualHelperToggle - ? requirement.getVisualHelperToggle(visualHelperToggleConfig) - : null; + public render(): JSX.Element { + const requirement: Readonly = this.props.assessmentsProvider.getStep( + this.props.assessmentNavState.selectedTestType, + this.props.assessmentNavState.selectedTestSubview, + ); + const requirementHasVisualHelper = !!requirement.getVisualHelperToggle; - return ( -
- - {props.requirement.description} - {visualHelperToggle} - -
- ); -}); + const visualHelperToggleConfig: VisualHelperToggleConfig = { + deps: this.props.deps, + assessmentNavState: this.props.assessmentNavState, + instancesMap: this.props.instancesMap, + isStepEnabled: this.props.isRequirementEnabled, + isStepScanned: this.props.isRequirementScanned, + }; + + const visualHelperToggle = requirementHasVisualHelper + ? requirement.getVisualHelperToggle(visualHelperToggleConfig) + : null; + + return ( +
+ + {this.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 bb6e800d911..2523d9d7b67 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 @@ -5,7 +5,13 @@ exports[`RequirementViewTest renders with content from props 1`] = ` className="requirementView" >
@@ -21,5 +27,46 @@ exports[`RequirementViewTest renders with content from props 1`] = `

} /> +
`; 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 0c8b36b3204..af5145c6138 100644 --- a/src/tests/unit/tests/DetailsView/components/requirement-view.test.tsx +++ b/src/tests/unit/tests/DetailsView/components/requirement-view.test.tsx @@ -1,37 +1,61 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { AssessmentsProviderImpl } from 'assessments/assessments-provider'; +import { AssessmentsProvider } from 'assessments/types/assessments-provider'; import { Requirement } from 'assessments/types/requirement'; -import { GeneratedAssessmentInstance } from 'common/types/store-data/assessment-result-data'; +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 { VisualizationType } from 'common/types/visualization-type'; +import { + AssessmentViewUpdateHandler, + AssessmentViewUpdateHandlerProps, +} from 'DetailsView/components/assessment-view-update-handler'; import { RequirementView, RequirementViewDeps, RequirementViewProps, } from 'DetailsView/components/requirement-view'; +import { AssessmentInstanceTableHandler } from 'DetailsView/handlers/assessment-instance-table-handler'; import { shallow } from 'enzyme'; +import { cloneDeep } from 'lodash'; import * as React from 'react'; -import { Mock } from 'typemoq'; +import { IMock, It, Mock, Times } from 'typemoq'; import { DictionaryStringTo } from 'types/common-types'; describe('RequirementViewTest', () => { - it('renders with content from props', () => { - const requirementStub = { + let requirementStub: Requirement; + let assessmentNavState: AssessmentNavState; + let selectedRequirementStub: Requirement; + let assessmentsProviderMock: IMock; + let props: RequirementViewProps; + let manualRequirementResultMapStub: DictionaryStringTo; + let assessmentInstanceTableHandlerStub: AssessmentInstanceTableHandler; + let featureFlagStoreDataStub: FeatureFlagStoreData; + let pathSnippetStoreDataStub: PathSnippetStoreData; + let updateHandlerMock: IMock; + + beforeEach(() => { + requirementStub = { name: 'test-requirement-name', description:
test-description
, howToTest:

how-to-test-stub

, } as Requirement; - const assessmentNavState = { + assessmentNavState = { selectedTestType: VisualizationType.Headings, selectedTestSubview: 'test-requirement-name', }; - const selectedRequirementStub = { + selectedRequirementStub = { getVisualHelperToggle: ({}) =>
test-visual-helper-toggle
, } as Readonly; - const assessmentsProviderMock = Mock.ofType(AssessmentsProviderImpl); + assessmentsProviderMock = Mock.ofType(AssessmentsProviderImpl); assessmentsProviderMock .setup(ap => ap.getStep( @@ -40,19 +64,100 @@ describe('RequirementViewTest', () => { ), ) .returns(() => selectedRequirementStub); + assessmentInstanceTableHandlerStub = { + changeRequirementStatus: null, + } as AssessmentInstanceTableHandler; + manualRequirementResultMapStub = { + 'some manual test step result id': null, + }; + featureFlagStoreDataStub = { + 'some feature flag': true, + }; + pathSnippetStoreDataStub = { + path: null, + } as PathSnippetStoreData; + updateHandlerMock = Mock.ofType(AssessmentViewUpdateHandler); - const props: RequirementViewProps = { - deps: {} as RequirementViewDeps, + props = { + deps: { assessmentViewUpdateHandler: updateHandlerMock.object } as RequirementViewDeps, requirement: requirementStub, assessmentsProvider: assessmentsProviderMock.object, assessmentNavState: assessmentNavState, instancesMap: {} as DictionaryStringTo, - isStepEnabled: true, - isStepScanned: true, - }; + isRequirementEnabled: true, + isRequirementScanned: true, + manualRequirementResultMap: manualRequirementResultMapStub, + assessmentInstanceTableHandler: assessmentInstanceTableHandlerStub, + featureFlagStoreData: featureFlagStoreDataStub, + pathSnippetStoreData: pathSnippetStoreDataStub, + prevTarget: { id: 4 }, + currentTarget: { id: 5 }, + assessmentData: {}, + } as RequirementViewProps; + }); + it('renders with content from props', () => { const rendered = shallow(); expect(rendered.getElement()).toMatchSnapshot(); }); + + test('componentDidUpdate', () => { + const newProps = cloneDeep(props); + newProps.deps.assessmentViewUpdateHandler = updateHandlerMock.object; + const prevProps = props; + prevProps.assessmentNavState.selectedTestSubview = 'prevTestStep'; + + updateHandlerMock + .setup(u => + u.update( + It.isValue(getUpdateHandlerProps(prevProps)), + It.isValue(getUpdateHandlerProps(newProps)), + ), + ) + .verifiable(Times.once()); + + const testObject = new RequirementView(newProps); + + testObject.componentDidUpdate(prevProps); + + updateHandlerMock.verifyAll(); + }); + + test('componentDidMount', () => { + updateHandlerMock + .setup(u => u.onMount(getUpdateHandlerProps(props))) + .verifiable(Times.once()); + + const testObject = new RequirementView(props); + + testObject.componentDidMount(); + + updateHandlerMock.verifyAll(); + }); + + test('componentWillUnmount', () => { + updateHandlerMock + .setup(u => u.onUnmount(getUpdateHandlerProps(props))) + .verifiable(Times.once()); + + const testObject = new RequirementView(props); + + testObject.componentWillUnmount(); + + updateHandlerMock.verifyAll(); + }); + + function getUpdateHandlerProps( + givenProps: RequirementViewProps, + ): AssessmentViewUpdateHandlerProps { + return { + deps: givenProps.deps, + isRequirementEnabled: givenProps.isRequirementEnabled, + assessmentNavState: givenProps.assessmentNavState, + assessmentData: givenProps.assessmentData, + prevTarget: givenProps.prevTarget, + currentTarget: givenProps.currentTarget, + }; + } });