diff options
Diffstat (limited to 'preact/test/shared/createElement.test.js')
-rw-r--r-- | preact/test/shared/createElement.test.js | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/preact/test/shared/createElement.test.js b/preact/test/shared/createElement.test.js new file mode 100644 index 0000000..a7231b6 --- /dev/null +++ b/preact/test/shared/createElement.test.js @@ -0,0 +1,299 @@ +import { createElement } from '../../'; +import { expect } from 'chai'; + +const h = createElement; +/** @jsx createElement */ +/*eslint-env browser, mocha */ + +// const buildVNode = (nodeName, attributes, children=[]) => ({ +// nodeName, +// children, +// attributes, +// key: attributes && attributes.key +// }); + +describe('createElement(jsx)', () => { + it('should return a VNode', () => { + let r; + expect(() => (r = h('foo'))).not.to.throw(); + expect(r).to.be.an('object'); + // expect(r).to.be.an.instanceof(VNode); + expect(r).to.have.property('type', 'foo'); + expect(r) + .to.have.property('props') + .that.eql({}); + // expect(r).to.have.deep.property('props.children').that.eql(null); + }); + + it('should set VNode#type property', () => { + expect(<div />).to.have.property('type', 'div'); + function Test() { + return <div />; + } + expect(<Test />).to.have.property('type', Test); + }); + + it('should set VNode.constructor property to prevent json injection', () => { + const vnode = <span />; + expect(vnode.constructor).to.equal(undefined); + }); + + it('should set VNode#props property', () => { + const props = {}; + expect(h('div', props).props).to.deep.equal(props); + }); + + it('should set VNode#key property', () => { + expect(<div />).to.have.property('key').that.does.not.exist; + expect(<div a="a" />).to.have.property('key').that.does.not.exist; + expect(<div key="1" />).to.have.property('key', '1'); + }); + + it('should not set VNode#props.key property', () => { + expect(<div />).to.not.have.nested.property('props.key'); + expect(<div key="1" />).to.not.have.nested.property('props.key'); + expect(<div key={0} />).to.not.have.nested.property('props.key'); + expect(<div key={''} />).to.not.have.nested.property('props.key'); + }); + + it('should set VNode#ref property', () => { + expect(<div />).to.have.property('ref').that.does.not.exist; + expect(<div a="a" />).to.have.property('ref').that.does.not.exist; + const emptyFunction = () => {}; + expect(<div ref={emptyFunction} />).to.have.property('ref', emptyFunction); + }); + + it('should not set VNode#props.ref property', () => { + expect(<div />).to.not.have.nested.property('props.ref'); + expect(<div ref={() => {}} />).to.not.have.nested.property('props.ref'); + }); + + it('should have ordered VNode properties', () => { + expect(Object.keys(<div />).filter(key => !/^_/.test(key))).to.deep.equal([ + 'type', + 'props', + 'key', + 'ref', + 'constructor' + ]); + }); + + it('should preserve raw props', () => { + let props = { foo: 'bar', baz: 10, func: () => {} }, + r = h('foo', props); + expect(r) + .to.be.an('object') + .with.property('props') + .that.deep.equals(props); + }); + + it('should support element children', () => { + let kid1 = h('bar'); + let kid2 = h('baz'); + let r = h('foo', null, kid1, kid2); + + expect(r) + .to.be.an('object') + .with.nested.deep.property('props.children', [kid1, kid2]); + }); + + it('should support multiple element children, given as arg list', () => { + let kid1 = h('bar'); + let kid3 = h('test'); + let kid2 = h('baz', null, kid3); + + let r = h('foo', null, kid1, kid2); + + expect(r) + .to.be.an('object') + .with.nested.deep.property('props.children', [kid1, kid2]); + }); + + it('should handle multiple element children, given as an array', () => { + let kid1 = h('bar'); + let kid3 = h('test'); + let kid2 = h('baz', null, kid3); + + let r = h('foo', null, [kid1, kid2]); + + expect(r) + .to.be.an('object') + .with.nested.deep.property('props.children', [kid1, kid2]); + }); + + it('should support nested children', () => { + const m = x => { + const result = h(x); + delete result._original; + return result; + }; + expect(h('foo', null, m('a'), [m('b'), m('c')], m('d'))) + .to.have.nested.property('props.children') + .that.eql([m('a'), [m('b'), m('c')], m('d')]); + + expect(h('foo', null, [m('a'), [m('b'), m('c')], m('d')])) + .to.have.nested.property('props.children') + .that.eql([m('a'), [m('b'), m('c')], m('d')]); + + expect(h('foo', { children: [m('a'), [m('b'), m('c')], m('d')] })) + .to.have.nested.property('props.children') + .that.eql([m('a'), [m('b'), m('c')], m('d')]); + + expect(h('foo', { children: [[m('a'), [m('b'), m('c')], m('d')]] })) + .to.have.nested.property('props.children') + .that.eql([[m('a'), [m('b'), m('c')], m('d')]]); + + expect(h('foo', { children: m('a') })) + .to.have.nested.property('props.children') + .that.eql(m('a')); + + expect(h('foo', { children: 'a' })) + .to.have.nested.property('props.children') + .that.eql('a'); + }); + + it('should support text children', () => { + let r = h('foo', null, 'textstuff'); + + expect(r) + .to.be.an('object') + .with.nested.property('props.children') + .that.equals('textstuff'); + }); + + it('should override children if null is provided as an argument', () => { + let r = h('foo', { foo: 'bar', children: 'baz' }, null); + + expect(r) + .to.be.an('object') + .to.deep.nested.include({ + 'props.foo': 'bar', + 'props.children': null + }); + }); + + it('should NOT set children prop when unspecified', () => { + let r = h('foo', { foo: 'bar' }); + + expect(r) + .to.be.an('object') + .to.have.nested.property('props.foo') + .not.to.have.nested.property('props.children'); + }); + + it('should NOT merge adjacent text children', () => { + const bar = h('bar'); + const barClone = h('bar'); + const baz = h('baz'); + const bazClone = h('baz'); + const baz2 = h('baz'); + const baz2Clone = h('baz'); + + delete bar._original; + delete barClone._original; + delete baz._original; + delete bazClone._original; + delete baz2._original; + delete baz2Clone._original; + + let r = h( + 'foo', + null, + 'one', + 'two', + bar, + 'three', + baz, + baz2, + 'four', + null, + 'five', + 'six' + ); + + expect(r) + .to.be.an('object') + .with.nested.property('props.children') + .that.deep.equals([ + 'one', + 'two', + barClone, + 'three', + bazClone, + baz2Clone, + 'four', + null, + 'five', + 'six' + ]); + }); + + it('should not merge nested adjacent text children', () => { + let r = h( + 'foo', + null, + 'one', + ['two', null, 'three'], + null, + ['four', null, 'five', null], + 'six', + null + ); + + expect(r) + .to.be.an('object') + .with.nested.property('props.children') + .that.deep.equals([ + 'one', + ['two', null, 'three'], + null, + ['four', null, 'five', null], + 'six', + null + ]); + }); + + it('should not merge children that are boolean values', () => { + let r = h('foo', null, 'one', true, 'two', false, 'three'); + + expect(r) + .to.be.an('object') + .with.nested.property('props.children') + .that.deep.equals(['one', true, 'two', false, 'three']); + }); + + it('should not merge children of components', () => { + let Component = ({ children }) => children; + let r = h(Component, null, 'x', 'y'); + + expect(r) + .to.be.an('object') + .with.nested.property('props.children') + .that.deep.equals(['x', 'y']); + }); + + it('should respect defaultProps', () => { + const Component = ({ children }) => children; + Component.defaultProps = { foo: 'bar' }; + expect(h(Component).props).to.deep.equal({ foo: 'bar' }); + }); + + it('should override defaultProps', () => { + const Component = ({ children }) => children; + Component.defaultProps = { foo: 'default' }; + expect(h(Component, { foo: 'bar' }).props).to.deep.equal({ foo: 'bar' }); + }); + + it('should ignore props.children if children are manually specified', () => { + const element = ( + <div a children={['a', 'b']}> + c + </div> + ); + const childrenless = <div a>c</div>; + delete element._original; + delete childrenless._original; + + expect(element).to.eql(childrenless); + }); +}); |