These tests can still be run in the browser using `grunt test --debug`.
This is a repeat of 42f8d155f8. For posterity, we
do this because Phantom has a problem with Object.freeze and the test runner
can't do __DEV__ right (because we get rid of that in the build step).
Let's start logging objects as maps for children. We may want to deprecate this
and replace it with ImmutableMap and Map data structures instead.
This should ideally be logged in the recursive function but since that loses the
scope of where these children are passed it's easier to start tracking them
here to get an idea of how frequently and where it's used.
While looking up a detail of how `transferPropsTo()` works I noticed that we never check `TransferStrategies.hasOwnProperty(thisKey)` when merging props, just `newProps.hasOwnProperty(thisKey)` and a truthy test for `TransferStrategies[thisKey]`. This means that if our `newProps` has keys like `toString`, `valueOf`, or `constructor` etc. set, we will pull these functions off `TransferStrategies` and invoke them when merging props. In most cases this will just result in a failure to merge and some code without side effects being run but in the case of `valueOf` it will actually generate an exception.
I'm thinking that setting up `this.refs` in `mountComponent` is better than `construct`. Followed the same pattern as `ReactComponent.Mixin` and nulling out
the value in `construct` and setting it to its initial value in `mountComponent`.
This bites people all of the time. Until we have a better solution, let's just make the error message more actionable (most people don't know how the DOM
gets unexpectedly mutated).
The component that gets passed into renderComponent isn't guaranteed to be the
instance that gets mounted. We want to clone the instance.
Unit tests need to reason about the mounted instance. The first code mod changes:
ReactTestUtils.renderIntoDocument(<identifier>)
into
<identifier> = ReactTestUtils.renderIntoDocument(<identifier>)
Using this scripts:
scripts/bin/codemod -m -d ~/www --extensions js \
'^(\s*)ReactTestUtils\.renderIntoDocument\(\s*([$a-zA-Z0-9_]+)\s*\)' \
'\1\2 = ReactTestUtils.renderIntoDocument(\2)'
In the second case I do the same for React.renderComponent. However, there are
alot more unnecessary matches so I only codemod if the same identifier occurs
later in the file.
scripts/bin/codemod -m -d ~/www --extensions js \
'^(\s*)React.renderComponent\(\s*([$a-zA-Z0-9_]+)\s*?,(.*?\n?.*?\s\2\b)' \
'\1\2 = React.renderComponent(\2,\3'
And one more for ReactMount.renderComponent used by internals.
scripts/bin/codemod -m -d ~/www --extensions js \
'^(\s*)ReactMount.renderComponent\(\s*([$a-zA-Z0-9_]+)\s*?,(.*?\n?.*?\s\2\b)' \
'\1\2 = ReactMount.renderComponent(\2,\3'
This still matches many unnecessary cases where the second occurance of the
identifier is a redeclaration or comment. But this code mod doesn't hurt in
those cases.
Finally I have to do the same for:
this.<identifier> = React.renderComponent(this.<identifier>,
This is a common pattern for production code but not tests. Some of these call
sites will likely break when we move to true descriptors.
scripts/bin/codemod -m -d ~/www --extensions js \
'^(\s*)React.renderComponent\((\s*)this\.([$a-zA-Z0-9\_\.]+)\s*?,' \
'\1this.\3 = React.renderComponent(\2this.\3,'
This is the first step towards descriptors. This will start cloning the
component when it's mounted instead of mounting the first instance.
This avoids an issue where a reference to the first instance can hang around
in props. Since a mounted component gets mutated, the descriptor changes.
We don't need to clone the props object itself. Mutating the shallow props
object of a child that's passed into you is already flawed. Those cases need to
use cloneWithProps. A props object is considered shallow frozen after it leaves
the render it was created in.
We found that the component would break if we set any statics with the
value 0. It turns out @chenglou already ran into this with
d71736b3ed but the statics code was copied
earlier, and still has this falsy check. Made the same change, updated
the unittest.
After we run `require('mock-modules').dumpCache()`, the object exported by
the `emptyObject` module will no longer be identical to previously
exported objects, so tests like `expect(component.refs).toBe(emptyObject)`
will fail.
Note that this behavior only manifests itself in tests, because of course
we do not call `dumpCache` in production code.
We could consider storing the `emptyObject` globally to thwart the effects
of `dumpCache`, but it's more idiomatic simply to re-`require` the latest
version of `emptyObject`.
If no refs are rendered, `this.refs` is undefined. This is bad since it deopts & is hard to look for. Instead we should make `this.refs` an immutable empty object.
This adds an instrumentation hook for logging so that we can monitor invalid API
usage before we're ready to issue a warning.
I took the opportunity to update some console.warns to use the warning module
instead. The remaining console.warns
will be replaced by the warning module after we've cleaned up the callsites.
When IE8 focuses a disabled item, it throws
This makes sure the we're not focusing the item during selection restoration/autofocus when the element's disabled.
Dealing with immutable data is hard. This provides a simple helper (ported from the IG codebase) that makes dealing with immutable JSON data easier. Designed to be familiar for people who use MongoDB.