jasmine_react

Jasmine utilities and helpers for testing React components.

jasmine_react

Turn a jasmine Suite into one suitable for testing React components.

Example:

var Checkbox = require('jsx!components/checkbox');
 
describe('Components.Checkbox', function() {
    this.reactSuite({ type: Checkbox });
 
    it('should render', function() {
        expect(subject.isMounted()).toBeTruthy();
    });
});

The following features will become available to your suite:

In your global suite context, "subject" will contain a reference to the mounted instance of the component you're testing, created and mounted during each test in your suite.

All the DOM helpers detailed below are injected into the global context throughout your tests, so you can conveniently use things like find() and click().

Note

Most of these helpers operate on nodes inside the node of the component being tested, so when you do find('.foo') it will look for a child that has the foo class only inside the mounted component instance.

Locate a single element using a jQuery-compatible selector. Returns an HTMLElement if found.

it('should show a link', function() {
  expect(find('a:contains("My Link Text")').length).toBe(1);
});

Like find() but returns a set of all elements that match the selector.

Simulate a mouse-click. If a selector was passed in and it did not yield an element, an error will be thrown.

it('should track clicks', function() {
  click('button');
  expect(subject.state.clickCount).toBe(1);
});

Toggle the checked state of a radio button or a checkbox. You can explicitly set the state by passing true or false as the second parameter.

it('should track the mute-sound preference', function() {
    check(':contains("Mute Sounds")', true);
    expect(subject.state.muteSound).toBe(true);
});

Choose an option from a <select /> dropdown menu. The value parameter should map to the <option /> element you want to choose.

There is currently no support for multiple-option dropdowns.

it('should choose my primary currency', function() {
    select('[name="currency"]', 'JOD');
    expect(subject.state.currency).toEqual('JOD');
});

Change a text-input field's value. This does not simulate typing, the typeIn helper does that instead.

it('should track my favorite colour', function() {
    fillIn('[name="colour"]', 'banana');
    expect(subject.state.colour).toEqual('banana');
});

Simulate typing into a text field.

Typing in will change the node's value, emit the change event, along with a keydown event for every character in the text.

it('should limit text to 10 chars', function() {
    typeIn('input', 'hello you should not cut me off really its not nice');
    expect(subject.state.text).toEqual('hello you');
});

WARNING!!!

This requires jasmine.promiseSuite to be available from jasmine_rsvp.

Update the component props. Returns an RSVP.Promise that fulfills when the component has been re-rendered with the new props.

it('should render the name', function() {
    expect(find('span.name').innerText).toEqual('');
 
    setProps({
        name: 'Ahmad'
    });
 
    expect(find('span.name').innerText).toEqual('Ahmad');
});

Similar to #setProps() but for the component's internal state, which generally you should avoid touching.

Shortcut for testing that a certain element exists in the DOM.

// Instead of: 
expect(findAll('.something').length).toEqual(1)
 
// You can do: 
expect('.something').toExist();

WARNING!!!

This requires jasmine.promiseSuite to be available from jasmine_rsvp.

This is very opinionated and most likely won't apply to your code, but it does to mine so it's here. My components are glued to only "emit" actions when there's any sort of processing required. This allows me to decouple the UI (components) from actual domain logic handling, and consequently, it makes testing component interaction pretty slick.

To test if a component is sending actions correctly, a custom matcher is exposed to your suite, called toSendAction(). The matcher accepts either a string, which would be the event such as user:signup, or account:save, or a more descriptive object (see below.)

Example:

it("should totally remove one's account when clicking the red button", function() {
  expect(function() {
    click('#the_red_button');
  }).toSendAction('users:unregister');
});

Example 2: verifying the correct parameters are being sent.

We can also test the parameters the component is sending. Let's assume we have a Preferences component that sends the updatePreferences action with the user's chosen preferences.

var Preferences = React.createClass({
    render: function() {
        return (
            <form>
                <select ref="weekday">
                    <option value="friday">Friday</option>
                    <option value="saturday">Saturday</option>
                    <option value="sunday">Sunday</option>
                </select>
                <button id="save">Save</button>
            </form>
        );
    },
 
    onClick: function() {
        this.sendAction('updatePreferences', {
            weekday: this.refs.weekday.value
        });
    }
});

If the user chooses Friday to be their starting day of the week, the component should emit the right action with that weekday:

it("set the prefered starting weekday", function() {
    expect(function() {
        select('[name="weekday"]', 'Friday');
        click('#save');
    }).toSendAction({
        action: 'updatePreferences',
        args: {
            weekday: 'friday'
        }
    });
});

MIT