I'm very pleased to announce the first release of Smokestack, a library for generating test fixtures for your Ash resources.

Declarative DSL

Smokestack uses a Spark, the system behind all the DSLs in the Ash ecosystem to define very simple factories:

defmodule MyApp.Factory do
  use Smokestack

  factory Character do
    attribute :name, &Faker.StarWars.character/0
    attribute :affiliation, choose(["Galactic Empire", "Rebel Alliance"])

Smokestack uses the introspection built in to Spark to introspect your resources and validate that each attribute refers to an actual attribute, what relationships are defined and how to build them.


Each attribute uses a template to generate a value when building a factory. Templates can be anything that implements the Smokestack.Template protocol. This protocol is automatically implemented for functions with arities zero through two - meaning you can just drop in your own functions - or use one of the built-in helpers.


Sometimes you need to define more than one factory for a resource to put it in a slightly different state. You can do this using variants, which allow you to name the factory with an atom.

Here's an example defining an alternate :trek variant for the character factory defined above:

factory Character, :trek do
  attribute :name, choose(["J.L. Pipes", "Severn", "Slickback"])
  attribute :affiliation, choose(["Entrepreneur", "Voyager"])


Smokestack can use your factory definitions to build records in your data storage using Ash.Seed.seed!/2 via the insert/2 and insert!/2 functions which are automatically defined on your factory module. It can also automatically build related records by passing a build option, much like an Ash load statement and load relationships, calculations and aggregates.

As well as creating records directly you can use the params/2 and params!/2 function to build a simple map of attributes, transform it and even JSON encode it, for use in controller and API testing.


I hope that Smokestack improves the ergonomics of writing tests for Ash applications and look forward to seeing how it works (and how it doesn't) in the future. Happy coding!