/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-dom/src/__tests__/ReactDOMSrcObject-test.js
217 строк
7 KB
Sebastian Markbåge
Allow Passing Blob/File/MediaSource/MediaStream to src of <img>, <video> and <audio> (#32828)
08 апр 2025, 19:11
Не верифицирован
08 апр 2025, 19:11
ea05b75
Код
Авторство
О чём код?
/** * 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 ./scripts/jest/ReactDOMServerIntegrationEnvironment */ 'use strict'; // Polyfills for test environment global.ReadableStream = require('web-streams-polyfill/ponyfill/es6').ReadableStream; global.TextEncoder = require('util').TextEncoder; describe('ReactDOMSrcObject', () => { let React; let ReactDOMClient; let ReactDOMFizzServer; let act; let container; let assertConsoleErrorDev; beforeEach(() => { jest.resetModules(); React = require('react'); ReactDOMClient = require('react-dom/client'); ReactDOMFizzServer = require('react-dom/server.edge'); act = require('internal-test-utils').act; assertConsoleErrorDev = require('internal-test-utils').assertConsoleErrorDev; container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); jest.restoreAllMocks(); }); // @gate enableSrcObject it('can render a Blob as an img src', async () => { const root = ReactDOMClient.createRoot(container); const ref = React.createRef(); const blob = new Blob(); await act(() => { root.render(<img src={blob} ref={ref} />); }); expect(ref.current.src).toMatch(/^blob:/); }); // @gate enableSrcObject it('can render a Blob as a picture img src', async () => { const root = ReactDOMClient.createRoot(container); const ref = React.createRef(); const blob = new Blob(); await act(() => { root.render( <picture> <img src={blob} ref={ref} /> </picture>, ); }); expect(ref.current.src).toMatch(/^blob:/); }); // @gate enableSrcObject it('can render a Blob as a video and audio src', async () => { const root = ReactDOMClient.createRoot(container); const videoRef = React.createRef(); const audioRef = React.createRef(); const blob = new Blob(); await act(() => { root.render( <> <video src={blob} ref={videoRef} /> <audio src={blob} ref={audioRef} /> </>, ); }); expect(videoRef.current.src).toMatch(/^blob:/); expect(audioRef.current.src).toMatch(/^blob:/); }); // @gate enableSrcObject || !__DEV__ it('warn when rendering a Blob as a source src of a video, audio or picture element', async () => { const root = ReactDOMClient.createRoot(container); const videoRef = React.createRef(); const audioRef = React.createRef(); const pictureRef = React.createRef(); const blob = new Blob(); await act(() => { root.render( <> <video ref={videoRef}> <source src={blob} /> </video> <audio ref={audioRef}> <source src={blob} /> </audio> <picture ref={pictureRef}> <source src={blob} /> <img /> </picture> </>, ); }); assertConsoleErrorDev([ 'Passing Blob, MediaSource or MediaStream to <source src> is not supported. ' + 'Pass it directly to <img src>, <video src> or <audio src> instead.', 'Passing Blob, MediaSource or MediaStream to <source src> is not supported. ' + 'Pass it directly to <img src>, <video src> or <audio src> instead.', 'Passing Blob, MediaSource or MediaStream to <source src> is not supported. ' + 'Pass it directly to <img src>, <video src> or <audio src> instead.', ]); expect(videoRef.current.firstChild.src).not.toMatch(/^blob:/); expect(videoRef.current.firstChild.src).toContain('[object%20Blob]'); // toString:ed expect(audioRef.current.firstChild.src).not.toMatch(/^blob:/); expect(audioRef.current.firstChild.src).toContain('[object%20Blob]'); // toString:ed expect(pictureRef.current.firstChild.src).not.toMatch(/^blob:/); expect(pictureRef.current.firstChild.src).toContain('[object%20Blob]'); // toString:ed }); async function readContent(stream) { const reader = stream.getReader(); let content = ''; while (true) { const {done, value} = await reader.read(); if (done) { return content; } content += Buffer.from(value).toString('utf8'); } } // @gate enableSrcObject it('can SSR a Blob as an img src', async () => { const blob = new Blob([new Uint8Array([69, 230, 156, 181, 68, 75])], { type: 'image/jpeg', }); const ref = React.createRef(); function App() { return <img src={blob} ref={ref} />; } const stream = await ReactDOMFizzServer.renderToReadableStream(<App />); container.innerHTML = await readContent(stream); expect(container.firstChild.src).toBe('data:image/jpeg;base64,ReactURL'); await act(() => { ReactDOMClient.hydrateRoot(container, <App />); }); expect(container.firstChild.src).toBe('data:image/jpeg;base64,ReactURL'); }); // @gate enableSrcObject it('errors in DEV when mismatching a Blob during hydration', async () => { const blob = new Blob([new Uint8Array([69, 230, 156, 181, 68, 75])], { type: 'image/jpeg', }); const ref = React.createRef(); const stream = await ReactDOMFizzServer.renderToReadableStream( <img src={blob} ref={ref} />, ); container.innerHTML = await readContent(stream); expect(container.firstChild.src).toBe('data:image/jpeg;base64,ReactURL'); const clientBlob = new Blob([new Uint8Array([69, 230, 156, 181, 68])], { type: 'image/jpeg', }); await act(() => { ReactDOMClient.hydrateRoot(container, <img src={clientBlob} ref={ref} />); }); assertConsoleErrorDev([ "A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. " + "This won't be patched up. This can happen if a SSR-ed Client Component used:\n\n" + "- A server/client branch `if (typeof window !== 'undefined')`.\n" + "- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" + "- Date formatting in a user's locale which doesn't match the server.\n" + '- External changing data without sending a snapshot of it along with the HTML.\n' + '- Invalid HTML tag nesting.\n\n' + 'It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n\n' + 'https://react.dev/link/hydration-mismatch\n\n' + ' <img\n' + '+ src={Blob:image/jpeg}\n' + '- src="data:image/jpeg;base64,ReactURL"\n' + ' ref={{current:null}}\n' + ' >\n' + '\n in img (at **)', ]); // The original URL left in place. expect(container.firstChild.src).toBe('data:image/jpeg;base64,ReactURL'); }); });