| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- import { renderHook, act } from '@testing-library/react-hooks'
- import { expect } from 'chai'
- import sinon from 'sinon'
- import useAsync from '../../../../frontend/js/shared/hooks/use-async'
- function deferred() {
- let res!: (
- value: Record<string, unknown> | PromiseLike<Record<string, unknown>>
- ) => void
- let rej!: (reason?: any) => void
- const promise = new Promise<Record<string, unknown>>((resolve, reject) => {
- res = resolve
- rej = reject
- })
- return { promise, resolve: res, reject: rej }
- }
- const defaultState = {
- status: 'idle',
- data: null,
- error: null,
- isIdle: true,
- isLoading: false,
- isError: false,
- isSuccess: false,
- }
- const pendingState = {
- ...defaultState,
- status: 'pending',
- isIdle: false,
- isLoading: true,
- }
- const resolvedState = {
- ...defaultState,
- status: 'resolved',
- isIdle: false,
- isSuccess: true,
- }
- const rejectedState = {
- ...defaultState,
- status: 'rejected',
- isIdle: false,
- isError: true,
- }
- describe('useAsync', function () {
- beforeEach(function () {
- global.console.error = sinon.stub()
- })
- afterEach(function () {
- // eslint-disable-next-line
- // @ts-ignore
- global.console.error.reset()
- })
- it('exposes the methods', function () {
- const { result } = renderHook(() => useAsync())
- expect(result.current.setData).to.be.a('function')
- expect(result.current.setError).to.be.a('function')
- expect(result.current.runAsync).to.be.a('function')
- })
- it('calling `runAsync` with a promise which resolves', async function () {
- const { promise, resolve } = deferred()
- const { result } = renderHook(() => useAsync())
- expect(result.current).to.include(defaultState)
- let p: Promise<unknown>
- act(() => {
- p = result.current.runAsync(promise)
- })
- expect(result.current).to.include(pendingState)
- const resolvedValue = {}
- await act(async () => {
- resolve(resolvedValue)
- await p
- })
- expect(result.current).to.include({
- ...resolvedState,
- data: resolvedValue,
- })
- act(() => {
- result.current.reset()
- })
- expect(result.current).to.include(defaultState)
- })
- it('calling `runAsync` with a promise which rejects', async function () {
- const { promise, reject } = deferred()
- const { result } = renderHook(() => useAsync())
- expect(result.current).to.include(defaultState)
- let p: Promise<unknown>
- act(() => {
- p = result.current.runAsync(promise).catch(() => {})
- })
- expect(result.current).to.include(pendingState)
- const rejectedValue = Symbol('rejected value')
- await act(async () => {
- reject(rejectedValue)
- await p
- })
- expect(result.current).to.include({
- ...rejectedState,
- error: rejectedValue,
- })
- })
- it('can specify an initial state', function () {
- const mockData = Symbol('resolved value')
- const customInitialState = { status: 'resolved' as const, data: mockData }
- const { result } = renderHook(() => useAsync(customInitialState))
- expect(result.current).to.include({
- ...resolvedState,
- ...customInitialState,
- })
- })
- it('can set the data', function () {
- const mockData = Symbol('resolved value')
- const { result } = renderHook(() => useAsync())
- act(() => {
- result.current.setData(mockData)
- })
- expect(result.current).to.include({
- ...resolvedState,
- data: mockData,
- })
- })
- it('can set the error', function () {
- const mockError = Symbol('rejected value')
- const { result } = renderHook(() => useAsync())
- act(() => {
- result.current.setError(mockError)
- })
- expect(result.current).to.include({
- ...rejectedState,
- error: mockError,
- })
- })
- it('no state updates happen if the component is unmounted while pending', async function () {
- const { promise, resolve } = deferred()
- const { result, unmount } = renderHook(() => useAsync())
- let p: Promise<unknown>
- act(() => {
- p = result.current.runAsync(promise)
- })
- unmount()
- await act(async () => {
- resolve({})
- await p
- })
- expect(global.console.error).not.to.have.been.called
- })
- })
|