aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/preact/test/browser
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2016-11-08 15:07:07 +0100
committerFlorian Dold <florian.dold@gmail.com>2016-11-08 15:19:39 +0100
commitafb9fba64be1f15a3ce3ed31214a704e73e5e8bb (patch)
tree6f69712a8c976178c05144483ff0c8e9b09445c8 /thirdparty/preact/test/browser
parentb37e7762bb5492cbd6788863232e7d2634ab5e5c (diff)
parent6e5fb04d3f3f9a6cd43ac20896d73321dd079f96 (diff)
downloadwallet-core-afb9fba64be1f15a3ce3ed31214a704e73e5e8bb.tar.xz
Update preact version
Diffstat (limited to 'thirdparty/preact/test/browser')
-rw-r--r--thirdparty/preact/test/browser/components.js19
-rw-r--r--thirdparty/preact/test/browser/context.js32
-rw-r--r--thirdparty/preact/test/browser/devtools.js234
-rw-r--r--thirdparty/preact/test/browser/lifecycle.js4
-rw-r--r--thirdparty/preact/test/browser/linked-state.js20
-rw-r--r--thirdparty/preact/test/browser/refs.js22
-rw-r--r--thirdparty/preact/test/browser/spec.js11
7 files changed, 307 insertions, 35 deletions
diff --git a/thirdparty/preact/test/browser/components.js b/thirdparty/preact/test/browser/components.js
index b4649a719..9ef43cb1c 100644
--- a/thirdparty/preact/test/browser/components.js
+++ b/thirdparty/preact/test/browser/components.js
@@ -70,7 +70,7 @@ describe('Components', () => {
expect(C3)
.to.have.been.calledOnce
- .and.to.have.been.calledWith(PROPS)
+ .and.to.have.been.calledWithMatch(PROPS)
.and.to.have.returned(sinon.match({
nodeName: 'div',
attributes: PROPS
@@ -197,7 +197,7 @@ describe('Components', () => {
expect(Outer)
.to.have.been.calledOnce
- .and.to.have.been.calledWith(PROPS)
+ .and.to.have.been.calledWithMatch(PROPS)
.and.to.have.returned(sinon.match({
nodeName: Inner,
attributes: PROPS
@@ -205,7 +205,7 @@ describe('Components', () => {
expect(Inner)
.to.have.been.calledOnce
- .and.to.have.been.calledWith(PROPS)
+ .and.to.have.been.calledWithMatch(PROPS)
.and.to.have.returned(sinon.match({
nodeName: 'div',
attributes: PROPS,
@@ -247,7 +247,7 @@ describe('Components', () => {
expect(Inner).to.have.been.calledTwice;
expect(Inner.secondCall)
- .to.have.been.calledWith({ foo:'bar', i:2 })
+ .to.have.been.calledWithMatch({ foo:'bar', i:2 })
.and.to.have.returned(sinon.match({
attributes: {
j: 2,
@@ -269,7 +269,7 @@ describe('Components', () => {
expect(Inner).to.have.been.calledThrice;
expect(Inner.thirdCall)
- .to.have.been.calledWith({ foo:'bar', i:3 })
+ .to.have.been.calledWithMatch({ foo:'bar', i:3 })
.and.to.have.returned(sinon.match({
attributes: {
j: 3,
@@ -344,7 +344,7 @@ describe('Components', () => {
expect(Inner.prototype.render).to.have.been.calledTwice;
expect(Inner.prototype.render.secondCall)
- .to.have.been.calledWith({ foo:'bar', i:2 })
+ .to.have.been.calledWithMatch({ foo:'bar', i:2 })
.and.to.have.returned(sinon.match({
attributes: {
j: 2,
@@ -372,7 +372,7 @@ describe('Components', () => {
expect(Inner.prototype.render).to.have.been.calledThrice;
expect(Inner.prototype.render.thirdCall)
- .to.have.been.calledWith({ foo:'bar', i:3 })
+ .to.have.been.calledWithMatch({ foo:'bar', i:3 })
.and.to.have.returned(sinon.match({
attributes: {
j: 3,
@@ -435,7 +435,7 @@ describe('Components', () => {
expect(Inner.prototype.componentDidMount).to.have.been.calledOnce;
expect(Inner.prototype.componentWillMount).to.have.been.calledBefore(Inner.prototype.componentDidMount);
- root = render(<asdf />, scratch, root);
+ render(<asdf />, scratch, root);
expect(Inner.prototype.componentWillUnmount).to.have.been.calledOnce;
expect(Inner.prototype.componentDidUnmount).to.have.been.calledOnce;
@@ -689,8 +689,7 @@ describe('Components', () => {
expect(C1.prototype.componentWillMount, 'unmount innermost w/ intermediary div, C1').not.to.have.been.called;
expect(C2.prototype.componentDidUnmount, 'unmount innermost w/ intermediary div, C2 ummount').not.to.have.been.called;
- // @TODO this was just incorrect?
- // expect(C2.prototype.componentWillMount, 'unmount innermost w/ intermediary div, C2').not.to.have.been.called;
+ expect(C2.prototype.componentWillMount, 'unmount innermost w/ intermediary div, C2').not.to.have.been.called;
expect(C3.prototype.componentDidUnmount, 'unmount innermost w/ intermediary div, C3').to.have.been.calledOnce;
reset();
diff --git a/thirdparty/preact/test/browser/context.js b/thirdparty/preact/test/browser/context.js
index e62a948a4..ed5f81471 100644
--- a/thirdparty/preact/test/browser/context.js
+++ b/thirdparty/preact/test/browser/context.js
@@ -1,6 +1,8 @@
import { h, render, Component } from '../../src/preact';
/** @jsx h */
+const CHILDREN_MATCHER = sinon.match( v => v==null || Array.isArray(v) && !v.length , '[empty children]');
+
describe('context', () => {
let scratch;
@@ -57,18 +59,19 @@ describe('context', () => {
expect(Outer.prototype.getChildContext).to.have.been.calledOnce;
// initial render does not invoke anything but render():
- expect(Inner.prototype.render).to.have.been.calledWith({}, {}, CONTEXT);
+ expect(Inner.prototype.render).to.have.been.calledWith({ children:CHILDREN_MATCHER }, {}, CONTEXT);
CONTEXT.foo = 'bar';
render(<Outer {...PROPS} />, scratch, scratch.lastChild);
expect(Outer.prototype.getChildContext).to.have.been.calledTwice;
- expect(Inner.prototype.shouldComponentUpdate).to.have.been.calledOnce.and.calledWith(PROPS, {}, CONTEXT);
- expect(Inner.prototype.componentWillReceiveProps).to.have.been.calledWith(PROPS, CONTEXT);
- expect(Inner.prototype.componentWillUpdate).to.have.been.calledWith(PROPS, {});
- expect(Inner.prototype.componentDidUpdate).to.have.been.calledWith({}, {});
- expect(Inner.prototype.render).to.have.been.calledWith(PROPS, {}, CONTEXT);
+ let props = { children: CHILDREN_MATCHER, ...PROPS };
+ expect(Inner.prototype.shouldComponentUpdate).to.have.been.calledOnce.and.calledWith(props, {}, CONTEXT);
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.calledWith(props, CONTEXT);
+ expect(Inner.prototype.componentWillUpdate).to.have.been.calledWith(props, {});
+ expect(Inner.prototype.componentDidUpdate).to.have.been.calledWith({ children:CHILDREN_MATCHER }, {});
+ expect(Inner.prototype.render).to.have.been.calledWith(props, {}, CONTEXT);
/* Future:
@@ -115,18 +118,19 @@ describe('context', () => {
expect(Outer.prototype.getChildContext).to.have.been.calledOnce;
// initial render does not invoke anything but render():
- expect(Inner.prototype.render).to.have.been.calledWith({}, {}, CONTEXT);
+ expect(Inner.prototype.render).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {}, CONTEXT);
CONTEXT.foo = 'bar';
render(<Outer {...PROPS} />, scratch, scratch.lastChild);
expect(Outer.prototype.getChildContext).to.have.been.calledTwice;
- expect(Inner.prototype.shouldComponentUpdate).to.have.been.calledOnce.and.calledWith(PROPS, {}, CONTEXT);
- expect(Inner.prototype.componentWillReceiveProps).to.have.been.calledWith(PROPS, CONTEXT);
- expect(Inner.prototype.componentWillUpdate).to.have.been.calledWith(PROPS, {});
- expect(Inner.prototype.componentDidUpdate).to.have.been.calledWith({}, {});
- expect(Inner.prototype.render).to.have.been.calledWith(PROPS, {}, CONTEXT);
+ let props = { children: CHILDREN_MATCHER, ...PROPS };
+ expect(Inner.prototype.shouldComponentUpdate).to.have.been.calledOnce.and.calledWith(props, {}, CONTEXT);
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.calledWith(props, CONTEXT);
+ expect(Inner.prototype.componentWillUpdate).to.have.been.calledWith(props, {});
+ expect(Inner.prototype.componentDidUpdate).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {});
+ expect(Inner.prototype.render).to.have.been.calledWith(props, {}, CONTEXT);
// make sure render() could make use of context.a
expect(Inner.prototype.render).to.have.returned(sinon.match({ children:['a'] }));
@@ -164,7 +168,7 @@ describe('context', () => {
render(<Outer />, scratch);
- expect(Inner.prototype.render).to.have.been.calledWith({}, {}, { outerContext });
- expect(InnerMost.prototype.render).to.have.been.calledWith({}, {}, { outerContext, innerContext });
+ expect(Inner.prototype.render).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {}, { outerContext });
+ expect(InnerMost.prototype.render).to.have.been.calledWith({ children: CHILDREN_MATCHER }, {}, { outerContext, innerContext });
});
});
diff --git a/thirdparty/preact/test/browser/devtools.js b/thirdparty/preact/test/browser/devtools.js
new file mode 100644
index 000000000..12c0e3369
--- /dev/null
+++ b/thirdparty/preact/test/browser/devtools.js
@@ -0,0 +1,234 @@
+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);
+ });
+});
diff --git a/thirdparty/preact/test/browser/lifecycle.js b/thirdparty/preact/test/browser/lifecycle.js
index d6204ca8f..4deb92163 100644
--- a/thirdparty/preact/test/browser/lifecycle.js
+++ b/thirdparty/preact/test/browser/lifecycle.js
@@ -3,6 +3,8 @@ import { h, render, rerender, Component } from '../../src/preact';
let spyAll = obj => Object.keys(obj).forEach( key => sinon.spy(obj,key) );
+const EMPTY_CHILDREN = [];
+
describe('Lifecycle methods', () => {
let scratch;
@@ -50,7 +52,7 @@ describe('Lifecycle methods', () => {
}
class Inner extends Component {
componentWillUpdate(nextProps, nextState) {
- expect(nextProps).to.be.deep.equal({i: 1});
+ expect(nextProps).to.be.deep.equal({ children:EMPTY_CHILDREN, i: 1 });
expect(nextState).to.be.deep.equal({});
}
render() {
diff --git a/thirdparty/preact/test/browser/linked-state.js b/thirdparty/preact/test/browser/linked-state.js
index 1ca84cdc6..03db2a7b8 100644
--- a/thirdparty/preact/test/browser/linked-state.js
+++ b/thirdparty/preact/test/browser/linked-state.js
@@ -26,7 +26,10 @@ describe('linked-state', () => {
element.type= 'text';
element.value = 'newValue';
- linkFunction({ currentTarget: element });
+ linkFunction({
+ currentTarget: element,
+ target: element
+ });
expect(TestComponent.prototype.setState).to.have.been.calledOnce;
expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': 'newValue'});
@@ -42,7 +45,10 @@ describe('linked-state', () => {
checkboxElement.type= 'checkbox';
checkboxElement.checked = true;
- linkFunction({ currentTarget: checkboxElement });
+ linkFunction({
+ currentTarget: checkboxElement,
+ target: checkboxElement
+ });
expect(TestComponent.prototype.setState).to.have.been.calledOnce;
expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': true});
@@ -53,7 +59,10 @@ describe('linked-state', () => {
radioElement.type= 'radio';
radioElement.checked = true;
- linkFunction({ currentTarget: radioElement });
+ linkFunction({
+ currentTarget: radioElement,
+ target: radioElement
+ });
expect(TestComponent.prototype.setState).to.have.been.calledOnce;
expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': true});
@@ -66,7 +75,10 @@ describe('linked-state', () => {
element.type= 'text';
element.value = 'newValue';
- linkFunction({ currentTarget: element });
+ linkFunction({
+ currentTarget: element,
+ target: element
+ });
expect(TestComponent.prototype.setState).to.have.been.calledOnce;
expect(TestComponent.prototype.setState).to.have.been.calledWith({nested: {state: {key: 'newValue'}}});
diff --git a/thirdparty/preact/test/browser/refs.js b/thirdparty/preact/test/browser/refs.js
index 89678b76e..337a9717b 100644
--- a/thirdparty/preact/test/browser/refs.js
+++ b/thirdparty/preact/test/browser/refs.js
@@ -200,8 +200,8 @@ describe('refs', () => {
</div>
), scratch);
- expect(Foo.prototype.render).to.have.been.calledWithExactly({ a:'a' }, { }, { });
- expect(Bar).to.have.been.calledWithExactly({ b:'b', ref:bar }, { });
+ expect(Foo.prototype.render).to.have.been.calledWithMatch({ ref:sinon.match.falsy, a:'a' }, { }, { });
+ expect(Bar).to.have.been.calledWithMatch({ b:'b', ref:bar }, { });
});
// Test for #232
@@ -284,4 +284,22 @@ describe('refs', () => {
expect(inst.handleMount.firstCall).to.have.been.calledWith(null);
expect(inst.handleMount.secondCall).to.have.been.calledWith(scratch.querySelector('#div'));
});
+
+
+ it('should add refs to components representing DOM nodes with no attributes if they have been pre-rendered', () => {
+ // Simulate pre-render
+ let parent = document.createElement('div');
+ let child = document.createElement('div');
+ parent.appendChild(child);
+ scratch.appendChild(parent); // scratch contains: <div><div></div></div>
+
+ let ref = spy('ref');
+
+ function Wrapper() {
+ return <div></div>;
+ }
+
+ render(<div><Wrapper ref={ref} /></div>, scratch, scratch.firstChild);
+ expect(ref).to.have.been.calledOnce.and.calledWith(scratch.firstChild.firstChild);
+ });
});
diff --git a/thirdparty/preact/test/browser/spec.js b/thirdparty/preact/test/browser/spec.js
index eb48151f0..d33cdb93f 100644
--- a/thirdparty/preact/test/browser/spec.js
+++ b/thirdparty/preact/test/browser/spec.js
@@ -1,6 +1,8 @@
import { h, render, rerender, Component } from '../../src/preact';
/** @jsx h */
+const EMPTY_CHILDREN = [];
+
describe('Component spec', () => {
let scratch;
@@ -24,6 +26,7 @@ describe('Component spec', () => {
constructor(props, context) {
super(props, context);
expect(props).to.be.deep.equal({
+ children: EMPTY_CHILDREN,
fieldA: 1, fieldB: 2,
fieldC: 1, fieldD: 2
});
@@ -81,14 +84,14 @@ describe('Component spec', () => {
fieldC: 1, fieldD: 2
};
- expect(proto.ctor).to.have.been.calledWith(PROPS1);
- expect(proto.render).to.have.been.calledWith(PROPS1);
+ expect(proto.ctor).to.have.been.calledWithMatch(PROPS1);
+ expect(proto.render).to.have.been.calledWithMatch(PROPS1);
rerender();
// expect(proto.ctor).to.have.been.calledWith(PROPS2);
- expect(proto.componentWillReceiveProps).to.have.been.calledWith(PROPS2);
- expect(proto.render).to.have.been.calledWith(PROPS2);
+ expect(proto.componentWillReceiveProps).to.have.been.calledWithMatch(PROPS2);
+ expect(proto.render).to.have.been.calledWithMatch(PROPS2);
});
// @TODO: migrate this to preact-compat