Scope Class

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>]>

Constructor

Scope(
  components: React.Component | Array.<React.Component>,
  nodes: Array.<Node>,
  path: String,
  parentScope: Scope
)

Parameters (4)

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 displayName of the component's type.

parentScope
Scope

The parent scope in which this scope resides. Null if this is the global scope.

Instance Properties

components: React.Component

A cursor to the React component instance this scope represents. Component selectors will be operating based on this instance.

nodes: Array.<HTMLElement>

The DOM nodes this scope contains. All DOM helpers will be operating against these nodes.

path: String

The path is used for displaying helpful assertion errors. It could look like this:

Root > Button > .icon
Root > .icon[] > .icon-close
parentScope: Scope

The parent scope for this scope, if any. We utilize this for things like #end() where we need to traverse the scope ancestry.

refs: ObjectPRIVATE
node: 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
)
component: 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.

Instance Methods

    find(
      selector: String | React.Class,
      cond: Matcher?
    )
    -> Scope

    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.

    Parameters (2)

    selector
    String | React.Class

    A query compatible with querySelectAll() or a React.Class type.

    cond
    Matcher?

    findAll(
      selector: String | React.Class,
      cond: Matcher?
    )
    -> Scope

    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.

    Parameters (2)

    selector
    String | React.Class

    Either a querySelector or a React.Class.

    cond
    Matcher?

    Predicate to filter the targets by.

    warp(
      componentLocator: (React.Component) -> React.Component,
      name: String
    )
    -> Scope

    "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.

    warpToNode(
      nodeLocator: (React.Component) -> HTMLElement,
      name: String
    )
    -> Scope

    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.

    morph(Class) -> Class

    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

    has(
      selector: Selector | React.Class,
      cond: Matcher?
    )
    -> Boolean

    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.

    end() -> Scope

    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.

    reload() -> Scope

    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.

    Return Value

    Scope

    A new scope instance pointing to the DOM node of the scope's component.

    toString() -> String

    Pretty-print the scope's path.

    String(Scope(component));
    // => MyComponent
    
    String(Scope(component).find('button'));
    // => MyComponent > button
    
    String(Scope(component).findAll(Button));
    // => MyComponent > Button[]

    ref(
      key: String,
      extract: (React.Component) -> Any
    )
    -> Scope

    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