Skip to content

Commit

Permalink
Allow searching with props via .subTree, return false when not found
Browse files Browse the repository at this point in the history
  • Loading branch information
glenjamin committed Oct 15, 2015
1 parent 32fcacf commit e788df0
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 19 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"no-nested-ternary": 1,
"space-after-keywords": [1, "always"],
"space-before-function-paren": [1, "never"],
"spaced-comment": [1, "always"]
"spaced-comment": [1, "always"],
"no-undef": 2
}
}
44 changes: 27 additions & 17 deletions skin-deep.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ function shallowRender(elementOrFunction, context) {
return shallowRenderer.getRenderOutput();
},
shallowRenderer,
/*eslint-disable no-underscore-dangle */
/* eslint-disable no-underscore-dangle */
shallowRenderer._instance._instance
/*eslint-enable no-underscore-dangle */
/* eslint-enable no-underscore-dangle */
);
}

Expand All @@ -76,26 +76,26 @@ function SkinDeep(getCurrentNode, renderer, instance) {
if (instance) return instance;
throw new Error('This tree has no mounted instance');
},
subTree: function(query) {
var node = findNodeIn(getCurrentNode(), query);
return skinDeepNode(node);
subTree: function(query, predicate) {
var node = findNode(getCurrentNode(), createFinder(query, predicate));
return node && skinDeepNode(node);
},
everySubTree: function(query) {
everySubTree: function(query, predicate) {
var predicate = createNodePredicate(query);
return findNodes(getCurrentNode(), predicate).map(skinDeepNode);
},
findNode: function(query) {
return findNodeIn(getCurrentNode(), query);
return findNode(getCurrentNode(), createNodePredicate(query));
},
textIn: function(query) {
var node = findNodeIn(getCurrentNode(), query);
var node = findNode(getCurrentNode(), createNodePredicate(query));
return getTextFromNode(node);
},
text: function() {
return getTextFromNode(getCurrentNode());
},
fillField: function(query, value) {
var node = findNodeIn(getCurrentNode(), query);
var node = findNode(getCurrentNode(), createNodePredicate(query));
if (!node || !node.props) throw new Error('Unknown field ' + query);

if (node.props.onChange) {
Expand All @@ -116,11 +116,7 @@ function SkinDeep(getCurrentNode, renderer, instance) {
type = getComponentName(search.type) || search.type;
props = search.props;
}
return findNode(getCurrentNode(), function(node) {
return matchComponentType(type, node) &&
subset(node.props, props) &&
subset(props, node.props);
});
return findNode(getCurrentNode(), createFinder(type, props));
},
findComponentLike: function(type, props) {
if (arguments.length == 1) {
Expand Down Expand Up @@ -173,11 +169,21 @@ function createNodePredicate(query) {
return function(n) { return n.type == query; };
}
// component displayName
return function(n) { return n.type && getComponentName(n.type) == query; };
return function(n) { return n.type && getComponentName(n.type) == query; };
}

function findNodeIn(node, query) {
return findNode(node, createNodePredicate(query));
function createFinder(selector, predicate) {
var nodeMatcher = createNodePredicate(selector);
var otherMatcher = alwaysTrue;
if (typeof predicate === 'object') {
// predicate is a props object to match
otherMatcher = function(node) {
return subset(node.props, predicate) && subset(predicate, node.props);
}
}
return function(node) {
return nodeMatcher(node) && otherMatcher(node);
}
}

function findNodeByClass(cls) {
Expand Down Expand Up @@ -268,3 +274,7 @@ function mapcat(array, fn) {
});
return result;
}

function alwaysTrue() {
return true;
}
51 changes: 50 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ describe("skin-deep", function() {
});

describe("subTree", function() {
var Widget = React.createClass({
displayName: 'Widget',
render: function() {}
});
var tree = sd.shallowRender(
$('div', {},
$('div', {id: "def", className: "abc"},
Expand All @@ -370,25 +374,70 @@ describe("skin-deep", function() {
$('object', {}, "objection!"),
'hello',
[$('div', {id: "abc2", className: "abc", key: "1"}, "ABC")]
)
),
$('div', { id: 'wut', prop: 'val' }),
$('div', { className: 'yup', prop: 'val' }),
$(Widget, {}, "stuff")
)
);
it("should return false when not found", function() {
var abc = tree.subTree("#blah");
expect(abc).to.eql(false);
});
it("should grab a subtree by id selector", function() {
var abc = tree.subTree("#abc");
expect(abc).to.be.an('object');
expect(abc.getRenderOutput().props).to.have.property("id", "abc");
});
it("should grab a subtree by id selector + props", function() {
var wut = tree.subTree("#wut", { id: 'wut', prop: "foo" });
expect(wut).to.eql(false);

var wut = tree.subTree("#wut", { id: 'wut', prop: "val" });
expect(wut).to.be.an('object');
expect(wut.getRenderOutput().props).to.have.property("id", "wut");
});
it("should grab a subtree by class selector", function() {
var abc = tree.subTree(".abc");
expect(abc).to.be.an('object');
expect(abc.getRenderOutput().props).to.have.property("className", "abc");
});
it("should grab a subtree by class selector + props", function() {
var yup = tree.subTree(".yup", { className: 'yup', prop: "foo" });
expect(yup).to.eql(false);

var yup = tree.subTree(".yup", { className: 'yup', prop: "val" });
expect(yup).to.be.an('object');
expect(yup.getRenderOutput().props).to.have.property("className", "yup");
});
it("should grab a subtree by tag selector", function() {
var abc = tree.subTree("object");
expect(abc).to.be.an('object');
expect(abc.getRenderOutput().props)
.to.have.property("children", "objection!");
});
it("should grab a subtree by tag selector + props", function() {
var subtree = tree.subTree("object", { children: 'not objection!' });
expect(subtree).to.eql(false);

var subtree = tree.subTree("object", { children: 'objection!' });
expect(subtree).to.be.an('object');
expect(subtree.getRenderOutput().type).to.eql('object');
});
it("should grab a subtree by component name", function() {
var abc = tree.subTree("Widget");
expect(abc).to.be.an('object');
expect(abc.getRenderOutput().props)
.to.have.property("children", "stuff");
});
it("should grab a subtree by component + props", function() {
var subtree = tree.subTree("Widget", { children: 'not stuff' });
expect(subtree).to.eql(false);

var subtree = tree.subTree("Widget", { children: 'stuff' });
expect(subtree).to.be.an('object');
expect(subtree.getRenderOutput().type).to.eql(Widget);
});
describe("methods", function() {
var subTree;
beforeEach(function() {
Expand Down

0 comments on commit e788df0

Please sign in to comment.