import { render, screen, waitFor } from '@testing-library/react-native' import React, { useContext, useMemo } from 'react' import { Text } from 'react-native' import { useApiGet } from '../../hooks/use_api' import { ApiClient, useApiClient } from '../../hooks/use_api_client' import { Session } from '../../utils' import { ApiProvider, chatQueryClient } from '../api_provider' import { ChatContext, ChatContextValue } from '../chat_context' jest.mock('../../hooks/use_api_client') const mockedUseApiClient = useApiClient as jest.MockedFunction type Deferred = { promise: Promise; reject: (_reason: unknown) => void } const defer = (): Deferred => { let reject: Deferred['reject'] = () => {} const promise = new Promise((_, rej) => { reject = rej }) promise.catch(() => {}) return { promise, reject } } let get: jest.Mock let staleRequest: Deferred const meRequests = () => get.mock.calls.filter(([url]) => url === '/me').map(([, token]) => token as string) const Probe = () => { const { status, fetchStatus, data } = useApiGet<{ type: 'Person'; id: number }>({ url: '/me', data: { fields: { Person: ['id'] } }, }) return {`${status}:${fetchStatus}:${data?.id ?? ''}`} } const Tree = ({ accessToken }: { accessToken: string }) => { const value = useMemo(() => { const session = new Session({ token: { access_token: accessToken } }) return { session, token: session.token, env: 'production', onUnauthorizedResponse: () => {}, } as unknown as ChatContextValue }, [accessToken]) return ( ) } beforeAll(() => { chatQueryClient.setDefaultOptions({ queries: { ...chatQueryClient.getDefaultOptions().queries, gcTime: 0 }, }) }) beforeEach(() => { staleRequest = defer() get = jest.fn((url: string, accessToken: string) => { if (url !== '/me') return Promise.resolve({ data: [] }) if (accessToken === 'stale') return staleRequest.promise return Promise.resolve({ data: { type: 'Person', id: 42 } }) }) mockedUseApiClient.mockImplementation(() => { const { session } = useContext(ChatContext) const accessToken = session.token?.access_token const client = { get: ({ url }: { url: string }) => get(url, accessToken) } return { chat: client, groups: client, services: client, people: client, } as unknown as ApiClient }) }) afterEach(() => { chatQueryClient.clear() jest.clearAllMocks() }) describe('ApiProvider on access token change', () => { it('restarts in-flight requests with the new token and ignores the stale result', async () => { const { rerender } = render() await waitFor(() => expect(meRequests()).toEqual(['stale'])) rerender() await waitFor(() => expect(meRequests()).toEqual(['stale', 'fresh'])) staleRequest.reject(new Response(null, { status: 401, statusText: 'Unauthorized' })) expect(await screen.findByText('success:idle:42')).toBeTruthy() }) })