npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@digital-commons-official/codeceptjs-storyboard

v1.0.3

Published

Storyboard plugin for CodeceptJS: one Gherkin sentence = one card = one pixel baseline, and every scenario renders itself as a single SVG storyboard

Readme

🎬 codeceptjs-storyboard

pipeline status

A CodeceptJS plugin that turns one Gherkin scenario into one human-readable SVG storyboard, straight from the real screenshots the test captures.

ONE Gherkin sentence = ONE card = ONE pixel baseline, asserted inside its step at tolerance: 0: a visual regression fails on the exact sentence whose image drifted. When the scenario ends the plugin assembles the whole story into one SVG: the frames stay bitmap, but every caption, note and reproduce-command around them is real selectable text you can copy from the SVG (Chromium/Safari).

Installation 📦

npm install --save-dev codeceptjs playwright @digital-commons-official/codeceptjs-storyboard @digital-commons-official/codeceptjs-visual-helper
npx playwright install chromium

Requires Node.js >= 22.19.0, CodeceptJS ^4.2.0 and @digital-commons-official/codeceptjs-visual-helper >= 1.3.0. The plugin captures and asserts through I.takeScreenshot, I.captureScreenshot and I.assertVisualMatch.

VisualHelper is required: enable it in CodeceptJS as shown below. Keeping it as a peer dependency lets the plugin use your project's helper and CodeceptJS installation.

Tested versions

The browser suite installs the actual packed package into six fresh projects:

| Node.js | CodeceptJS | VisualHelper | |---------------------------|------------|--------------| | 22.19.0, 24.21.0, 26.10.0 | 4.2.0 | 1.3.0 | | 22.19.0, 24.21.0, 26.10.0 | 4.2.0 | 2.0.3 |

Each project imports its own four packages, passes npm audit, records one English journey and three French Rule cases, then reruns with strict pixel comparison. All fourteen baseline hashes must stay unchanged and match across the six combinations. The real gallery must link all four journeys.

Node 18 is rejected with --engine-strict; CodeceptJS 4.0 is rejected with --strict-peer-deps. Older CodeceptJS 4.0 consumers also fail the security audit. The declared ranges allow later compatible versions; the table states the exact versions exercised in CI. Use the same Playwright browser and fonts when comparing pictures across machines.

These installation tests use npm pack and real npm commands. They do not authenticate a publication to the registry; the release job and npm provenance provide that separate proof.

Public API and compatibility

The package root exports the CodeceptJS plugin factory and these functions. Their signatures are defined in src/index.d.ts.

| Functions | Contract | |--------------------------------------------------------------|------------------------------------------------------------------------------------------| | storyboardStep | Register a literal sentence and its optional note/copy annotation. | | capturePageFrame, captureElementFrame, frameOutputPath | Capture a real viewport or element and return its frame path. | | addStoryboardFrame, assertOrUpdateBaseline | Assert pixels strictly; only TASK_E2E_UPDATE_BASELINES=1 outside CI records baselines. | | begin, baseDir, panel, frame, annotate, panels | Manage a scenario's cards; frame attaches an image without asserting it. | | parseScenarioLines, render | Read the original Gherkin sentences and render their SVG. | | tryTo | Re-export the CodeceptJS effect for an optional action. |

The supported plugin options are theme and replayCommand; CodeceptJS owns require and enabled. From 1.0.0, compatible releases preserve this public API and the documented baseline recording behaviour. Removing a public function, changing its required arguments or raising a supported minimum requires a major release. Internal modules under src/ are implementation details; use the package root.

The parser follows Cucumber's Gherkin dialects. Feature and Rule backgrounds, Scenario Outlines and Examples, inherited tags, repeated titles, data tables and doc strings are supported. Real browser journeys cover English, French and German; parser tests cover other dialects, including joined keywords. Tables and doc strings are step arguments, not extra cards. A filtered run with no matching scenario fails. Future dependency versions still need the same compatibility checks; the matrix above identifies the versions verified.

Configuration ⚙️

Register the plugin next to the visual helper in codecept.conf.js, and point Gherkin at your step files:

exports.config = {
  output: './_output',
  noGlobals: true,
  helpers: {
    Playwright: {
      browser: 'chromium',
      url: 'http://localhost:8080',
      show: false,
      windowSize: '1280x720'
    },
    VisualHelper: {
      require: require.resolve('@digital-commons-official/codeceptjs-visual-helper'),
      baselineDir: './screenshots/base/',
      diffDir: './screenshots/diff/',
      actualDir: './_output/',
      tolerance: 0,
      captureBaseline: false
    }
  },
  gherkin: {
    features: './features/**/*.feature',
    steps: ['./steps/first-run.js']
  },
  plugins: {
    storyboard: {
      require: '@digital-commons-official/codeceptjs-storyboard',
      enabled: true
    }
  }
}

