docs/contributing/testing.md
Ghost has several test suites across the monorepo. Start with the suite closest to the behavior you changed, then run the broader checks before submitting your pull request.
From the repository root, run:
pnpm check
This is the default one-stop command for linting and testing. It runs
pnpm lint followed by pnpm test across the monorepo.
pnpm check does not run the Playwright browser end-to-end suite or Ember
Admin's test suite. Run those separately when your change affects those areas.
Put tests as close as possible to the code and behavior under test:
test or test:unit target.ghost/core/test/integration/.ghost/core/test/e2e-*/. These are Vitest suites, not browser
tests. See the Ghost Core E2E guide for the
request agents, fixtures, mocks, and snapshot helpers.test:acceptance target.e2e/. See
Writing Browser E2E Tests for conventions and examples.apps/ember-admin/ and run through Ember Exam via Nx.When a regression crosses several layers, prefer a focused test at the lowest layer that proves the fix. Add a broader acceptance or browser E2E test when the integration between layers is itself the behavior being protected.
For physical-device testing and URL configurations such as HTTPS, subdirectories, or a separate Admin origin, see Testing development URLs and devices.
Nx can run a target for one workspace from the repository root:
pnpm nx test <project-name>
pnpm nx test:unit <project-name>
pnpm nx test:acceptance <project-name>
Check the workspace's package.json or list its Nx targets when you are unsure
which targets it provides:
pnpm nx show project <project-name>
For Ghost Core, run its suites from ghost/core/:
cd ghost/core
pnpm test:unit
pnpm test:integration
pnpm test:e2e
pnpm test:all
test:all runs Ghost Core's unit, integration, server E2E, and lint targets. To
run one Ghost Core test file, use:
pnpm test:single test/unit/path/to/test.test.js
pnpm test:single test/integration/path/to/test.test.js
Watch mode at the repository root covers unit tests across the workspace:
pnpm test:watch
To watch a single database-backed Ghost Core file, point Vitest at the database configuration explicitly:
cd ghost/core
pnpm exec vitest -c vitest.config.db.ts test/integration/path/to/test.test.js
Ghost Core's database-backed suites use SQLite by default locally. Tests for optional Redis and object-storage adapters skip when their services are not available; start the relevant development services when you need to exercise those adapters.
The browser suite needs its test infrastructure running. For the normal
development flow, keep pnpm dev running in one terminal and run the suite from
another:
# Terminal 1, from the repository root
pnpm dev
# Terminal 2, from the repository root
pnpm test:e2e
Run a specific file or match a test title by passing Playwright arguments. For example, the first command runs the existing Admin sign-in test:
pnpm test:e2e tests/admin/signin.test.ts
pnpm test:e2e --grep "publish a post"
Use pnpm test:e2e:debug for Ghost E2E debug logs. See the
E2E workspace README for infrastructure modes, test
isolation, fixtures, and debugging, and
Writing Browser E2E Tests for test conventions, selectors,
and Page Objects.
Always run Ember Admin tests through Nx so its dependency graph is built first:
# From the repository root
pnpm nx run ghost-admin:test
For one file, pass the numeric parallel value required by the Ember Admin test script before the Ember Exam arguments:
pnpm nx run ghost-admin:test -- 1 \
--file-path=tests/acceptance/editor/publish-flow-test.js
Do not run ember test or ember exam directly from apps/ember-admin/.
Doing so bypasses Nx's dependency builds and can leave required Admin and
Koenig outputs missing.
Run pnpm check to ensure everything works. Also run the relevant browser E2E,
app acceptance, or Ember Admin suite when your change affects those areas.
If a full suite is impractical locally, run the most relevant focused tests and state exactly what you ran in the pull request.