main
js 241 lines 7.16 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @emails react-core
8 */
9 'use strict';
10
11 let React;
12 let ReactDOMClient;
13 let ReactDOMServer;
14 let act;
15
16 describe('ReactDOMSVG', () => {
17 beforeEach(() => {
18 React = require('react');
19 ReactDOMClient = require('react-dom/client');
20 ReactDOMServer = require('react-dom/server');
21 act = require('internal-test-utils').act;
22 });
23
24 it('creates initial namespaced markup', () => {
25 const markup = ReactDOMServer.renderToString(
26 <svg>
27 <image xlinkHref="http://i.imgur.com/w7GCRPb.png" />
28 </svg>,
29 );
30 expect(markup).toContain('xlink:href="http://i.imgur.com/w7GCRPb.png"');
31 });
32
33 it('creates elements with SVG namespace inside SVG tag during mount', async () => {
34 const node = document.createElement('div');
35 let div,
36 div2,
37 div3,
38 foreignObject,
39 foreignObject2,
40 g,
41 image,
42 image2,
43 image3,
44 p,
45 svg,
46 svg2,
47 svg3,
48 svg4;
49 const root = ReactDOMClient.createRoot(node);
50 await act(() => {
51 root.render(
52 <div>
53 <svg ref={el => (svg = el)}>
54 <g ref={el => (g = el)} strokeWidth="5">
55 <svg ref={el => (svg2 = el)}>
56 <foreignObject ref={el => (foreignObject = el)}>
57 <svg ref={el => (svg3 = el)}>
58 <svg ref={el => (svg4 = el)} />
59 <image
60 ref={el => (image = el)}
61 xlinkHref="http://i.imgur.com/w7GCRPb.png"
62 />
63 </svg>
64 <div ref={el => (div = el)} />
65 </foreignObject>
66 </svg>
67 <image
68 ref={el => (image2 = el)}
69 xlinkHref="http://i.imgur.com/w7GCRPb.png"
70 />
71 <foreignObject ref={el => (foreignObject2 = el)}>
72 <div ref={el => (div2 = el)} />
73 </foreignObject>
74 </g>
75 </svg>
76 <p ref={el => (p = el)}>
77 <svg>
78 <image
79 ref={el => (image3 = el)}
80 xlinkHref="http://i.imgur.com/w7GCRPb.png"
81 />
82 </svg>
83 </p>
84 <div ref={el => (div3 = el)} />
85 </div>,
86 );
87 });
88 [svg, svg2, svg3, svg4].forEach(el => {
89 expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
90 // SVG tagName is case sensitive.
91 expect(el.tagName).toBe('svg');
92 });
93 expect(g.namespaceURI).toBe('http://www.w3.org/2000/svg');
94 expect(g.tagName).toBe('g');
95 expect(g.getAttribute('stroke-width')).toBe('5');
96 expect(p.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
97 // DOM tagName is capitalized by browsers.
98 expect(p.tagName).toBe('P');
99 [image, image2, image3].forEach(el => {
100 expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
101 expect(el.tagName).toBe('image');
102 expect(el.getAttributeNS('http://www.w3.org/1999/xlink', 'href')).toBe(
103 'http://i.imgur.com/w7GCRPb.png',
104 );
105 });
106 [foreignObject, foreignObject2].forEach(el => {
107 expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
108 expect(el.tagName).toBe('foreignObject');
109 });
110 [div, div2, div3].forEach(el => {
111 expect(el.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
112 expect(el.tagName).toBe('DIV');
113 });
114 });
115
116 it('creates elements with SVG namespace inside SVG tag during update', async () => {
117 let inst,
118 div,
119 div2,
120 foreignObject,
121 foreignObject2,
122 g,
123 image,
124 image2,
125 svg,
126 svg2,
127 svg3,
128 svg4;
129
130 class App extends React.Component {
131 state = {step: 0};
132
133 render() {
134 inst = this;
135 const {step} = this.state;
136 if (step === 0) {
137 return null;
138 }
139 return (
140 <g ref={el => (g = el)} strokeWidth="5">
141 <svg ref={el => (svg2 = el)}>
142 <foreignObject ref={el => (foreignObject = el)}>
143 <svg ref={el => (svg3 = el)}>
144 <svg ref={el => (svg4 = el)} />
145 <image
146 ref={el => (image = el)}
147 xlinkHref="http://i.imgur.com/w7GCRPb.png"
148 />
149 </svg>
150 <div ref={el => (div = el)} />
151 </foreignObject>
152 </svg>
153 <image
154 ref={el => (image2 = el)}
155 xlinkHref="http://i.imgur.com/w7GCRPb.png"
156 />
157 <foreignObject ref={el => (foreignObject2 = el)}>
158 <div ref={el => (div2 = el)} />
159 </foreignObject>
160 </g>
161 );
162 }
163 }
164
165 const node = document.createElement('div');
166 const root = ReactDOMClient.createRoot(node);
167 await act(() => {
168 root.render(
169 <svg ref={el => (svg = el)}>
170 <App />
171 </svg>,
172 );
173 });
174 await act(() => {
175 inst.setState({step: 1});
176 });
177
178 [svg, svg2, svg3, svg4].forEach(el => {
179 expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
180 // SVG tagName is case sensitive.
181 expect(el.tagName).toBe('svg');
182 });
183 expect(g.namespaceURI).toBe('http://www.w3.org/2000/svg');
184 expect(g.tagName).toBe('g');
185 expect(g.getAttribute('stroke-width')).toBe('5');
186 [image, image2].forEach(el => {
187 expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
188 expect(el.tagName).toBe('image');
189 expect(el.getAttributeNS('http://www.w3.org/1999/xlink', 'href')).toBe(
190 'http://i.imgur.com/w7GCRPb.png',
191 );
192 });
193 [foreignObject, foreignObject2].forEach(el => {
194 expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
195 expect(el.tagName).toBe('foreignObject');
196 });
197 [div, div2].forEach(el => {
198 expect(el.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
199 // DOM tagName is capitalized by browsers.
200 expect(el.tagName).toBe('DIV');
201 });
202 });
203
204 it('can render SVG into a non-React SVG tree', async () => {
205 const outerSVGRoot = document.createElementNS(
206 'http://www.w3.org/2000/svg',
207 'svg',
208 );
209 const container = document.createElementNS(
210 'http://www.w3.org/2000/svg',
211 'g',
212 );
213 outerSVGRoot.appendChild(container);
214 let image;
215 const root = ReactDOMClient.createRoot(container);
216 await act(() => {
217 root.render(<image ref={el => (image = el)} />);
218 });
219 expect(image.namespaceURI).toBe('http://www.w3.org/2000/svg');
220 expect(image.tagName).toBe('image');
221 });
222
223 it('can render HTML into a foreignObject in non-React SVG tree', async () => {
224 const outerSVGRoot = document.createElementNS(
225 'http://www.w3.org/2000/svg',
226 'svg',
227 );
228 const container = document.createElementNS(
229 'http://www.w3.org/2000/svg',
230 'foreignObject',
231 );
232 outerSVGRoot.appendChild(container);
233 let div;
234 const root = ReactDOMClient.createRoot(container);
235 await act(() => {
236 root.render(<div ref={el => (div = el)} />);
237 });
238 expect(div.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
239 expect(div.tagName).toBe('DIV');
240 });
241 });