A scope is an object that represents the React components and DOM nodes you want to interact with. When you drill into a tree, you get a scope back.
The scope APIs are chainable in that most of them return another scope back for you, unless they're actions then they return the same scope back.
drill(component) // => Scope.<component.type, nodes: [findDOMNode(component)]>
.find(Menu) // => Scope.<Menu, nodes: [findDOMNode(Menu)]>
.find('button') // => Scope.<Menu, nodes: [HTMLElement.<button>]>
.click() // => Scope.<Menu, nodes: [HTMLElement.<button>]>
.blur() // => Scope.<Menu, nodes: [HTMLElement.<button>]>
components | React.Component | Array.<React.Component> These must be rendered instances not actual classes/types. |
nodes | Array.<Node> The DOM nodes this scope represents otherwise we'll look for the nodes of the components. |
path | String The path of this scope.
Defaults to the |
parentScope | Scope The parent scope in which this scope resides. Null if this is the global scope. |
React.Component
A cursor to the React component instance this scope represents. Component selectors will be operating based on this instance.
Array.<HTMLElement>
The DOM nodes this scope contains. All DOM helpers will be operating against these nodes.
String
The path is used for displaying helpful assertion errors. It could look like this:
Root > Button > .icon
Root > .icon[] > .icon-close
Scope
The parent scope for this scope, if any. We utilize this for things like
#end()
where we need to traverse the scope ancestry.
Node
The first node of this scope. Most of the time, we only have one node to operate on (like a React component's root node) and so this is a convenient accessor.
assert(drill(component).node.textContent === 'foobar')
assert.ok(
drill(component)
.find('input')
.node.disabled
)
React.Component
A cursor to the the first component in this scope. Most of the time, we only have one for a scope so this is a useful shortcut.
assert.ok(
drill(component)
.find(Button)
.component.props.disabled
)
It's worth mentioning that it's usually bad practice to reach out to components in test with the exception, perhaps, of inspecting their props.
Find a single component or DOM node within this scope.
If you query using a React class, the new scope will represent the component that was found plus its DOM node.
If you query using a DOM selector, the new scope will represent the same component plus the DOM node that was found.
If the target could not be found, an AssertionError will be thrown.
selector | String | React.Class A query compatible with querySelectAll() or a React.Class type. |
cond | Matcher? |
Find one or more components or DOM nodes within this scope.
If you query using a React class, the new scope will represent all the components that were found plus their DOM nodes.
If you query using a DOM selector, the new scope will represent the same components plus the DOM nodes that were found.
If not a single target could be found, an AssertionError will be thrown.
selector | String | React.Class Either a querySelector or a React.Class. |
cond | Matcher? Predicate to filter the targets by. |
"Warp" the scope to another component that may be outside of the current DOM tree and is accessible only through a property on the scope's current component(s).
drill(component)
.find(ReactModal)
.warp(modal => modal.portal)
.find(Button)
Warping is shown in practice in this example.
Like Scope#warp but only affects the DOM nodes.
drill(component)
.find(PikadayDatePicker)
.warpToNode(component => component.pikaday.el)
.find('button', m.hasText('Choose date'))
.click()
Warping is shown in practice in this example.
Change this scope into another type provided by an addon or by your own implementation.
class CustomScope extends Scope {
smack() {
console.log('ouch')
return this
}
}
drill(component)
.morph(CustomScope) // => CustomScope
.smack() // => "ouch"
// => CustomScope
//
// You can still use the stock Scope APIs:
.find('button') // => CustomScope
Find out whether the current scope contains a certain element.
This is a graceful version of Scope#find that will not throw any errors if the target could not be found.
Go back to the previous scope, unless this is already the root scope.
Scope(component)
.find(Button, n => n.textContent === 'Remove')
.click()
.end()
.find(Button, n => n.textContent === 'Confirm Removal')
.click()
This is similar to the .end()
routine in jQuery and d3 if you're familiar
with them.
Clone this scope with the component's DOM node re-evaluated. Use this API when you know the component's DOM node has changed and the scope's pointer has become stale.
Scope A new scope instance pointing to the DOM node of the scope's component. |
Pretty-print the scope's path.
String(Scope(component));
// => MyComponent
String(Scope(component).find('button'));
// => MyComponent > button
String(Scope(component).findAll(Button));
// => MyComponent > Button[]
Create a reference to a property found on the scope's first component that will survive through the drilling.
This is for advanced usage and is really discouraged unless you have no other choice (e.g. you're interfacing with a non-React library.)
const scope = drill(component)
.find(JQueryChosen)
.ref('chosen', component => component._chzn)
scope.refs.chosen // => Object
scope
.find('blah')
.refs.chosen // => Object