Skip to content

Commit

Permalink
Moar attribute tests (facebook#10509)
Browse files Browse the repository at this point in the history
* WIP

* WIP Add the rest of the tests for what we expect re: unknown attributes

**what is the change?:**
Adds tests for the following behavior -

- Numbers and booleans should be converted to strings, and not warn
- NaN, Symbols, functions, and objects should be converted to strings,
  and *should* warn

Going to add tests for the not-warning behavior in a follow-up.

These tests are not entirely passing - we either need to change what we
expect or change the behavior.

**why make this change?:**
Gets everyone on the same page about expected behavior, and codifies it
in a maintainable way

**test plan:**
`yarn test src/renderers/dom/shared/__tests__/ReactDOMAttribute-test.js`

**issue:**
facebook#10399

* WIP Add check that we *don't* warn when handling some unknown attributes

**what is the change?:**
We are testing the behavior of unknown attributes, which has changed
since React 15.

We want to *not* warn for the following cases -
- null
- undefined
- missing
- strings
- numbers
- booleans

**why make this change?:**
We want to verify that warnings don't get fired at the wrong time.

**test plan:**
`yarn test src/renderers/dom/shared/__tests__/ReactDOMAttribute-test.js`

**issue:**
facebook#10399

* ran prettier

* Symbols and functions passed to unknown attributes should remove and warn

* Abstract tests a bit to make them easier to read

* Remove Markdown from test names

I don't think we use this convention anywhere.

* Add an assertion for NaN warning message

* Update ReactDOMAttribute test based on attribute fixture

**what is the change?:**
- booleans don't get stringified
- some warnings have changed since we originally wrote this

**why make this change?:**
The attribute behavior is finalized and now we can test it :D

I also found it handy to have a row with a truly unknown attribute, so
added "imaginaryFriend".

**test plan:**
`yarn test src/renderers/dom/shared/__tests__/ReactDOMAttribute-test.js`
and comparing the tests to the attribute table

**issue:**
facebook#10399

* remove imaginaryFriend to resolve conflict

* ran prettier
  • Loading branch information
acdlite authored and flarnie committed Sep 8, 2017
1 parent 565e358 commit e16a0d6
Showing 1 changed file with 137 additions and 0 deletions.
137 changes: 137 additions & 0 deletions src/renderers/dom/shared/__tests__/ReactDOMAttribute-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/

'use strict';

describe('ReactDOM unknown attribute', () => {
var React;
var ReactDOM;

beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOM = require('react-dom');
});

function normalizeCodeLocInfo(str) {
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
}

function testUnknownAttributeRemoval(givenValue) {
var el = document.createElement('div');
ReactDOM.render(<div unknown="something" />, el);
expect(el.firstChild.getAttribute('unknown')).toBe('something');
ReactDOM.render(<div unknown={givenValue} />, el);
expect(el.firstChild.hasAttribute('unknown')).toBe(false);
}

function testUnknownAttributeAssignment(givenValue, expectedDOMValue) {
var el = document.createElement('div');
ReactDOM.render(<div unknown="something" />, el);
expect(el.firstChild.getAttribute('unknown')).toBe('something');
ReactDOM.render(<div unknown={givenValue} />, el);
expect(el.firstChild.getAttribute('unknown')).toBe(expectedDOMValue);
}

describe('unknown attributes', () => {
it('removes values null and undefined', () => {
testUnknownAttributeRemoval(null);
testUnknownAttributeRemoval(undefined);
});

it('changes values true, false to null, and also warns once', () => {
spyOn(console, 'error');

testUnknownAttributeAssignment(true, null);
testUnknownAttributeAssignment(false, null);

expectDev(
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
).toMatch(
'Warning: Received `true` for non-boolean attribute `unknown`. ' +
'If this is expected, cast the value to a string.\n' +
' in div (at **)',
);
expectDev(console.error.calls.count()).toBe(1);
});

it('removes unknown attributes that were rendered but are now missing', () => {
var el = document.createElement('div');
ReactDOM.render(<div unknown="something" />, el);
expect(el.firstChild.getAttribute('unknown')).toBe('something');
ReactDOM.render(<div />, el);
expect(el.firstChild.hasAttribute('unknown')).toBe(false);
});

it('passes through strings', () => {
testUnknownAttributeAssignment('a string', 'a string');
});

it('coerces numbers to strings', () => {
testUnknownAttributeAssignment(0, '0');
testUnknownAttributeAssignment(-1, '-1');
testUnknownAttributeAssignment(42, '42');
testUnknownAttributeAssignment(9000.99, '9000.99');
});

it('coerces NaN to strings and warns', () => {
spyOn(console, 'error');

testUnknownAttributeAssignment(NaN, 'NaN');
expectDev(
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
).toMatch(
'Warning: Received NaN for numeric attribute `unknown`. ' +
'If this is expected, cast the value to a string.\n' +
' in div (at **)',
);
expectDev(console.error.calls.count()).toBe(1);
});

it('coerces objects to strings **and warns**', () => {
const lol = {
toString() {
return 'lol';
},
};

testUnknownAttributeAssignment({hello: 'world'}, '[object Object]');
testUnknownAttributeAssignment(lol, 'lol');
});

it('removes symbols and warns', () => {
spyOn(console, 'error');

testUnknownAttributeRemoval(Symbol('foo'));
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Invalid prop `unknown` on <div> tag. Either remove this ' +
'prop from the element, or pass a string or number value to keep it ' +
'in the DOM. For details, see https://fb.me/react-unknown-prop\n' +
' in div (at **)',
);
expectDev(console.error.calls.count()).toBe(1);
});

it('removes functions and warns', () => {
spyOn(console, 'error');

testUnknownAttributeRemoval(function someFunction() {});
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Invalid prop `unknown` on <div> tag. Either remove this ' +
'prop from the element, or pass a string or number value to ' +
'keep it in the DOM. For details, see ' +
'https://fb.me/react-unknown-prop\n' +
' in div (at **)',
);
expectDev(console.error.calls.count()).toBe(1);
});
});
});

0 comments on commit e16a0d6

Please sign in to comment.