Project Structure

This page explains the files and folders generated by hsemulate init [python|js] and how they are used.

The structure is intentionally minimal and mirrors how HubSpot custom code actions are authored and tested.


Generated Structure

.
├── config.yaml
├── actions/
│   └── action.js
├── fixtures/
│   └── event.json
├── assertions.json
├── snapshots/
│   └── action.snapshot.json

File and Folder Breakdown

config.yaml

The main configuration file.

Defines:

  • Which action to run

  • Runtime (Node or Python)

  • Fixtures to load

  • Environment variables

  • Budgets, output mode, and snapshot settings

This file is required.


actions/

Contains your HubSpot custom code action files.

  • Place the exact code you paste into HubSpot here

  • No wrapper or adapter code is needed

  • Supports JavaScript and Python

Only one entry file is executed per run.


fixtures/

Contains JSON files representing HubSpot workflow events.

  • Each file is passed to the action as the event payload

  • Fixtures should match real HubSpot events as closely as possible

  • Multiple fixtures can be defined and executed

Fixtures enable deterministic, repeatable runs.


assertions.json

Defines correctness checks applied after execution.

Used to:

  • Validate output fields

  • Assert JSON paths exist or match expected values

  • Fail the run when expectations are not met

Assertions run after the action completes.


snapshots/

Stores snapshot outputs for regression testing.

  • Snapshots capture action output and metadata

  • Ignore rules can be applied for non-deterministic fields

  • Snapshots are compared on subsequent runs

This folder is optional but recommended for non-trivial logic.


Minimal Required Files

At minimum, a runnable project requires:

  • config.yaml

  • An action file in actions/

  • At least one fixture in fixtures/

Assertions and snapshots are optional but strongly recommended.


Design Notes

  • The structure mirrors the mental model of “code + event + expectations”

  • No hidden state or global configuration is used

  • All behaviour is defined within the project directory

This makes projects easy to version, share, and run in CI.