/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-reconciler/src/__tests__/ReactCache-test.js
307 строк
8 KB
Sebastian Markbåge
Expose cacheSignal() alongside cache() (#33557)
18 июн 2025, 00:04
Не верифицирован
18 июн 2025, 00:04
e1dc034
Код
Авторство
О чём код?
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @emails react-core * @jest-environment node */ 'use strict'; let React; let ReactNoopFlightServer; let ReactNoopFlightClient; let cache; let cacheSignal; describe('ReactCache', () => { beforeEach(() => { jest.resetModules(); jest.mock('react', () => require('react/react.react-server')); React = require('react'); ReactNoopFlightServer = require('react-noop-renderer/flight-server'); ReactNoopFlightClient = require('react-noop-renderer/flight-client'); cache = React.cache; cacheSignal = React.cacheSignal; jest.resetModules(); __unmockReact(); }); it('cache objects and primitive arguments and a mix of them', async () => { const types = cache((a, b) => ({a: typeof a, b: typeof b})); function Print({a, b}) { return types(a, b).a + ' ' + types(a, b).b + ' '; } function Same({a, b}) { const x = types(a, b); const y = types(a, b); return (x === y).toString() + ' '; } function FlippedOrder({a, b}) { return (types(a, b) === types(b, a)).toString() + ' '; } function FewerArgs({a, b}) { return (types(a, b) === types(a)).toString() + ' '; } function MoreArgs({a, b}) { return (types(a) === types(a, b)).toString() + ' '; } expect( ( await ReactNoopFlightClient.read( ReactNoopFlightServer.render( <> <Print a="e" b="f" /> <Same a="a" b="b" /> <FlippedOrder a="c" b="d" /> <FewerArgs a="e" b="f" /> <MoreArgs a="g" b="h" /> </>, ), ) ).join(''), ).toEqual('string string true false false false '); expect( ( await ReactNoopFlightClient.read( ReactNoopFlightServer.render( <> <Print a="e" b={null} /> <Same a="a" b={null} /> <FlippedOrder a="c" b={null} /> <FewerArgs a="e" b={null} /> <MoreArgs a="g" b={null} /> </>, ), ) ).join(''), ).toEqual('string object true false false false '); const obj = {}; expect( ( await ReactNoopFlightClient.read( ReactNoopFlightServer.render( <> <Print a="e" b={obj} /> <Same a="a" b={obj} /> <FlippedOrder a="c" b={obj} /> <FewerArgs a="e" b={obj} /> <MoreArgs a="g" b={obj} /> </>, ), ) ).join(''), ).toEqual('string object true false false false '); const sameObj = {}; expect( ( await ReactNoopFlightClient.read( ReactNoopFlightServer.render( <> <Print a={sameObj} b={sameObj} /> <Same a={sameObj} b={sameObj} /> <FlippedOrder a={sameObj} b={sameObj} /> <FewerArgs a={sameObj} b={sameObj} /> <MoreArgs a={sameObj} b={sameObj} /> </>, ), ) ).join(''), ).toEqual('object object true true false false '); const objA = {}; const objB = {}; expect( ( await ReactNoopFlightClient.read( ReactNoopFlightServer.render( <> <Print a={objA} b={objB} /> <Same a={objA} b={objB} /> <FlippedOrder a={objA} b={objB} /> <FewerArgs a={objA} b={objB} /> <MoreArgs a={objA} b={objB} /> </>, ), ) ).join(''), ).toEqual('object object true false false false '); const sameSymbol = Symbol(); expect( ( await ReactNoopFlightClient.read( ReactNoopFlightServer.render( <> <Print a={sameSymbol} b={sameSymbol} /> <Same a={sameSymbol} b={sameSymbol} /> <FlippedOrder a={sameSymbol} b={sameSymbol} /> <FewerArgs a={sameSymbol} b={sameSymbol} /> <MoreArgs a={sameSymbol} b={sameSymbol} /> </>, ), ) ).join(''), ).toEqual('symbol symbol true true false false '); const notANumber = +'nan'; expect( ( await ReactNoopFlightClient.read( ReactNoopFlightServer.render( <> <Print a={1} b={notANumber} /> <Same a={1} b={notANumber} /> <FlippedOrder a={1} b={notANumber} /> <FewerArgs a={1} b={notANumber} /> <MoreArgs a={1} b={notANumber} /> </>, ), ) ).join(''), ).toEqual('number number true false false false '); }); it('cached functions that throw should cache the error', async () => { const throws = cache(v => { throw new Error(v); }); let x; let y; let z; function Test() { try { throws(1); } catch (e) { x = e; } try { throws(1); } catch (e) { y = e; } try { throws(2); } catch (e) { z = e; } return 'Blank'; } ReactNoopFlightServer.render(<Test />); expect(x).toBe(y); expect(z).not.toBe(x); }); it('introspection of returned wrapper function is same on client and server', async () => { // When the variant flag is true, test the client version of `cache`. if (gate(flags => flags.variant)) { jest.resetModules(); jest.mock('react', () => jest.requireActual('react')); const ClientReact = require('react'); cache = ClientReact.cache; } function foo(a, b, c) { return a + b + c; } foo.displayName = 'Custom display name'; const cachedFoo = cache(foo); expect(cachedFoo).not.toBe(foo); expect(cachedFoo.length).toBe(0); expect(cachedFoo.displayName).toBe(undefined); }); it('cacheSignal() returns null outside a render', async () => { expect(cacheSignal()).toBe(null); }); it('cacheSignal() aborts when the render finishes normally', async () => { let renderedCacheSignal = null; let resolve; const promise = new Promise(r => (resolve = r)); async function Test() { renderedCacheSignal = cacheSignal(); await promise; return 'Hi'; } const controller = new AbortController(); const errors = []; const result = ReactNoopFlightServer.render(<Test />, { signal: controller.signal, onError(x) { errors.push(x); }, }); expect(errors).toEqual([]); expect(renderedCacheSignal).not.toBe(controller.signal); // In the future we might make these the same expect(renderedCacheSignal.aborted).toBe(false); await resolve(); await 0; await 0; expect(await ReactNoopFlightClient.read(result)).toBe('Hi'); expect(errors).toEqual([]); expect(renderedCacheSignal.aborted).toBe(true); expect(renderedCacheSignal.reason.message).toContain( 'This render completed successfully.', ); }); it('cacheSignal() aborts when the render is aborted', async () => { let renderedCacheSignal = null; const promise = new Promise(() => {}); async function Test() { renderedCacheSignal = cacheSignal(); await promise; return 'Hi'; } const controller = new AbortController(); const errors = []; const result = ReactNoopFlightServer.render(<Test />, { signal: controller.signal, onError(x) { errors.push(x); return 'hi'; }, }); expect(errors).toEqual([]); expect(renderedCacheSignal).not.toBe(controller.signal); // In the future we might make these the same expect(renderedCacheSignal.aborted).toBe(false); const reason = new Error('Timed out'); controller.abort(reason); expect(errors).toEqual([reason]); expect(renderedCacheSignal.aborted).toBe(true); expect(renderedCacheSignal.reason).toBe(reason); let clientError = null; try { await ReactNoopFlightClient.read(result); } catch (x) { clientError = x; } expect(clientError).not.toBe(null); if (__DEV__) { expect(clientError.message).toBe('Timed out'); } expect(clientError.digest).toBe('hi'); }); });