Skip to content

Bumped @tryghost test-helper packages to v2.1.0#27514

Merged
9larsons merged 3 commits intomainfrom
bump-tryghost-test-helpers-v2
Apr 22, 2026
Merged

Bumped @tryghost test-helper packages to v2.1.0#27514
9larsons merged 3 commits intomainfrom
bump-tryghost-test-helpers-v2

Conversation

@9larsons
Copy link
Copy Markdown
Contributor

@9larsons 9larsons commented Apr 22, 2026

Summary

Bumps the three @tryghost/* test-helper packages from their pre-1.0 versions up to 2.1.0, the current releases from the TryGhost/Framework monorepo.

Package From To
@tryghost/express-test 0.15.5 2.1.0
@tryghost/email-mock-receiver 0.3.16 2.1.0
@tryghost/webhook-mock-receiver 0.2.22 2.1.0

Scope is intentionally narrow — only ghost/core devDependencies (plus email-mock-receiver which was a regular dep). The public API surface consumed in ghost/core/test/utils/** (the default Agent export, .snapshot.{snapshotManager,any,stringMatching}, WebhookMockReceiver, EmailMockReceiver) is preserved in the new versions.

Password-reset snapshot change — not a regression

The legacy suite's Authentication API > Password reset > reset password test produced a snapshot diff with a new set-cookie: ghost-admin-api-session=... entry. Root cause:

  • @tryghost/express-test@0.15.5 built fake req/res using the reqresnext package
  • @tryghost/express-test@2.1.0 builds real http.IncomingMessage / http.ServerResponse objects wired to a mock socket

The old mock wasn't spec-compliant enough to drive Ghost's admin-session middleware, so any Set-Cookie it produced never reached the response snapshot. The new real-http implementation runs the middleware pipeline fully, so the session cookie Ghost has always issued on a successful password reset (the reset logs the user in) now shows up where it always should have.

Updated the snapshot to match, using the same stringMatching(/^ghost-admin-api-session=/) pattern already in use in test/e2e-api/admin/session.test.js so dynamic cookie values/expiries don't make the snapshot brittle.

E2E validation of the cookie behavior

Added a one-line assertion to e2e/tests/admin/reset-password.test.ts to independently confirm the cookie is emitted by the real server, not just by the new mock layer:

const cookies = await page.context().cookies();
expect(cookies.find(({name}) => name === 'ghost-admin-api-session')).toBeDefined();

Why this is the right level of validation:

  • The existing assertion (analyticsPage.header is visible) only implicitly proves session auth works — if the cookie were missing, the UI would redirect back to login and the check would fail with a generic navigation timeout
  • Reading from page.context().cookies() after the UI transition directly pins down the mechanism, so a future regression in session emission fails here with a precise message
  • No new fixtures, no waitForResponse plumbing — just reads cookies already populated by the browser by the time the test gets there
  • Confirmed end-to-end against pnpm dev: the test passes, meaning a real browser receives and stores the cookie after a real password reset through Ghost's real middleware stack

This matches the v2 behavior of express-test to genuine server behavior, confirming the snapshot change is correct.

Why the big snapshot churn

The 80-ish .snap files in this diff have only a single-line change each — the @tryghost/jest-snapshot banner comment URL was updated upstream:

-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

No snapshot content changed. The rewrite is a cosmetic artifact of running the snapshot serializer from the new jest-snapshot version (transitive via express-test).

pnpm install reports net +23 / -25 packages — the Framework repo dropped several runtime deps (got from webhook-mock-receiver's runtime, lodash.template, etc.).

Test plan

  • pnpm install (clean)
  • cd ghost/core && pnpm test:unit — 6121 passing
  • cd ghost/core && pnpm test:integration — 242 passing
  • cd ghost/core && pnpm test:e2e — 1569 passing
  • cd ghost/core && pnpm test:legacy — 451 passing (the suite that initially caught the snapshot change)
  • cd e2e && pnpm test tests/admin/reset-password.test.ts — passing against pnpm dev
  • CI green

- @tryghost/express-test 0.15.5 -> 2.1.0
- @tryghost/email-mock-receiver 0.3.16 -> 2.1.0
- @tryghost/webhook-mock-receiver 0.2.22 -> 2.1.0

- first wave of a multi-step upgrade to catch ghost/core up with the
  TryGhost/Framework monorepo releases; test helpers first because the
  blast radius is limited to ghost/core's test suite
- snapshot files touched only in the v1 header comment URL, a no-op
  rewrite by the transitive @tryghost/jest-snapshot bump
- unit, integration, and e2e-api suites all pass locally
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: de7b2c80-4b3d-4dff-9223-0b8a46ca43e5

📥 Commits

Reviewing files that changed from the base of the PR and between a7f9abd and 55634f7.

📒 Files selected for processing (1)
  • e2e/tests/admin/reset-password.test.ts

Walkthrough

Updated versions for three mock/test packages in ghost/core/package.json: @tryghost/email-mock-receiver from 0.3.16 to 2.1.0 (dependencies), and @tryghost/express-test from 0.15.5 to 2.1.0 plus @tryghost/webhook-mock-receiver from 0.2.22 to 2.1.0 (devDependencies). Test changes: import stringMatching from matchers, add set-cookie header assertions matching /^ghost-admin-api-session=/ in authentication tests, and add a Playwright assertion that a ghost-admin-api-session cookie exists. No public API changes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: bumping three @tryghost test-helper packages to v2.1.0, which is the primary focus of this PR.
Description check ✅ Passed The description comprehensively explains the changeset, including package version updates, API compatibility, snapshot changes, e2e validation, and test results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bump-tryghost-test-helpers-v2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ghost/core/package.json (1)

102-102: Move @tryghost/email-mock-receiver to devDependencies to match usage scope.

This package is referenced only in test utilities (ghost/core/test/utils/e2e-framework-mock-manager.js) and has no usage in production code. Moving it from dependencies to devDependencies aligns with the scope of related test helpers (@tryghost/express-test, @tryghost/webhook-mock-receiver) already in devDependencies and reduces production install surface.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/package.json` at line 102, Remove "@tryghost/email-mock-receiver":
"2.1.0" from the dependencies block in package.json and add the same entry under
devDependencies (matching the version "2.1.0"); update lockfile by running the
package manager (npm/yarn/pnpm) to regenerate the lockfile so installs reflect
the move and run tests that use test/utils/e2e-framework-mock-manager.js to
verify nothing breaks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ghost/core/package.json`:
- Line 102: Remove "@tryghost/email-mock-receiver": "2.1.0" from the
dependencies block in package.json and add the same entry under devDependencies
(matching the version "2.1.0"); update lockfile by running the package manager
(npm/yarn/pnpm) to regenerate the lockfile so installs reflect the move and run
tests that use test/utils/e2e-framework-mock-manager.js to verify nothing
breaks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eeab39bf-0397-4483-8d0d-05ea5977a2df

📥 Commits

Reviewing files that changed from the base of the PR and between ffc637e and e35e44b.

⛔ Files ignored due to path filters (82)
  • ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/authentication.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/automated-email-design.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/automated-emails.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/backup.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/comments.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/config.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/custom-theme-settings.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/db.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/email-previews.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/emails.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/explore.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/images.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/integrations.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/labels.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/links.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/member-commenting.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/members-edit-subscriptions.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/members-exporter.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/members-newsletters.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/members-stripe-connect.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/members.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/mentions.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/newsletters.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/notifications.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/offers.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/pages-bulk.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/pages.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/post-analytics-export.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/posts-bulk.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/posts.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/rate-limiting.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/recommendations.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/roles.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/search-index.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/session.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/settings-files.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/site.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/slack.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/slugs.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/snippets.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/sso.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/stats.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/tiers.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/users.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/admin/__snapshots__/webhooks.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/authors.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/newsletters.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/offers.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/pages.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/posts.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/recommendations.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/search-index.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/settings.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/content/__snapshots__/tiers.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members-comments/__snapshots__/comments.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/announcement.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/create-stripe-checkout-session.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/donation-checkout-session.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/feedback.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/gift-subscriptions.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/middleware.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/recommendations.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/send-magic-link.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/site.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/webhooks.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-api/members/__snapshots__/well-known.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-server/__snapshots__/1-options-requests.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-server/__snapshots__/click-tracking.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-server/__snapshots__/well-known.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-server/services/__snapshots__/recommendation-emails.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-webhooks/__snapshots__/members.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-webhooks/__snapshots__/pages.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-webhooks/__snapshots__/posts.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-webhooks/__snapshots__/site.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/e2e-webhooks/__snapshots__/tags.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/integration/services/__snapshots__/member-welcome-emails-snapshot.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/integration/services/email-service/__snapshots__/cards.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/unit/frontend/helpers/__snapshots__/ghost-head.test.js.snap is excluded by !**/*.snap
  • ghost/core/test/unit/server/services/settings/__snapshots__/settings-bread-service.test.js.snap is excluded by !**/*.snap
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • ghost/core/package.json

- v2 of @tryghost/express-test swaps the reqresnext mock req/res for
  real http.IncomingMessage / http.ServerResponse objects, so Ghost's
  admin-session middleware now executes fully during the test and the
  ghost-admin-api-session cookie that Ghost has always set on a
  successful password reset actually reaches the response snapshot
- matched the cookie with stringMatching(/^ghost-admin-api-session=/),
  the same pattern already used in test/e2e-api/admin/session.test.js,
  so dynamic cookie values and expiries don't make the snapshot brittle
- test/legacy/ isn't part of ghost/core's pnpm test:e2e script, which is
  why this slipped past the local verification run
- follow-up to the ghost-admin-api-session cookie showing up in the
  ghost/core password-reset snapshot after the @tryghost/express-test
  v2 bump: verified the cookie is actually emitted by Ghost, not an
  artifact of the new mock req/res implementation
- the existing "analyticsPage.header is visible" check proves the UI
  lands on the admin dashboard, but relies on the session middleware
  working to get there; asserting the cookie directly pins down the
  mechanism so a future regression in session emission fails here
  with a clear message instead of a generic navigation timeout
- two lines, no new fixtures, no new waits - uses page.context()
  cookies which is already populated by the time the assertion runs
@sonarqubecloud
Copy link
Copy Markdown

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.95%. Comparing base (ffc637e) to head (55634f7).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #27514      +/-   ##
==========================================
+ Coverage   72.94%   72.95%   +0.01%     
==========================================
  Files        1556     1556              
  Lines      125792   125792              
  Branches    15215    15212       -3     
==========================================
+ Hits        91757    91777      +20     
+ Misses      33056    33036      -20     
  Partials      979      979              
Flag Coverage Δ
admin-tests 49.79% <ø> (ø)
e2e-tests 72.95% <ø> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@9larsons 9larsons merged commit 562fc27 into main Apr 22, 2026
45 checks passed
@9larsons 9larsons deleted the bump-tryghost-test-helpers-v2 branch April 22, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant