Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inventory #4

Closed
wants to merge 10 commits into from
2 changes: 2 additions & 0 deletions src/HospitalRun.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Route, Switch } from 'react-router-dom'
import Dashboard from './dashboard/Dashboard'
import Imagings from './imagings/Imagings'
import Incidents from './incidents/Incidents'
import Inventory from './inventory/Inventory'
import Labs from './labs/Labs'
import Medications from './medications/Medications'
import Breadcrumbs from './page-header/breadcrumbs/Breadcrumbs'
Expand Down Expand Up @@ -55,6 +56,7 @@ const HospitalRun = () => {
<Route path="/incidents" component={Incidents} />
<Route path="/settings" component={Settings} />
<Route path="/imaging" component={Imagings} />
<Route path="/inventory" component={Inventory} />
</Switch>
</div>
<Toaster autoClose={5000} hideProgressBar draggable />
Expand Down
9 changes: 9 additions & 0 deletions src/__tests__/inventory/AddInventoryItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
describe('AddInventoryItem', () => {
it('add item and cancel buttons render', () => {})

it('cancel returns you to inventory page', () => {})

it('save takes you to view item', () => {})

it('text fields are editable', () => {})
})
11 changes: 11 additions & 0 deletions src/__tests__/inventory/EditItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
describe('EditItem', () => {
it('text fields are editable', () => {})

it('save and cancel buttons render', () => {})

it('if data is loading the spinner should render', () => {})

it('check that useUpdateItem is called when save is clicked', () => {})

it('cancel should return to View Item', () => {})
})
108 changes: 108 additions & 0 deletions src/__tests__/inventory/Inventory.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Code taken from Incidents.test.tsx

import { mount, ReactWrapper } from 'enzyme'
import React from 'react'
import { act } from 'react-dom/test-utils'
import { Provider } from 'react-redux'
import { MemoryRouter } from 'react-router-dom'
import createMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'

import Incidents from '../../incidents/Incidents'
import ReportIncident from '../../incidents/report/ReportIncident'
import ViewIncident from '../../incidents/view/ViewIncident'
import VisualizeIncidents from '../../incidents/visualize/VisualizeIncidents'
import * as titleUtil from '../../page-header/title/TitleContext'
import IncidentRepository from '../../shared/db/IncidentRepository'
import Incident from '../../shared/model/Incident'
import Permissions from '../../shared/model/Permissions'
import { RootState } from '../../shared/store'

const mockStore = createMockStore<RootState, any>([thunk])

describe('Incidents', () => {
const setup = async (permissions: Permissions[], path: string) => {
const expectedIncident = {
id: '1234',
code: '1234',
date: new Date().toISOString(),
reportedOn: new Date().toISOString(),
} as Incident
jest.spyOn(titleUtil, 'useUpdateTitle').mockImplementation(() => jest.fn())
jest.spyOn(IncidentRepository, 'search').mockResolvedValue([])
jest.spyOn(IncidentRepository, 'find').mockResolvedValue(expectedIncident)
const store = mockStore({
user: { permissions },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
} as any)

let wrapper: any
await act(async () => {
wrapper = await mount(
<Provider store={store}>
<MemoryRouter initialEntries={[path]}>
<titleUtil.TitleProvider>
<Incidents />
</titleUtil.TitleProvider>
</MemoryRouter>
</Provider>,
)
})
wrapper.find(Incidents).props().updateTitle = jest.fn()
wrapper.update()

return { wrapper: wrapper as ReactWrapper }
}

describe('title', () => {
it('should have called the useUpdateTitle hook', async () => {
await setup([Permissions.ViewIncidents], '/incidents')
expect(titleUtil.useUpdateTitle).toHaveBeenCalledTimes(1)
})
})

describe('routing', () => {
describe('/incidents/new', () => {
it('should render the new incident screen when /incidents/new is accessed', async () => {
const { wrapper } = await setup([Permissions.ReportIncident], '/incidents/new')

expect(wrapper.find(ReportIncident)).toHaveLength(1)
})

it('should not navigate to /incidents/new if the user does not have ReportIncident permissions', async () => {
const { wrapper } = await setup([], '/incidents/new')

expect(wrapper.find(ReportIncident)).toHaveLength(0)
})
})

describe('/incidents/visualize', () => {
it('should render the incident visualize screen when /incidents/visualize is accessed', async () => {
const { wrapper } = await setup([Permissions.ViewIncidentWidgets], '/incidents/visualize')

expect(wrapper.find(VisualizeIncidents)).toHaveLength(1)
})

it('should not navigate to /incidents/visualize if the user does not have ViewIncidentWidgets permissions', async () => {
const { wrapper } = await setup([], '/incidents/visualize')

expect(wrapper.find(VisualizeIncidents)).toHaveLength(0)
})
})

describe('/incidents/:id', () => {
it('should render the view incident screen when /incidents/:id is accessed', async () => {
const { wrapper } = await setup([Permissions.ViewIncident], '/incidents/1234')

expect(wrapper.find(ViewIncident)).toHaveLength(1)
})

it('should not navigate to /incidents/:id if the user does not have ViewIncident permissions', async () => {
const { wrapper } = await setup([], '/incidents/1234')

expect(wrapper.find(ViewIncident)).toHaveLength(0)
})
})
})
})
57 changes: 57 additions & 0 deletions src/__tests__/inventory/hooks/useAddInventoryItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* eslint-disable no-console */

import shortid from 'shortid'

import * as itemValidator from '../../../inventory/add/validate-inventory-item'
import { InventoryItemError } from '../../../inventory/add/validate-inventory-item'
import useAddInventoryItem from '../../../inventory/hooks/useAddInventoryItem'
import InventoryRepository from '../../../shared/db/InventoryRepository'
import InventoryItem from '../../../shared/model/InventoryItem'
import executeMutation from '../../test-utils/use-mutation.util'

// This is code taken and slightly edited from Incidents. Not sure if you want
// to make use of it or start from scracth

describe('useAddInventoryItem', () => {
// beforeEach(() => {
// jest.restoreAllMocks()
// console.error = jest.fn()
// })
// it('should add an item with the correct data', async () => {
// const expectedId = '123456'
// const givenItemInformation = {
// name: 'some name',
// rank: 'some rank',
// type: 'clothing',
// crossReference: 'some cross reference',
// reorderPoint: 'some reorder point',
// distributionUnit: 'ampoule',
// pricePerUnit: 0,
// note: 'some note',
// } as InventoryItem
// const expectedItem = {
// ...givenItemInformation,
// id: `I-${expectedId}`,
// } as InventoryItem
// jest.spyOn(shortid, 'generate').mockReturnValue(expectedId)
// jest.spyOn(InventoryRepository, 'save').mockResolvedValue(expectedItem)
// const actualData = await executeMutation(() => useAddInventoryItem(), givenItemInformation)
// expect(InventoryRepository.save).toHaveBeenCalledTimes(1)
// expect(InventoryRepository.save).toBeCalledWith(expectedItem)
// expect(actualData).toEqual(expectedItem)
// })
// it('should throw an error if validation fails', async () => {
// // review InventoryItemError
// const expectedInventoryError = {
// description: 'some description error',
// } as InventoryItemError
// jest.spyOn(itemValidator, 'default').mockReturnValue(expectedInventoryError)
// jest.spyOn(InventoryRepository, 'save').mockResolvedValue({} as InventoryItem)
// try {
// await executeMutation(() => useAddInventoryItem(), {})
// } catch (e) {
// expect(e).toEqual(expectedInventoryError)
// expect(InventoryRepository.save).not.toHaveBeenCalled()
// }
// })
})
Empty file.
34 changes: 34 additions & 0 deletions src/__tests__/inventory/hooks/useInventory.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { act, renderHook } from '@testing-library/react-hooks'

import useInventory from '../../../inventory/hooks/useInventory'
import InventorySearchRequest from '../../../inventory/model/InventorySearchRequest'
import InventoryRepository from '../../../shared/db/InventoryRepository'
import InventoryItem from '../../../shared/model/InventoryItem'
import waitUntilQueryIsSuccessful from '../../test-utils/wait-for-query.util'

describe('useInventory', () => {
it('should search inventory', async () => {
const expectedSearchRequest: InventorySearchRequest = {
type: 'all',
text: '',
}
const expectedItems = [
{
id: 'some id',
},
] as InventoryItem[]
jest.spyOn(InventoryRepository, 'search').mockResolvedValue(expectedItems)

let actualData: any
await act(async () => {
const renderHookResult = renderHook(() => useInventory(expectedSearchRequest))
const { result } = renderHookResult
await waitUntilQueryIsSuccessful(renderHookResult)
actualData = result.current.data
})

expect(InventoryRepository.search).toHaveBeenCalledTimes(1)
expect(InventoryRepository.search).toBeCalledWith(expectedSearchRequest)
expect(actualData).toEqual(expectedItems)
})
})
28 changes: 28 additions & 0 deletions src/__tests__/inventory/hooks/useItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { renderHook, act } from '@testing-library/react-hooks'

import useItem from '../../../inventory/hooks/useItem'
import InventoryRepository from '../../../shared/db/InventoryRepository'
import InventoryItem from '../../../shared/model/InventoryItem'
import waitUntilQueryIsSuccessful from '../../test-utils/wait-for-query.util'

describe('useItem', () => {
it('should get an item by id', async () => {
const expectedItemId = 'some id'
const expectedItem = {
id: expectedItemId,
} as InventoryItem
jest.spyOn(InventoryRepository, 'find').mockResolvedValue(expectedItem)

let actualData: any
await act(async () => {
const renderHookResult = renderHook(() => useItem(expectedItemId))
const { result } = renderHookResult
await waitUntilQueryIsSuccessful(renderHookResult)
actualData = result.current.data
})

expect(InventoryRepository.find).toHaveBeenCalledTimes(1)
expect(InventoryRepository.find).toBeCalledWith(expectedItemId)
expect(actualData).toEqual(expectedItem)
})
})
Empty file.
5 changes: 5 additions & 0 deletions src/__tests__/inventory/view/InventorySearch.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
describe('InventorySearch', () => {
it('typing in search bar calls onChange', () => {})

it('filtering calls onChange', () => {})
})
5 changes: 5 additions & 0 deletions src/__tests__/inventory/view/ViewInventory.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
describe('ViewInventory', () => {
it('test if props of table component match a given list', () => {})

it('add inventory button renders', () => {})
})
11 changes: 11 additions & 0 deletions src/__tests__/inventory/view/ViewInventoryTable.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
describe('ViewInventoryTable', () => {
it('spinner renders when loading', () => {})

it('renders table', () => {})

it('clicking view takes you to item details', () => {})

it('if there are no items, alert should pop up', () => {})

it('data columns should match column headers', () => {})
})
29 changes: 29 additions & 0 deletions src/__tests__/inventory/view/ViewItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { mount, ReactWrapper } from 'enzyme'
import { createMemoryHistory } from 'history'
import React from 'react'
import { act } from 'react-dom/test-utils'
import { Provider } from 'react-redux'
import { Route, Router } from 'react-router-dom'
import createMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'

import ViewIncident from '../../../incidents/view/ViewIncident'
import ViewIncidentDetails from '../../../incidents/view/ViewIncidentDetails'
import * as breadcrumbUtil from '../../../page-header/breadcrumbs/useAddBreadcrumbs'
import * as ButtonBarProvider from '../../../page-header/button-toolbar/ButtonBarProvider'
import * as titleUtil from '../../../page-header/title/TitleContext'
import IncidentRepository from '../../../shared/db/IncidentRepository'
import Incident from '../../../shared/model/Incident'
import Permissions from '../../../shared/model/Permissions'
import { RootState } from '../../../shared/store'

const { TitleProvider } = titleUtil
const mockStore = createMockStore<RootState, any>([thunk])

describe('ViewItem', () => {
it('clicking edit takes you to EditItem', () => {})

it('text fields should not be editable', () => {})

it('check if delete button exists and leads you to a confirmation', () => {})
})
17 changes: 17 additions & 0 deletions src/__tests__/inventory/view/ViewItemDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Button } from '@hospitalrun/components'
import { mount, ReactWrapper } from 'enzyme'
import { createMemoryHistory } from 'history'
import React from 'react'
import { act } from 'react-dom/test-utils'
import { Router } from 'react-router'

import ViewIncidentDetails from '../../../incidents/view/ViewIncidentDetails'
import * as breadcrumbUtil from '../../../page-header/breadcrumbs/useAddBreadcrumbs'
import * as ButtonBarProvider from '../../../page-header/button-toolbar/ButtonBarProvider'
import IncidentRepository from '../../../shared/db/IncidentRepository'
import Incident from '../../../shared/model/Incident'
import Permissions from '../../../shared/model/Permissions'

describe('ViewItemDetails', () => {
it('renders correct data in each field', () => {})
})