/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-dom/src/__tests__/ReactDOMOption-test.js
289 строк
8 KB
Ricky
[flags] remove enableOwnerStacks (#32426)
04 мар 2025, 20:34
Не верифицирован
04 мар 2025, 20:34
e0fe347
Код
Авторство
О чём код?
/** * 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 */ 'use strict'; describe('ReactDOMOption', () => { let React; let ReactDOMClient; let ReactDOMServer; let act; let assertConsoleErrorDev; beforeEach(() => { jest.resetModules(); React = require('react'); ReactDOMClient = require('react-dom/client'); ReactDOMServer = require('react-dom/server'); act = require('internal-test-utils').act; assertConsoleErrorDev = require('internal-test-utils').assertConsoleErrorDev; }); async function renderIntoDocument(children) { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); await act(async () => root.render(children)); return container; } it('should flatten children to a string', async () => { const stub = ( <option> {1} {'foo'} </option> ); const container = await renderIntoDocument(stub); expect(container.firstChild.innerHTML).toBe('1 foo'); }); it('should warn for invalid child tags', async () => { const el = ( <option value="12"> {1} <div /> {2} </option> ); const container = await renderIntoDocument(el); assertConsoleErrorDev([ 'In HTML, <div> cannot be a child of <option>.\n' + 'This will cause a hydration error.\n' + '\n' + '> <option value="12">\n' + '> <div>\n' + ' ...\n' + '\n' + ' in div (at **)', ]); expect(container.firstChild.innerHTML).toBe('1 <div></div> 2'); await renderIntoDocument(el); }); it('should warn for component child if no value prop is provided', async () => { function Foo() { return '2'; } const el = ( <option> {1} <Foo /> {3} </option> ); const container = await renderIntoDocument(el); assertConsoleErrorDev([ 'Cannot infer the option value of complex children. ' + 'Pass a `value` prop or use a plain string as children to <option>.\n' + ' in option (at **)', ]); expect(container.firstChild.innerHTML).toBe('1 2 3'); await renderIntoDocument(el); }); it('should not warn for component child if value prop is provided', async () => { function Foo() { return '2'; } const el = ( <option value="123"> {1} <Foo /> {3} </option> ); const container = await renderIntoDocument(el); expect(container.firstChild.innerHTML).toBe('1 2 3'); await renderIntoDocument(el); }); it('should ignore null/undefined/false children without warning', async () => { const stub = ( <option> {1} {false} {true} {null} {undefined} {2} </option> ); const container = await renderIntoDocument(stub); expect(container.firstChild.innerHTML).toBe('1 2'); }); it('should throw on object children', async () => { await expect(async () => renderIntoDocument(<option>{{}}</option>), ).rejects.toThrow('Objects are not valid as a React child'); await expect(async () => { await renderIntoDocument(<option>{[{}]}</option>); }).rejects.toThrow('Objects are not valid as a React child'); await expect(async () => { await renderIntoDocument( <option> {{}} <span /> </option>, ); }).rejects.toThrow('Objects are not valid as a React child'); await expect(async () => { await renderIntoDocument( <option> {'1'} {{}} {2} </option>, ); }).rejects.toThrow('Objects are not valid as a React child'); }); // @gate www && !renameElementSymbol it('should support element-ish child', async () => { // This is similar to <fbt>. // We don't toString it because you must instead provide a value prop. const obj = { $$typeof: Symbol.for('react.element'), type: props => props.content, ref: null, key: null, props: { content: 'hello', }, toString() { return this.props.content; }, }; let container = await renderIntoDocument(<option value="a">{obj}</option>); expect(container.firstChild.innerHTML).toBe('hello'); container = await renderIntoDocument(<option value="b">{[obj]}</option>); expect(container.firstChild.innerHTML).toBe('hello'); container = await renderIntoDocument(<option value={obj}>{obj}</option>); expect(container.firstChild.innerHTML).toBe('hello'); expect(container.firstChild.value).toBe('hello'); container = await renderIntoDocument( <option value={obj}> {'1'} {obj} {2} </option>, ); expect(container.firstChild.innerHTML).toBe('1hello2'); expect(container.firstChild.value).toBe('hello'); }); it('should support bigint values', async () => { const container = await renderIntoDocument(<option>{5n}</option>); expect(container.firstChild.innerHTML).toBe('5'); expect(container.firstChild.value).toBe('5'); }); it('should be able to use dangerouslySetInnerHTML on option', async () => { const stub = <option dangerouslySetInnerHTML={{__html: 'foobar'}} />; const container = await renderIntoDocument(stub); assertConsoleErrorDev([ 'Pass a `value` prop if you set dangerouslyInnerHTML so React knows which value should be selected.\n' + ' in option (at **)', ]); expect(container.firstChild.innerHTML).toBe('foobar'); }); it('should set attribute for empty value', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); let option; await act(() => { root.render(<option value="" />); }); option = container.firstChild; expect(option.hasAttribute('value')).toBe(true); expect(option.getAttribute('value')).toBe(''); await act(() => { root.render(<option value="lava" />); }); option = container.firstChild; expect(option.hasAttribute('value')).toBe(true); expect(option.getAttribute('value')).toBe('lava'); }); it('should allow ignoring `value` on option', async () => { const a = 'a'; let node; const stub = ( <select value="giraffe" onChange={() => {}}> <option>monkey</option> <option>gir{a}ffe</option> <option>gorill{a}</option> </select> ); const options = stub.props.children; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); await act(() => { root.render(stub); }); node = container.firstChild; expect(node.selectedIndex).toBe(1); await act(() => { root.render(<select value="gorilla">{options}</select>); }); node = container.firstChild; expect(node.selectedIndex).toEqual(2); }); it('generates a hydration error when an invalid nested tag is used as a child', async () => { const ref = React.createRef(); const children = ( <select readOnly={true} value="bar"> <option value="bar"> {['Bar', false, 'Foo', <div key="1" ref={ref} />, 'Baz']} </option> </select> ); const container = document.createElement('div'); container.innerHTML = ReactDOMServer.renderToString(children); expect(container.firstChild.getAttribute('value')).toBe(null); expect(container.firstChild.getAttribute('defaultValue')).toBe(null); let option = container.firstChild.firstChild; expect(option.nodeName).toBe('OPTION'); expect(option.textContent).toBe('BarFooBaz'); expect(option.selected).toBe(true); await act(async () => { ReactDOMClient.hydrateRoot(container, children, { onRecoverableError: () => {}, }); }); assertConsoleErrorDev([ 'In HTML, <div> cannot be a child of <option>.\n' + 'This will cause a hydration error.\n' + '\n' + ' <select readOnly={true} value="bar">\n' + '> <option value="bar">\n' + '> <div ref={{current:null}}>\n' + ' ...\n' + '\n' + ' in div (at **)', ]); option = container.firstChild.firstChild; expect(option.textContent).toBe('BarFooBaz'); expect(option.selected).toBe(true); expect(ref.current.nodeName).toBe('DIV'); expect(ref.current.parentNode).toBe(option); }); });