We use:
We went from ~200 unit tests to ~1000 tests in 7 months.
December 2015
chai-jsx based on react-element-to-jsx-string
it('manages loading only (default)', function() {
button = render(<Button loading onClick={dummyClickHandler}/>);
expect(button).jsx.to.equal(
<button className="button" disabled type="submit"
onClick={dummyClickHandler} onMouseDown={undefined}>
<span style={{position: 'relative'}}>
<span className="spinner shown spinner--white spinner--md"/>
<span style={{visibility: 'hidden'}}/>
</span>
</button>
);
});
Luckily announced when we were looking for something better
There was a bit of setup involved but…
it('has a default spinner', function() {
wrapper = render(<Button loading block onClick={dummyClickHandler}/>);
const button = wrapper.find('button.button--block');
expect(button).to.have.length(1);
expect(button.find('.spinner.shown.spinner--white.spinner--md'))
.to.have.length(1);
});
<Button/> loading has a default spinner
✘ expected { Object (options, _root, ...) } to have a length of 2 but
got 1
Sugar on top of enzyme and chai.
Provides expressive assertions.
it('has a default spinner', function() {
wrapper = render(<Button loading onClick={dummyClickHandler}/>);
const button = wrapper.find('button');
expect(button).to.have.exactly(1).descendants('.spinner.shown.spinner--white.spinner--md');
});
<Button/> loading has a default spinner
✘ expected the node in <??? /> to have 2 descendants
'.spinner.shown.spinner--white.spinner--md' but actually found 1
HTML:
<button type="submit" class="button button--block" disabled>
<span style="position:relative;"><span class="spinn
er shown spinner--white spinner--md"></span><span></span></span>
</button>
context('when a payment is errored', function() {
beforeEach(function() {
wrapper = shallow(<PaymentPage
{...baseProps}
serverRespondedWithError
/>);
});
it('renders an error payment page', function() {
expect(wrapper).to.have.descendants(ErrorPayment);
});
it('renders a back to basket link', function() {
expect(wrapper).to.have.descendants(BackToBasketLink);
});
});
Notice object spread to avoid propTypes warnings
it('calls payWithNewCard when submitting form', function() {
const paySpy = sinon.spy();
const preventDefaultSpy = sinon.spy();
const wrapper = shallow(<CreditCardForm
{...defaultProps}
payWithNewCard={paySpy}
/>);
const form = wrapper.find('form');
form.simulate('submit', {preventDefault: preventDefaultSpy});
sinon.assert.called(preventDefaultSpy);
sinon.assert.called(paySpy);
});
.state(). It's an internal implementation detail. Rather test the props. Refactoring will be easier.setTimeout.Move the business logic outside of components:
beforeEach(function() {
PaymentPageContainerRewireAPI.__set__('redirectTo', sinon.stub());
});
afterEach(function() {
PaymentPageContainerRewireAPI.__ResetDependency__('redirectTo');
});
// …
sinon.assert.calledWith(
PaymentPageContainerRewireAPI.__get__('redirectTo'),
fakePayWithDirectDebit.redirectUrl
);
const methodsToStubWithPromise = [
'payWithRegisteredCard',
'fetchPaymentData',
];
methodsToStubWithPromise.forEach(method => {
let deferred;
const stub = sinon.stub().returns(new Promise((resolve, reject) => {
deferred = {
resolve,
reject,
};
}));
PaymentPageContainerRewireAPI.__Rewire__(method, stub);
promiseStubs[method] = {
deferred,
stub,
};
});
promiseStubs.fetchPaymentData.deferred.resolve({ body: fakePaymentData});
//…
sinon.assert.calledWith(
promiseStubs.payWithRegisteredCard.stub,
fakePaymentUuid,
{
cardId: cardA.id,
keepCard,
}
);