At first I was really bothered that AVA didn't have support for nested tests, but now I consider nesting tests to be an anti-pattern.
Here's an example of the kind of thing I mean (see this in a syntax-highlighted gist here):
Mocha with nesting (don't mind the actual tests, just imagine what this would be like with a larger test file):
import Customers from './Customers'
import getMockCustomers from './Customers/mocks'
describe('Customers', () => {
let mockCustomers
beforeEach(() => {
Customers.setCustomers([]) // initialize to empty for most tests
mockCustomers = getMockCustomers() // have mock customers available
})
afterEach(() => {
Customers.setCustomers([]) // clean up just in case
})
describe('getCustomers', () => {
beforeEach(() => {
Customers.setCustomers(mockCustomers)
})
it('should return the existing customers', () => {
const customers = Customers.getCustomers()
expect(customers).to.be.eql(mockCustomers)
// questions you must ask if you're not familiar with this file and
it's bigger:
// - where does `mockCustomers` come from?
// - what make `getCustomers` return the mockCustomers?
})
})
describe('setCustomers', () => {
it('should set the customers array', () => {
Customers.setCustomers(mockCustomers)
const customers = Customers.getCustomers()
expect(customers).to.be.eql(mockCustomers)
// question you must ask if you're not familiar with this file and
it's bigger:
// - where does `mockCustomers` come from? What is it initialized as?
})
})
})
Here's what it would look like without nesting (with AVA, though you could mostly do this with Mocha too):
import test from 'ava'
test('getCustomers: should return the existing customers', t => {
const mockCustomers = initializeCustomers()
const customers = Customers.getCustomers()
t.deepEqual(customers, mockCustomers)
cleanupCustomers()
})
test('setCustomers: should set the customers array', t => {
initializeCustomers([])
const mockCustomers = getMockCustomers()
Customers.setCustomers(mockCustomers)
const customers = Customers.getCustomers()
t.deepEqual(customers, mockCustomers)
cleanupCustomers()
})
function initializeCustomers(initialCustomers = getMockCustomers()) {
Customers.setCustomers(initialCustomers)
return initialCustomers
}
function cleanupCustomers() {
Customers.setCustomers([])
}
Like I said, this may be a bad example. Don't be distracted by the tests
themselves. Just look at the it
blocks above in the Mocha tests and
compare it to the test
block in the AVA tests below. The difference is
that with the it
blocks, you have to keep in your head what's going on in
a beforeEach
and that relationship is implicit. In the test
block,
there is a level of abstraction, but it's explicit so you don't need to
worry about keeping it in your head because it's in front of your face.
I hope this is helpful!