UNPKG

rquery

Version:

jQuery-like functionality for React to facilitate testing.

810 lines (664 loc) 21.2 kB
function runSelectors (shallow) { var MyComponent = React.createClass({ displayName: "MyComponent", render: function () { return ( React.createElement('div', { id: 'my-component', className: 'my-class some-other-class' }, React.createElement('p', {}, 'Hello, world!'), React.createElement('p', {}, React.createElement('span', {}, 'not descendant')), React.createElement('a', { className: 'button', target: '_blank', 'data-something': 'hello ' }, 'Click me!'), React.createElement('button', { className: 'button button-default' }, 'Save'), React.createElement('span', {}, 'descendant'), React.createElement(ChildComponent), React.createElement(NullComponent), React.createElement('div', {}, React.createElement('span', {}, 'not a child of p')) ) ); } }); var ChildComponent = React.createClass({ displayName: 'ChildComponent', render: function () { return ( React.createElement('button', { className: 'child-component' }, 'my child component') ); } }); var NullComponent = React.createClass({ render: function () { return null; } }); var TestUtils = React.addons.TestUtils; function getProp (component, prop) { if (TestUtils.isDOMComponent(component)) { if (prop === 'className') { prop = 'class'; } if (component.hasAttribute(prop)) { return component.getAttribute(prop); } } else { return component.props[prop]; } } function expectType (component, type) { if (shallow) { expect(component.type).to.equal(type); } else { if (typeof type === 'string') { expect(component).to.be.componentWithTag(type); } else { expect(component).to.be.componentOfType(type); } } } function expectAttribute (component, attribute) { var hasAttribute; if (shallow) { hasAttribute = attribute in component.props; } else { hasAttribute = component.hasAttribute(attribute); } expect(hasAttribute).to.be.true; } function className (component) { return getProp(component, 'className'); } function tagName (component) { if (shallow) { if (typeof component.type === 'string') { return component.type.toUpperCase(); } } else { return component.tagName; } } function run (selector, element) { var component, renderer; if (!element) { element = React.createElement(MyComponent) } if (shallow) { renderer = TestUtils.createRenderer(); renderer.render(element); return $R(renderer.getRenderOutput(), selector); } else { component = TestUtils.renderIntoDocument(element); return $R(component, selector); } }; describe('text description of component', function () { before(function () { this.$r = run('ChildComponent'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of ChildComponent', function () { expectType(this.$r[0], ChildComponent); }); }); describe('text description of connected component', function () { before(function () { this.originalChildComponentDisplayName = ChildComponent.displayName; ChildComponent.displayName = 'Connect(ChildComponent)'; this.$r = run('ChildComponent'); }); after(function () { ChildComponent.displayName = this.originalChildComponentDisplayName; }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of ChildComponent', function () { expectType(this.$r[0], ChildComponent); }); }); describe('text description of DOM component', function () { before(function () { this.$r = run('a'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); }); describe('chained calls to find', function () { it('correctly matches composite components', function () { this.$r = run('div').find('ChildComponent'); expect(this.$r).to.have.length(1); }); it('matches composite components chained from a DOM component', function () { var TestComponent = React.createClass({ render: function () { return ( React.createElement('div', {}, React.createElement('div', { className: 'my-class' }, React.createElement(ChildComponent) ) ) ); } }); this.$r = run('', React.createElement(TestComponent)); expect(this.$r.find('.my-class').find('ChildComponent')).to.have.length(1); }); }); describe('union selector', function () { before(function () { this.$r = run('a, p'); }); it('finds all a & p components', function () { expect(this.$r).to.have.length(3); }); it('components are found in union order, then document order', function () { expectType(this.$r[0], 'a'); expectType(this.$r[1], 'p'); expectType(this.$r[2], 'p'); }); }); describe('descendant selector', function () { it('finds all span components', function () { this.$r = run('div span'); expect(this.$r).to.have.length(3); }); it('finds all p components', function () { this.$r = run('div p'); expect(this.$r).to.have.length(2); }); if (!shallow) { it('finds composite components that are descendants of composite components', function () { this.$r = run('MyComponent ChildComponent'); expect(this.$r).to.have.length(1); }); } it('finds composite components that are descendants of DOM components', function () { this.$r = run('div ChildComponent'); expect(this.$r).to.have.length(1); }); }); describe('child selector', function () { before(function () { this.$r = run('div > span'); }); it('finds all child span components', function () { expect(this.$r).to.have.length(2); }); describe('when descendant is of same depth, but not a child', function () { before(function () { this.$r = run('p > span') }); it('does not match the cousin', function () { expect(this.$r).to.have.length(1); }); }); if (!shallow) { describe('DOM components that are children of DOM components', function () { before(function () { this.$r = run('div > button'); }); it('finds the button components', function () { expect(this.$r).to.have.length(2); }); it('only matches DOM components', function () { expect(this.$r.components.map(tagName)).to.be.eql(['BUTTON', 'BUTTON']); }); }); describe('composite components that are children of DOM components', function () { before(function () { this.$r = run('div > ChildComponent'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('finds the composite component', function () { expect(TestUtils.isCompositeComponentWithType(this.$r[0], ChildComponent)).to.be.true; }); }); it('composite components that are children of composite components', function () { this.$r = run('MyComponent > ChildComponent'); expect(this.$r).to.have.length(1); }); } it('finds composite components that are children of DOM components', function () { this.$r = run('div > ChildComponent'); expect(this.$r).to.have.length(1); }); }); if (!shallow) { describe('composite selector with child selector', function () { before(function () { this.$r = run('MyComponent > span'); }); it('finds all child span components', function () { expect(this.$r).to.have.length(1); }); describe('composite component\'s DOM component', function () { before(function () { this.$r = run('MyComponent > div'); }); it('returns the composite component\'s DOM component', function () { expect(this.$r).to.have.length(1); }); }); }); } describe('DOM selector with multiple matches', function () { before(function () { this.$r = run('p'); }); it('finds two components', function () { expect(this.$r).to.have.length(2); }); it('first component is instance of "p" tag', function () { expectType(this.$r[0], 'p'); }); it('second component is instance of "p" tag', function () { expectType(this.$r[1], 'p'); }); }); describe('DOM class selector', function () { before(function () { this.$r = run('.button'); }); it('finds two components', function () { expect(this.$r).to.have.length(2); }); it('first component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); it('second component is instance of "button" tag', function () { expectType(this.$r[1], 'button'); }); }); describe('DOM class selector with dash', function () { before(function () { this.$r = run('.my-class'); }); it('find one component', function () { expect(this.$r).to.have.length(1); }); it('first component is instance of "div" tag', function () { expectType(this.$r[0], 'div'); }); }); describe('chained DOM class selector', function () { before(function () { this.$r = run('.my-class.some-other-class'); }); it('find one component', function () { expect(this.$r).to.have.length(1); }); it('has the correct class names', function () { expect(className(this.$r[0])).to.equal('my-class some-other-class'); }); }); describe('index selector', function () { it('matches the indexed element', function () { this.$r = run('button[0]'); expect(this.$r).to.have.length(1); expect(tagName(this.$r[0])).to.eql('BUTTON'); expect(className(this.$r[0])).to.eql('button button-default'); }); it('matches nothing if index out of range', function () { this.$r = run('div[3]'); expect(this.$r).to.have.length(0); }); }); describe('attribute selector', function () { before(function () { this.$r = run('[target]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); it('component has target property', function () { expectAttribute(this.$r[0], 'target'); }); }); describe('chained attribute selectors', function () { before(function () { this.$r = run('div[id="my-component"][class~="my-class"]'); }); it('finds the correct component', function () { expect(this.$r).to.have.length(1); expect(getProp(this.$r[0], 'id')).to.equal('my-component'); }); }); describe('attribute selector with dash in name', function () { before(function () { this.$r = run('[data-something]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); it('component has data-something property', function () { expectAttribute(this.$r[0], 'data-something'); }); }); describe('attribute value selector', function () { before(function () { this.$r = run('[target="_blank"]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); it('component has target property', function () { expectAttribute(this.$r[0], 'target'); }); }); describe('attribute ~= selector', function () { before(function () { this.$r = run('[class~="my-class"]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "div" tag', function () { expectType(this.$r[0], 'div'); }); it('component has target property', function () { expect(className(this.$r[0])).to.equal('my-class some-other-class'); }); }); describe('attribute |= selector', function () { before(function () { this.$r = run('[class|="my"]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "div" tag', function () { expectType(this.$r[0], 'div'); }); it('component has target property', function () { expect(className(this.$r[0])).to.equal('my-class some-other-class'); }); }); describe('attribute ^= selector', function () { before(function () { this.$r = run('[data-something^="he"]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); it('component has target property', function () { expectAttribute(this.$r[0], 'data-something'); }); }); describe('attribute $= selector', function () { before(function () { this.$r = run('[data-something$="lo "]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); it('component has target property', function () { expectAttribute(this.$r[0], 'data-something'); }); }); describe('attribute *= selector', function () { before(function () { this.$r = run('[data-something*="ell"]'); }); it('finds one component', function () { expect(this.$r).to.have.length(1); }); it('component is instance of "a" tag', function () { expectType(this.$r[0], 'a'); }); it('component has target property', function () { expectAttribute(this.$r[0], 'data-something'); }); }); describe(':contains() selector', function () { describe('when not scoped to a specific element', function () { before(function () { this.$r = run(':contains(descendant)'); }); it('finds all components that contain the text', function () { expect(this.$r).to.have.length(shallow ? 4 : 5); }); }); describe('when scoped to a specific element', function () { before(function () { this.$r = run('div :contains(descendant)'); }); it('finds all scoped components that contain the text', function () { expect(this.$r).to.have.length(3); }); }); }); describe(':not() selector', function () { describe('when scoped to descendants', function () { before(function () { this.$r = run('div :not(p)'); }); it('finds all the descendants that do not match the given selector', function () { expect(this.$r).to.have.length(shallow ? 8 : 8); }); it('the matched descendants have the expected tag names', function () { var expected; if (shallow) { expected = [ 'SPAN', 'SPAN', 'A', 'BUTTON', 'SPAN', undefined, undefined, 'DIV' ]; } else { expected = [ 'SPAN', 'A', 'BUTTON', 'SPAN', undefined, 'BUTTON', 'DIV', 'SPAN' ]; } expect(this.$r.components.map(tagName)).to.eql(expected); }); it('the matched descendants have the expected class names', function () { var expected; if (shallow) { expected = [ undefined, undefined, 'button', 'button button-default', undefined, undefined, undefined, undefined ]; } else { expected = [ undefined, 'button', 'button button-default', undefined, undefined, 'child-component', undefined, undefined ]; } expect(this.$r.components.map(className)).to.eql(expected); }); it('the composite component is matched', function () { expectType(this.$r[shallow ? 5 : 4], ChildComponent); }); }); describe('when scoped to children', function () { before(function () { this.$r = run('div > :not(p)'); }); it('finds all the children that do not match the given selector', function () { expect(this.$r).to.have.length(shallow ? 7 : 7); }); it('the matched children have the expected tag names', function () { var expected; if (shallow) { expected = [ 'SPAN', 'A', 'BUTTON', 'SPAN', undefined, undefined, 'DIV' ]; } else { expected = [ 'A', 'BUTTON', 'SPAN', undefined, 'BUTTON', 'DIV', 'SPAN' ]; } expect(this.$r.components.map(tagName)).to.eql(expected); }); it('the matched children have the expected class names', function () { var expected; if (shallow) { expected = [ undefined, 'button', 'button button-default', undefined, undefined, undefined, undefined ]; } else { expected = [ 'button', 'button button-default', undefined, undefined, 'child-component', undefined, undefined ]; } expect(this.$r.components.map(className)).to.eql(expected); }); }); describe('when using union selector', function () { before(function () { this.$r = run('div :not(p, button, span)'); }); it('finds all the descendants that do not match any of the union expressions', function () { expect(this.$r).to.have.length(shallow ? 4 : 3); }); it('the matched children have the expected tag names', function () { var expected; if (shallow) { expected = [ 'A', undefined, undefined, 'DIV' ]; } else { expected = [ 'A', undefined, 'DIV' ]; } expect(this.$r.components.map(tagName)).to.eql(expected); }); it('the matched children have the expected class names', function () { var expected; if (shallow) { expected = [ 'button', undefined, undefined, undefined ]; } else { expected = [ 'button', undefined, undefined ]; } expect(this.$r.components.map(className)).to.eql(expected); }); }); describe('when match negates self', function () { before(function () { this.$r = run('div.my-class:not(.my-class)'); }); it('matches nothing', function () { expect(this.$r).to.have.length(0); }); }); it('throws an error on missing )', function () { expect(function () { run(':not('); }).to.throw('Syntax error, unclosed )'); }); it('throws an error on un-matched )', function () { expect(function () { run(')'); }).to.throw('Syntax error, unmatched )'); }); }); describe('#style', function () { before(function () { this.component = TestUtils.renderIntoDocument(React.createElement('div', { style: { height: 123, display: 'none' } })); this.$r = $R(this.component); }); it('returns a px value for height', function() { expect(this.$r.style('height')).to.eq('123px'); }); it('returns the string value for display property', function() { expect(this.$r.style('display')).to.eq('none'); }); it('returns undefined when no style is defined', function() { expect(this.$r.style('abc')).to.be.undefined; }); it('throws an error when no component is in the scope', function() { var $r = this.$r; expect(function () { $r.find('p').style('a'); }).to.throw('$R#style requires at least one component. No components in current scope.'); }); }); } describe('Normal Selectors', function () { runSelectors(false); }); describe('Shallow Selectors', function () { runSelectors(true); });