skolplattformen-backup/libs/hooks/src/useNewsDetails.test.js

261 lines
7.1 KiB
JavaScript
Raw Normal View History

2021-02-10 09:48:46 +00:00
import React from 'react'
import { renderHook, act } from '@testing-library/react-hooks'
import { ApiProvider } from './provider'
import { useNewsDetails } from './hooks'
import store from './store'
import init from './__mocks__/@skolplattformen/embedded-api'
import createStorage from './__mocks__/AsyncStorage'
import reporter from './__mocks__/reporter'
const pause = (ms = 0) => new Promise((r) => setTimeout(r, ms))
describe('useNewsDetails(child, newsItem)', () => {
let api
let storage
let response
let cached
2021-02-10 09:48:46 +00:00
let child
let newsItem
const wrapper = ({ children }) => (
2021-10-06 20:47:50 +00:00
<ApiProvider api={api} storage={storage} reporter={reporter}>
2021-02-10 09:48:46 +00:00
{children}
</ApiProvider>
)
beforeEach(() => {
cached = { id: '1337', modified: 'yesterday', body: 'rich and old' }
response = { id: '1337', modified: 'now', body: 'rich and new' }
2021-02-10 09:48:46 +00:00
api = init()
api.getPersonalNumber.mockReturnValue('123')
2021-10-06 20:47:50 +00:00
api.getNewsDetails.mockImplementation(
() =>
new Promise((res) => {
setTimeout(() => res(response), 50)
})
)
storage = createStorage(
{
'123_news_details_1337': { ...cached },
},
2
)
2021-02-10 09:48:46 +00:00
child = { id: 10 }
newsItem = { id: '1337', modified: 'now', body: 'simple' }
2021-02-10 09:48:46 +00:00
})
afterEach(async () => {
await act(async () => {
await pause(70)
store.dispatch({ entity: 'ALL', type: 'CLEAR' })
})
})
it('returns correct initial value', () => {
2021-10-06 20:47:50 +00:00
const { result } = renderHook(() => useNewsDetails(child, newsItem), {
wrapper,
})
2021-02-10 09:48:46 +00:00
expect(result.current.status).toEqual('pending')
})
it('calls api', async () => {
await act(async () => {
api.isLoggedIn = true
2021-10-06 20:47:50 +00:00
const { waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
expect(api.getNewsDetails).toHaveBeenCalled()
})
})
it('only calls api once', async () => {
await act(async () => {
api.isLoggedIn = true
renderHook(() => useNewsDetails(child, newsItem), { wrapper })
2021-10-06 20:47:50 +00:00
const { waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
renderHook(() => useNewsDetails(child, newsItem), { wrapper })
await waitForNextUpdate()
renderHook(() => useNewsDetails(child, newsItem), { wrapper })
await waitForNextUpdate()
2021-10-06 20:47:50 +00:00
const { result } = renderHook(() => useNewsDetails(child, newsItem), {
wrapper,
})
2021-02-10 09:48:46 +00:00
expect(api.getNewsDetails).toHaveBeenCalledTimes(1)
expect(result.current.status).toEqual('loaded')
})
})
it('calls cache', async () => {
await act(async () => {
api.isLoggedIn = true
2021-10-06 20:47:50 +00:00
const { result, waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.data).toEqual(cached)
2021-02-10 09:48:46 +00:00
})
})
it('updates status to loading', async () => {
await act(async () => {
api.isLoggedIn = true
2021-10-06 20:47:50 +00:00
const { result, waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.status).toEqual('loading')
})
})
it('updates status to loaded', async () => {
await act(async () => {
api.isLoggedIn = true
2021-10-06 20:47:50 +00:00
const { result, waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.status).toEqual('loaded')
})
})
it('stores in cache if not fake', async () => {
await act(async () => {
api.isLoggedIn = true
api.isFake = false
2021-10-06 20:47:50 +00:00
const { waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
await waitForNextUpdate()
await pause(20)
2021-10-06 20:47:50 +00:00
expect(storage.cache['123_news_details_1337']).toEqual(
JSON.stringify(response)
)
2021-02-10 09:48:46 +00:00
})
})
it('does not store in cache if fake', async () => {
await act(async () => {
api.isLoggedIn = true
api.isFake = true
2021-10-06 20:47:50 +00:00
const { waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
await pause(20)
2021-10-06 20:47:50 +00:00
expect(storage.cache['123_news_details_1337']).toEqual(
JSON.stringify(cached)
)
2021-02-10 09:48:46 +00:00
})
})
it('retries if api fails', async () => {
await act(async () => {
api.isLoggedIn = true
const error = new Error('fail')
api.getNewsDetails.mockRejectedValueOnce(error)
2021-10-06 20:47:50 +00:00
const { result, waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.error).toEqual(error)
expect(result.current.status).toEqual('loading')
expect(result.current.data).toEqual({ ...cached })
2021-02-10 09:48:46 +00:00
jest.advanceTimersToNextTimer()
await waitForNextUpdate()
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.status).toEqual('loaded')
expect(result.current.data).toEqual({ ...response })
2021-02-10 09:48:46 +00:00
})
})
it('gives up after 3 retries', async () => {
await act(async () => {
api.isLoggedIn = true
const error = new Error('fail')
api.getNewsDetails.mockRejectedValueOnce(error)
api.getNewsDetails.mockRejectedValueOnce(error)
api.getNewsDetails.mockRejectedValueOnce(error)
2021-10-06 20:47:50 +00:00
const { result, waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.error).toEqual(error)
expect(result.current.status).toEqual('loading')
expect(result.current.data).toEqual({ ...cached })
2021-02-10 09:48:46 +00:00
jest.advanceTimersToNextTimer()
await waitForNextUpdate()
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.error).toEqual(error)
expect(result.current.status).toEqual('error')
expect(result.current.data).toEqual({ ...cached })
2021-02-10 09:48:46 +00:00
})
})
it('reports if api fails', async () => {
await act(async () => {
api.isLoggedIn = true
const error = new Error('fail')
api.getNewsDetails.mockRejectedValueOnce(error)
2021-10-06 20:47:50 +00:00
const { result, waitForNextUpdate } = renderHook(
() => useNewsDetails(child, newsItem),
{ wrapper }
)
2021-02-10 09:48:46 +00:00
await waitForNextUpdate()
await waitForNextUpdate()
await waitForNextUpdate()
expect(result.current.error).toEqual(error)
2021-10-06 20:47:50 +00:00
expect(reporter.error).toHaveBeenCalledWith(
error,
'Error getting NEWS_DETAILS from API'
)
2021-02-10 09:48:46 +00:00
})
})
})