diff --git a/test/use-swr-config-callbacks.test.tsx b/test/use-swr-config-callbacks.test.tsx index c9d1fa3714..8e51d372b7 100644 --- a/test/use-swr-config-callbacks.test.tsx +++ b/test/use-swr-config-callbacks.test.tsx @@ -1,17 +1,21 @@ import { act, render, screen, fireEvent } from '@testing-library/react' import React from 'react' import useSWR from '../src' -import { sleep } from './utils' +import { sleep, createResponse } from './utils' describe('useSWR - config callbacks', () => { it('should trigger the onSuccess event with the latest version of the onSuccess callback', async () => { let state = null let count = 0 + let promise function Page(props: { text: string }) { const { data, revalidate } = useSWR( 'config callbacks - onSuccess', - () => new Promise(res => setTimeout(() => res(count++), 200)), + () => { + promise = createResponse(count++) + return promise + }, { onSuccess: () => (state = props.text) } ) return ( @@ -20,11 +24,9 @@ describe('useSWR - config callbacks', () => { ) } - const { container, rerender } = render() + const { rerender } = render() // the onSuccess callback does not trigger yet, the state still null. - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, , a"` - ) + expect(screen.getByText('hello, , a')).toBeInTheDocument() expect(state).toEqual(null) await screen.findByText('hello, 0, a') @@ -33,18 +35,15 @@ describe('useSWR - config callbacks', () => { // props changed, but the onSuccess callback does not trigger yet, `state` is same as before rerender() - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, 0, b"` - ) + expect(screen.getByText('hello, 0, b')).toBeInTheDocument() expect(state).toEqual('a') // trigger revalidation, this would re-trigger the onSuccess callback - fireEvent.click(container.firstElementChild) + fireEvent.click(screen.getByText(/hello/)) + + await act(() => promise) + expect(screen.getByText('hello, 1, b')).toBeInTheDocument() - await act(() => sleep(201)) - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, 1, b"` - ) // the onSuccess callback should capture the latest `props.text` expect(state).toEqual('b') }) @@ -52,14 +51,15 @@ describe('useSWR - config callbacks', () => { it('should trigger the onError event with the latest version of the onError callback', async () => { let state = null let count = 0 + let promise function Page(props: { text: string }) { const { data, revalidate, error } = useSWR( 'config callbacks - onError', - () => - new Promise((_, rej) => - setTimeout(() => rej(new Error(`Error: ${count++}`)), 200) - ), + () => { + promise = createResponse(new Error(`Error: ${count++}`)) + return promise + }, { onError: () => (state = props.text) } ) if (error) @@ -75,11 +75,9 @@ describe('useSWR - config callbacks', () => { ) } - const { container, rerender } = render() + const { rerender } = render() - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, , a"` - ) + expect(screen.getByText('hello, , a')).toBeInTheDocument() expect(state).toEqual(null) await screen.findByText('Error: 0') @@ -87,31 +85,39 @@ describe('useSWR - config callbacks', () => { // props changed, but the onError callback doese not trigger yet. rerender() - expect(container.firstChild.textContent).toMatchInlineSnapshot(`"Error: 0"`) - expect(container.firstElementChild.getAttribute('title')).toEqual('b') + expect(screen.getByText('Error: 0')).toBeInTheDocument() + expect(screen.getByTitle('b')).toBeInTheDocument() expect(state).toEqual('a') - fireEvent.click(container.firstElementChild) - await act(() => sleep(210)) + fireEvent.click(screen.getByTitle('b')) + + try { + await act(() => promise) + } catch (e) { + // expect an error + } - expect(container.firstChild.textContent).toMatchInlineSnapshot(`"Error: 1"`) - expect(container.firstElementChild.getAttribute('title')).toEqual('b') + expect(screen.getByText('Error: 1')).toBeInTheDocument() + expect(screen.getByTitle('b')).toBeInTheDocument() expect(state).toEqual('b') }) it('should trigger the onErrorRetry event with the latest version of the onErrorRetry callback', async () => { let state = null let count = 0 + let promise + let revalidatePromise + function Page(props: { text: string }) { const { data, error } = useSWR( 'config callbacks - onErrorRetry', - () => - new Promise((_, rej) => - setTimeout(() => rej(new Error(`Error: ${count++}`)), 200) - ), + () => { + promise = createResponse(new Error(`Error: ${count++}`)) + return promise + }, { onErrorRetry: (_, __, ___, revalidate, revalidateOpts) => { state = props.text - setTimeout(() => revalidate(revalidateOpts), 100) + revalidatePromise = revalidate(revalidateOpts) } } ) @@ -123,37 +129,40 @@ describe('useSWR - config callbacks', () => { ) } - const { container, rerender } = render() - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, , a"` - ) + const { rerender } = render() + expect(screen.getByText('hello, , a')).toBeInTheDocument() expect(state).toEqual(null) await screen.findByText('Error: 0') - expect(container.firstElementChild.getAttribute('title')).toEqual('a') + expect(screen.getByTitle('a')).toBeInTheDocument() expect(state).toEqual('a') // since the onErrorRetry schedule a timer to trigger revalidation, update props.text now rerender() // not revalidate yet. - expect(container.firstChild.textContent).toMatchInlineSnapshot(`"Error: 0"`) - expect(container.firstElementChild.getAttribute('title')).toEqual('b') + expect(screen.getByText('Error: 0')).toBeInTheDocument() + expect(screen.getByTitle('b')).toBeInTheDocument() expect(state).toEqual('a') - await act(() => sleep(350)) - expect(container.firstChild.textContent).toMatchInlineSnapshot(`"Error: 1"`) - expect(container.firstElementChild.getAttribute('title')).toEqual('b') + await act(() => revalidatePromise) + expect(screen.getByText('Error: 1')).toBeInTheDocument() + expect(screen.getByTitle('b')).toBeInTheDocument() expect(state).toEqual('b') }) it('should trigger the onLoadingSlow and onSuccess event with the lastest version of the callbacks', async () => { + const LOADING_TIMEOUT = 5 let state = null let count = 0 + let promise function Page(props: { text: string }) { const { data } = useSWR( 'config callbacks - onLoadingSlow', - () => new Promise(res => setTimeout(() => res(count++), 200)), + () => { + promise = createResponse(count++, { delay: LOADING_TIMEOUT * 2 }) + return promise + }, { onLoadingSlow: () => { state = props.text @@ -161,7 +170,7 @@ describe('useSWR - config callbacks', () => { onSuccess: () => { state = props.text }, - loadingTimeout: 100 + loadingTimeout: LOADING_TIMEOUT } ) return ( @@ -171,24 +180,18 @@ describe('useSWR - config callbacks', () => { ) } - const { container, rerender } = render() + const { rerender } = render() - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, , a"` - ) + expect(screen.getByText('hello, , a')).toBeInTheDocument() expect(state).toEqual(null) - await act(() => sleep(101)) - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, , a"` - ) + await act(() => sleep(LOADING_TIMEOUT)) + expect(screen.getByText('hello, , a')).toBeInTheDocument() expect(state).toEqual('a') rerender() - await act(() => sleep(100)) - expect(container.firstChild.textContent).toMatchInlineSnapshot( - `"hello, 0, b"` - ) + await act(() => promise) + expect(screen.getByText('hello, 0, b')).toBeInTheDocument() expect(state).toEqual('b') }) })