Nothing configures paths: everything is derived from the feature file location. Frames land in _output/storyboard-frames/, baselines in screenshots/base/<feature-dir>/<scenario-tag>/, the committed SVG in storyboards/<feature-dir>/<scenario-tag>.svg. A scenario that never calls addStoryboardFrame renders no SVG, so plain Gherkin tests are left untouched.

When the run ends, open _output/index.html to browse its storyboards. The page groups scenarios by feature directory, puts failed groups and scenarios first, and shows the failed sentence with its replay command. Links open the actual SVGs.

A filtered run lists only the scenarios it ran. In baseline-update mode, storyboards/index.html lists the passing scenarios from that update; failed scenarios never replace reviewed storyboards. Run the full suite in update mode to rebuild the complete reviewed gallery.

Replay commands

The gallery and SVG default to npx codeceptjs run --steps --grep "{tag}". {tag} becomes the scenario's last tag. This command works in a standalone CodeceptJS project with a local installation and its default configuration file.

Toolbox projects can set their Task command on the plugin:

storyboard: {
  require: '@digital-commons-official/codeceptjs-storyboard',
  enabled: true,
  replayCommand: 'task test -- --grep "{tag}"'
}

For another configuration file, include its --config argument in the template. Use a unique scenario tag so the command selects the intended journey.

Colours and fonts

Set theme on the storyboard plugin to an object, a CSS file path, or an HTTP(S) URL:

storyboard: {
  require: '@digital-commons-official/codeceptjs-storyboard',
  enabled: true,
  theme: './storyboard.css'
  // Or: theme: 'https://example.org/storyboard.css'
  // Or: theme: { bg: '#f6f8fb', text: '#192b3d', sans: 'Georgia, serif' }
}

Relative paths start at the directory containing codecept.conf.js. The plugin loads the theme once per run, before the first scenario's steps, and embeds its values in every SVG. Remote requests time out after five seconds. A missing, unreachable or invalid theme emits a warning and uses the default dark theme.

:root {
  --sb-bg: #f6f8fb;
  --sb-card: #ffffff;
  --sb-slot: #edf2f8;
  --sb-text: #192b3d;
  --sb-dim: #42576b;
  --sb-accent: #175fa4;
  --sb-code-bg: #e7eef7;
  --sb-given: #356b16;
  --sb-when: #175fa4;
  --sb-then: #7b3990;
  --sb-font-sans: Georgia, serif;
}

Supported object keys are bg, card, slot, text, dim, accent, badge, codeBg, given, when, then, fail, sans and mono. CSS uses --sb-<key>, except codeBg becomes --sb-code-bg, and the fonts use --sb-font-sans and --sb-font-mono. Omitted values keep their defaults. Colours accept hex, named colours, rgb() and hsl() values; fonts accept installed font family names and fallback lists.

Only these properties are read. Imports, external fonts and arbitrary CSS rules are not embedded. The SVG works offline; install the same fonts on machines where matching typography matters. Themes change the labels and cards around captured frames; the screenshot pixels stay unchanged.

Usage 🚀

The .feature is the single human-authored source

Attach structured comments to the sentence just below them. The feature file carries the story, the step file only drives and captures:

  • # Chapter: Title opens a full-width chapter band before that card.
  • # Note: text is the card's explanation: what to look at, why it matters. Repeat the line to stack paragraphs.
  • # Copy: command is the exact command shown one-click-copyable under the card.

The scenario's LAST tag names the baseline directory and the replay command printed on the board.

@e2e @first-run
Feature: A developer opens their new project
  Scenario: The project home shows the framework
    # Chapter: The empty project
    # Note: The project as GitLab shows it, before anything is installed.
    # Copy: http://gitlab/<user>/<project>
    Given a fresh project with only a README on its main branch

The step file drives and captures

/* global inject Given */
const { I } = inject()
const storyboard = require('@digital-commons-official/codeceptjs-storyboard')

storyboard.storyboardStep(Given, 'a fresh project with only a README on its main branch', async () => {
  await I.amOnPage('/my/project')
  await storyboard.addStoryboardFrame(I, await storyboard.capturePageFrame(I, 'project-home'))
})
  • storyboardStep(register, sentence, fn) registers the step and escapes cucumber-expression metacharacters, so CI/CD or (y/N) in a sentence never breaks the match. Cards open automatically for every sentence.
  • capturePageFrame(I, name) captures the full viewport; captureElementFrame(I, name, selector) crops the frame to one element, so a short verdict yields a short card.
  • addStoryboardFrame(I, png) refuses a blank frame, attaches the frame to the open card and asserts it against its own baseline at once. On drift the error names the frame, the pixel diff, the failure storyboard and the command that regenerates the baseline.
  • annotate({ note, copy }) overrides the feature comments for a value only known at runtime.

