Skip to content

Commit d289d4b

Browse files
authored
Update to Jest 22 (#11956)
* Bump deps to Jest 22 * Prevent jsdom from logging intentionally thrown errors This relies on our existing special field that we use to mute errors. Perhaps, it would be better to instead rely on preventDefault() directly. I outlined a possible strategy here: #11098 (comment) * Update snapshots * Mock out a method called by ReactART that now throws * Calling .click() no longer works, dispatch event instead * Fix incorrect SVG element creation in test * Render SVG elements inside <svg> to avoid extra warnings * Fix range input test to use numeric value * Fix creating SVG element in test * Replace brittle test that relied on jsdom behavior The test passed in jsdom due to its implementation details. The original intention was to test the mutation method, but it was removed a while ago. Following @nhunzaker's suggestion, I moved the tests to ReactDOMInput and adjusted them to not rely on implementation details. * Add a workaround for the expected extra client-side warning This is a bit ugly but it's just two places. I think we can live with this. * Only warn once for mismatches caused by bad attribute casing We used to warn both about bad casing and about a mismatch. The mismatch warning was a bit confusing. We didn't know we warned twice because jsdom didn't faithfully emulate SVG. This changes the behavior to only leave the warning about bad casing if that's what caused the mismatch. It also adjusts the test to have an expectation that matches the real world behavior. * Add an expected warning per comment in the same test
1 parent 4d37040 commit d289d4b

14 files changed

Lines changed: 724 additions & 321 deletions

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"babel-code-frame": "^6.26.0",
1212
"babel-core": "^6.0.0",
1313
"babel-eslint": "^7.1.0",
14-
"babel-jest": "^21.3.0-beta.4",
14+
"babel-jest": "^22.0.4",
1515
"babel-plugin-check-es2015-constants": "^6.5.0",
1616
"babel-plugin-external-helpers": "^6.22.0",
1717
"babel-plugin-syntax-trailing-function-commas": "^6.5.0",
@@ -67,10 +67,7 @@
6767
"gzip-js": "~0.3.2",
6868
"gzip-size": "^3.0.0",
6969
"jasmine-check": "^1.0.0-rc.0",
70-
"jest": "^21.3.0-beta.4",
71-
"jest-config": "^21.3.0-beta.4",
72-
"jest-jasmine2": "^21.3.0-beta.4",
73-
"jest-runtime": "^21.3.0-beta.4",
70+
"jest": "^22.0.4",
7471
"merge-stream": "^1.0.0",
7572
"minimatch": "^3.0.4",
7673
"minimist": "^1.2.0",

packages/react-art/src/__tests__/ReactART-test.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ function testDOMNodeStructure(domNode, expectedStructure) {
5454
}
5555

5656
describe('ReactART', () => {
57+
let container;
58+
5759
beforeEach(() => {
60+
container = document.createElement('div');
61+
document.body.appendChild(container);
62+
5863
ARTCurrentMode.setCurrent(ARTSVGMode);
5964

6065
Group = ReactART.Group;
@@ -104,6 +109,11 @@ describe('ReactART', () => {
104109
};
105110
});
106111

112+
afterEach(() => {
113+
document.body.removeChild(container);
114+
container = null;
115+
});
116+
107117
it('should have the correct lifecycle state', () => {
108118
let instance = <TestComponent />;
109119
instance = ReactTestUtils.renderIntoDocument(instance);
@@ -142,7 +152,6 @@ describe('ReactART', () => {
142152
});
143153

144154
it('should be able to reorder components', () => {
145-
const container = document.createElement('div');
146155
const instance = ReactDOM.render(
147156
<TestComponent flipped={false} />,
148157
container,
@@ -189,8 +198,6 @@ describe('ReactART', () => {
189198
});
190199

191200
it('should be able to reorder many components', () => {
192-
const container = document.createElement('div');
193-
194201
class Component extends React.Component {
195202
render() {
196203
const chars = this.props.chars.split('');
@@ -296,17 +303,13 @@ describe('ReactART', () => {
296303
);
297304
}
298305
}
299-
300-
const container = document.createElement('div');
301306
ReactDOM.render(<Outer />, container);
302307
expect(ref).not.toBeDefined();
303308
ReactDOM.render(<Outer mountCustomShape={true} />, container);
304309
expect(ref.constructor).toBe(CustomShape);
305310
});
306311

307312
it('adds and updates event handlers', () => {
308-
const container = document.createElement('div');
309-
310313
function render(onClick) {
311314
return ReactDOM.render(
312315
<Surface>
@@ -319,8 +322,11 @@ describe('ReactART', () => {
319322
function doClick(instance) {
320323
const path = ReactDOM.findDOMNode(instance).querySelector('path');
321324

322-
// ReactTestUtils.Simulate.click doesn't work with SVG elements
323-
path.click();
325+
path.dispatchEvent(
326+
new MouseEvent('click', {
327+
bubbles: true,
328+
}),
329+
);
324330
}
325331

326332
const onClick1 = jest.fn();

packages/react-art/src/__tests__/__snapshots__/ReactART-test.js.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
exports[`ReactARTComponents should generate a <Shape> with props for drawing the Circle 1`] = `
44
<Shape
55
d={
6-
{
6+
Object {
77
"_pivotX": 0,
88
"_pivotY": -10,
99
"path": Array [
@@ -28,7 +28,7 @@ exports[`ReactARTComponents should generate a <Shape> with props for drawing the
2828
exports[`ReactARTComponents should generate a <Shape> with props for drawing the Rectangle 1`] = `
2929
<Shape
3030
d={
31-
{
31+
Object {
3232
"_pivotX": 0,
3333
"_pivotY": 0,
3434
"path": Array [
@@ -54,7 +54,7 @@ exports[`ReactARTComponents should generate a <Shape> with props for drawing the
5454
exports[`ReactARTComponents should generate a <Shape> with props for drawing the Wedge 1`] = `
5555
<Shape
5656
d={
57-
{
57+
Object {
5858
"_pivotX": 0,
5959
"_pivotY": 50,
6060
"path": Array [

packages/react-dom/src/__tests__/DOMPropertyOperations-test.js

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ describe('DOMPropertyOperations', () => {
3434
});
3535

3636
it('should set values as namespace attributes if necessary', () => {
37-
const container = document.createElement('svg');
37+
const container = document.createElementNS(
38+
'http://www.w3.org/2000/svg',
39+
'svg',
40+
);
3841
ReactDOM.render(<image xlinkHref="about:blank" />, container);
3942
expect(
4043
container.firstChild.getAttributeNS(
@@ -113,22 +116,6 @@ describe('DOMPropertyOperations', () => {
113116
ReactDOM.render(<div hidden={false} />, container);
114117
expect(container.firstChild.hasAttribute('hidden')).toBe(false);
115118
});
116-
});
117-
118-
describe('value mutation method', function() {
119-
it('should update an empty attribute to zero', function() {
120-
const container = document.createElement('div');
121-
ReactDOM.render(
122-
<input type="radio" value="" onChange={function() {}} />,
123-
container,
124-
);
125-
spyOnDevAndProd(container.firstChild, 'setAttribute');
126-
ReactDOM.render(
127-
<input type="radio" value={0} onChange={function() {}} />,
128-
container,
129-
);
130-
expect(container.firstChild.setAttribute.calls.count()).toBe(1);
131-
});
132119

133120
it('should always assign the value attribute for non-inputs', function() {
134121
const container = document.createElement('div');

packages/react-dom/src/__tests__/ReactDOMComponent-test.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,12 +1162,14 @@ describe('ReactDOMComponent', () => {
11621162
expect(returnedValue).toContain('</menuitem>');
11631163

11641164
expect(function() {
1165-
ReactDOM.render(
1166-
<menu>
1167-
<menuitem>children</menuitem>
1168-
</menu>,
1169-
container,
1170-
);
1165+
expect(() => {
1166+
ReactDOM.render(
1167+
<menu>
1168+
<menuitem>children</menuitem>
1169+
</menu>,
1170+
container,
1171+
);
1172+
}).toWarnDev('The tag <menuitem> is unrecognized in this browser.');
11711173
}).toThrowError(
11721174
'menuitem is a void element tag and must neither have `children` nor use ' +
11731175
'`dangerouslySetInnerHTML`.',

packages/react-dom/src/__tests__/ReactDOMInput-test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,34 @@ describe('ReactDOMInput', () => {
261261
expect(node.value).toEqual('0');
262262
});
263263

264+
it('updates the value on radio buttons from "" to 0', function() {
265+
const container = document.createElement('div');
266+
ReactDOM.render(
267+
<input type="radio" value="" onChange={function() {}} />,
268+
container,
269+
);
270+
ReactDOM.render(
271+
<input type="radio" value={0} onChange={function() {}} />,
272+
container,
273+
);
274+
expect(container.firstChild.value).toBe('0');
275+
expect(container.firstChild.getAttribute('value')).toBe('0');
276+
});
277+
278+
it('updates the value on checkboxes from "" to 0', function() {
279+
const container = document.createElement('div');
280+
ReactDOM.render(
281+
<input type="checkbox" value="" onChange={function() {}} />,
282+
container,
283+
);
284+
ReactDOM.render(
285+
<input type="checkbox" value={0} onChange={function() {}} />,
286+
container,
287+
);
288+
expect(container.firstChild.value).toBe('0');
289+
expect(container.firstChild.getAttribute('value')).toBe('0');
290+
});
291+
264292
it('distinguishes precision for extra zeroes in string number values', () => {
265293
class Stub extends React.Component {
266294
state = {

packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ function initModules() {
2929
};
3030
}
3131

32-
const {resetModules, itRenders} = ReactDOMServerIntegrationUtils(initModules);
32+
const {
33+
resetModules,
34+
itRenders,
35+
clientCleanRender,
36+
} = ReactDOMServerIntegrationUtils(initModules);
3337

3438
describe('ReactDOMServerIntegration', () => {
3539
beforeEach(() => {
@@ -488,21 +492,49 @@ describe('ReactDOMServerIntegration', () => {
488492
);
489493

490494
itRenders('badly cased SVG attribute with a warning', async render => {
491-
const e = await render(<text textlength="10" />, 1);
492-
expect(e.getAttribute('textLength')).toBe('10');
495+
const e = await render(
496+
<svg>
497+
<text textlength="10" />
498+
</svg>,
499+
1,
500+
);
501+
// The discrepancy is expected as long as we emit a warning
502+
// both on the client and the server.
503+
if (render === clientCleanRender) {
504+
// On the client, "textlength" is treated as a case-sensitive
505+
// SVG attribute so the wrong attribute ("textlength") gets set.
506+
expect(e.firstChild.getAttribute('textlength')).toBe('10');
507+
expect(e.firstChild.hasAttribute('textLength')).toBe(false);
508+
} else {
509+
// When parsing HTML (including the hydration case), the browser
510+
// correctly maps "textlength" to "textLength" SVG attribute.
511+
// So it happens to work on the initial render.
512+
expect(e.firstChild.getAttribute('textLength')).toBe('10');
513+
expect(e.firstChild.hasAttribute('textlength')).toBe(false);
514+
}
493515
});
494516

495517
itRenders('no badly cased aliased SVG attribute alias', async render => {
496-
const e = await render(<text strokedasharray="10 10" />, 1);
497-
expect(e.hasAttribute('stroke-dasharray')).toBe(false);
498-
expect(e.getAttribute('strokedasharray')).toBe('10 10');
518+
const e = await render(
519+
<svg>
520+
<text strokedasharray="10 10" />
521+
</svg>,
522+
1,
523+
);
524+
expect(e.firstChild.hasAttribute('stroke-dasharray')).toBe(false);
525+
expect(e.firstChild.getAttribute('strokedasharray')).toBe('10 10');
499526
});
500527

501528
itRenders(
502529
'no badly cased original SVG attribute that is aliased',
503530
async render => {
504-
const e = await render(<text stroke-dasharray="10 10" />, 1);
505-
expect(e.getAttribute('stroke-dasharray')).toBe('10 10');
531+
const e = await render(
532+
<svg>
533+
<text stroke-dasharray="10 10" />
534+
</svg>,
535+
1,
536+
);
537+
expect(e.firstChild.getAttribute('stroke-dasharray')).toBe('10 10');
506538
},
507539
);
508540
});
@@ -558,6 +590,16 @@ describe('ReactDOMServerIntegration', () => {
558590
);
559591

560592
itRenders('custom attributes for non-standard elements', async render => {
593+
// This test suite generally assumes that we get exactly
594+
// the same warnings (or none) for all scenarios including
595+
// SSR + innerHTML, hydration, and client-side rendering.
596+
// However this particular warning fires only when creating
597+
// DOM nodes on the client side. We force it to fire early
598+
// so that it gets deduplicated later, and doesn't fail the test.
599+
expect(() => {
600+
ReactDOM.render(<nonstandard />, document.createElement('div'));
601+
}).toWarnDev('The tag <nonstandard> is unrecognized in this browser.');
602+
561603
const e = await render(<nonstandard foo="bar" />);
562604
expect(e.getAttribute('foo')).toBe('bar');
563605
});

packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,16 @@ describe('ReactDOMServerIntegration', () => {
134134
});
135135

136136
itRenders('a non-standard element with text', async render => {
137+
// This test suite generally assumes that we get exactly
138+
// the same warnings (or none) for all scenarios including
139+
// SSR + innerHTML, hydration, and client-side rendering.
140+
// However this particular warning fires only when creating
141+
// DOM nodes on the client side. We force it to fire early
142+
// so that it gets deduplicated later, and doesn't fail the test.
143+
expect(() => {
144+
ReactDOM.render(<nonstandard />, document.createElement('div'));
145+
}).toWarnDev('The tag <nonstandard> is unrecognized in this browser.');
146+
137147
const e = await render(<nonstandard>Text</nonstandard>);
138148
expect(e.tagName).toBe('NONSTANDARD');
139149
expect(e.childNodes.length).toBe(1);

packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ module.exports = function(initModules) {
321321
itThrowsWhenRendering,
322322
asyncReactDOMRender,
323323
serverRender,
324+
clientCleanRender,
324325
clientRenderOnServerString,
325326
renderIntoDom,
326327
streamRender,

packages/react-dom/src/__tests__/validateDOMNesting-test.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ function expectWarnings(tags, warnings = []) {
1717
warnings = [...warnings];
1818

1919
let element = null;
20-
const container = document.createElement(tags.splice(0, 1));
20+
const containerTag = tags.shift();
21+
const container =
22+
containerTag === 'svg'
23+
? document.createElementNS('http://www.w3.org/2000/svg', containerTag)
24+
: document.createElement(containerTag);
25+
2126
while (tags.length) {
2227
const Tag = tags.pop();
2328
element = <Tag>{element}</Tag>;
@@ -108,7 +113,6 @@ describe('validateDOMNesting', () => {
108113
'validateDOMNesting(...): <body> cannot appear as a child of <foreignObject>.\n' +
109114
' in body (at **)\n' +
110115
' in foreignObject (at **)',
111-
'<foreignObject /> is using uppercase HTML',
112116
],
113117
);
114118
});

0 commit comments

Comments
 (0)