zaha v0.1.5
Zaha
Zaha is a javascript utility for generating test builders! Builders allow you to:
- Quickly create test objects automatically populated with default fields
- Abstract the structure of complex objects behind a fluent interface
Get Started
First, you'll want to install the library:
npm i -D zahaThen create a test builder:
// room-builder.js
import zaha, { is } from 'zaha';
export default zaha({
length: is.number(),
width: is.number(),
furniture: is.arrayOf(is.string())
});Then use your new builder in a test!
// room.spec.js
import RoomBuilder from './room-builder';
const room = new RoomBuilder()
.withWidth(500),
.withFurniture(['chair', 'bed'])
.build();Details
Zaha is a function which takes as input a schema and outputs a builder class.
Schemas
A schema is an object whose fields are all builders. It defines what fields you want your eventually build object to contain. The following example of a schema defines an object with a string and numeric field, for instance.
import { is } from 'zaha';
const schema = {
name: is.string(),
age: is.number()
};is
You might notice that this mystical is object can be used to define the types of fields. is provides the following:
is(value): An exact value the field should be when the final object is builtis.string(): A string fieldis.datestring(): A string which represents a dateis.number(): A decimal numberis.int(): An integer numberis.boolean(): A boolean valueis.object(schema): Converts the schema into a basic builder; useful for nested structuresis.array(): Defines an array of any typeis.arrayOf(builder): Defines an array of the provided builder typeis.function(): A callable functionis.oneOf(values): Value must be exactly one of the provided values; values is an array
The following example shows how to use is.object and is.arrayOf:
const schema = {
nested: is.object({
array: is.arrayOf(is.int()),
exact: is('This particular string')
})
};Zaha Builders
Though is is useful, in reality these fields can take any builder. A builder object is simply an object which has the build() method defined on it. This means you can pass in builders created by Zaha into the schema:
const InnerBuilder = zaha(innerSchema);
const schema = {
value: new InnerBuilder()
};Custom Builders
A builder is any object which has build() defined on it. This means you can make your own collection of domain-specific basic builders that you can pass to a Zaha schema.
const randomString = {
build: () => random.string()
};
const author = is.object({
name: randomString,
age: is.number()
});
const schema = { author };Builders
The purpose of Zaha is to create configurable builders. The zaha function converts a schema into a builder class that can be instantiated, like so:
const Builder = zaha(schema);
const builder = new Builder();Builders define two function types:
with<PropertyName>(value): Sets the value of the given property to the given argumentbuild(): Emits an object with the values provided bywith
A with function is generated for each first-order property defined in the schema. You can chain them like so:
const room = new RoomBuilder()
.withWidth(100)
.withLength(200)
.build();Note on property names
- Snake-cased property names, like
last_name, will end up with awithfunction likewithLast_name - Property names which contain arbitrary symbols, like
is-admin?, are not supported
Extending Builders
Zaha emits a class which can be extended. If you want to define custom methods on the builder, it's simple to do:
const Base = zaha({
furniture: is.arrayOf(is.string())
});
export default class RoomBuilder extends Base {
withoutFurniture() {
this.schema.furniture = is([]);
return this;
}
}Example
Here is a full use-case example. Chai is being used here, but any testing framework works with Zaha.
// room-builder.js
import zaha, { is } from 'zaha';
export default zaha({
length: is.number(),
width: is.number(),
furniture: is.arrayOf(is.string())
});import { expect } from 'chai';
import RoomBuilder from './room-builder';
import { moveAllFurniture } from './room-utils';
describe('Furniture Mover', () => {
it('moves all furniture from one room into the other', () => {
const furniture = ['chair', 'table'];
const formerRoom = new RoomBuilder()
.withFurniture(furniture)
.build();
const newRoom = new RoomBuilder()
.withFurniture([])
.build();
moveAllFurniture.from(formerRoom).to(newRoom);
expect(formerRoom.furniture).to.be.empty;
expect(newRoom.furniture).to.deep.equal(furniture);
});
});