Skip to content

Commit

Permalink
test: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Birkbjo committed Aug 3, 2023
1 parent 6b64c98 commit 93a84ea
Show file tree
Hide file tree
Showing 7 changed files with 911 additions and 44 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@
"cypress:run": "REACT_APP_NODE_ENV=test yarn cypress run"
},
"devDependencies": {
"@dhis2/cli-app-scripts": "^10.2.0",
"@dhis2/cli-app-scripts": "^10.3.9",
"@dhis2/cli-style": "^10.5.1",
"@dhis2/cypress-commands": "^10.0.3",
"@dhis2/cypress-plugins": "^10.0.3",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "^12.8.3",
"@types/jest": "^29.5.1",
"@types/react": "^18.2.6",
Expand All @@ -35,8 +36,8 @@
"dependencies": {
"@dhis2/app-runtime": "^3.9.3",
"@dhis2/ui": "^8.13.10",
"use-query-params": "^2.2.1",
"react-router-dom": "^6.11.2",
"use-query-params": "^2.2.1",
"zustand": "^4.3.8"
}
}
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './user'
export * from './sections'
export * from './useDebounce'
export * from './routeUtils'
export * from './systemSettings'
2 changes: 1 addition & 1 deletion src/lib/sections/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './isSectionAuthorized'
export * from './sectionAuthorities'
192 changes: 192 additions & 0 deletions src/lib/sections/sectionAuthorities.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import { renderHook } from '@testing-library/react-hooks'
import { SECTIONS_MAP } from '../../constants'
import { useSystemSetting } from '../systemSettings'
import { useCurrentUserAuthorities } from '../user'
import { SchemaName } from './../../types/schemaBase'
import {
useCanCreateModelInSection,
useIsSectionAuthorizedPredicate,
} from './sectionAuthorities'

const mockedSchemas = {
[SchemaName.dataElement]: {
singular: 'dataElement',
plural: 'dataElements',
name: 'dataElement',
displayName: 'Data Element',
collectionName: 'dataElements',
authorities: [
{
type: 'CREATE_PUBLIC',
authorities: ['F_DATAELEMENT_PUBLIC_ADD'],
},
{
type: 'CREATE_PRIVATE',
authorities: ['F_DATAELEMENT_PRIVATE_ADD'],
},
{
type: 'DELETE',
authorities: ['F_DATAELEMENT_DELETE'],
},
],
},
[SchemaName.category]: {
singular: 'category',
plural: 'categories',
name: 'category',
displayName: 'Category',
collectionName: 'categories',
authorities: [
{
type: 'CREATE_PUBLIC',
authorities: ['F_CATEGORY_PUBLIC_ADD'],
},
{
type: 'CREATE_PRIVATE',
authorities: ['F_CATEGORY_PRIVATE_ADD'],
},
{
type: 'DELETE',
authorities: ['F_CATEGORY_DELETE'],
},
],
},
[SchemaName.categoryOptionCombo]: {
singular: 'categoryOptionCombo',
plural: 'categoryOptionCombos',
name: 'categoryOptionCombo',
displayName: 'Category option combo',
collectionName: 'categoryOptionCombos',
authorities: [
{
type: 'CREATE_PUBLIC',
authorities: ['F_CATEGORY_COMBO_PUBLIC_ADD'],
},
{
type: 'CREATE_PRIVATE',
authorities: ['F_CATEGORY_COMBO_PRIVATE_ADD'],
},
{
type: 'DELETE',
authorities: ['F_CATEGORY_COMBO_DELETE'],
},
],
},
}

jest.mock('../systemSettings', () => {
const originalModule = jest.requireActual('../systemSettings')
return {
...originalModule,
useSystemSetting: jest.fn(),
}
})
jest.mock('../schemas', () => {
const originalModule = jest.requireActual('../schemas')
return {
...originalModule,
useSchemas: jest.fn(() => mockedSchemas),
}
})

jest.mock('../user', () => {
const originalModule = jest.requireActual('../user')
return {
...originalModule,
useCurrentUserAuthorities: jest.fn(),
}
})

const mockedUseCurrentUserAuthorities = jest.mocked(useCurrentUserAuthorities)
const mockedUseSystemSetting = jest.mocked(useSystemSetting)

