1
+/**
2
+ * Copyright 2013-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @emails react-core
10
+ */
11
+
12
+'use strict';
13
+
14
+describe('ReactDOM unknown attribute', () => {
15
+ var React;
16
+ var ReactDOM;
17
+
18
+ beforeEach(() => {
19
+ jest.resetModules();
20
+ React = require('react');
21
+ ReactDOM = require('react-dom');
22
+ });
23
+
24
+ function normalizeCodeLocInfo(str) {
25
+ return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
26
+ }
27
+
28
+ function testUnknownAttributeRemoval(givenValue) {
29
+ var el = document.createElement('div');
30
+ ReactDOM.render(<div unknown="something" />, el);
31
+ expect(el.firstChild.getAttribute('unknown')).toBe('something');
32
+ ReactDOM.render(<div unknown={givenValue} />, el);
33
+ expect(el.firstChild.hasAttribute('unknown')).toBe(false);
34
+ }
35
+
36
+ function testUnknownAttributeAssignment(givenValue, expectedDOMValue) {
37
+ var el = document.createElement('div');
38
+ ReactDOM.render(<div unknown="something" />, el);
39
+ expect(el.firstChild.getAttribute('unknown')).toBe('something');
40
+ ReactDOM.render(<div unknown={givenValue} />, el);
41
+ expect(el.firstChild.getAttribute('unknown')).toBe(expectedDOMValue);
42
+ }
43
+
44
+ describe('unknown attributes', () => {
45
+ it('removes values null and undefined', () => {
46
+ testUnknownAttributeRemoval(null);
47
+ testUnknownAttributeRemoval(undefined);
48
+ });
49
+
50
+ it('changes values true, false to null, and also warns once', () => {
51
+ spyOn(console, 'error');
52
+
53
+ testUnknownAttributeAssignment(true, null);
54
+ testUnknownAttributeAssignment(false, null);
55
+
56
+ expectDev(
57
+ normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
58
+ ).toMatch(
59
+ 'Warning: Received `true` for non-boolean attribute `unknown`. ' +
60
+ 'If this is expected, cast the value to a string.\n' +
61
+ ' in div (at **)',
62
+ );
63
+ expectDev(console.error.calls.count()).toBe(1);
64
+ });
65
+
66
+ it('removes unknown attributes that were rendered but are now missing', () => {
67
+ var el = document.createElement('div');
68
+ ReactDOM.render(<div unknown="something" />, el);
69
+ expect(el.firstChild.getAttribute('unknown')).toBe('something');
70
+ ReactDOM.render(<div />, el);
71
+ expect(el.firstChild.hasAttribute('unknown')).toBe(false);
72
+ });
73
+
74
+ it('passes through strings', () => {
75
+ testUnknownAttributeAssignment('a string', 'a string');
76
+ });
77
+
78
+ it('coerces numbers to strings', () => {
79
+ testUnknownAttributeAssignment(0, '0');
80
+ testUnknownAttributeAssignment(-1, '-1');
81
+ testUnknownAttributeAssignment(42, '42');
82
+ testUnknownAttributeAssignment(9000.99, '9000.99');
83
+ });
84
+
85
+ it('coerces NaN to strings and warns', () => {
86
+ spyOn(console, 'error');
87
+
88
+ testUnknownAttributeAssignment(NaN, 'NaN');
89
+ expectDev(
90
+ normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
91
+ ).toMatch(
92
+ 'Warning: Received NaN for numeric attribute `unknown`. ' +
93
+ 'If this is expected, cast the value to a string.\n' +
94
+ ' in div (at **)',
95
+ );
96
+ expectDev(console.error.calls.count()).toBe(1);
97
+ });
98
+
99
+ it('coerces objects to strings **and warns**', () => {
100
+ const lol = {
101
+ toString() {
102
+ return 'lol';
103
+ },
104
+ };
105
+
106
+ testUnknownAttributeAssignment({hello: 'world'}, '[object Object]');
107
+ testUnknownAttributeAssignment(lol, 'lol');
108
+ });
109
+
110
+ it('removes symbols and warns', () => {
111
+ spyOn(console, 'error');
112
+
113
+ testUnknownAttributeRemoval(Symbol('foo'));
114
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
115
+ 'Warning: Invalid prop `unknown` on <div> tag. Either remove this ' +
116
+ 'prop from the element, or pass a string or number value to keep it ' +
117
+ 'in the DOM. For details, see https://fb.me/react-unknown-prop\n' +
118
+ ' in div (at **)',
119
+ );
120
+ expectDev(console.error.calls.count()).toBe(1);
121
+ });
122
+
123
+ it('removes functions and warns', () => {
124
+ spyOn(console, 'error');
125
+
126
+ testUnknownAttributeRemoval(function someFunction() {});
127
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
128
+ 'Warning: Invalid prop `unknown` on <div> tag. Either remove this ' +
129
+ 'prop from the element, or pass a string or number value to ' +
130
+ 'keep it in the DOM. For details, see ' +
131
+ 'https://fb.me/react-unknown-prop\n' +
132
+ ' in div (at **)',
133
+ );
134
+ expectDev(console.error.calls.count()).toBe(1);
135
+ });
136
+ });
137
+});