diff --git a/src/compiler.js b/src/compiler.js index 610a950..8b395b2 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -99,7 +99,8 @@ export function create(options = {}) { if (rule.classNames) fns.push( - failText(({ props: { className }}) => { + failText(({ props }) => { + let className = props && props.className return rule.classNames.every(clsName => className && className.indexOf(clsName) !== -1) }) diff --git a/src/node.js b/src/node.js index e4cba5d..734f2c3 100644 --- a/src/node.js +++ b/src/node.js @@ -4,7 +4,7 @@ import isPlainObject from 'lodash/lang/isPlainObject'; import { create as createCompiler, parse } from './compiler'; import { anyParent, directParent - , isDomElement, isCompositeElement + , isDomElement, isCompositeElement, isTextElement , isReactInstance, isDOMComponent, isCompositeComponent } from './utils'; export function eachChild(subject, fn) { @@ -22,15 +22,18 @@ export function eachChild(subject, fn) { publicInst = inst.getPublicInstance() if (isDOMComponent(publicInst)) { - let renderedChildren = inst._renderedChildren || {} + let renderedChildren = inst._renderedChildren , child = element && element.props.children; - if (child != null && !isPlainObject(child) && !Array.isArray(child) && !isReactInstance(child)) + // in cases where there is a single child + // renderedChildren will be null if that child is a non-element + // renderable thing, like a string or number. + if (renderedChildren != null) + Object.keys(renderedChildren || {}).forEach( + key => fn(renderedChildren[key]) + ); + else if (child != null && isTextElement(child)) fn(child) - - Object.keys(renderedChildren).forEach( - key => fn(renderedChildren[key]) - ); } else if (isCompositeComponent(publicInst) && inst._renderedComponent != null) { fn(inst._renderedComponent); diff --git a/src/utils.js b/src/utils.js index 7fd7d1c..7d6f42f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,10 +1,11 @@ import has from 'lodash/object/has'; import React from 'react'; -let isValidPlainElement = element => typeof element === 'object' && element != null; +export let isValidPlainElement = + element => typeof element === 'object' && element != null && has(element, 'type'); export let isTextElement = - element => !isValidPlainElement(element) && element !== false + element => !isValidPlainElement(element) && element !== false && element != null export let isDomElement = element => !isTextElement(element) && typeof element.type === 'string' && element.type.toLowerCase() === element.type diff --git a/test/compiler.js b/test/compiler.js index 65dd2a4..dad635d 100644 --- a/test/compiler.js +++ b/test/compiler.js @@ -1,11 +1,16 @@ import React from 'react'; import { create } from '../src/compiler'; +import { isTextElement } from '../src/utils'; -let { compile, selector: s } = create() chai.use(require('sinon-chai')) describe('create compiler', ()=> { + let compile, s, registerPseudo; + + beforeEach(() => { + ({ compile, registerPseudo, selector: s } = create()) + }) it('should return a function', ()=>{ let result = compile('a.foo') @@ -35,10 +40,26 @@ describe('create compiler', ()=> { }).should.equal(false) }) + it('should handle non element values', ()=> { + registerPseudo('text', ()=> element => isTextElement(element)) + let result = compile(':text') + + result({}).should.equal(true) + result('hello').should.equal(true) + result(500).should.equal(true) + result(/regex/).should.equal(true) + result([1, 2, 3]).should.equal(true) + result(new Date()).should.equal(true) + result(true).should.equal(true) + result(false).should.equal(false) + result(null).should.equal(false) + }) + it('should match props', ()=>{ let result = compile('[foo="5"]') result({ + type: 'p', props: { foo: 5 } @@ -49,6 +70,7 @@ describe('create compiler', ()=> { let result = compile('[foo]') result({ + type: 'p', props: { foo: true } diff --git a/test/traversal.js b/test/traversal.js index 28854e5..a6f6f07 100644 --- a/test/traversal.js +++ b/test/traversal.js @@ -7,7 +7,7 @@ let renderIntoDocument = (elements) => let c = fn => React.createClass({ render(){ return fn(this.props, this.context) } }) -describe.only('instance tree traversal', () => { +describe('instance tree traversal', () => { it('should find all text nodes', ()=> { let Example = c(()=>