Skip to content

Moved core publishing browser tests to e2e - #27004

Merged
9larsons merged 10 commits into
mainfrom
migrate-publishing-e2e-slice-1
Mar 30, 2026
Merged

Moved core publishing browser tests to e2e#27004
9larsons merged 10 commits into
mainfrom
migrate-publishing-e2e-slice-1

Conversation

@9larsons

Copy link
Copy Markdown
Contributor

Summary

  • Migrated 7 deterministic publishing tests from ghost/core/test/e2e-browser/admin/publishing.spec.js to the e2e suite
  • Tests moved: publish only, publish+email, email only, delete saved post, delete with unsaved changes, primary lexical editor, secondary hidden lexical editor
  • Extended PostEditorPage with publish flow close/delete methods, createDraft() helper, and lexical editor locators
  • Extended PostPage with articleTitle and articleBody locators

Context

This is slice 1 of 4 in an incremental migration of browser tests to the e2e suite. This slice covers the simplest, most deterministic tests — no scheduling waits, no visibility/access changes, no settings mutations. Remaining slices will cover publish page + update post, schedule post, and post access tests.

Test plan

  • cd e2e && yarn test tests/admin/posts/publishing.test.ts passes
  • cd e2e && yarn test tests/admin/posts/lexical-editor.test.ts passes
  • cd e2e && yarn lint passes (0 new errors)
  • cd e2e && yarn test:types passes
  • Remaining 13 browser tests in publishing.spec.js still pass

Moved 7 tests (publish only, publish+email, email only, delete saved post,
delete with unsaved changes, lexical editor, secondary lexical editor) from
ghost/core/test/e2e-browser/admin/publishing.spec.js to the e2e suite.

This is the first slice of an incremental migration — the simplest,
most deterministic tests that don't involve scheduling or access control.
@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Added new locators and actions to admin post helpers: SettingsMenu (deletePost/delete confirmation), PublishFlow (close, openPublishedPost), and PostEditorPage (screenTitle, lexicalEditor, secondaryEditor, createDraft, waitForSaved). Public PostPage exposes articleTitle and articleBody locators. New Playwright E2E test suites were added: e2e/tests/admin/posts/lexical-editor.test.ts and e2e/tests/admin/posts/publishing.test.ts (publishing variants and deletion flows). Legacy in-file tests were removed from ghost/core/test/e2e-browser/admin/publishing.spec.js and replaced with comments. .lintstagedrc.cjs updated to run ESLint via yarn --cwd <workspace>.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: migrating publishing browser tests from ghost/core to the e2e suite, which is reflected in the file changes and test migration.
Description check ✅ Passed The description is directly related to the changeset, detailing the specific tests migrated, helper methods added, and context for the incremental migration effort.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch migrate-publishing-e2e-slice-1

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
e2e/tests/admin/posts/publishing.test.ts (2)

42-46: Type mismatch hidden by as never cast.

The newsletters parameter expects string[] per the MemberFactory interface, but getNewsletters() returns {id: string}[]. The as never cast bypasses TypeScript's type checking. This works at runtime because the API adapter handles the transformation, but it's fragile.

Consider updating the type signature or using a more explicit cast:

Suggested improvement
 await memberFactory.create({
     email: 'publish-email-test@example.com',
     name: 'Publishing member',
-    newsletters: newsletters as never
+    newsletters: newsletters as unknown as string[]
 });

Or better, update the MemberFactory interface to accept {id: string}[] for newsletters since that's what the API expects.

Also applies to: 71-75

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

In `@e2e/tests/admin/posts/publishing.test.ts` around lines 42 - 46, The test is
hiding a type mismatch by using `as never` when calling `memberFactory.create`;
`getNewsletters()` returns `{id: string}[]` but `MemberFactory` currently
expects `string[]`. Fix by either updating the `MemberFactory` interface to
accept `Array<{id: string}>` for the `newsletters` parameter (so
`memberFactory.create` and tests pass naturally) or explicitly map the result of
`getNewsletters()` to a `string[]` (e.g., `getNewsletters().map(n => n.id)`)
before passing it to `memberFactory.create`; update calls at the two test sites
(the call at `memberFactory.create` around lines ~42 and the similar one around
lines ~71) and adjust types on the `MemberFactory` definition accordingly to
keep typesafe code.