describe('sectionAuthorities', () => {
beforeEach(() => {
mockedUseCurrentUserAuthorities.mockReset()
mockedUseSystemSetting.mockReset()
mockedUseCurrentUserAuthorities.mockImplementation(
() => new Set(['F_DATAELEMENT_PUBLIC_ADD'])
)
mockedUseSystemSetting.mockImplementation(() => true)
})
describe('useIsSectionAuthorizedPredicate', () => {
it('should return a predicate function', () => {
const { result } = renderHook(() =>
useIsSectionAuthorizedPredicate()
)
expect(result.current).toBeInstanceOf(Function)
})

it('predicate function should return true when user has required authorites', async () => {
const { result } = renderHook(() =>
useIsSectionAuthorizedPredicate()
)
const isSectionAuthorized = result.current

const isAllowed = isSectionAuthorized(SECTIONS_MAP.dataElement)
expect(isAllowed).toBe(true)
})
it('predicate function should return false when user does not have required authorites', async () => {
mockedUseCurrentUserAuthorities.mockImplementation(
() => new Set(['F_DATAELEMENT_DELETE'])
)
const { result } = renderHook(() =>
useIsSectionAuthorizedPredicate()
)
const isSectionAuthorized = result.current

const isAllowed = isSectionAuthorized(SECTIONS_MAP.dataElement)
expect(isAllowed).toBe(false)
})
it('predicate function should return true if systemSetting keyRequireAddToView is false, even without required auth', async () => {
mockedUseSystemSetting.mockImplementation(() => false)
const { result } = renderHook(() =>
useIsSectionAuthorizedPredicate()
)
const isSectionAuthorized = result.current

const isAllowed = isSectionAuthorized(SECTIONS_MAP.dataElement)
expect(isAllowed).toBe(true)
})
})
describe('useCanCreateModelInSection', () => {
it('should return true if user has required authorities', () => {
const { result } = renderHook(() =>
useCanCreateModelInSection(SECTIONS_MAP.dataElement)
)
const isSectionAuthorized = result.current

expect(isSectionAuthorized).toBe(true)
})
it('should return false if user does not have required authorities', () => {
const { result } = renderHook(() =>
useCanCreateModelInSection(SECTIONS_MAP.category)
)
const isSectionAuthorized = result.current

expect(isSectionAuthorized).toBe(false)
})
it('should return false if section is categoryOptionCombo, even with required auth', () => {
mockedUseCurrentUserAuthorities.mockImplementation(
() =>
new Set([
'F_CATEGORY_COMBO_PUBLIC_ADD',
'F_CATEGORY_COMB_PRIVATE_ADD',
])
)
const { result } = renderHook(() =>
useCanCreateModelInSection(SECTIONS_MAP.categoryOptionCombo)
)
const isSectionAuthorized = result.current
expect(isSectionAuthorized).toBe(false)
})
it('should return false if user does not have required authorities, even if keyRequiredAddToView is false', () => {
const { result } = renderHook(() =>
useCanCreateModelInSection(SECTIONS_MAP.category)
)
const isSectionAuthorized = result.current

expect(isSectionAuthorized).toBe(false)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
isNonCreateableSchema,
useCurrentUserAuthorities,
} from '../user'

type UserAuthorities = ReturnType<typeof useCurrentUserAuthorities>

const isNonCreateableSection = (section: Section): section is SchemaSection => {
Expand Down Expand Up @@ -54,7 +53,7 @@ function canCreateModelInSection(
}

/**
* Authorization of a section is determined by the following:
* Authorization (ie if a section should be viewable) of a section is determined by the following:
* - the user must have any CREATE authority on the schema
* - if systemSetting keyRequireAddToView is false, sections are always authorized
* - overviewSections are authorized if any of their child sections are authorized
Expand Down Expand Up @@ -89,14 +88,6 @@ export const useIsSectionAuthorizedPredicate = () => {
return isSectionAuthorizedPredicate
}

/**
* Checks if a section is authorized, ie. the user can view the section
*/
export const useIsSectionAuthorized = (section: Section) => {
const isSectionAuthorizedPredicate = useIsSectionAuthorizedPredicate()
return isSectionAuthorizedPredicate(section)
}

export const useCanCreateModelInSection = (section: Section) => {
const userAuthorities = useCurrentUserAuthorities()
const schemas = useSchemas()
Expand Down
2 changes: 1 addition & 1 deletion src/lib/user/authorities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const hasAuthorityForOperation = (
return true
}

const authoritiesNeeded = schemaAuthorities.find((auth) => {
const authoritiesNeeded = schemaAuthorities?.find((auth) => {
// if operation is CREATE it can be any of types in canCreateAuthTypes
if (operation === SchemaAuthorityType.CREATE) {
return canCreateAuthTypes.has(auth.type)
Expand Down
Loading

0 comments on commit 93a84ea

Please sign in to comment.