diff options
Diffstat (limited to 'thirdparty/preact/test/browser')
-rw-r--r-- | thirdparty/preact/test/browser/components.js | 712 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/context.js | 174 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/devtools.js | 234 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/keys.js | 85 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/lifecycle.js | 495 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/linked-state.js | 110 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/performance.js | 245 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/refs.js | 305 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/render.js | 439 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/spec.js | 127 | ||||
-rw-r--r-- | thirdparty/preact/test/browser/svg.js | 112 |
11 files changed, 0 insertions, 3038 deletions
diff --git a/thirdparty/preact/test/browser/components.js b/thirdparty/preact/test/browser/components.js deleted file mode 100644 index 9ef43cb1c..000000000 --- a/thirdparty/preact/test/browser/components.js +++ /dev/null @@ -1,712 +0,0 @@ -import { h, render, rerender, Component } from '../../src/preact'; -/** @jsx h */ - -let spyAll = obj => Object.keys(obj).forEach( key => sinon.spy(obj,key) ); - -function getAttributes(node) { - let attrs = {}; - if (node.attributes) { - for (let i=node.attributes.length; i--; ) { - attrs[node.attributes[i].name] = node.attributes[i].value; - } - } - return attrs; -} - -// hacky normalization of attribute order across browsers. -function sortAttributes(html) { - return html.replace(/<([a-z0-9-]+)((?:\s[a-z0-9:_.-]+=".*?")+)((?:\s*\/)?>)/gi, (s, pre, attrs, after) => { - let list = attrs.match(/\s[a-z0-9:_.-]+=".*?"/gi).sort( (a, b) => a>b ? 1 : -1 ); - if (~after.indexOf('/')) after = '></'+pre+'>'; - return '<' + pre + list.join('') + after; - }); -} - -const Empty = () => null; - -describe('Components', () => { - let scratch; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - let c = scratch.firstElementChild; - if (c) render(<Empty />, scratch, c); - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - it('should render components', () => { - class C1 extends Component { - render() { - return <div>C1</div>; - } - } - sinon.spy(C1.prototype, 'render'); - render(<C1 />, scratch); - - expect(C1.prototype.render) - .to.have.been.calledOnce - .and.to.have.been.calledWithMatch({}, {}) - .and.to.have.returned(sinon.match({ nodeName:'div' })); - - expect(scratch.innerHTML).to.equal('<div>C1</div>'); - }); - - - it('should render functional components', () => { - const PROPS = { foo:'bar', onBaz:()=>{} }; - - const C3 = sinon.spy( props => <div {...props} /> ); - - render(<C3 {...PROPS} />, scratch); - - expect(C3) - .to.have.been.calledOnce - .and.to.have.been.calledWithMatch(PROPS) - .and.to.have.returned(sinon.match({ - nodeName: 'div', - attributes: PROPS - })); - - expect(scratch.innerHTML).to.equal('<div foo="bar"></div>'); - }); - - - it('should render components with props', () => { - const PROPS = { foo:'bar', onBaz:()=>{} }; - let constructorProps; - - class C2 extends Component { - constructor(props) { - super(props); - constructorProps = props; - } - render(props) { - return <div {...props} />; - } - } - sinon.spy(C2.prototype, 'render'); - - render(<C2 {...PROPS} />, scratch); - - expect(constructorProps).to.deep.equal(PROPS); - - expect(C2.prototype.render) - .to.have.been.calledOnce - .and.to.have.been.calledWithMatch(PROPS, {}) - .and.to.have.returned(sinon.match({ - nodeName: 'div', - attributes: PROPS - })); - - expect(scratch.innerHTML).to.equal('<div foo="bar"></div>'); - }); - - - // Test for Issue #73 - it('should remove orphaned elements replaced by Components', () => { - class Comp extends Component { - render() { - return <span>span in a component</span>; - } - } - - let root; - function test(content) { - root = render(content, scratch, root); - } - - test(<Comp />); - test(<div>just a div</div>); - test(<Comp />); - - expect(scratch.innerHTML).to.equal('<span>span in a component</span>'); - }); - - - // Test for Issue #176 - it('should remove children when root changes to text node', () => { - let comp; - - class Comp extends Component { - render(_, { alt }) { - return alt ? 'asdf' : <div>test</div>; - } - } - - render(<Comp ref={c=>comp=c} />, scratch); - - comp.setState({ alt:true }); - comp.forceUpdate(); - expect(scratch.innerHTML, 'switching to textnode').to.equal('asdf'); - - comp.setState({ alt:false }); - comp.forceUpdate(); - expect(scratch.innerHTML, 'switching to element').to.equal('<div>test</div>'); - - comp.setState({ alt:true }); - comp.forceUpdate(); - expect(scratch.innerHTML, 'switching to textnode 2').to.equal('asdf'); - }); - - - describe('props.children', () => { - it('should support passing children as a prop', () => { - const Foo = props => <div {...props} />; - - render(<Foo a="b" children={[ - <span class="bar">bar</span>, - '123', - 456 - ]} />, scratch); - - expect(scratch.innerHTML).to.equal('<div a="b"><span class="bar">bar</span>123456</div>'); - }); - - it('should be ignored when explicit children exist', () => { - const Foo = props => <div {...props}>a</div>; - - render(<Foo children={'b'} />, scratch); - - expect(scratch.innerHTML).to.equal('<div>a</div>'); - }); - }); - - - describe('High-Order Components', () => { - it('should render nested functional components', () => { - const PROPS = { foo:'bar', onBaz:()=>{} }; - - const Outer = sinon.spy( - props => <Inner {...props} /> - ); - - const Inner = sinon.spy( - props => <div {...props}>inner</div> - ); - - render(<Outer {...PROPS} />, scratch); - - expect(Outer) - .to.have.been.calledOnce - .and.to.have.been.calledWithMatch(PROPS) - .and.to.have.returned(sinon.match({ - nodeName: Inner, - attributes: PROPS - })); - - expect(Inner) - .to.have.been.calledOnce - .and.to.have.been.calledWithMatch(PROPS) - .and.to.have.returned(sinon.match({ - nodeName: 'div', - attributes: PROPS, - children: ['inner'] - })); - - expect(scratch.innerHTML).to.equal('<div foo="bar">inner</div>'); - }); - - it('should re-render nested functional components', () => { - let doRender = null; - class Outer extends Component { - componentDidMount() { - let i = 1; - doRender = () => this.setState({ i: ++i }); - } - componentWillUnmount() {} - render(props, { i }) { - return <Inner i={i} {...props} />; - } - } - sinon.spy(Outer.prototype, 'render'); - sinon.spy(Outer.prototype, 'componentWillUnmount'); - - let j = 0; - const Inner = sinon.spy( - props => <div j={ ++j } {...props}>inner</div> - ); - - render(<Outer foo="bar" />, scratch); - - // update & flush - doRender(); - rerender(); - - expect(Outer.prototype.componentWillUnmount) - .not.to.have.been.called; - - expect(Inner).to.have.been.calledTwice; - - expect(Inner.secondCall) - .to.have.been.calledWithMatch({ foo:'bar', i:2 }) - .and.to.have.returned(sinon.match({ - attributes: { - j: 2, - i: 2, - foo: 'bar' - } - })); - - expect(getAttributes(scratch.firstElementChild)).to.eql({ - j: '2', - i: '2', - foo: 'bar' - }); - - // update & flush - doRender(); - rerender(); - - expect(Inner).to.have.been.calledThrice; - - expect(Inner.thirdCall) - .to.have.been.calledWithMatch({ foo:'bar', i:3 }) - .and.to.have.returned(sinon.match({ - attributes: { - j: 3, - i: 3, - foo: 'bar' - } - })); - - expect(getAttributes(scratch.firstElementChild)).to.eql({ - j: '3', - i: '3', - foo: 'bar' - }); - }); - - it('should re-render nested components', () => { - let doRender = null, - alt = false; - - class Outer extends Component { - componentDidMount() { - let i = 1; - doRender = () => this.setState({ i: ++i }); - } - componentWillUnmount() {} - render(props, { i }) { - if (alt) return <div is-alt />; - return <Inner i={i} {...props} />; - } - } - sinon.spy(Outer.prototype, 'render'); - sinon.spy(Outer.prototype, 'componentDidMount'); - sinon.spy(Outer.prototype, 'componentWillUnmount'); - - let j = 0; - class Inner extends Component { - constructor(...args) { - super(); - this._constructor(...args); - } - _constructor() {} - componentWillMount() {} - componentDidMount() {} - componentWillUnmount() {} - componentDidUnmount() {} - render(props) { - return <div j={ ++j } {...props}>inner</div>; - } - } - sinon.spy(Inner.prototype, '_constructor'); - sinon.spy(Inner.prototype, 'render'); - sinon.spy(Inner.prototype, 'componentWillMount'); - sinon.spy(Inner.prototype, 'componentDidMount'); - sinon.spy(Inner.prototype, 'componentDidUnmount'); - sinon.spy(Inner.prototype, 'componentWillUnmount'); - - render(<Outer foo="bar" />, scratch); - - expect(Outer.prototype.componentDidMount).to.have.been.calledOnce; - - // update & flush - doRender(); - rerender(); - - expect(Outer.prototype.componentWillUnmount).not.to.have.been.called; - - expect(Inner.prototype._constructor).to.have.been.calledOnce; - expect(Inner.prototype.componentWillUnmount).not.to.have.been.called; - expect(Inner.prototype.componentDidUnmount).not.to.have.been.called; - expect(Inner.prototype.componentWillMount).to.have.been.calledOnce; - expect(Inner.prototype.componentDidMount).to.have.been.calledOnce; - expect(Inner.prototype.render).to.have.been.calledTwice; - - expect(Inner.prototype.render.secondCall) - .to.have.been.calledWithMatch({ foo:'bar', i:2 }) - .and.to.have.returned(sinon.match({ - attributes: { - j: 2, - i: 2, - foo: 'bar' - } - })); - - expect(getAttributes(scratch.firstElementChild)).to.eql({ - j: '2', - i: '2', - foo: 'bar' - }); - - expect(sortAttributes(scratch.innerHTML)).to.equal(sortAttributes('<div foo="bar" j="2" i="2">inner</div>')); - - // update & flush - doRender(); - rerender(); - - expect(Inner.prototype.componentWillUnmount).not.to.have.been.called; - expect(Inner.prototype.componentDidUnmount).not.to.have.been.called; - expect(Inner.prototype.componentWillMount).to.have.been.calledOnce; - expect(Inner.prototype.componentDidMount).to.have.been.calledOnce; - expect(Inner.prototype.render).to.have.been.calledThrice; - - expect(Inner.prototype.render.thirdCall) - .to.have.been.calledWithMatch({ foo:'bar', i:3 }) - .and.to.have.returned(sinon.match({ - attributes: { - j: 3, - i: 3, - foo: 'bar' - } - })); - - expect(getAttributes(scratch.firstElementChild)).to.eql({ - j: '3', - i: '3', - foo: 'bar' - }); - - - // update & flush - alt = true; - doRender(); - rerender(); - - expect(Inner.prototype.componentWillUnmount).to.have.been.calledOnce; - expect(Inner.prototype.componentDidUnmount).to.have.been.calledOnce; - - expect(scratch.innerHTML).to.equal('<div is-alt="true"></div>'); - - // update & flush - alt = false; - doRender(); - rerender(); - - expect(sortAttributes(scratch.innerHTML)).to.equal(sortAttributes('<div foo="bar" j="4" i="5">inner</div>')); - }); - - it('should resolve intermediary functional component', () => { - let ctx = {}; - class Root extends Component { - getChildContext() { - return { ctx }; - } - render() { - return <Func />; - } - } - const Func = sinon.spy( () => <Inner /> ); - class Inner extends Component { - componentWillMount() {} - componentDidMount() {} - componentWillUnmount() {} - componentDidUnmount() {} - render() { - return <div>inner</div>; - } - } - - spyAll(Inner.prototype); - - let root = render(<Root />, scratch); - - expect(Inner.prototype.componentWillMount).to.have.been.calledOnce; - expect(Inner.prototype.componentDidMount).to.have.been.calledOnce; - expect(Inner.prototype.componentWillMount).to.have.been.calledBefore(Inner.prototype.componentDidMount); - - render(<asdf />, scratch, root); - - expect(Inner.prototype.componentWillUnmount).to.have.been.calledOnce; - expect(Inner.prototype.componentDidUnmount).to.have.been.calledOnce; - expect(Inner.prototype.componentWillUnmount).to.have.been.calledBefore(Inner.prototype.componentDidUnmount); - }); - - it('should unmount children of high-order components without unmounting parent', () => { - let outer, inner2, counter=0; - - class Outer extends Component { - constructor(props, context) { - super(props, context); - outer = this; - this.state = { - child: this.props.child - }; - } - componentWillUnmount(){} - componentDidUnmount(){} - componentWillMount(){} - componentDidMount(){} - render(_, { child:C }) { - return <C />; - } - } - spyAll(Outer.prototype); - - class Inner extends Component { - componentWillUnmount(){} - componentDidUnmount(){} - componentWillMount(){} - componentDidMount(){} - render() { - return h('element'+(++counter)); - } - } - spyAll(Inner.prototype); - - class Inner2 extends Component { - constructor(props, context) { - super(props, context); - inner2 = this; - } - componentWillUnmount(){} - componentDidUnmount(){} - componentWillMount(){} - componentDidMount(){} - render() { - return h('element'+(++counter)); - } - } - spyAll(Inner2.prototype); - - render(<Outer child={Inner} />, scratch); - - // outer should only have been mounted once - expect(Outer.prototype.componentWillMount, 'outer initial').to.have.been.calledOnce; - expect(Outer.prototype.componentDidMount, 'outer initial').to.have.been.calledOnce; - expect(Outer.prototype.componentWillUnmount, 'outer initial').not.to.have.been.called; - expect(Outer.prototype.componentDidUnmount, 'outer initial').not.to.have.been.called; - - // inner should only have been mounted once - expect(Inner.prototype.componentWillMount, 'inner initial').to.have.been.calledOnce; - expect(Inner.prototype.componentDidMount, 'inner initial').to.have.been.calledOnce; - expect(Inner.prototype.componentWillUnmount, 'inner initial').not.to.have.been.called; - expect(Inner.prototype.componentDidUnmount, 'inner initial').not.to.have.been.called; - - outer.setState({ child:Inner2 }); - outer.forceUpdate(); - - expect(Inner2.prototype.render).to.have.been.calledOnce; - - // outer should still only have been mounted once - expect(Outer.prototype.componentWillMount, 'outer swap').to.have.been.calledOnce; - expect(Outer.prototype.componentDidMount, 'outer swap').to.have.been.calledOnce; - expect(Outer.prototype.componentWillUnmount, 'outer swap').not.to.have.been.called; - expect(Outer.prototype.componentDidUnmount, 'outer swap').not.to.have.been.called; - - // inner should only have been mounted once - expect(Inner2.prototype.componentWillMount, 'inner2 swap').to.have.been.calledOnce; - expect(Inner2.prototype.componentDidMount, 'inner2 swap').to.have.been.calledOnce; - expect(Inner2.prototype.componentWillUnmount, 'inner2 swap').not.to.have.been.called; - expect(Inner2.prototype.componentDidUnmount, 'inner2 swap').not.to.have.been.called; - - inner2.forceUpdate(); - - expect(Inner2.prototype.render, 'inner2 update').to.have.been.calledTwice; - expect(Inner2.prototype.componentWillMount, 'inner2 update').to.have.been.calledOnce; - expect(Inner2.prototype.componentDidMount, 'inner2 update').to.have.been.calledOnce; - expect(Inner2.prototype.componentWillUnmount, 'inner2 update').not.to.have.been.called; - expect(Inner2.prototype.componentDidUnmount, 'inner2 update').not.to.have.been.called; - }); - - it('should remount when swapping between HOC child types', () => { - class Outer extends Component { - render({ child: Child }) { - return <Child />; - } - } - - class Inner extends Component { - componentWillMount() {} - componentWillUnmount() {} - render() { - return <div class="inner">foo</div>; - } - } - spyAll(Inner.prototype); - - const InnerFunc = () => ( - <div class="inner-func">bar</div> - ); - - let root = render(<Outer child={Inner} />, scratch, root); - - expect(Inner.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce; - expect(Inner.prototype.componentWillUnmount, 'initial mount').not.to.have.been.called; - - Inner.prototype.componentWillMount.reset(); - root = render(<Outer child={InnerFunc} />, scratch, root); - - expect(Inner.prototype.componentWillMount, 'unmount').not.to.have.been.called; - expect(Inner.prototype.componentWillUnmount, 'unmount').to.have.been.calledOnce; - - Inner.prototype.componentWillUnmount.reset(); - root = render(<Outer child={Inner} />, scratch, root); - - expect(Inner.prototype.componentWillMount, 'remount').to.have.been.calledOnce; - expect(Inner.prototype.componentWillUnmount, 'remount').not.to.have.been.called; - }); - }); - - describe('Component Nesting', () => { - let useIntermediary = false; - - let createComponent = (Intermediary) => { - class C extends Component { - componentWillMount() {} - componentDidUnmount() {} - render({ children }) { - if (!useIntermediary) return children[0]; - let I = useIntermediary===true ? Intermediary : useIntermediary; - return <I>{children}</I>; - } - } - spyAll(C.prototype); - return C; - }; - - let createFunction = () => sinon.spy( ({ children }) => children[0] ); - - let root; - let rndr = n => root = render(n, scratch, root); - - let F1 = createFunction(); - let F2 = createFunction(); - let F3 = createFunction(); - - let C1 = createComponent(F1); - let C2 = createComponent(F2); - let C3 = createComponent(F3); - - let reset = () => [C1, C2, C3].reduce( - (acc, c) => acc.concat( Object.keys(c.prototype).map(key => c.prototype[key]) ), - [F1, F2, F3] - ).forEach( c => c.reset && c.reset() ); - - - it('should handle lifecycle for no intermediary in component tree', () => { - reset(); - rndr(<C1><C2><C3>Some Text</C3></C2></C1>); - - expect(C1.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce; - expect(C2.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce; - - reset(); - rndr(<C1><C2>Some Text</C2></C1>); - - expect(C1.prototype.componentWillMount, 'unmount innermost, C1').not.to.have.been.called; - expect(C2.prototype.componentWillMount, 'unmount innermost, C2').not.to.have.been.called; - expect(C3.prototype.componentDidUnmount, 'unmount innermost, C3').to.have.been.calledOnce; - - reset(); - rndr(<C1><C3>Some Text</C3></C1>); - - expect(C1.prototype.componentWillMount, 'swap innermost').not.to.have.been.called; - expect(C2.prototype.componentDidUnmount, 'swap innermost').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'swap innermost').to.have.been.calledOnce; - - reset(); - rndr(<C1><C2><C3>Some Text</C3></C2></C1>); - - expect(C1.prototype.componentDidUnmount, 'inject between, C1').not.to.have.been.called; - expect(C1.prototype.componentWillMount, 'inject between, C1').not.to.have.been.called; - expect(C2.prototype.componentWillMount, 'inject between, C2').to.have.been.calledOnce; - expect(C3.prototype.componentDidUnmount, 'inject between, C3').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'inject between, C3').to.have.been.calledOnce; - }); - - - it('should handle lifecycle for nested intermediary functional components', () => { - useIntermediary = true; - - rndr(<div />); - reset(); - rndr(<C1><C2><C3>Some Text</C3></C2></C1>); - - expect(C1.prototype.componentWillMount, 'initial mount w/ intermediary fn, C1').to.have.been.calledOnce; - expect(C2.prototype.componentWillMount, 'initial mount w/ intermediary fn, C2').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'initial mount w/ intermediary fn, C3').to.have.been.calledOnce; - - reset(); - rndr(<C1><C2>Some Text</C2></C1>); - - expect(C1.prototype.componentWillMount, 'unmount innermost w/ intermediary fn, C1').not.to.have.been.called; - expect(C2.prototype.componentWillMount, 'unmount innermost w/ intermediary fn, C2').not.to.have.been.called; - expect(C3.prototype.componentDidUnmount, 'unmount innermost w/ intermediary fn, C3').to.have.been.calledOnce; - - reset(); - rndr(<C1><C3>Some Text</C3></C1>); - - expect(C1.prototype.componentWillMount, 'swap innermost w/ intermediary fn').not.to.have.been.called; - expect(C2.prototype.componentDidUnmount, 'swap innermost w/ intermediary fn').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'swap innermost w/ intermediary fn').to.have.been.calledOnce; - - reset(); - rndr(<C1><C2><C3>Some Text</C3></C2></C1>); - - expect(C1.prototype.componentDidUnmount, 'inject between, C1 w/ intermediary fn').not.to.have.been.called; - expect(C1.prototype.componentWillMount, 'inject between, C1 w/ intermediary fn').not.to.have.been.called; - expect(C2.prototype.componentWillMount, 'inject between, C2 w/ intermediary fn').to.have.been.calledOnce; - expect(C3.prototype.componentDidUnmount, 'inject between, C3 w/ intermediary fn').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'inject between, C3 w/ intermediary fn').to.have.been.calledOnce; - }); - - - it('should handle lifecycle for nested intermediary elements', () => { - useIntermediary = 'div'; - - rndr(<div />); - reset(); - rndr(<C1><C2><C3>Some Text</C3></C2></C1>); - - expect(C1.prototype.componentWillMount, 'initial mount w/ intermediary div, C1').to.have.been.calledOnce; - expect(C2.prototype.componentWillMount, 'initial mount w/ intermediary div, C2').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'initial mount w/ intermediary div, C3').to.have.been.calledOnce; - - reset(); - rndr(<C1><C2>Some Text</C2></C1>); - - 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; - 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(); - rndr(<C1><C3>Some Text</C3></C1>); - - expect(C1.prototype.componentWillMount, 'swap innermost w/ intermediary div').not.to.have.been.called; - expect(C2.prototype.componentDidUnmount, 'swap innermost w/ intermediary div').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'swap innermost w/ intermediary div').to.have.been.calledOnce; - - reset(); - rndr(<C1><C2><C3>Some Text</C3></C2></C1>); - - expect(C1.prototype.componentDidUnmount, 'inject between, C1 w/ intermediary div').not.to.have.been.called; - expect(C1.prototype.componentWillMount, 'inject between, C1 w/ intermediary div').not.to.have.been.called; - expect(C2.prototype.componentWillMount, 'inject between, C2 w/ intermediary div').to.have.been.calledOnce; - expect(C3.prototype.componentDidUnmount, 'inject between, C3 w/ intermediary div').to.have.been.calledOnce; - expect(C3.prototype.componentWillMount, 'inject between, C3 w/ intermediary div').to.have.been.calledOnce; - }); - }); -}); diff --git a/thirdparty/preact/test/browser/context.js b/thirdparty/preact/test/browser/context.js deleted file mode 100644 index ed5f81471..000000000 --- a/thirdparty/preact/test/browser/context.js +++ /dev/null @@ -1,174 +0,0 @@ -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; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - it('should pass context to grandchildren', () => { - const CONTEXT = { a:'a' }; - const PROPS = { b:'b' }; - // let inner; - - class Outer extends Component { - getChildContext() { - return CONTEXT; - } - render(props) { - return <div><Inner {...props} /></div>; - } - } - sinon.spy(Outer.prototype, 'getChildContext'); - - class Inner extends Component { - // constructor() { - // super(); - // inner = this; - // } - shouldComponentUpdate() { return true; } - componentWillReceiveProps() {} - componentWillUpdate() {} - componentDidUpdate() {} - render(props, state, context) { - return <div>{ context && context.a }</div>; - } - } - sinon.spy(Inner.prototype, 'shouldComponentUpdate'); - sinon.spy(Inner.prototype, 'componentWillReceiveProps'); - sinon.spy(Inner.prototype, 'componentWillUpdate'); - sinon.spy(Inner.prototype, 'componentDidUpdate'); - sinon.spy(Inner.prototype, 'render'); - - render(<Outer />, scratch, scratch.lastChild); - - expect(Outer.prototype.getChildContext).to.have.been.calledOnce; - - // initial render does not invoke anything but render(): - 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; - - 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: - * Newly created context objects are *not* currently cloned. - * This test checks that they *are* cloned. - */ - // Inner.prototype.render.reset(); - // CONTEXT.foo = 'baz'; - // inner.forceUpdate(); - // expect(Inner.prototype.render).to.have.been.calledWith(PROPS, {}, { a:'a', foo:'bar' }); - }); - - it('should pass context to direct children', () => { - const CONTEXT = { a:'a' }; - const PROPS = { b:'b' }; - - class Outer extends Component { - getChildContext() { - return CONTEXT; - } - render(props) { - return <Inner {...props} />; - } - } - sinon.spy(Outer.prototype, 'getChildContext'); - - class Inner extends Component { - shouldComponentUpdate() { return true; } - componentWillReceiveProps() {} - componentWillUpdate() {} - componentDidUpdate() {} - render(props, state, context) { - return <div>{ context && context.a }</div>; - } - } - sinon.spy(Inner.prototype, 'shouldComponentUpdate'); - sinon.spy(Inner.prototype, 'componentWillReceiveProps'); - sinon.spy(Inner.prototype, 'componentWillUpdate'); - sinon.spy(Inner.prototype, 'componentDidUpdate'); - sinon.spy(Inner.prototype, 'render'); - - render(<Outer />, scratch, scratch.lastChild); - - expect(Outer.prototype.getChildContext).to.have.been.calledOnce; - - // initial render does not invoke anything but render(): - 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; - - 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'] })); - }); - - it('should preserve existing context properties when creating child contexts', () => { - let outerContext = { outer:true }, - innerContext = { inner:true }; - class Outer extends Component { - getChildContext() { - return { outerContext }; - } - render() { - return <div><Inner /></div>; - } - } - - class Inner extends Component { - getChildContext() { - return { innerContext }; - } - render() { - return <InnerMost />; - } - } - - class InnerMost extends Component { - render() { - return <strong>test</strong>; - } - } - - sinon.spy(Inner.prototype, 'render'); - sinon.spy(InnerMost.prototype, 'render'); - - render(<Outer />, scratch); - - 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 deleted file mode 100644 index 12c0e3369..000000000 --- a/thirdparty/preact/test/browser/devtools.js +++ /dev/null @@ -1,234 +0,0 @@ -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/keys.js b/thirdparty/preact/test/browser/keys.js deleted file mode 100644 index e0a6b9ae8..000000000 --- a/thirdparty/preact/test/browser/keys.js +++ /dev/null @@ -1,85 +0,0 @@ -import { h, Component, render } from '../../src/preact'; -/** @jsx h */ - -describe('keys', () => { - let scratch; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - // See developit/preact-compat#21 - it('should remove orphaned keyed nodes', () => { - let root = render(( - <div> - <div>1</div> - <li key="a">a</li> - </div> - ), scratch); - - root = render(( - <div> - <div>2</div> - <li key="b">b</li> - </div> - ), scratch, root); - - expect(scratch.innerHTML).to.equal('<div><div>2</div><li>b</li></div>'); - }); - - it('should set VNode#key property', () => { - expect(<div />).to.have.property('key').that.is.empty; - expect(<div a="a" />).to.have.property('key').that.is.empty; - expect(<div key="1" />).to.have.property('key', '1'); - }); - - it('should remove keyed nodes (#232)', () => { - class App extends Component { - componentDidMount() { - setTimeout(() => this.setState({opened: true,loading: true}), 10); - setTimeout(() => this.setState({opened: true,loading: false}), 20); - } - - render({ opened, loading }) { - return ( - <BusyIndicator id="app" busy={loading}> - <div>This div needs to be here for this to break</div> - { opened && !loading && <div>{[]}</div> } - </BusyIndicator> - ); - } - } - - class BusyIndicator extends Component { - render({ children, busy }) { - return <div class={busy ? "busy" : ""}> - { children && children.length ? children : <div class="busy-placeholder"></div> } - <div class="indicator"> - <div>indicator</div> - <div>indicator</div> - <div>indicator</div> - </div> - </div>; - } - } - - let root; - - root = render(<App />, scratch, root); - root = render(<App opened loading />, scratch, root); - root = render(<App opened />, scratch, root); - - let html = String(root.innerHTML).replace(/ class=""/g, ''); - expect(html).to.equal('<div>This div needs to be here for this to break</div><div></div><div class="indicator"><div>indicator</div><div>indicator</div><div>indicator</div></div>'); - }); -}); diff --git a/thirdparty/preact/test/browser/lifecycle.js b/thirdparty/preact/test/browser/lifecycle.js deleted file mode 100644 index 4deb92163..000000000 --- a/thirdparty/preact/test/browser/lifecycle.js +++ /dev/null @@ -1,495 +0,0 @@ -import { h, render, rerender, Component } from '../../src/preact'; -/** @jsx h */ - -let spyAll = obj => Object.keys(obj).forEach( key => sinon.spy(obj,key) ); - -const EMPTY_CHILDREN = []; - -describe('Lifecycle methods', () => { - let scratch; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - - describe('#componentWillUpdate', () => { - it('should NOT be called on initial render', () => { - class ReceivePropsComponent extends Component { - componentWillUpdate() {} - render() { - return <div />; - } - } - sinon.spy(ReceivePropsComponent.prototype, 'componentWillUpdate'); - render(<ReceivePropsComponent />, scratch); - expect(ReceivePropsComponent.prototype.componentWillUpdate).not.to.have.been.called; - }); - - it('should be called when rerender with new props from parent', () => { - let doRender; - class Outer extends Component { - constructor(p, c) { - super(p, c); - this.state = { i: 0 }; - } - componentDidMount() { - doRender = () => this.setState({ i: this.state.i + 1 }); - } - render(props, { i }) { - return <Inner i={i} {...props} />; - } - } - class Inner extends Component { - componentWillUpdate(nextProps, nextState) { - expect(nextProps).to.be.deep.equal({ children:EMPTY_CHILDREN, i: 1 }); - expect(nextState).to.be.deep.equal({}); - } - render() { - return <div />; - } - } - sinon.spy(Inner.prototype, 'componentWillUpdate'); - sinon.spy(Outer.prototype, 'componentDidMount'); - - // Initial render - render(<Outer />, scratch); - expect(Inner.prototype.componentWillUpdate).not.to.have.been.called; - - // Rerender inner with new props - doRender(); - rerender(); - expect(Inner.prototype.componentWillUpdate).to.have.been.called; - }); - - it('should be called on new state', () => { - let doRender; - class ReceivePropsComponent extends Component { - componentWillUpdate() {} - componentDidMount() { - doRender = () => this.setState({ i: this.state.i + 1 }); - } - render() { - return <div />; - } - } - sinon.spy(ReceivePropsComponent.prototype, 'componentWillUpdate'); - render(<ReceivePropsComponent />, scratch); - expect(ReceivePropsComponent.prototype.componentWillUpdate).not.to.have.been.called; - - doRender(); - rerender(); - expect(ReceivePropsComponent.prototype.componentWillUpdate).to.have.been.called; - }); - }); - - describe('#componentWillReceiveProps', () => { - it('should NOT be called on initial render', () => { - class ReceivePropsComponent extends Component { - componentWillReceiveProps() {} - render() { - return <div />; - } - } - sinon.spy(ReceivePropsComponent.prototype, 'componentWillReceiveProps'); - render(<ReceivePropsComponent />, scratch); - expect(ReceivePropsComponent.prototype.componentWillReceiveProps).not.to.have.been.called; - }); - - it('should be called when rerender with new props from parent', () => { - let doRender; - class Outer extends Component { - constructor(p, c) { - super(p, c); - this.state = { i: 0 }; - } - componentDidMount() { - doRender = () => this.setState({ i: this.state.i + 1 }); - } - render(props, { i }) { - return <Inner i={i} {...props} />; - } - } - class Inner extends Component { - componentWillMount() { - expect(this.props.i).to.be.equal(0); - } - componentWillReceiveProps(nextProps) { - expect(nextProps.i).to.be.equal(1); - } - render() { - return <div />; - } - } - sinon.spy(Inner.prototype, 'componentWillReceiveProps'); - sinon.spy(Outer.prototype, 'componentDidMount'); - - // Initial render - render(<Outer />, scratch); - expect(Inner.prototype.componentWillReceiveProps).not.to.have.been.called; - - // Rerender inner with new props - doRender(); - rerender(); - expect(Inner.prototype.componentWillReceiveProps).to.have.been.called; - }); - - it('should be called in right execution order', () => { - let doRender; - class Outer extends Component { - constructor(p, c) { - super(p, c); - this.state = { i: 0 }; - } - componentDidMount() { - doRender = () => this.setState({ i: this.state.i + 1 }); - } - render(props, { i }) { - return <Inner i={i} {...props} />; - } - } - class Inner extends Component { - componentDidUpdate() { - expect(Inner.prototype.componentWillReceiveProps).to.have.been.called; - expect(Inner.prototype.componentWillUpdate).to.have.been.called; - } - componentWillReceiveProps() { - expect(Inner.prototype.componentWillUpdate).not.to.have.been.called; - expect(Inner.prototype.componentDidUpdate).not.to.have.been.called; - } - componentWillUpdate() { - expect(Inner.prototype.componentWillReceiveProps).to.have.been.called; - expect(Inner.prototype.componentDidUpdate).not.to.have.been.called; - } - render() { - return <div />; - } - } - sinon.spy(Inner.prototype, 'componentWillReceiveProps'); - sinon.spy(Inner.prototype, 'componentDidUpdate'); - sinon.spy(Inner.prototype, 'componentWillUpdate'); - sinon.spy(Outer.prototype, 'componentDidMount'); - - render(<Outer />, scratch); - doRender(); - rerender(); - - expect(Inner.prototype.componentWillReceiveProps).to.have.been.calledBefore(Inner.prototype.componentWillUpdate); - expect(Inner.prototype.componentWillUpdate).to.have.been.calledBefore(Inner.prototype.componentDidUpdate); - }); - }); - - - let _it = it; - describe('#constructor and component(Did|Will)(Mount|Unmount)', () => { - /* global DISABLE_FLAKEY */ - let it = DISABLE_FLAKEY ? xit : _it; - - let setState; - class Outer extends Component { - constructor(p, c) { - super(p, c); - this.state = { show:true }; - setState = s => this.setState(s); - } - render(props, { show }) { - return ( - <div> - { show && ( - <Inner {...props} /> - ) } - </div> - ); - } - } - - class LifecycleTestComponent extends Component { - constructor(p, c) { super(p, c); this._constructor(); } - _constructor() {} - componentWillMount() {} - componentDidMount() {} - componentWillUnmount() {} - componentDidUnmount() {} - render() { return <div />; } - } - - class Inner extends LifecycleTestComponent { - render() { - return ( - <div> - <InnerMost /> - </div> - ); - } - } - - class InnerMost extends LifecycleTestComponent { - render() { return <div />; } - } - - let spies = ['_constructor', 'componentWillMount', 'componentDidMount', 'componentWillUnmount', 'componentDidUnmount']; - - let verifyLifycycleMethods = (TestComponent) => { - let proto = TestComponent.prototype; - spies.forEach( s => sinon.spy(proto, s) ); - let reset = () => spies.forEach( s => proto[s].reset() ); - - it('should be invoked for components on initial render', () => { - reset(); - render(<Outer />, scratch); - expect(proto._constructor).to.have.been.called; - expect(proto.componentDidMount).to.have.been.called; - expect(proto.componentWillMount).to.have.been.calledBefore(proto.componentDidMount); - expect(proto.componentDidMount).to.have.been.called; - }); - - it('should be invoked for components on unmount', () => { - reset(); - setState({ show:false }); - rerender(); - - expect(proto.componentDidUnmount).to.have.been.called; - expect(proto.componentWillUnmount).to.have.been.calledBefore(proto.componentDidUnmount); - expect(proto.componentDidUnmount).to.have.been.called; - }); - - it('should be invoked for components on re-render', () => { - reset(); - setState({ show:true }); - rerender(); - - expect(proto._constructor).to.have.been.called; - expect(proto.componentDidMount).to.have.been.called; - expect(proto.componentWillMount).to.have.been.calledBefore(proto.componentDidMount); - expect(proto.componentDidMount).to.have.been.called; - }); - }; - - describe('inner components', () => { - verifyLifycycleMethods(Inner); - }); - - describe('innermost components', () => { - verifyLifycycleMethods(InnerMost); - }); - - describe('when shouldComponentUpdate() returns false', () => { - let setState; - - class Outer extends Component { - constructor() { - super(); - this.state = { show:true }; - setState = s => this.setState(s); - } - render(props, { show }) { - return ( - <div> - { show && ( - <div> - <Inner {...props} /> - </div> - ) } - </div> - ); - } - } - - class Inner extends Component { - shouldComponentUpdate(){ return false; } - componentWillMount() {} - componentDidMount() {} - componentWillUnmount() {} - componentDidUnmount() {} - render() { - return <div />; - } - } - - let proto = Inner.prototype; - let spies = ['componentWillMount', 'componentDidMount', 'componentWillUnmount', 'componentDidUnmount']; - spies.forEach( s => sinon.spy(proto, s) ); - - let reset = () => spies.forEach( s => proto[s].reset() ); - - beforeEach( () => reset() ); - - it('should be invoke normally on initial mount', () => { - render(<Outer />, scratch); - expect(proto.componentWillMount).to.have.been.called; - expect(proto.componentWillMount).to.have.been.calledBefore(proto.componentDidMount); - expect(proto.componentDidMount).to.have.been.called; - }); - - it('should be invoked normally on unmount', () => { - setState({ show:false }); - rerender(); - - expect(proto.componentWillUnmount).to.have.been.called; - expect(proto.componentWillUnmount).to.have.been.calledBefore(proto.componentDidUnmount); - expect(proto.componentDidUnmount).to.have.been.called; - }); - - it('should still invoke mount for shouldComponentUpdate():false', () => { - setState({ show:true }); - rerender(); - - expect(proto.componentWillMount).to.have.been.called; - expect(proto.componentWillMount).to.have.been.calledBefore(proto.componentDidMount); - expect(proto.componentDidMount).to.have.been.called; - }); - - it('should still invoke unmount for shouldComponentUpdate():false', () => { - setState({ show:false }); - rerender(); - - expect(proto.componentWillUnmount).to.have.been.called; - expect(proto.componentWillUnmount).to.have.been.calledBefore(proto.componentDidUnmount); - expect(proto.componentDidUnmount).to.have.been.called; - }); - }); - }); - - describe('Lifecycle DOM Timing', () => { - it('should be invoked when dom does (DidMount, WillUnmount) or does not (WillMount, DidUnmount) exist', () => { - let setState; - class Outer extends Component { - constructor() { - super(); - this.state = { show:true }; - setState = s => { - this.setState(s); - this.forceUpdate(); - }; - } - componentWillMount() { - expect(document.getElementById('OuterDiv'), 'Outer componentWillMount').to.not.exist; - } - componentDidMount() { - expect(document.getElementById('OuterDiv'), 'Outer componentDidMount').to.exist; - } - componentWillUnmount() { - expect(document.getElementById('OuterDiv'), 'Outer componentWillUnmount').to.exist; - } - componentDidUnmount() { - expect(document.getElementById('OuterDiv'), 'Outer componentDidUnmount').to.not.exist; - } - render(props, { show }) { - return ( - <div id="OuterDiv"> - { show && ( - <div> - <Inner {...props} /> - </div> - ) } - </div> - ); - } - } - - class Inner extends Component { - componentWillMount() { - expect(document.getElementById('InnerDiv'), 'Inner componentWillMount').to.not.exist; - } - componentDidMount() { - expect(document.getElementById('InnerDiv'), 'Inner componentDidMount').to.exist; - } - componentWillUnmount() { - // @TODO Component mounted into elements (non-components) - // are currently unmounted after those elements, so their - // DOM is unmounted prior to the method being called. - //expect(document.getElementById('InnerDiv'), 'Inner componentWillUnmount').to.exist; - } - componentDidUnmount() { - expect(document.getElementById('InnerDiv'), 'Inner componentDidUnmount').to.not.exist; - } - - render() { - return <div id="InnerDiv" />; - } - } - - let proto = Inner.prototype; - let spies = ['componentWillMount', 'componentDidMount', 'componentWillUnmount', 'componentDidUnmount']; - spies.forEach( s => sinon.spy(proto, s) ); - - let reset = () => spies.forEach( s => proto[s].reset() ); - - render(<Outer />, scratch); - expect(proto.componentWillMount).to.have.been.called; - expect(proto.componentWillMount).to.have.been.calledBefore(proto.componentDidMount); - expect(proto.componentDidMount).to.have.been.called; - - reset(); - setState({ show:false }); - - expect(proto.componentWillUnmount).to.have.been.called; - expect(proto.componentWillUnmount).to.have.been.calledBefore(proto.componentDidUnmount); - expect(proto.componentDidUnmount).to.have.been.called; - - reset(); - setState({ show:true }); - - expect(proto.componentWillMount).to.have.been.called; - expect(proto.componentWillMount).to.have.been.calledBefore(proto.componentDidMount); - expect(proto.componentDidMount).to.have.been.called; - }); - - it('should remove this.base for HOC', () => { - let createComponent = (name, fn) => { - class C extends Component { - componentWillUnmount() { - expect(this.base, `${name}.componentWillUnmount`).to.exist; - } - componentDidUnmount() { - expect(this.base, `${name}.componentDidUnmount`).not.to.exist; - } - render(props) { return fn(props); } - } - spyAll(C.prototype); - return C; - }; - - class Wrapper extends Component { - render({ children }) { - return <div class="wrapper">{children}</div>; - } - } - - let One = createComponent('One', () => <Wrapper>one</Wrapper> ); - let Two = createComponent('Two', () => <Wrapper>two</Wrapper> ); - let Three = createComponent('Three', () => <Wrapper>three</Wrapper> ); - - let components = [One, Two, Three]; - - let Selector = createComponent('Selector', ({ page }) => { - let Child = components[page]; - return <Child />; - }); - - class App extends Component { - render(_, { page }) { - return <Selector page={page} />; - } - } - - let app; - render(<App ref={ c => app=c } />, scratch); - - for (let i=0; i<20; i++) { - app.setState({ page: i%components.length }); - app.forceUpdate(); - } - }); - }); -}); diff --git a/thirdparty/preact/test/browser/linked-state.js b/thirdparty/preact/test/browser/linked-state.js deleted file mode 100644 index 03db2a7b8..000000000 --- a/thirdparty/preact/test/browser/linked-state.js +++ /dev/null @@ -1,110 +0,0 @@ -import { Component } from '../../src/preact'; -import { createLinkedState } from '../../src/linked-state'; - -describe('linked-state', () => { - class TestComponent extends Component { } - let testComponent, linkFunction; - - before( () => { - testComponent = new TestComponent(); - sinon.spy(TestComponent.prototype, 'setState'); - }); - - describe('createLinkedState without eventPath argument', () => { - - before( () => { - linkFunction = createLinkedState(testComponent,'testStateKey'); - expect(linkFunction).to.be.a('function'); - }); - - beforeEach( () => { - TestComponent.prototype['setState'].reset(); - }); - - it('should use value attribute on text input when no eventPath is supplied', () => { - let element = document.createElement('input'); - element.type= 'text'; - element.value = 'newValue'; - - linkFunction({ - currentTarget: element, - target: element - }); - - expect(TestComponent.prototype.setState).to.have.been.calledOnce; - expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': 'newValue'}); - - linkFunction.call(element); - - expect(TestComponent.prototype.setState).to.have.been.calledTwice; - expect(TestComponent.prototype.setState.secondCall).to.have.been.calledWith({'testStateKey': 'newValue'}); - }); - - it('should use checked attribute on checkbox input when no eventPath is supplied', () => { - let checkboxElement = document.createElement('input'); - checkboxElement.type= 'checkbox'; - checkboxElement.checked = true; - - linkFunction({ - currentTarget: checkboxElement, - target: checkboxElement - }); - - expect(TestComponent.prototype.setState).to.have.been.calledOnce; - expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': true}); - }); - - it('should use checked attribute on radio input when no eventPath is supplied', () => { - let radioElement = document.createElement('input'); - radioElement.type= 'radio'; - radioElement.checked = true; - - linkFunction({ - currentTarget: radioElement, - target: radioElement - }); - - expect(TestComponent.prototype.setState).to.have.been.calledOnce; - expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': true}); - }); - - - it('should set dot notated state key appropriately', () => { - linkFunction = createLinkedState(testComponent,'nested.state.key'); - let element = document.createElement('input'); - element.type= 'text'; - element.value = 'newValue'; - - 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'}}}); - }); - - }); - - describe('createLinkedState with eventPath argument', () => { - - before( () => { - linkFunction = createLinkedState(testComponent,'testStateKey', 'nested.path'); - expect(linkFunction).to.be.a('function'); - }); - - beforeEach( () => { - TestComponent.prototype['setState'].reset(); - }); - - it('should give precedence to nested.path on event over nested.path on component', () => { - let event = {nested: {path: 'nestedPathValueFromEvent'}}; - let component = {_component: {nested: {path: 'nestedPathValueFromComponent'}}}; - - linkFunction.call(component, event); - - expect(TestComponent.prototype.setState).to.have.been.calledOnce; - expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': 'nestedPathValueFromEvent'}); - }); - }); -}); diff --git a/thirdparty/preact/test/browser/performance.js b/thirdparty/preact/test/browser/performance.js deleted file mode 100644 index e1f7d7956..000000000 --- a/thirdparty/preact/test/browser/performance.js +++ /dev/null @@ -1,245 +0,0 @@ -/*global coverage, ENABLE_PERFORMANCE, NODE_ENV*/ -/*eslint no-console:0*/ -/** @jsx h */ - -let { h, Component, render } = require(NODE_ENV==='production' ? '../../dist/preact.min.js' : '../../src/preact'); - -const MULTIPLIER = ENABLE_PERFORMANCE ? (coverage ? 5 : 1) : 999999; - - -let now = typeof performance!=='undefined' && performance.now ? () => performance.now() : () => +new Date(); - -function loop(iter, time) { - let start = now(), - count = 0; - while ( now()-start < time ) { - count++; - iter(); - } - return count; -} - - -function benchmark(iter, callback) { - let a = 0; - function noop() { - try { a++; } finally { a += Math.random(); } - } - - // warm - for (let i=3; i--; ) noop(), iter(); - - let count = 5, - time = 200, - passes = 0, - noops = loop(noop, time), - iterations = 0; - - function next() { - iterations += loop(iter, time); - setTimeout(++passes===count ? done : next, 10); - } - - function done() { - let ticks = Math.round(noops / iterations * count), - hz = iterations / count / time * 1000, - message = `${hz|0}/s (${ticks} ticks)`; - callback({ iterations, noops, count, time, ticks, hz, message }); - } - - next(); -} - - -describe('performance', function() { - let scratch; - - this.timeout(10000); - - before( () => { - if (coverage) { - console.warn('WARNING: Code coverage is enabled, which dramatically reduces performance. Do not pay attention to these numbers.'); - } - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - it('should rerender without changes fast', done => { - let jsx = ( - <div class="foo bar" data-foo="bar" p={2}> - <header> - <h1 class="asdf">a {'b'} c {0} d</h1> - <nav> - <a href="/foo">Foo</a> - <a href="/bar">Bar</a> - </nav> - </header> - <main> - <form onSubmit={()=>{}}> - <input type="checkbox" checked={true} /> - <input type="checkbox" checked={false} /> - <fieldset> - <label><input type="radio" checked /></label> - <label><input type="radio" /></label> - </fieldset> - <button-bar> - <button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</button> - <button style="top:0 ; right: 20">Poor CSS</button> - <button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</button> - <button style={{ margin:0, padding:'10px', overflow:'visible' }}>Object CSS</button> - </button-bar> - </form> - </main> - </div> - ); - - let root; - benchmark( () => { - root = render(jsx, scratch, root); - }, ({ ticks, message }) => { - console.log(`PERF: empty diff: ${message}`); - expect(ticks).to.be.below(350 * MULTIPLIER); - done(); - }); - }); - - it('should rerender repeated trees fast', done => { - class Header extends Component { - render() { - return ( - <header> - <h1 class="asdf">a {'b'} c {0} d</h1> - <nav> - <a href="/foo">Foo</a> - <a href="/bar">Bar</a> - </nav> - </header> - ); - } - } - class Form extends Component { - render() { - return ( - <form onSubmit={()=>{}}> - <input type="checkbox" checked={true} /> - <input type="checkbox" checked={false} /> - <fieldset> - <label><input type="radio" checked /></label> - <label><input type="radio" /></label> - </fieldset> - <ButtonBar /> - </form> - ); - } - } - class ButtonBar extends Component { - render() { - return ( - <button-bar> - <Button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</Button> - <Button style="top:0 ; right: 20">Poor CSS</Button> - <Button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</Button> - <Button style={{ margin:0, padding:'10px', overflow:'visible' }}>Object CSS</Button> - </button-bar> - ); - } - } - class Button extends Component { - render(props) { - return <button {...props} />; - } - } - class Main extends Component { - render() { - return <Form />; - } - } - class Root extends Component { - render() { - return ( - <div class="foo bar" data-foo="bar" p={2}> - <Header /> - <Main /> - </div> - ); - } - } - class Empty extends Component { - render() { - return <div />; - } - } - class Parent extends Component { - render({ child:C }) { - return <C />; - } - } - - let root; - benchmark( () => { - root = render(<Parent child={Root} />, scratch, root); - root = render(<Parent child={Empty} />, scratch, root); - }, ({ ticks, message }) => { - console.log(`PERF: repeat diff: ${message}`); - expect(ticks).to.be.below(2000 * MULTIPLIER); - done(); - }); - }); - - it('should construct large VDOM trees fast', done => { - const FIELDS = []; - for (let i=100; i--; ) FIELDS.push((i*999).toString(36)); - - let out = []; - function digest(vnode) { - out.push(vnode); - out.length = 0; - } - benchmark( () => { - digest( - <div class="foo bar" data-foo="bar" p={2}> - <header> - <h1 class="asdf">a {'b'} c {0} d</h1> - <nav> - <a href="/foo">Foo</a> - <a href="/bar">Bar</a> - </nav> - </header> - <main> - <form onSubmit={()=>{}}> - <input type="checkbox" checked /> - <input type="checkbox" /> - <fieldset> - { FIELDS.map( field => ( - <label> - {field}: - <input placeholder={field} /> - </label> - )) } - </fieldset> - <button-bar> - <button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</button> - <button style="top:0 ; right: 20">Poor CSS</button> - <button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</button> - <button style={{ margin:0, padding:'10px', overflow:'visible' }}>Object CSS</button> - </button-bar> - </form> - </main> - </div> - ); - }, ({ ticks, message }) => { - console.log(`PERF: large VTree: ${message}`); - expect(ticks).to.be.below(2000 * MULTIPLIER); - done(); - }); - }); -}); diff --git a/thirdparty/preact/test/browser/refs.js b/thirdparty/preact/test/browser/refs.js deleted file mode 100644 index 337a9717b..000000000 --- a/thirdparty/preact/test/browser/refs.js +++ /dev/null @@ -1,305 +0,0 @@ -import { h, render, Component } from '../../src/preact'; -/** @jsx h */ - -// gives call count and argument errors names (otherwise sinon just uses "spy"): -let spy = (name, ...args) => { - let spy = sinon.spy(...args); - spy.displayName = `spy('${name}')`; - return spy; -}; - -describe('refs', () => { - let scratch; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - it('should invoke refs in render()', () => { - let ref = spy('ref'); - render(<div ref={ref} />, scratch); - expect(ref).to.have.been.calledOnce.and.calledWith(scratch.firstChild); - }); - - it('should invoke refs in Component.render()', () => { - let outer = spy('outer'), - inner = spy('inner'); - class Foo extends Component { - render() { - return ( - <div ref={outer}> - <span ref={inner} /> - </div> - ); - } - } - render(<Foo />, scratch); - - expect(outer).to.have.been.calledWith(scratch.firstChild); - expect(inner).to.have.been.calledWith(scratch.firstChild.firstChild); - }); - - it('should pass components to ref functions', () => { - let ref = spy('ref'), - instance; - class Foo extends Component { - constructor() { - super(); - instance = this; - } - render() { - return <div />; - } - } - render(<Foo ref={ref} />, scratch); - - expect(ref).to.have.been.calledOnce.and.calledWith(instance); - }); - - it('should pass rendered DOM from functional components to ref functions', () => { - let ref = spy('ref'); - - const Foo = () => <div />; - - let root = render(<Foo ref={ref} />, scratch); - expect(ref).to.have.been.calledOnce.and.calledWith(scratch.firstChild); - - ref.reset(); - render(<Foo ref={ref} />, scratch, root); - expect(ref).to.have.been.calledOnce.and.calledWith(scratch.firstChild); - - ref.reset(); - render(<span />, scratch, root); - expect(ref).to.have.been.calledOnce.and.calledWith(null); - }); - - it('should pass children to ref functions', () => { - let outer = spy('outer'), - inner = spy('inner'), - rerender, inst; - class Outer extends Component { - constructor() { - super(); - rerender = () => this.forceUpdate(); - } - render() { - return ( - <div> - <Inner ref={outer} /> - </div> - ); - } - } - class Inner extends Component { - constructor() { - super(); - inst = this; - } - render() { - return <span ref={inner} />; - } - } - - let root = render(<Outer />, scratch); - - expect(outer).to.have.been.calledOnce.and.calledWith(inst); - expect(inner).to.have.been.calledOnce.and.calledWith(inst.base); - - outer.reset(); - inner.reset(); - - rerender(); - - expect(outer).to.have.been.calledOnce.and.calledWith(inst); - expect(inner).to.have.been.calledOnce.and.calledWith(inst.base); - - outer.reset(); - inner.reset(); - - render(<div />, scratch, root); - - expect(outer).to.have.been.calledOnce.and.calledWith(null); - expect(inner).to.have.been.calledOnce.and.calledWith(null); - }); - - it('should pass high-order children to ref functions', () => { - let outer = spy('outer'), - inner = spy('inner'), - innermost = spy('innermost'), - outerInst, - innerInst; - class Outer extends Component { - constructor() { - super(); - outerInst = this; - } - render() { - return <Inner ref={inner} />; - } - } - class Inner extends Component { - constructor() { - super(); - innerInst = this; - } - render() { - return <span ref={innermost} />; - } - } - - let root = render(<Outer ref={outer} />, scratch); - - expect(outer, 'outer initial').to.have.been.calledOnce.and.calledWith(outerInst); - expect(inner, 'inner initial').to.have.been.calledOnce.and.calledWith(innerInst); - expect(innermost, 'innerMost initial').to.have.been.calledOnce.and.calledWith(innerInst.base); - - outer.reset(); - inner.reset(); - innermost.reset(); - root = render(<Outer ref={outer} />, scratch, root); - - expect(outer, 'outer update').to.have.been.calledOnce.and.calledWith(outerInst); - expect(inner, 'inner update').to.have.been.calledOnce.and.calledWith(innerInst); - expect(innermost, 'innerMost update').to.have.been.calledOnce.and.calledWith(innerInst.base); - - outer.reset(); - inner.reset(); - innermost.reset(); - root = render(<div />, scratch, root); - - expect(outer, 'outer unmount').to.have.been.calledOnce.and.calledWith(null); - expect(inner, 'inner unmount').to.have.been.calledOnce.and.calledWith(null); - expect(innermost, 'innerMost unmount').to.have.been.calledOnce.and.calledWith(null); - }); - - it('should not pass ref into component as a prop', () => { - let foo = spy('foo'), - bar = spy('bar'); - - class Foo extends Component { - render(){ return <div />; } - } - const Bar = spy('Bar', () => <div />); - - sinon.spy(Foo.prototype, 'render'); - - render(( - <div> - <Foo ref={foo} a="a" /> - <Bar ref={bar} b="b" /> - </div> - ), scratch); - - 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 - it('should only null refs after unmount', () => { - let root, outer, inner; - - class TestUnmount extends Component { - componentWillUnmount() { - expect(this).to.have.property('outer', outer); - expect(this).to.have.property('inner', inner); - } - - componentDidUnmount() { - expect(this).to.have.property('outer', null); - expect(this).to.have.property('inner', null); - } - - render() { - return ( - <div id="outer" ref={ c => this.outer=c }> - <div id="inner" ref={ c => this.inner=c } /> - </div> - ); - } - } - - sinon.spy(TestUnmount.prototype, 'componentWillUnmount'); - sinon.spy(TestUnmount.prototype, 'componentDidUnmount'); - - root = render(<div><TestUnmount /></div>, scratch, root); - outer = scratch.querySelector('#outer'); - inner = scratch.querySelector('#inner'); - - expect(TestUnmount.prototype.componentWillUnmount).not.to.have.been.called; - expect(TestUnmount.prototype.componentDidUnmount).not.to.have.been.called; - - root = render(<div />, scratch, root); - - expect(TestUnmount.prototype.componentWillUnmount).to.have.been.calledOnce; - expect(TestUnmount.prototype.componentDidUnmount).to.have.been.calledOnce; - }); - - it('should null and re-invoke refs when swapping component root element type', () => { - let inst; - - class App extends Component { - render() { - return <div><Child /></div>; - } - } - - class Child extends Component { - constructor(props, context) { - super(props, context); - this.state = { show:false }; - inst = this; - } - handleMount(){} - render(_, { show }) { - if (!show) return <div id="div" ref={this.handleMount}></div>; - return <span id="span" ref={this.handleMount}>some test content</span>; - } - } - sinon.spy(Child.prototype, 'handleMount'); - - render(<App />, scratch); - expect(inst.handleMount).to.have.been.calledOnce.and.calledWith(scratch.querySelector('#div')); - inst.handleMount.reset(); - - inst.setState({ show:true }); - inst.forceUpdate(); - expect(inst.handleMount).to.have.been.calledTwice; - expect(inst.handleMount.firstCall).to.have.been.calledWith(null); - expect(inst.handleMount.secondCall).to.have.been.calledWith(scratch.querySelector('#span')); - inst.handleMount.reset(); - - inst.setState({ show:false }); - inst.forceUpdate(); - expect(inst.handleMount).to.have.been.calledTwice; - 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/render.js b/thirdparty/preact/test/browser/render.js deleted file mode 100644 index 5d18fb282..000000000 --- a/thirdparty/preact/test/browser/render.js +++ /dev/null @@ -1,439 +0,0 @@ -/* global DISABLE_FLAKEY */ - -import { h, render } from '../../src/preact'; -/** @jsx h */ - -function getAttributes(node) { - let attrs = {}; - for (let i=node.attributes.length; i--; ) { - attrs[node.attributes[i].name] = node.attributes[i].value; - } - return attrs; -} - -// hacky normalization of attribute order across browsers. -function sortAttributes(html) { - return html.replace(/<([a-z0-9-]+)((?:\s[a-z0-9:_.-]+=".*?")+)((?:\s*\/)?>)/gi, (s, pre, attrs, after) => { - let list = attrs.match(/\s[a-z0-9:_.-]+=".*?"/gi).sort( (a, b) => a>b ? 1 : -1 ); - if (~after.indexOf('/')) after = '></'+pre+'>'; - return '<' + pre + list.join('') + after; - }); -} - -describe('render()', () => { - let scratch; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - it('should create empty nodes (<* />)', () => { - render(<div />, scratch); - expect(scratch.childNodes) - .to.have.length(1) - .and.to.have.deep.property('0.nodeName', 'DIV'); - - scratch.innerHTML = ''; - - render(<span />, scratch); - expect(scratch.childNodes) - .to.have.length(1) - .and.to.have.deep.property('0.nodeName', 'SPAN'); - - scratch.innerHTML = ''; - - render(<foo />, scratch); - render(<x-bar />, scratch); - expect(scratch.childNodes).to.have.length(2); - expect(scratch.childNodes[0]).to.have.property('nodeName', 'FOO'); - expect(scratch.childNodes[1]).to.have.property('nodeName', 'X-BAR'); - }); - - it('should nest empty nodes', () => { - render(( - <div> - <span /> - <foo /> - <x-bar /> - </div> - ), scratch); - - expect(scratch.childNodes) - .to.have.length(1) - .and.to.have.deep.property('0.nodeName', 'DIV'); - - let c = scratch.childNodes[0].childNodes; - expect(c).to.have.length(3); - expect(c).to.have.deep.property('0.nodeName', 'SPAN'); - expect(c).to.have.deep.property('1.nodeName', 'FOO'); - expect(c).to.have.deep.property('2.nodeName', 'X-BAR'); - }); - - it('should not render falsey values', () => { - render(( - <div> - {null},{undefined},{false},{0},{NaN} - </div> - ), scratch); - - expect(scratch.firstChild).to.have.property('innerHTML', ',,,0,NaN'); - }); - - it('should clear falsey attributes', () => { - let root = render(( - <div anull="anull" aundefined="aundefined" afalse="afalse" anan="aNaN" a0="a0" /> - ), scratch); - - root = render(( - <div anull={null} aundefined={undefined} afalse={false} anan={NaN} a0={0} /> - ), scratch, root); - - expect(getAttributes(scratch.firstChild), 'from previous truthy values').to.eql({ - a0: '0', - anan: 'NaN' - }); - - scratch.innerHTML = ''; - - root = render(( - <div anull={null} aundefined={undefined} afalse={false} anan={NaN} a0={0} /> - ), scratch); - - expect(getAttributes(scratch.firstChild), 'initial render').to.eql({ - a0: '0', - anan: 'NaN' - }); - }); - - it('should clear falsey input values', () => { - let root = render(( - <div> - <input value={0} /> - <input value={false} /> - <input value={null} /> - <input value={undefined} /> - </div> - ), scratch); - - expect(root.children[0]).to.have.property('value', '0'); - expect(root.children[1]).to.have.property('value', 'false'); - expect(root.children[2]).to.have.property('value', ''); - expect(root.children[3]).to.have.property('value', ''); - }); - - it('should clear falsey DOM properties', () => { - let root; - function test(val) { - root = render(( - <div> - <input value={val} /> - <table border={val} /> - </div> - ), scratch, root); - } - - test('2'); - test(false); - expect(scratch).to.have.property('innerHTML', '<div><input><table></table></div>', 'for false'); - - test('3'); - test(null); - expect(scratch).to.have.property('innerHTML', '<div><input><table></table></div>', 'for null'); - - test('4'); - test(undefined); - expect(scratch).to.have.property('innerHTML', '<div><input><table></table></div>', 'for undefined'); - }); - - it('should apply string attributes', () => { - render(<div foo="bar" data-foo="databar" />, scratch); - - let div = scratch.childNodes[0]; - expect(div).to.have.deep.property('attributes.length', 2); - - expect(div).to.have.deep.property('attributes[0].name', 'foo'); - expect(div).to.have.deep.property('attributes[0].value', 'bar'); - - expect(div).to.have.deep.property('attributes[1].name', 'data-foo'); - expect(div).to.have.deep.property('attributes[1].value', 'databar'); - }); - - it('should apply class as String', () => { - render(<div class="foo" />, scratch); - expect(scratch.childNodes[0]).to.have.property('className', 'foo'); - }); - - it('should alias className to class', () => { - render(<div className="bar" />, scratch); - expect(scratch.childNodes[0]).to.have.property('className', 'bar'); - }); - - it('should apply style as String', () => { - render(<div style="top:5px; position:relative;" />, scratch); - expect(scratch.childNodes[0]).to.have.deep.property('style.cssText') - .that.matches(/top\s*:\s*5px\s*/) - .and.matches(/position\s*:\s*relative\s*/); - }); - - it('should only register on* functions as handlers', () => { - let click = () => {}, - onclick = () => {}; - - let proto = document.createElement('div').constructor.prototype; - - sinon.spy(proto, 'addEventListener'); - - render(<div click={ click } onClick={ onclick } />, scratch); - - expect(scratch.childNodes[0]).to.have.deep.property('attributes.length', 0); - - expect(proto.addEventListener).to.have.been.calledOnce - .and.to.have.been.calledWithExactly('click', sinon.match.func, false); - - proto.addEventListener.restore(); - }); - - it('should add and remove event handlers', () => { - let click = sinon.spy(), - mousedown = sinon.spy(); - - let proto = document.createElement('div').constructor.prototype; - sinon.spy(proto, 'addEventListener'); - sinon.spy(proto, 'removeEventListener'); - - function fireEvent(on, type) { - let e = document.createEvent('Event'); - e.initEvent(type, true, true); - on.dispatchEvent(e); - } - - render(<div onClick={ () => click(1) } onMouseDown={ mousedown } />, scratch); - - expect(proto.addEventListener).to.have.been.calledTwice - .and.to.have.been.calledWith('click') - .and.calledWith('mousedown'); - - fireEvent(scratch.childNodes[0], 'click'); - expect(click).to.have.been.calledOnce - .and.calledWith(1); - - proto.addEventListener.reset(); - click.reset(); - - render(<div onClick={ () => click(2) } />, scratch, scratch.firstChild); - - expect(proto.addEventListener).not.to.have.been.called; - - expect(proto.removeEventListener) - .to.have.been.calledOnce - .and.calledWith('mousedown'); - - fireEvent(scratch.childNodes[0], 'click'); - expect(click).to.have.been.calledOnce - .and.to.have.been.calledWith(2); - - fireEvent(scratch.childNodes[0], 'mousedown'); - expect(mousedown).not.to.have.been.called; - - proto.removeEventListener.reset(); - click.reset(); - mousedown.reset(); - - render(<div />, scratch, scratch.firstChild); - - expect(proto.removeEventListener) - .to.have.been.calledOnce - .and.calledWith('click'); - - fireEvent(scratch.childNodes[0], 'click'); - expect(click).not.to.have.been.called; - - proto.addEventListener.restore(); - proto.removeEventListener.restore(); - }); - - it('should use capturing for events that do not bubble', () => { - let click = sinon.spy(), - focus = sinon.spy(); - - let root = render(( - <div onClick={click} onFocus={focus}> - <button /> - </div> - ), scratch); - - root.firstElementChild.click(); - root.firstElementChild.focus(); - - expect(click, 'click').to.have.been.calledOnce; - - if (DISABLE_FLAKEY!==true) { - // Focus delegation requires a 50b hack I'm not sure we want to incur - expect(focus, 'focus').to.have.been.calledOnce; - - // IE doesn't set it - expect(click).to.have.been.calledWithMatch({ eventPhase: 0 }); // capturing - expect(focus).to.have.been.calledWithMatch({ eventPhase: 0 }); // capturing - } - }); - - it('should serialize style objects', () => { - let root = render(( - <div style={{ - color: 'rgb(255, 255, 255)', - background: 'rgb(255, 100, 0)', - backgroundPosition: '10px 10px', - 'background-size': 'cover', - padding: 5, - top: 100, - left: '100%' - }}> - test - </div> - ), scratch); - - let { style } = scratch.childNodes[0]; - expect(style).to.have.property('color').that.equals('rgb(255, 255, 255)'); - expect(style).to.have.property('background').that.contains('rgb(255, 100, 0)'); - expect(style).to.have.property('backgroundPosition').that.equals('10px 10px'); - expect(style).to.have.property('backgroundSize', 'cover'); - expect(style).to.have.property('padding', '5px'); - expect(style).to.have.property('top', '100px'); - expect(style).to.have.property('left', '100%'); - - root = render(( - <div style={{ color: 'rgb(0, 255, 255)' }}>test</div> - ), scratch, root); - - expect(root).to.have.deep.property('style.cssText').that.equals('color: rgb(0, 255, 255);'); - - root = render(( - <div style="display: inline;">test</div> - ), scratch, root); - - expect(root).to.have.deep.property('style.cssText').that.equals('display: inline;'); - - root = render(( - <div style={{ backgroundColor: 'rgb(0, 255, 255)' }}>test</div> - ), scratch, root); - - expect(root).to.have.deep.property('style.cssText').that.equals('background-color: rgb(0, 255, 255);'); - }); - - it('should serialize class/className', () => { - render(<div class={{ - no1: false, - no2: 0, - no3: null, - no4: undefined, - no5: '', - yes1: true, - yes2: 1, - yes3: {}, - yes4: [], - yes5: ' ' - }} />, scratch); - - let { className } = scratch.childNodes[0]; - expect(className).to.be.a.string; - expect(className.split(' ')) - .to.include.members(['yes1', 'yes2', 'yes3', 'yes4', 'yes5']) - .and.not.include.members(['no1', 'no2', 'no3', 'no4', 'no5']); - }); - - it('should support dangerouslySetInnerHTML', () => { - let html = '<b>foo & bar</b>'; - let root = render(<div dangerouslySetInnerHTML={{ __html: html }} />, scratch); - - expect(scratch.firstChild).to.have.property('innerHTML', html); - expect(scratch.innerHTML).to.equal('<div>'+html+'</div>'); - - root = render(<div>a<strong>b</strong></div>, scratch, root); - - expect(scratch).to.have.property('innerHTML', `<div>a<strong>b</strong></div>`); - - root = render(<div dangerouslySetInnerHTML={{ __html: html }} />, scratch, root); - - expect(scratch.innerHTML).to.equal('<div>'+html+'</div>'); - }); - - it('should reconcile mutated DOM attributes', () => { - let check = p => render(<input type="checkbox" checked={p} />, scratch, scratch.lastChild), - value = () => scratch.lastChild.checked, - setValue = p => scratch.lastChild.checked = p; - check(true); - expect(value()).to.equal(true); - check(false); - expect(value()).to.equal(false); - check(true); - expect(value()).to.equal(true); - setValue(true); - check(false); - expect(value()).to.equal(false); - setValue(false); - check(true); - expect(value()).to.equal(true); - }); - - it('should ignore props.children if children are manually specified', () => { - expect( - <div a children={['a', 'b']}>c</div> - ).to.eql( - <div a>c</div> - ); - }); - - it('should reorder child pairs', () => { - let root = render(( - <div> - <a>a</a> - <b>b</b> - </div> - ), scratch, root); - - let a = scratch.firstChild.firstChild; - let b = scratch.firstChild.lastChild; - - expect(a).to.have.property('nodeName', 'A'); - expect(b).to.have.property('nodeName', 'B'); - - root = render(( - <div> - <b>b</b> - <a>a</a> - </div> - ), scratch, root); - - expect(scratch.firstChild.firstChild).to.have.property('nodeName', 'B'); - expect(scratch.firstChild.lastChild).to.have.property('nodeName', 'A'); - expect(scratch.firstChild.firstChild).to.equal(b); - expect(scratch.firstChild.lastChild).to.equal(a); - }); - - // Discussion: https://github.com/developit/preact/issues/287 - ('HTMLDataListElement' in window ? it : xit)('should allow <input list /> to pass through as an attribute', () => { - render(( - <div> - <input type="range" min="0" max="100" list="steplist" /> - <datalist id="steplist"> - <option>0</option> - <option>50</option> - <option>100</option> - </datalist> - </div> - ), scratch); - - let html = scratch.firstElementChild.firstElementChild.outerHTML; - expect(sortAttributes(html)).to.equal(sortAttributes('<input type="range" min="0" max="100" list="steplist">')); - }); -}); diff --git a/thirdparty/preact/test/browser/spec.js b/thirdparty/preact/test/browser/spec.js deleted file mode 100644 index d33cdb93f..000000000 --- a/thirdparty/preact/test/browser/spec.js +++ /dev/null @@ -1,127 +0,0 @@ -import { h, render, rerender, Component } from '../../src/preact'; -/** @jsx h */ - -const EMPTY_CHILDREN = []; - -describe('Component spec', () => { - let scratch; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - describe('defaultProps', () => { - it('should apply default props on initial render', () => { - class WithDefaultProps extends Component { - constructor(props, context) { - super(props, context); - expect(props).to.be.deep.equal({ - children: EMPTY_CHILDREN, - fieldA: 1, fieldB: 2, - fieldC: 1, fieldD: 2 - }); - } - render() { - return <div />; - } - } - WithDefaultProps.defaultProps = { fieldC: 1, fieldD: 1 }; - render(<WithDefaultProps fieldA={1} fieldB={2} fieldD={2} />, scratch); - }); - - it('should apply default props on rerender', () => { - let doRender; - class Outer extends Component { - constructor() { - super(); - this.state = { i:1 }; - } - componentDidMount() { - doRender = () => this.setState({ i: 2 }); - } - render(props, { i }) { - return <WithDefaultProps fieldA={1} fieldB={i} fieldD={i} />; - } - } - class WithDefaultProps extends Component { - constructor(props, context) { - super(props, context); - this.ctor(props, context); - } - ctor(){} - componentWillReceiveProps() {} - render() { - return <div />; - } - } - WithDefaultProps.defaultProps = { fieldC: 1, fieldD: 1 }; - - let proto = WithDefaultProps.prototype; - sinon.spy(proto, 'ctor'); - sinon.spy(proto, 'componentWillReceiveProps'); - sinon.spy(proto, 'render'); - - render(<Outer />, scratch); - doRender(); - - const PROPS1 = { - fieldA: 1, fieldB: 1, - fieldC: 1, fieldD: 1 - }; - - const PROPS2 = { - fieldA: 1, fieldB: 2, - fieldC: 1, fieldD: 2 - }; - - 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.calledWithMatch(PROPS2); - expect(proto.render).to.have.been.calledWithMatch(PROPS2); - }); - - // @TODO: migrate this to preact-compat - xit('should cache default props', () => { - class WithDefaultProps extends Component { - constructor(props, context) { - super(props, context); - expect(props).to.be.deep.equal({ - fieldA: 1, fieldB: 2, - fieldC: 1, fieldD: 2, - fieldX: 10 - }); - } - getDefaultProps() { - return { fieldA: 1, fieldB: 1 }; - } - render() { - return <div />; - } - } - WithDefaultProps.defaultProps = { fieldC: 1, fieldD: 1 }; - sinon.spy(WithDefaultProps.prototype, 'getDefaultProps'); - render(( - <div> - <WithDefaultProps fieldB={2} fieldD={2} fieldX={10} /> - <WithDefaultProps fieldB={2} fieldD={2} fieldX={10} /> - <WithDefaultProps fieldB={2} fieldD={2} fieldX={10} /> - </div> - ), scratch); - expect(WithDefaultProps.prototype.getDefaultProps).to.be.calledOnce; - }); - }); -}); diff --git a/thirdparty/preact/test/browser/svg.js b/thirdparty/preact/test/browser/svg.js deleted file mode 100644 index 684f4dd96..000000000 --- a/thirdparty/preact/test/browser/svg.js +++ /dev/null @@ -1,112 +0,0 @@ -import { h, render } from '../../src/preact'; -/** @jsx h */ - - -// hacky normalization of attribute order across browsers. -function sortAttributes(html) { - return html.replace(/<([a-z0-9-]+)((?:\s[a-z0-9:_.-]+=".*?")+)((?:\s*\/)?>)/gi, (s, pre, attrs, after) => { - let list = attrs.match(/\s[a-z0-9:_.-]+=".*?"/gi).sort( (a, b) => a>b ? 1 : -1 ); - if (~after.indexOf('/')) after = '></'+pre+'>'; - return '<' + pre + list.join('') + after; - }); -} - - -describe('svg', () => { - let scratch; - - before( () => { - scratch = document.createElement('div'); - (document.body || document.documentElement).appendChild(scratch); - }); - - beforeEach( () => { - scratch.innerHTML = ''; - }); - - after( () => { - scratch.parentNode.removeChild(scratch); - scratch = null; - }); - - it('should render SVG to string', () => { - render(( - <svg viewBox="0 0 360 360"> - <path stroke="white" fill="black" d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z" /> - </svg> - ), scratch); - - let html = sortAttributes(String(scratch.innerHTML).replace(' xmlns="http://www.w3.org/2000/svg"', '')); - expect(html).to.equal(sortAttributes(` - <svg viewBox="0 0 360 360"> - <path d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z" fill="black" stroke="white"></path> - </svg> - `.replace(/[\n\t]+/g,''))); - }); - - it('should render SVG to DOM', () => { - const Demo = () => ( - <svg viewBox="0 0 360 360"> - <path d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z" fill="black" stroke="white" /> - </svg> - ); - render(<Demo />, scratch); - - let html = sortAttributes(String(scratch.innerHTML).replace(' xmlns="http://www.w3.org/2000/svg"', '')); - expect(html).to.equal(sortAttributes('<svg viewBox="0 0 360 360"><path stroke="white" fill="black" d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z"></path></svg>')); - }); - - it('should use attributes for className', () => { - const Demo = ({ c }) => ( - <svg viewBox="0 0 360 360" {...(c ? {class:'foo_'+c} : {})}> - <path class={c && ('bar_'+c)} stroke="white" fill="black" d="M347.1 357.9L183.3 256.5 13 357.9V1.7h334.1v356.2zM58.5 47.2v231.4l124.8-74.1 118.3 72.8V47.2H58.5z" /> - </svg> - ); - let root = render(<Demo c="1" />, scratch, root); - sinon.spy(root, 'removeAttribute'); - root = render(<Demo />, scratch, root); - expect(root.removeAttribute).to.have.been.calledOnce.and.calledWith('class'); - root.removeAttribute.restore(); - - root = render(<div />, scratch, root); - root = render(<Demo />, scratch, root); - sinon.spy(root, 'setAttribute'); - root = render(<Demo c="2" />, scratch, root); - expect(root.setAttribute).to.have.been.calledOnce.and.calledWith('class', 'foo_2'); - root.setAttribute.restore(); - root = render(<Demo c="3" />, scratch, root); - root = render(<Demo />, scratch, root); - }); - - it('should still support class attribute', () => { - render(( - <svg viewBox="0 0 1 1" class="foo bar" /> - ), scratch); - - expect(scratch.innerHTML).to.contain(` class="foo bar"`); - }); - - it('should serialize class', () => { - render(( - <svg viewBox="0 0 1 1" class={{ foo: true, bar: false, other: 'hello' }} /> - ), scratch); - - expect(scratch.innerHTML).to.contain(` class="foo other"`); - }); - - it('should switch back to HTML for <foreignObject>', () => { - render(( - <svg> - <g> - <foreignObject> - <a href="#foo">test</a> - </foreignObject> - </g> - </svg> - ), scratch); - - expect(scratch.getElementsByTagName('a')) - .to.have.property('0') - .that.is.a('HTMLAnchorElement'); - }); -}); |