wallet-core/thirdparty/preact/test/browser/devtools.js

235 lines
7.3 KiB
JavaScript
Raw Normal View History

Squashed 'thirdparty/preact/' changes from b2d90cc..ba094e2 ba094e2 Run only local tests for pull requests (#390) e9fc3c2 Fix CI build (#386) 70a5ca3 This adds a link to preact-i18nline. (#382) 5dffd85 Merge branch 'pr-fix-build-for-windows' of https://github.com/Download/preact f14edf7 kilobits => kilobytes (#383) c193547 Test for #292 284e4aa 6.4.0 24eab2f Prevent accidental duplicate recycling of elements when swapping the base element of a component. Fixes #373. 76c5ef7 fix lint error 8008886 When swapping the base of a composed child component, update its parent's base reference. Fixes #349. fd4f21f Add an equality check prior to setting `.nodeValue` on text nodes, since Firefox (and maybe others) don't do this internally by default. Fixes #368 - thanks @zbinlin! 1555e2b Add CDNJS version badge in readme (#365) 79c8bae Disable React Developer Tools integration tests under IE (#362) 84f4eeb Refactor `linkState()` a bit to drop around 40 bytes. Coincidentally, that's the exact size of the hooks just added for DevTools... 👌 22bbfcb Little tweaks 👯 f8b326e Document how to use the React DevTools with Preact (#354) 1f4a8eb Correct "preact/devtools" type definitions (#355) 68f22eb Add React Developer Tools integration (#339) 2a7a027 Add ref and allow objects in className (#316) 4a59cca fix readme todomvc link (#345) 37ca4e0 Fixes build for Windows #343 cf93387 6.3.0 ff05818 Make `VNode.children` *always* be an Array, even when there are no children. 9b095f4 Added link to preact-layout (#342) git-subtree-dir: thirdparty/preact git-subtree-split: ba094e27b602cb16aded7dcad95f71e44b7b0476
2016-11-08 15:07:07 +01:00
import { h, Component, render } from '../../src/preact';
import { initDevTools } from '../../devtools/devtools';
import { unmountComponent } from '../../src/vdom/component';
class StatefulComponent extends Component {
constructor(props) {
super(props);
this.state = {count: 0};
}
render() {
return h('span', {}, String(this.state.count));
}
}
function FunctionalComponent() {
return h('span', {class: 'functional'}, 'Functional');
}
function Label({label}) {
return label;
}
class MultiChild extends Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
render() {
return h('div', {}, Array(this.state.count).fill('child'));
}
}
let describe_ = describe;
if (!('name' in Function.prototype)) {
// Skip these tests under Internet Explorer
describe_ = describe.skip;
}
describe_('React Developer Tools integration', () => {
let cleanup;
let container;
let renderer;
// Maps of DOM node to React*Component-like objects.
// For composite components, there will be two instances for each node, one
// for the composite component (instanceMap) and one for the root child DOM
// component rendered by that component (domInstanceMap)
let instanceMap = new Map();
let domInstanceMap = new Map();
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
const onMount = instance => {
if (instance._renderedChildren) {
domInstanceMap.set(instance.node, instance);
} else {
instanceMap.set(instance.node, instance);
}
};
const onUnmount = instance => {
instanceMap.delete(instance.node);
domInstanceMap.delete(instance.node);
};
global.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
inject: sinon.spy(_renderer => {
renderer = _renderer;
renderer.Mount._renderNewRootComponent = sinon.stub();
renderer.Reconciler.mountComponent = sinon.spy(onMount);
renderer.Reconciler.unmountComponent = sinon.spy(onUnmount);
renderer.Reconciler.receiveComponent = sinon.stub();
})
};
cleanup = initDevTools();
});
afterEach(() => {
container.remove();
cleanup();
});
it('registers preact as a renderer with the React DevTools hook', () => {
expect(global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject).to.be.called;
});
// Basic component addition/update/removal tests
it('notifies dev tools about new components', () => {
render(h(StatefulComponent), container);
expect(renderer.Reconciler.mountComponent).to.be.called;
});
it('notifies dev tools about component updates', () => {
const node = render(h(StatefulComponent), container);
node._component.forceUpdate();
expect(renderer.Reconciler.receiveComponent).to.be.called;
});
it('notifies dev tools when components are removed', () => {
const node = render(h(StatefulComponent), container);
unmountComponent(node._component, true);
expect(renderer.Reconciler.unmountComponent).to.be.called;
});
// Test properties of DOM components exposed to devtools via
// ReactDOMComponent-like instances
it('exposes the tag name of DOM components', () => {
const node = render(h(StatefulComponent), container);
const domInstance = domInstanceMap.get(node);
expect(domInstance._currentElement.type).to.equal('span');
});
it('exposes DOM component props', () => {
const node = render(h(FunctionalComponent), container);
const domInstance = domInstanceMap.get(node);
expect(domInstance._currentElement.props.class).to.equal('functional');
});
it('exposes text component contents', () => {
const node = render(h(Label, {label: 'Text content'}), container);
const textInstance = domInstanceMap.get(node);
expect(textInstance._stringText).to.equal('Text content');
});
// Test properties of composite components exposed to devtools via
// ReactCompositeComponent-like instances
it('exposes the name of composite component classes', () => {
const node = render(h(StatefulComponent), container);
expect(instanceMap.get(node).getName()).to.equal('StatefulComponent');
});
it('exposes composite component props', () => {
const node = render(h(Label, {label: 'Text content'}), container);
const instance = instanceMap.get(node);
expect(instance._currentElement.props.label).to.equal('Text content');
});
it('exposes composite component state', () => {
const node = render(h(StatefulComponent), container);
node._component.setState({count: 42});
node._component.forceUpdate();
expect(instanceMap.get(node).state).to.deep.equal({count: 42});
});
// Test setting state via devtools
it('updates component when setting state from devtools', () => {
const node = render(h(StatefulComponent), container);
instanceMap.get(node).setState({count: 10});
instanceMap.get(node).forceUpdate();
expect(node.textContent).to.equal('10');
});
// Test that the original instance is exposed via `_instance` so it can
// be accessed conveniently via `$r` in devtools
// Functional component handling tests
it('wraps functional components with stateful ones', () => {
const vnode = h(FunctionalComponent);
expect(vnode.nodeName.prototype).to.have.property('render');
});
it('exposes the name of functional components', () => {
const node = render(h(FunctionalComponent), container);
const instance = instanceMap.get(node);
expect(instance.getName()).to.equal('FunctionalComponent');
});
it('exposes a fallback name if the component has no useful name', () => {
const node = render(h(() => h('div')), container);
const instance = instanceMap.get(node);
expect(instance.getName()).to.equal('(Function.name missing)');
});
// Test handling of DOM children
it('notifies dev tools about DOM children', () => {
const node = render(h(StatefulComponent), container);
const domInstance = domInstanceMap.get(node);
expect(renderer.Reconciler.mountComponent).to.have.been.calledWith(domInstance);
});
it('notifies dev tools when a component update adds DOM children', () => {
const node = render(h(MultiChild, {initialCount: 2}), container);
node._component.setState({count: 4});
node._component.forceUpdate();
expect(renderer.Reconciler.mountComponent).to.have.been.called.twice;
});
it('notifies dev tools when a component update modifies DOM children', () => {
const node = render(h(StatefulComponent), container);
instanceMap.get(node).setState({count: 10});
instanceMap.get(node).forceUpdate();
const textInstance = domInstanceMap.get(node.childNodes[0]);
expect(textInstance._stringText).to.equal('10');
});
it('notifies dev tools when a component update removes DOM children', () => {
const node = render(h(MultiChild, {initialCount: 1}), container);
node._component.setState({count: 0});
node._component.forceUpdate();
expect(renderer.Reconciler.unmountComponent).to.be.called;
});
// Root component info
it('exposes root components on the _instancesByReactRootID map', () => {
render(h(StatefulComponent), container);
expect(Object.keys(renderer.Mount._instancesByReactRootID).length).to.equal(1);
});
it('notifies dev tools when new root components are mounted', () => {
render(h(StatefulComponent), container);
expect(renderer.Mount._renderNewRootComponent).to.be.called;
});
it('removes root components when they are unmounted', () => {
const node = render(h(StatefulComponent), container);
unmountComponent(node._component, true);
expect(Object.keys(renderer.Mount._instancesByReactRootID).length).to.equal(0);
});
});