7-11: Consider adding error handling for the API call.

The getNewsletters() helper doesn't check the response status before parsing JSON. If the API call fails, this could produce confusing errors.

Suggested improvement
 async function getNewsletters(request: APIRequestContext): Promise<{id: string}[]> {
     const response = await request.get('/ghost/api/admin/newsletters/?status=active&limit=all');
+    if (!response.ok()) {
+        throw new Error(`Failed to fetch newsletters: ${response.status()}`);
+    }
     const data = await response.json();
     return data.newsletters.map((n: {id: string}) => ({id: n.id}));
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/admin/posts/publishing.test.ts` around lines 7 - 11, The
getNewsletters helper currently calls request.get and immediately parses
response.json which can produce confusing errors on non-2xx responses; update
getNewsletters to check response.ok (or response.status) after
request.get('/ghost/api/admin/newsletters/?status=active&limit=all') and if not
ok throw or return a clear error that includes response.status and
response.statusText (optionally include the response body for debugging by
awaiting response.text()), otherwise proceed to await response.json() and map
data.newsletters to ({id: n.id}) as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/helpers/pages/admin/posts/post/post-editor-page.ts`:
- Around line 115-122: The hard-coded waitForTimeout(100) inside createDraft()
causes flakiness; replace it with an explicit wait that asserts the editor has
completed the new->draft transition before typing the body. Concretely, after
filling title and pressing Enter (in createDraft), wait on the editor locator
returned by page.locator('[data-lexical-editor="true"]').first() for a stable
condition such as: the editor becoming editable/focused, its innerText or child
paragraph element appearing/containing expected content, or a specific
attribute/class that indicates the draft state has been applied; then proceed
with page.keyboard.type(body). Use createDraft, titleInput, and the editor
locator to locate and wait for that deterministic condition instead of
waitForTimeout.

---

Nitpick comments:
In `@e2e/tests/admin/posts/publishing.test.ts`:
- Around line 42-46: The test is hiding a type mismatch by using `as never` when
calling `memberFactory.create`; `getNewsletters()` returns `{id: string}[]` but
`MemberFactory` currently expects `string[]`. Fix by either updating the
`MemberFactory` interface to accept `Array<{id: string}>` for the `newsletters`
parameter (so `memberFactory.create` and tests pass naturally) or explicitly map
the result of `getNewsletters()` to a `string[]` (e.g., `getNewsletters().map(n
=> n.id)`) before passing it to `memberFactory.create`; update calls at the two
test sites (the call at `memberFactory.create` around lines ~42 and the similar
one around lines ~71) and adjust types on the `MemberFactory` definition
accordingly to keep typesafe code.
- Around line 7-11: The getNewsletters helper currently calls request.get and
immediately parses response.json which can produce confusing errors on non-2xx
responses; update getNewsletters to check response.ok (or response.status) after
request.get('/ghost/api/admin/newsletters/?status=active&limit=all') and if not
ok throw or return a clear error that includes response.status and
response.statusText (optionally include the response body for debugging by
awaiting response.text()), otherwise proceed to await response.json() and map
data.newsletters to ({id: n.id}) as before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a2a16031-7556-4f40-9baf-7e317fc4f284

📥 Commits

Reviewing files that changed from the base of the PR and between d28725e and b6a7cf1.

📒 Files selected for processing (5)
  • e2e/helpers/pages/admin/posts/post/post-editor-page.ts
  • e2e/helpers/pages/public/post-page.ts
  • e2e/tests/admin/posts/lexical-editor.test.ts
  • e2e/tests/admin/posts/publishing.test.ts
  • ghost/core/test/e2e-browser/admin/publishing.spec.js

Comment thread e2e/helpers/pages/admin/posts/post/post-editor-page.ts
@9larsons
9larsons enabled auto-merge (squash) March 27, 2026 15:22
@github-actions

Copy link
Copy Markdown
Contributor

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 23652926430 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

- Removed premature 'Draft - Saved' wait from createDraft (auto-save
  may not complete before publish flow opens, matching original behavior)
- Added separate waitForSaved() method for tests that need it
- Removed 'Published' status assertion after closing publish flow
  (close now navigates to posts list, not back to editor)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
e2e/tests/admin/posts/publishing.test.ts (3)

52-59: Inconsistent publish flow closing between tests.

The first test calls editor.publishFlow.close() after confirming, but this test navigates directly without closing the modal. While this may work due to page navigation, the inconsistency could lead to flaky behavior if the modal interferes with navigation.

Consider either:

  1. Adding await editor.publishFlow.close() for consistency, or
  2. Documenting why it's intentionally omitted here
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/admin/posts/publishing.test.ts` around lines 52 - 59, The publish
flow modal is left open in this test which is inconsistent with the first test;
after calling editor.publishFlow.confirm() you should explicitly close the modal
to avoid flakiness by calling await editor.publishFlow.close() before navigating
to the PostPage (refer to editor.publishFlow.confirm(),
editor.publishFlow.close(), publishFlow.selectPublishType, PostPage,
generateSlug and postData in this block), so add the close call immediately
after confirm() or add a short comment explaining why the modal remaining open
is intentional.

7-11: Add defensive error handling for the API response.

The helper assumes a successful response with the expected structure. If the API fails or returns an unexpected shape, the error message will be unclear (e.g., "Cannot read properties of undefined").

🛡️ Suggested improvement
 async function getNewsletters(request: APIRequestContext): Promise<{id: string}[]> {
     const response = await request.get('/ghost/api/admin/newsletters/?status=active&limit=all');
+    if (!response.ok()) {
+        throw new Error(`Failed to fetch newsletters: ${response.status()}`);
+    }
     const data = await response.json();
+    if (!data.newsletters?.length) {
+        throw new Error('No active newsletters found - tests require at least one newsletter');
+    }
     return data.newsletters.map((n: {id: string}) => ({id: n.id}));
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/admin/posts/publishing.test.ts` around lines 7 - 11, The helper
getNewsletters currently assumes a successful response and valid shape; add
defensive checks: after
request.get('/ghost/api/admin/newsletters/?status=active&limit=all') verify
response.ok and if not throw a descriptive Error that includes response.status
and statusText (and optionally response.text()); parse JSON and ensure the
parsed object has a newsletters array (Array.isArray(data.newsletters)); if the
shape is invalid throw a clear Error describing the unexpected payload; finally
return the mapped ids only when validation passes.

39-43: The as never type assertion bypasses type safety.

This cast suggests a type mismatch between the newsletter structure from the API and what memberFactory.create expects. Consider aligning the types or using a proper type assertion.

♻️ Suggested approach

If the factory expects a different newsletter type, define an explicit interface and map accordingly:

-        await memberFactory.create({
-            email: 'publish-email-test@example.com',
-            name: 'Publishing member',
-            newsletters: newsletters as never
-        });
+        await memberFactory.create({
+            email: 'publish-email-test@example.com',
+            name: 'Publishing member',
+            newsletters
+        });

If the factory's type definition is incorrect, updating the factory's type signature would be cleaner than using as never in multiple places.

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

In `@e2e/tests/admin/posts/publishing.test.ts` around lines 39 - 43, The test is
skipping type checking by using "newsletters as never" when calling
memberFactory.create; update the call to pass a correctly typed value instead of
casting to never: either convert/map the existing newsletters variable to the
shape expected by memberFactory.create (create a small mapper or explicit
interface to transform newsletter objects) or fix the factory's type signature
so it accepts the API newsletter type; locate the memberFactory.create
invocation and the newsletters definition and replace the "as never" cast with a
proper typed object or adjusted factory type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/tests/admin/posts/publishing.test.ts`:
- Around line 52-59: The publish flow modal is left open in this test which is
inconsistent with the first test; after calling editor.publishFlow.confirm() you
should explicitly close the modal to avoid flakiness by calling await
editor.publishFlow.close() before navigating to the PostPage (refer to
editor.publishFlow.confirm(), editor.publishFlow.close(),
publishFlow.selectPublishType, PostPage, generateSlug and postData in this
block), so add the close call immediately after confirm() or add a short comment
explaining why the modal remaining open is intentional.
- Around line 7-11: The helper getNewsletters currently assumes a successful
response and valid shape; add defensive checks: after
request.get('/ghost/api/admin/newsletters/?status=active&limit=all') verify
response.ok and if not throw a descriptive Error that includes response.status
and statusText (and optionally response.text()); parse JSON and ensure the
parsed object has a newsletters array (Array.isArray(data.newsletters)); if the
shape is invalid throw a clear Error describing the unexpected payload; finally
return the mapped ids only when validation passes.
- Around line 39-43: The test is skipping type checking by using "newsletters as
never" when calling memberFactory.create; update the call to pass a correctly
typed value instead of casting to never: either convert/map the existing
newsletters variable to the shape expected by memberFactory.create (create a
small mapper or explicit interface to transform newsletter objects) or fix the
factory's type signature so it accepts the API newsletter type; locate the
memberFactory.create invocation and the newsletters definition and replace the
"as never" cast with a proper typed object or adjusted factory type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 834d5ef0-fb28-452c-83df-d0e5affda203

📥 Commits

Reviewing files that changed from the base of the PR and between b6a7cf1 and c3ba89f.

📒 Files selected for processing (2)
  • e2e/helpers/pages/admin/posts/post/post-editor-page.ts
  • e2e/tests/admin/posts/publishing.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/helpers/pages/admin/posts/post/post-editor-page.ts

@github-actions

Copy link
Copy Markdown
Contributor

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 23654932768 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

@9larsons 9larsons changed the title Moved core publishing browser tests to e2e suite (slice 1/4) Moved core publishing browser tests to e2e Mar 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/helpers/pages/admin/posts/post/post-editor-page.ts`:
- Line 4: Replace the assertion-style expect.poll() in the PostEditorPage page
object with a guard using page.waitForFunction(): remove the expect.poll() call
and instead call await this.page.waitForFunction(...) (or
this.page.waitForFunction bound to the Page instance used in the page object)
with the same predicate and timeout so the page object only waits for the
condition rather than asserting; update the method that currently contains
expect.poll() to return after the wait completes (preserve any timeout/options)
and remove any expect-based error handling from that page object method.

In `@e2e/tests/admin/posts/publishing.test.ts`:
- Around line 39-43: The test currently bypasses type checking by casting
newsletters to never when calling memberFactory.create; instead, remove the "as
never" cast and map the newsletter objects returned by getNewsletters() to a
string[] of IDs (e.g., newsletters.map(n => n.id)) before passing into
memberFactory.create (reference the newsletters variable and the
memberFactory.create call); apply the same change to the second occurrence
around the other memberFactory.create call so both pass a string[] to the
Member.newsletters parameter.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ab1350d1-c670-4503-ac17-b09e58d2393c

📥 Commits

Reviewing files that changed from the base of the PR and between c3ba89f and 61150b2.

📒 Files selected for processing (2)
  • e2e/helpers/pages/admin/posts/post/post-editor-page.ts
  • e2e/tests/admin/posts/publishing.test.ts

Comment thread e2e/helpers/pages/admin/posts/post/post-editor-page.ts Outdated
Comment thread e2e/tests/admin/posts/publishing.test.ts
@github-actions

Copy link
Copy Markdown
Contributor

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 23752993036 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
e2e/helpers/pages/admin/posts/post/post-editor-page.ts (2)

10-11: Make newly added locators explicitly public readonly.

These new locators are currently readonly only. Please align them with the page-object visibility rule.

♻️ Suggested update
-    readonly deletePostButton: Locator;
-    readonly deletePostConfirmButton: Locator;
+    public readonly deletePostButton: Locator;
+    public readonly deletePostConfirmButton: Locator;
...
-    readonly closeButton: Locator;
-    readonly completeBookmark: Locator;
+    public readonly closeButton: Locator;
+    public readonly completeBookmark: Locator;
...
-    readonly screenTitle: Locator;
-    readonly lexicalEditor: Locator;
-    readonly secondaryEditor: Locator;
+    public readonly screenTitle: Locator;
+    public readonly lexicalEditor: Locator;
+    public readonly secondaryEditor: Locator;

As per coding guidelines: "Page Objects should be located in helpers/pages/ and expose locators as public readonly".

Also applies to: 36-37, 87-89

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

In `@e2e/helpers/pages/admin/posts/post/post-editor-page.ts` around lines 10 - 11,
The new locators are declared as readonly but must follow the page-object
visibility rule and be declared public readonly; update the declarations for
deletePostButton and deletePostConfirmButton (and the other affected locator
declarations around the indicated areas, e.g., the members at lines referenced
like the ones near 36-37 and 87-89) to use the public readonly modifier so the
class exposes them correctly (locate the declarations by the symbol names
deletePostButton and deletePostConfirmButton and change their signatures to
public readonly).

123-135: Use locator waitFor() guard here instead of page.waitForFunction().

In page objects, guards should stay on locator waitFor() rather than function polling.

♻️ Suggested update
-        await this.page.waitForFunction(() => {
-            const element = document.querySelector('[data-lexical-editor="true"]');
-            if (!element) {
-                return false;
-            }
-
-            const activeElement = document.activeElement;
-
-            return Boolean(
-                activeElement &&
-                (activeElement === element || element.contains(activeElement))
-            );
-        });
+        await editor.locator(':focus-within').waitFor({state: 'visible'});

As per coding guidelines: "Use waitFor() for guards in page objects, never expect() in page objects".

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

In `@e2e/helpers/pages/admin/posts/post/post-editor-page.ts` around lines 123 -
135, Replace the use of this.page.waitForFunction polling with a locator-based
guard: locate the editor via the selector '[data-lexical-editor="true"]' and
call the locator's waitFor() to wait for it to be attached/visible, then use the
locator API (e.g., locator.isFocused() or
locator.evaluate(()=>document.activeElement) ) to verify focus; specifically
change the this.page.waitForFunction call to await
this.page.locator('[data-lexical-editor="true"]').waitFor(...) and then check
focus using the same locator rather than polling with page.waitForFunction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/helpers/pages/admin/posts/post/post-editor-page.ts`:
- Around line 10-11: The new locators are declared as readonly but must follow
the page-object visibility rule and be declared public readonly; update the
declarations for deletePostButton and deletePostConfirmButton (and the other
affected locator declarations around the indicated areas, e.g., the members at
lines referenced like the ones near 36-37 and 87-89) to use the public readonly
modifier so the class exposes them correctly (locate the declarations by the
symbol names deletePostButton and deletePostConfirmButton and change their
signatures to public readonly).
- Around line 123-135: Replace the use of this.page.waitForFunction polling with
a locator-based guard: locate the editor via the selector
'[data-lexical-editor="true"]' and call the locator's waitFor() to wait for it
to be attached/visible, then use the locator API (e.g., locator.isFocused() or
locator.evaluate(()=>document.activeElement) ) to verify focus; specifically
change the this.page.waitForFunction call to await
this.page.locator('[data-lexical-editor="true"]').waitFor(...) and then check
focus using the same locator rather than polling with page.waitForFunction.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 31efacf3-b050-46f4-bc39-64d210f58fa8

📥 Commits

Reviewing files that changed from the base of the PR and between 61150b2 and 6dba235.

📒 Files selected for processing (2)
  • .lintstagedrc.cjs
  • e2e/helpers/pages/admin/posts/post/post-editor-page.ts

@github-actions

Copy link
Copy Markdown
Contributor

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 23755814930 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
e2e/tests/admin/posts/publishing.test.ts (1)

7-11: Consider adding error handling to getNewsletters for more informative test failures.

If the API call fails or returns unexpected data (e.g., data.newsletters is undefined), this function will throw a cryptic error. Adding basic validation would improve debuggability.

🛡️ Optional improvement for robustness
 async function getNewsletters(request: APIRequestContext): Promise<string[]> {
     const response = await request.get('/ghost/api/admin/newsletters/?status=active&limit=all');
+    if (!response.ok()) {
+        throw new Error(`Failed to fetch newsletters: ${response.status()}`);
+    }
     const data = await response.json();
+    if (!data.newsletters?.length) {
+        throw new Error('No active newsletters found');
+    }
     return data.newsletters.map((n: {id: string}) => n.id);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/admin/posts/publishing.test.ts` around lines 7 - 11, getNewsletters
currently assumes the request succeeds and data.newsletters exists; add basic
error handling in getNewsletters to make failures informative: after awaiting
request.get, check response.ok and throw an error including response.status and
text if not ok; after parsing JSON into data, validate that data.newsletters is
an array (and throw a descriptive error showing the parsed data if not), then
return data.newsletters.map as before (referencing getNewsletters, response,
data, and the mapping to n.id).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/tests/admin/posts/publishing.test.ts`:
- Around line 7-11: getNewsletters currently assumes the request succeeds and
data.newsletters exists; add basic error handling in getNewsletters to make
failures informative: after awaiting request.get, check response.ok and throw an
error including response.status and text if not ok; after parsing JSON into
data, validate that data.newsletters is an array (and throw a descriptive error
showing the parsed data if not), then return data.newsletters.map as before
(referencing getNewsletters, response, data, and the mapping to n.id).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4a68eddb-5cf2-4e87-bc69-6467e3c07818

📥 Commits

Reviewing files that changed from the base of the PR and between 6dba235 and b9fd05d.

📒 Files selected for processing (1)
  • e2e/tests/admin/posts/publishing.test.ts

@github-actions

Copy link
Copy Markdown
Contributor

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 23756680185 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
24.8% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@9larsons
9larsons merged commit 023a812 into main Mar 30, 2026
66 of 69 checks passed
@9larsons
9larsons deleted the migrate-publishing-e2e-slice-1 branch March 30, 2026 19:39
cmraible pushed a commit that referenced this pull request Mar 30, 2026
ref https://linear.app/ghost/issue/PLA-10/
- Migrated 7 deterministic publishing tests from
`ghost/core/test/e2e-browser/admin/publishing.spec.js` to the e2e suite
- Tests moved: publish only, publish+email, email only, delete saved
post, delete with unsaved changes, primary lexical editor, secondary
hidden lexical editor
- Extended `PostEditorPage` with publish flow close/delete methods,
`createDraft()` helper, and lexical editor locators
- Extended `PostPage` with `articleTitle` and `articleBody` locators
franky19 pushed a commit to franky19/Ghost that referenced this pull request Apr 18, 2026
…t#27004)

ref https://linear.app/ghost/issue/PLA-10/
- Migrated 7 deterministic publishing tests from
`ghost/core/test/e2e-browser/admin/publishing.spec.js` to the e2e suite
- Tests moved: publish only, publish+email, email only, delete saved
post, delete with unsaved changes, primary lexical editor, secondary
hidden lexical editor
- Extended `PostEditorPage` with publish flow close/delete methods,
`createDraft()` helper, and lexical editor locators
- Extended `PostPage` with `articleTitle` and `articleBody` locators
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