Gherkin languages and examples

Set # language: fr (or another Cucumber dialect) on the first line of a feature file. Without this header, Gherkin uses English. Storyboards keep the source keywords, accents and scenario title, including keywords joined directly to the sentence. Register the translated sentences in your CodeceptJS step definitions.

Background steps and outline examples appear in execution order. Each example row gets its own SVG and baseline directory, with an -example-<line> suffix. Repeated sentences keep their own annotations.

# Chapter, # Note and # Copy remain the annotation keys in every language; outline values are substituted in them too. Text inside doc strings and data tables does not become an extra card or annotation.

Invalid syntax or an unknown dialect produces an error naming the feature file. The enabled plugin completes CodeceptJS's Gherkin loader for Rule scenarios, including localized keywords such as Règle. The feature background runs before each case; a rule background runs only for cases in that rule. Outline examples remain separate tests and rule tags can be selected with --grep. Repeated scenario titles in different rules keep their own source annotations. An empty selection fails clearly instead of succeeding with zero tests.

The multilingual storyboard runs English, French and German examples and shows a real visual regression on a French sentence.

The rule storyboard executes two French outline examples and a second rule, checks both backgrounds and the tag filter, and proves the exact sentence of a deliberate visual regression.

What you get

  • On every run the SVG of the scenario is written under _output/<feature-dir>/<scenario-tag>.svg.
  • On a failed run that SVG shows, in place of the drifted card, a red band with the expected image, the changed pixels and the actual image, each over its copyable path, then lists the sentences the run never reached.
  • In baseline-update mode the plugin asserts first and rewrites a baseline only when its assert fails, then rebuilds the committed SVG under storyboards/ from the reviewed baselines:
TASK_E2E_UPDATE_BASELINES=1 npx codeceptjs run

Only the exact value 1 enables recording. An empty value, 0 or false keeps strict comparison. Every baseline written in recording mode must be inspected by a human, which is why that mode throws when CI is set.

API 📚

| Function | Purpose | |-------------------------------------------------|--------------------------------------------------------------------------| | storyboardStep(register, sentence, fn) | Register a sentence literally through Given, When or Then | | capturePageFrame(I, name) | Full-viewport frame, returns the PNG path | | captureElementFrame(I, name, selector) | Element-cropped frame, returns the PNG path | | addStoryboardFrame(I, png) | Attach the frame to the open card and assert it at tolerance: 0 | | annotate({ note, copy }) | Runtime override of the open card's note and copyable command | | assertOrUpdateBaseline(I, name) | The assert-or-rewrite primitive addStoryboardFrame relies on | | render(outFile, { imageDir, failure, theme }) | Write the SVG, optionally with a theme object | | parseScenarioLines(featureFile, title) | Every sentence of a scenario with its # Chapter / # Note / # Copy | | begin, panel, frame, panels | The board primitives the plugin drives (useful for standalone rendering) |

Type definitions ship in src/index.d.ts.

Development 🛠️

task build                              # install dependencies + build the e2e runner image
task test                               # unit tests, then the e2e storyboard suite
task project:test:storyboard            # unit tests only (vitest)
task project:test:storyboard:e2e        # e2e storyboard suite only, inside the pinned Playwright runner
task project:test:storyboard:e2e -- --grep "@storyboard-happy-path"
TASK_E2E_UPDATE_BASELINES=1 task project:test:storyboard:e2e   # regenerate drifted baselines + committed SVGs, then LOOK at them
task code                               # linters (MegaLinter)

The e2e suite is the plugin's own dogfood: every scenario is a storyboard rendered by the plugin under test, committed under tests/e2e/storyboards/.

The installation storyboard packs the current source, installs the tarball into a fresh project, and runs the README configuration verbatim. It checks CodeceptJS 4.2.0, Playwright 1.63.0 and VisualHelper 1.3.5 in Chromium. It opens the generated index.html and SVG, repeats the run with strict baselines, then proves that a changed page fails on its exact sentence.

The consumer manifest pins those tools and overrides vulnerable transitive dependencies. Its lockfile makes the test repeatable. The separate version matrix verifies the six combinations listed above. Complete installation and run logs are kept in tests/e2e/_output/consumer-install.log and tests/e2e/_output/matrix/.

The clean-consumer test also copies the replay command from the generated gallery and executes it unchanged, then checks that every strict baseline hash is intact.

Licence 📜

EUPL-1.2