178
);
179
});
180
181
+ it('should warn for unknown string event handlers', () => {
182
+ spyOn(console, 'error');
183
+ var container = document.createElement('div');
184
+ ReactDOM.render(<div onUnknown="alert("hack")" />, container);
185
+ expect(container.firstChild.hasAttribute('onUnknown')).toBe(false);
186
+ expect(container.firstChild.onUnknown).toBe(undefined);
187
+ ReactDOM.render(<div onunknown="alert("hack")" />, container);
188
+ expect(container.firstChild.hasAttribute('onunknown')).toBe(false);
189
+ expect(container.firstChild.onunknown).toBe(undefined);
190
+ ReactDOM.render(<div on-unknown="alert("hack")" />, container);
191
+ expect(container.firstChild.hasAttribute('on-unknown')).toBe(false);
192
+ expect(container.firstChild['on-unknown']).toBe(undefined);
193
+ expectDev(console.error.calls.count(0)).toBe(3);
194
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
195
+ 'Warning: Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)',
196
+ );
197
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
198
+ 'Warning: Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)',
199
+ );
200
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe(
201
+ 'Warning: Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)',
202
+ );
203
+ });
204
+
205
+ it('should warn for unknown function event handlers', () => {
206
+ spyOn(console, 'error');
207
+ var container = document.createElement('div');
208
+ ReactDOM.render(<div onUnknown={function() {}} />, container);
209
+ expect(container.firstChild.hasAttribute('onUnknown')).toBe(false);
210
+ expect(container.firstChild.onUnknown).toBe(undefined);
211
+ ReactDOM.render(<div onunknown={function() {}} />, container);
212
+ expect(container.firstChild.hasAttribute('onunknown')).toBe(false);
213
+ expect(container.firstChild.onunknown).toBe(undefined);
214
+ ReactDOM.render(<div on-unknown={function() {}} />, container);
215
+ expect(container.firstChild.hasAttribute('on-unknown')).toBe(false);
216
+ expect(container.firstChild['on-unknown']).toBe(undefined);
217
+ expectDev(console.error.calls.count(0)).toBe(3);
218
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
219
+ 'Warning: Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)',
220
+ );
221
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
222
+ 'Warning: Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)',
223
+ );
224
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe(
225
+ 'Warning: Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)',
226
+ );
227
+ });
228
+
229
+ it('should warn for badly cased React attributes', () => {
230
+ spyOn(console, 'error');
231
+ var container = document.createElement('div');
232
+ ReactDOM.render(<div CHILDREN="5" />, container);
233
+ expect(container.firstChild.getAttribute('CHILDREN')).toBe('5');
234
+ expectDev(console.error.calls.count(0)).toBe(1);
235
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
236
+ 'Warning: Invalid DOM property `CHILDREN`. Did you mean `children`?\n in div (at **)',
237
+ );
238
+ });
239
+
240
it('should not warn for "0" as a unitless style value', () => {
241
spyOn(console, 'error');
242
694
expect(nodeValueSetter.mock.calls.length).toBe(3);
695
});
696
638
- it('should ignore attribute whitelist for elements with the "is: attribute', () => {
697
+ it('should ignore attribute whitelist for elements with the "is" attribute', () => {
698
var container = document.createElement('div');
699
ReactDOM.render(<button is="test" cowabunga="chevynova" />, container);
700
expect(container.firstChild.hasAttribute('cowabunga')).toBe(true);
701
});
702
703
+ it('should warn about non-string "is" attribute', () => {
704
+ spyOn(console, 'error');
705
+ var container = document.createElement('div');
706
+ ReactDOM.render(<button is={function() {}} />, container);
707
+
708
+ expectDev(console.error.calls.count()).toBe(1);
709
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
710
+ 'Received a `function` for string attribute `is`. If this is expected, cast ' +
711
+ 'the value to a string.',
712
+ );
713
+ });
714
+
715
it('should not update when switching between null/undefined', () => {
716
var container = document.createElement('div');
717
var node = ReactDOM.render(<div />, container);
886
);
887
});
888
889
+ it('should warn on props reserved for future use', () => {
890
+ spyOn(console, 'error');
891
+ ReactTestUtils.renderIntoDocument(<div aria="hello" />);
892
+ expectDev(console.error.calls.count()).toBe(1);
893
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
894
+ 'The `aria` attribute is reserved for future use in React. ' +
895
+ 'Pass individual `aria-` attributes instead.',
896
+ );
897
+ });
898
+
899
it('should warn if the tag is unrecognized', () => {
900
spyOn(console, 'error');
901
2084
expect(el.hasAttribute('whatever')).toBe(false);
2085
2086
expectDev(console.error.calls.argsFor(0)[0]).toContain(
2006
- 'Warning: Invalid prop `whatever` on <div> tag',
2087
+ 'Warning: Received `true` for non-boolean attribute `whatever`',
2088
);
2089
});
2090
2097
expect(el.hasAttribute('whatever')).toBe(false);
2098
2099
expectDev(console.error.calls.argsFor(0)[0]).toContain(
2019
- 'Warning: Invalid prop `whatever` on <div> tag',
2100
+ 'Warning: Received `true` for non-boolean attribute `whatever`',
2101
);
2102
});
2103
2177
2178
describe('Object stringification', function() {
2179
it('allows objects on known properties', function() {
2099
- var el = ReactTestUtils.renderIntoDocument(
2100
- <div allowTransparency={{}} />,
2101
- );
2102
- expect(el.getAttribute('allowtransparency')).toBe('[object Object]');
2180
+ var el = ReactTestUtils.renderIntoDocument(<div acceptCharset={{}} />);
2181
+ expect(el.getAttribute('accept-charset')).toBe('[object Object]');
2182
});
2183
2184
it('should pass objects as attributes if they define toString', () => {
2236
expect(el.getAttribute('ajaxify')).toBe('ajaxy');
2237
});
2238
});
2239
+
2240
+ describe('String boolean attributes', function() {
2241
+ it('does not assign string boolean attributes for custom attributes', function() {
2242
+ spyOn(console, 'error');
2243
+
2244
+ var el = ReactTestUtils.renderIntoDocument(<div whatever={true} />);
2245
+
2246
+ expect(el.hasAttribute('whatever')).toBe(false);
2247
+
2248
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
2249
+ 'Warning: Received `true` for non-boolean attribute `whatever`.',
2250
+ );
2251
+ });
2252
+
2253
+ it('stringifies the boolean true for allowed attributes', function() {
2254
+ var el = ReactTestUtils.renderIntoDocument(<div spellCheck={true} />);
2255
+
2256
+ expect(el.getAttribute('spellCheck')).toBe('true');
2257
+ });
2258
+
2259
+ it('stringifies the boolean false for allowed attributes', function() {
2260
+ var el = ReactTestUtils.renderIntoDocument(<div spellCheck={false} />);
2261
+
2262
+ expect(el.getAttribute('spellCheck')).toBe('false');
2263
+ });
2264
+
2265
+ it('stringifies implicit booleans for allowed attributes', function() {
2266
+ // eslint-disable-next-line react/jsx-boolean-value
2267
+ var el = ReactTestUtils.renderIntoDocument(<div spellCheck />);
2268
+
2269
+ expect(el.getAttribute('spellCheck')).toBe('true');
2270
+ });
2271
+ });
2272
+
2273
+ if (ReactDOMFeatureFlags.useFiber) {
2274
+ // This is currently broken (and has been broken for a while).
2275
+ // We had a fix based on reading namespace, but it was too convoluted.
2276
+ // TODO: a proper fix that would happen at the diffing stage.
2277
+ describe.skip('Hyphenated SVG elements', function() {
2278
+ it('the font-face element is not a custom element', function() {
2279
+ spyOn(console, 'error');
2280
+ var el = ReactTestUtils.renderIntoDocument(
2281
+ <svg><font-face x-height={false} /></svg>,
2282
+ );
2283
+
2284
+ expect(el.querySelector('font-face').hasAttribute('x-height')).toBe(
2285
+ false,
2286
+ );
2287
+
2288
+ expectDev(console.error.calls.count()).toBe(1);
2289
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
2290
+ 'Warning: Invalid DOM property `x-height`. Did you mean `xHeight`',
2291
+ );
2292
+ });
2293
+
2294
+ it('the font-face element does not allow unknown boolean values', function() {
2295
+ spyOn(console, 'error');
2296
+ var el = ReactTestUtils.renderIntoDocument(
2297
+ <svg><font-face whatever={false} /></svg>,
2298
+ );
2299
+
2300
+ expect(el.querySelector('font-face').hasAttribute('whatever')).toBe(
2301
+ false,
2302
+ );
2303
+
2304
+ expectDev(console.error.calls.count()).toBe(1);
2305
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
2306
+ 'Warning: Received `false` for non-boolean attribute `whatever`.',
2307
+ );
2308
+ });
2309
+ });
2310
+ }
2311
});