Skip to content
Pages

Introduction

Ezu (絵図) is an old word for a picture map: a plan of a town or temple grounds with the buildings drawn in. This Ezu draws one of your web app: every page, every UI state on it, and the flows that connect them, from screenshots of the app actually running.

After reading this page, you will know:

  • What Ezu gives you.
  • Where it lives and where your app's part lives.
  • The words the rest of the docs use.

What you get

A map you can browse. bin/ezu map writes tmp/ezu/index.html in your app. It lists every GET route, says which ones a flow reached, and shows each reached page's states as screenshots, in every screen size, language and theme. See the example map, which is this site mapping itself.

A check that fails when a screen changes. Once you approve a map, bin/ezu check runs it again and exits with status 1 if any screenshot differs, a new state has no approval, or an approved state is no longer reached. It works as a visual regression test for the whole app, written as user flows.

Where things live

Ezu is a tool you keep beside your app, like a linter you run from its own checkout. It never goes in your app's Gemfile and adds no code to it.

ezu/                      ← the tool: a Ruby gem with an executable, plus Playwright
your-app/
  bin/ezu                 ← three lines: run ../ezu/exe/ezu with --app pointing here
  ezu/config.rb           ← how to boot the app, its locales, clock, routes to skip
  ezu/flows/*.rb          ← what a user clicks through
  ezu/seed.rb             ← test data, run inside the app
  ezu/approved.json       ← fingerprints of approved screenshots (committed)
  tmp/ezu/                ← the map (ignored by Git)

Your app describes itself. Ezu boots it against a throwaway database, walks the flows in a real Chromium, and writes the map back into your app's tmp/. Add Ezu to an app walks through setting this up.

Words

  • Flow. A named journey through the app, such as "Create a group, split an expense, settle up". It lives in ezu/flows/.
  • Step. One action in a flow and the state it lands on. Each step takes screenshots.
  • State. What a page looks like at a moment: its main state, a variant (an empty list, a form with errors), or an overlay (a dialog open). Its id is the page plus the state's name, such as groups#show/Balance graph.
  • Page. A route, named by its controller and action, such as groups#show.
  • Slot. One screen size in one language, such as mobile-ja. Every flow runs in every slot, in parallel.
  • Adapter. How Ezu boots your app and asks it questions: rails, or command for anything started by a shell command.

What it is not

  • It doesn't test behaviour beyond what a screen shows; keep your system tests.
  • It doesn't run on its own in production or against a shared server. Each run starts its own copies of the app.
  • It doesn't crawl. A page appears on the map only when a flow you wrote lands on it, so the map is also a list of which pages have flows.