Skip to content

Commit

Permalink
fix(workflow-context): attach additional properties and tests (#22)
Browse files Browse the repository at this point in the history
* refactor: split approval-status into state and alllowed-actions

* fix: add params to workflow-provider value

* refactor: rename use-approval-state to get-tag-display-data

* test: add unit tests for get-tag-display-data

* test(workflow-context): add unit tests for workflow context
  • Loading branch information
HendrikThePendric authored Jul 8, 2021
1 parent 22fd9bd commit 407ebf8
Show file tree
Hide file tree
Showing 12 changed files with 348 additions and 62 deletions.
53 changes: 0 additions & 53 deletions src/app-context/app-provider.test.js

This file was deleted.

4 changes: 2 additions & 2 deletions src/bottom-bar/bottom-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { StatusTag } from '../shared/index.js'
import { useWorkflowContext } from '../workflow-context/index.js'

const BottomBar = () => {
const { approvalStatus } = useWorkflowContext()
const { approvalState } = useWorkflowContext()

return (
<>
<StatusTag approvalState={approvalStatus.state} />
<StatusTag approvalState={approvalState} />
</>
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/data-workspace/data-workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const DataWorkspace = () => {
<TitleBar
name={workflow.displayName}
dataSetsCount={workflow.dataSets.length}
approvalState={workflow.approvalStatus.state}
approvalState={workflow.approvalState}
/>
<DataSetNavigation
dataSets={workflow.dataSets}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Approved, Ready, Waiting } from './icons.js'
* B. Should we show a red tag for UNAPPROVABLE and show a negative tag?
* This was not included in the design specs.
*/
const useApprovalState = approvalState => {
const getTagDisplayData = approvalState => {
switch (approvalState) {
case 'APPROVED_HERE':
case 'APPROVED_ELSEWHERE':
Expand Down Expand Up @@ -56,4 +56,4 @@ const useApprovalState = approvalState => {
}
}

export { useApprovalState }
export { getTagDisplayData }
66 changes: 66 additions & 0 deletions src/shared/status-tag/get-tag-display-data.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { getTagDisplayData } from './get-tag-display-data.js'
import { Approved, Ready, Waiting } from './icons.js'

describe('getTagDisplayData', () => {
it('returns "approved" display data for the correct approval states', () => {
const expectedDisplayData = {
icon: Approved,
displayName: 'Approved',
type: 'positive',
}
expect(getTagDisplayData('APPROVED_HERE')).toEqual(expectedDisplayData)
expect(getTagDisplayData('APPROVED_ELSEWHERE')).toEqual(
expectedDisplayData
)
})
it('returns "ready for approval and accepted" display data for the correct approval states', () => {
const expectedDisplayData = {
icon: Ready,
displayName: 'Ready for approval and accepted',
type: 'neutral',
}
expect(getTagDisplayData('ACCEPTED_HERE')).toEqual(expectedDisplayData)
expect(getTagDisplayData('ACCEPTED_ELSEWHERE')).toEqual(
expectedDisplayData
)
})
it('returns "ready for approval" display data for the correct approval states', () => {
const expectedDisplayData = {
icon: Ready,
displayName: 'Ready for approval',
type: 'neutral',
}
expect(getTagDisplayData('UNAPPROVED_READY')).toEqual(
expectedDisplayData
)
})
it('returns "waiting" display data for the correct approval states', () => {
const expectedDisplayData = {
icon: Waiting,
displayName: 'Waiting',
type: 'default',
}
expect(getTagDisplayData('UNAPPROVED_WAITING')).toEqual(
expectedDisplayData
)
expect(getTagDisplayData('UNAPPROVED_ELSEWHERE')).toEqual(
expectedDisplayData
)
expect(getTagDisplayData('UNAPPROVED_ABOVE')).toEqual(
expectedDisplayData
)
})
it('returns "cannot approve" display data for the correct approval states', () => {
const expectedDisplayData = {
icon: Waiting,
displayName: 'Cannot approve',
type: 'negative',
}
expect(getTagDisplayData('UNAPPROVABLE')).toEqual(expectedDisplayData)
})
it('throws an error when encountering an unknown approval state', () => {
expect(() => getTagDisplayData('bad input')).toThrow(
"Unknown approval state: 'bad input'"
)
})
})
4 changes: 2 additions & 2 deletions src/shared/status-tag/status-tag.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Tag } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import { useApprovalState } from './use-approval-state.js'
import { getTagDisplayData } from './get-tag-display-data.js'

const StatusTag = ({ approvalState }) => {
const { icon: Icon, displayName, type } = useApprovalState(approvalState)
const { icon: Icon, displayName, type } = getTagDisplayData(approvalState)
const props = {
[type]: true,
icon: <Icon />,
Expand Down
46 changes: 46 additions & 0 deletions src/workflow-context/use-selected-workflow.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useAppContext } from '../app-context/index.js'
import { useSelectedWorkflow } from './use-selected-workflow.js'

const mockWorkflows = [
{
displayName: 'Workflow a',
id: 'i5m0JPw4DQi',
periodType: 'Daily',
},
{
displayName: 'Workflow B',
id: 'rIUL3hYOjJc',
periodType: 'Daily',
},
]

jest.mock('../app-context/index.js', () => ({
useAppContext: jest.fn(() => ({
dataApprovalWorkflows: mockWorkflows,
})),
}))

describe('useSelectedWorkflow', () => {
it('returns the selected workflow if params.wf matches a workflow id', () => {
expect(useSelectedWorkflow({ wf: 'i5m0JPw4DQi' })).toBe(
mockWorkflows[0]
)
})
it('returns an empty object if params.wf does not match the id of any workflows', () => {
expect(useSelectedWorkflow({ wf: 'badID' })).toEqual({})
})
it('returns an empty object if params.wf is undefined', () => {
expect(useSelectedWorkflow({ wf: undefined })).toEqual({})
expect(useSelectedWorkflow()).toEqual({})
})
it('returns an empty object if no workflows are found', () => {
useAppContext.mockImplementationOnce(() => ({
dataApprovalWorkflows: [],
}))
expect(useSelectedWorkflow({ wf: 'i5m0JPw4DQi' })).toEqual({})
})
it('returns an empty object if workflows are undefined', () => {
useAppContext.mockImplementationOnce(() => ({}))
expect(useSelectedWorkflow({ wf: 'i5m0JPw4DQi' })).toEqual({})
})
})
3 changes: 2 additions & 1 deletion src/workflow-context/use-selection-params.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useState, useEffect } from 'react'
import { history, readQueryParams } from '../navigation/index.js'

const getParamsIfAllAvailable = () => {
export const getParamsIfAllAvailable = () => {
const { wf, pe, ou: orgUnitPath } = readQueryParams()

if (wf && pe && orgUnitPath) {
const orgUnitPathSegments = orgUnitPath.split('/')
const orgUnitId = orgUnitPathSegments[orgUnitPathSegments.length - 1]
Expand Down
58 changes: 58 additions & 0 deletions src/workflow-context/use-selection-params.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { act, renderHook } from '@testing-library/react-hooks'
import React from 'react'
import { history } from '../navigation/history.js'
import { readQueryParams } from '../navigation/read-query-params.js'
import {
useSelectionParams,
getParamsIfAllAvailable,
} from './use-selection-params.js'
import { WorkflowProvider } from './workflow-provider.js'

jest.mock('../navigation/read-query-params.js', () => ({
readQueryParams: jest.fn(() => ({})),
}))

describe('useSelectionParams', () => {
const wrapper = ({ children }) => (
<WorkflowProvider>{children}</WorkflowProvider>
)
it('responds to history changes', () => {
const spy = jest.spyOn(history, 'listen')
renderHook(() => useSelectionParams(), { wrapper })

act(() => {
history.push({
pathname: '/',
search: `?wf=123&pe=456&ou=789`,
})
})

expect(spy).toHaveBeenCalledTimes(1)
})
})

describe('getParamsIfAllAvailable', () => {
it('returns an object if all required query params are found', () => {
readQueryParams.mockImplementationOnce(() => ({
wf: '123',
pe: '123',
ou: '/123/456',
}))
expect(getParamsIfAllAvailable()).toEqual({
ou: '456',
pe: '123',
wf: '123',
})
})
it('returns null if query params are only partially complete', () => {
readQueryParams.mockImplementationOnce(() => ({
wf: '123',
pe: '123',
}))
expect(getParamsIfAllAvailable()).toEqual(null)
})
it('returns null if no query params are found', () => {
readQueryParams.mockImplementationOnce(() => ({}))
expect(getParamsIfAllAvailable()).toEqual(null)
})
})
64 changes: 64 additions & 0 deletions src/workflow-context/use-workflow-context.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { renderHook } from '@testing-library/react-hooks'
import React from 'react'
import { useWorkflowContext } from './use-workflow-context.js'
import { WorkflowProvider } from './workflow-provider.js'

jest.mock('./use-selection-params.js', () => ({
useSelectionParams: jest.fn(() => ({
wf: 'rIUL3hYOjJc',
pe: '20120404',
ou: '456',
})),
}))

jest.mock('./use-selected-workflow.js', () => ({
useSelectedWorkflow: jest.fn(() => ({
displayName: 'Workflow a',
id: 'i5m0JPw4DQi',
periodType: 'Daily',
dataSets: [{ id: '123', displayName: 'Dataset Z' }],
})),
}))

jest.mock('@dhis2/app-runtime', () => ({
useDataQuery: jest.fn(() => ({
loading: false,
error: null,
data: {
approvalStatus: {
state: 'SOME_STATE_LABEL',
canApprove: true,
},
},
called: true,
refetch: () => {},
})),
}))

describe('useWorkflowContext', () => {
const wrapper = ({ children }) => (
<WorkflowProvider>{children}</WorkflowProvider>
)
it('combines data from various hooks', () => {
const { result } = renderHook(() => useWorkflowContext(), { wrapper })

expect(result.current).toEqual({
allowedActions: {
canApprove: true,
},
approvalState: 'SOME_STATE_LABEL',
dataSets: [
{
displayName: 'Dataset Z',
id: '123',
},
],
displayName: 'Workflow a',
params: {
ou: '456',
pe: '20120404',
wf: 'rIUL3hYOjJc',
},
})
})
})
6 changes: 5 additions & 1 deletion src/workflow-context/workflow-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,16 @@ const WorkflowProvider = ({ children }) => {
)
}

const { state: approvalState, ...allowedActions } = data.approvalStatus

return (
<WorkflowContext.Provider
value={{
displayName,
dataSets,
approvalStatus: data.approvalStatus,
approvalState,
allowedActions,
params,
}}
>
{children}
Expand Down
Loading

0 comments on commit 407ebf8

Please sign in to comment.