Skip to content

BER-3361: Remove members-forward release gate#27221

Open
jonatansberg wants to merge 13 commits intomainfrom
ber-3361-remove-feature-flag-release
Open

BER-3361: Remove members-forward release gate#27221
jonatansberg wants to merge 13 commits intomainfrom
ber-3361-remove-feature-flag-release

Conversation

@jonatansberg
Copy link
Copy Markdown
Member

Summary

This PR removes the membersForward rollout machinery and the /members-forward route so the released React members experience owns /members and /members/import directly.

What changed

  • removed the membersForward labs flag and related feature-service/settings exposure
  • removed the members route gate and /members-forward route so React owns the released members routes directly
  • kept the retained Ember member detail and new-member flows working by carrying the current members URL through the back path
  • aligned the remaining tests with the released route ownership

Why

BER-3506 landed the route handoff foundation. This branch finishes the release by deleting the rollout gate and flag-specific behavior without mixing in the broader Ember dead-code cleanup.

Testing

  • YARN_IGNORE_ENGINES=1 yarn workspace @tryghost/admin test:unit src/members-route.test.tsx
  • YARN_IGNORE_ENGINES=1 yarn workspace @tryghost/posts exec vitest run test/unit/views/members/members-actions.test.tsx
  • cd ghost/core && YARN_IGNORE_ENGINES=1 yarn test:single test/unit/shared/labs.test.js
  • YARN_IGNORE_ENGINES=1 yarn workspace @tryghost/e2e test:types

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
This releases the React-owned /members routes while keeping Ember detail flows intact and deferring dead-code cleanup to the next stacked PR.
ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
This aligns the import-route unit coverage with the released behavior after removing the members-forward flag.
ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
This drops the extra routes test file so the release branch stays focused on the shipped members routing change.
ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
The config and runtime changes already cover the flag removal, so this extra assertion only added noise to the branch.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 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: ce7a40ca-f29f-412a-8774-ea84c8bf539c

📥 Commits

Reviewing files that changed from the base of the PR and between 4a25fdb and 428d463.

📒 Files selected for processing (1)
  • e2e/helpers/pages/admin/members/members-import-modal.ts

Walkthrough

This PR removes the membersForward feature flag and its gating throughout the codebase: the flag is deleted from labs/feature service and related feature lists, the /members-forward route and MembersRouteGate component are removed, nav logic no longer branches on the flag, and Ember templates were changed to use hash #/members links. Members routes now render nested routes via React Router Outlet. Member detail/back navigation gains a backPath flow (buildMemberDetailPath and threaded props). Many e2e and unit tests were updated or simplified to use the new members list page and to drop per-test membersForward overrides.

Possibly related PRs

  • Remove members-forward route #27040: Modifies/removes members-forward routing and feature-flag gating across routes, nav, labs, and related tests — targets the same code areas and intent.

Suggested reviewers

  • 9larsons
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% 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 clearly and specifically identifies the main change: removing the members-forward release gate and feature flag machinery.
Description check ✅ Passed The description is directly related to the changeset, explaining the removal of membersForward flag, route gates, and supporting infrastructure, with clear rationale and testing guidance.

✏️ 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 ber-3361-remove-feature-flag-release

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

E2E Tests Failed

To view the Playwright test report locally, run:

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

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
Reused the shared link active matcher for the React-owned members routes and dropped the bespoke pathname check.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

E2E Tests Failed

To view the Playwright test report locally, run:

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

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
The release branch moved /members out of the Ember test lane, so the auth acceptance tests now use an Ember-owned protected route and the analytics assertion matches the released React copy.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 8, 2026

Codecov Report

❌ Patch coverage is 38.46154% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.92%. Comparing base (7d6c296) to head (428d463).
⚠️ Report is 76 commits behind head on main.

Files with missing lines Patch % Lines
ghost/admin/app/controllers/member.js 50.00% 3 Missing and 2 partials ⚠️
ghost/admin/app/routes/member.js 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #27221      +/-   ##
==========================================
- Coverage   73.07%   72.92%   -0.15%     
==========================================
  Files        1541     1545       +4     
  Lines      122884   123694     +810     
  Branches    14801    14965     +164     
==========================================
+ Hits        89798    90205     +407     
- Misses      32090    32522     +432     
+ Partials      996      967      -29     
Flag Coverage Δ
admin-tests 49.86% <38.46%> (-4.53%) ⬇️
e2e-tests 72.92% <38.46%> (-0.15%) ⬇️

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

E2E Tests Failed

To view the Playwright test report locally, run:

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

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
The old filter-actions Playwright spec still drove Ember-only members filter controls that no longer exist on the released React /members route, while equivalent bulk-label coverage already exists in the React members suite.
ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
These Playwright tests still asserted the old Ember members list surface even though /members is now React-owned, and the retained Ember detail flows are covered by the remaining detail-focused specs.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 2026

E2E Tests Failed

To view the Playwright test report locally, run:

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

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release

Row clicks on the React members list were bypassing the back query string even though the rendered links already carried it. This shares one detail-hash builder between link and row navigation so retained Ember detail screens can return to the filtered list state.
ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release

The release branch still ran Ember-list import and export coverage even though those routes are no longer part of the shipped members list. This drops the dead import spec and keeps the export coverage focused on the React-owned members route.
@jonatansberg jonatansberg marked this pull request as ready for review April 9, 2026 10:18
@jonatansberg jonatansberg requested a review from 9larsons as a code owner April 9, 2026 10:18
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.

Actionable comments posted: 3

🧹 Nitpick comments (5)
ghost/admin/tests/acceptance/members-test.js (1)

11-11: Avoid disabling the entire acceptance suite with describe.skip.

Line 11 currently skips every members acceptance test in this file, which drops CI coverage for still-supported /members behavior and can hide regressions. Please keep the suite enabled and only skip/remove truly obsolete cases.

Proposed minimal fix
-describe.skip('Acceptance: Members Test', function () {
+describe('Acceptance: Members Test', function () {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/admin/tests/acceptance/members-test.js` at line 11, The test suite is
entirely disabled by using describe.skip for the 'Acceptance: Members Test'
suite; change describe.skip to describe to re-enable the acceptance tests in
members-test.js, and if certain individual specs are truly obsolete mark those
with it.skip or remove them instead of skipping the whole suite (locate the
top-level describe.skip('Acceptance: Members Test', ...) and update it
accordingly).
e2e/tests/admin/members/export.test.ts (1)

96-105: Extract repeated export metadata assertions into a shared helper.

Both scenarios repeat the same assertions for IDs/timestamps and filename shape. Pulling that into one helper will reduce drift as export behavior evolves.

♻️ Optional refactor
+function assertExportMetadata(
+    suggestedFilename: string,
+    contentIds: RegExpMatchArray | null,
+    contentTimestamps: RegExpMatchArray | null,
+    expectedCount: number
+) {
+    expect(contentIds).toHaveLength(expectedCount);
+    expect(contentTimestamps).toHaveLength(expectedCount);
+    expect(suggestedFilename.startsWith('members')).toBe(true);
+    expect(suggestedFilename.endsWith('.csv')).toBe(true);
+}
+
 test.describe('Ghost Admin - Members Export', () => {
@@
-        expect(contentIds).toHaveLength(MEMBERS_FIXTURE.length);
-        expect(contentTimestamps).toHaveLength(MEMBERS_FIXTURE.length);
-        expect(suggestedFilename.startsWith('members')).toBe(true);
-        expect(suggestedFilename.endsWith('.csv')).toBe(true);
+        assertExportMetadata(suggestedFilename, contentIds, contentTimestamps, MEMBERS_FIXTURE.length);
@@
-        expect(contentIds).toHaveLength(filteredMembers.length);
-        expect(contentTimestamps).toHaveLength(filteredMembers.length);
-        expect(suggestedFilename.startsWith('members')).toBe(true);
-        expect(suggestedFilename.endsWith('.csv')).toBe(true);
+        assertExportMetadata(suggestedFilename, contentIds, contentTimestamps, filteredMembers.length);

Also applies to: 119-127

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

In `@e2e/tests/admin/members/export.test.ts` around lines 96 - 105, Create a
shared test helper that centralizes the repeated export assertions: move the
checks referencing membersPage.exportMembers() results (suggestedFilename,
content), extractDownloadedContentSpecifics(content) outputs (contentIds,
contentTimestamps), and assertExportedMembers(content, MEMBERS_FIXTURE) into one
function (e.g., assertExportedMembersMetadata or verifyExportDownload) and call
it from both test sites; the helper should assert contentIds and
contentTimestamps lengths equal MEMBERS_FIXTURE.length and that
suggestedFilename startsWith 'members' and endsWith '.csv', then replace the
duplicated assertions in the tests with a single call to this new helper.
apps/admin/src/layout/app-sidebar/nav-content.tsx (2)

80-97: Extract the members base path to one constant.

'members' is now hardcoded in both the useIsActiveLink call and the nav target. Pulling that into a shared constant will make future route cleanup less error-prone.

♻️ Suggested cleanup
+const MEMBERS_ROUTE = 'members';
 const LEGACY_MEMBERS_ACTIVE_ROUTES = ['member', 'member.new', 'members-activity'];
 ...
-const isMembersRouteActive = useIsActiveLink({path: 'members', activeOnSubpath: true});
+const isMembersRouteActive = useIsActiveLink({path: MEMBERS_ROUTE, activeOnSubpath: true});
 ...
-const membersRoute = 'members';
+const membersRoute = MEMBERS_ROUTE;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/admin/src/layout/app-sidebar/nav-content.tsx` around lines 80 - 97,
Extract the hardcoded 'members' string into a single constant (e.g.,
MEMBERS_ROUTE) and use that constant wherever the literal is used: replace the
argument in useIsActiveLink({path: 'members', ...}) and the membersRoute
assignment (currently membersRoute = 'members'), and any other occurrences in
this file (e.g., references involving isMembersRouteActive or membersNavActive)
so all member-route logic references the new MEMBERS_ROUTE constant
consistently.

91-93: Please add regression coverage for the legacy active-route fallback.

This branch is now what keeps the Members item highlighted on Ember-only detail/new/activity screens after the /members-forward removal. A focused test here would make the follow-up cleanup much safer.

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

In `@apps/admin/src/layout/app-sidebar/nav-content.tsx` around lines 91 - 93, Add
a focused regression test for the legacy active-route fallback used by
membersNavActive: exercise the branch where isMembersRouteActive is false so the
code falls back to routing.isRouteActive(LEGACY_MEMBERS_ACTIVE_ROUTES), and
assert the Members item remains highlighted when routing.isRouteActive returns
true; also include cases where isMembersRouteActive is true but either
hasActiveMemberView or membersExpanded cause the expression to resolve false to
ensure the original Ember-only detail/new/activity screens remain covered. Mock
or stub routing.isRouteActive and render the component (or call the selector) to
assert expected boolean outcomes for membersNavActive across these permutations.
ghost/admin/app/routes/member.js (1)

57-65: Truncated comment at line 57.

The cleanup logic is correct. However, the comment "Make sure we clear" appears to be incomplete. Consider completing it to explain what's being cleared and why.

📝 Suggested comment improvement
-        // Make sure we clear
+        // Make sure we clear navigation state when leaving the member route
         if (isExiting) {
             controller.set('backPath', null);
             controller.set('directlyFromAnalytics', false);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/admin/app/routes/member.js` around lines 57 - 65, The comment "Make
sure we clear" is incomplete—update it to briefly explain what and why is being
cleared: when isExiting is true, we're resetting transient navigation state on
the controller (clearing backPath and directlyFromAnalytics) and clearing
postAnalytics if present to avoid leaking state between member route visits;
modify the comment above the conditional that references isExiting and
controller.postAnalytics (the block that sets backPath, directlyFromAnalytics,
and postAnalytics to null/false) to a concise sentence like "Clear transient
navigation and analytics state when exiting the route to avoid carrying state
into the next visit."
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ghost/admin/app/controllers/member.js`:
- Around line 54-56: The current check this.backPath?.startsWith('/members') is
too permissive and can match unintended routes like '/members-forward'; tighten
validation by matching only the exact /members route or subpaths (e.g. use a
strict test like /^\/members(?:$|\/)/ or normalize and compare path segments)
before returning this.backPath so stale or manipulated back links cannot fall
through; update the conditional around this.backPath to use that stricter
pattern (reference: this.backPath and the startsWith check).

In `@ghost/admin/tests/acceptance/members/filter-test.js`:
- Line 16: The test suite is entirely skipped via describe.skip in the
Acceptance: Members filtering suite; remove or replace describe.skip in the
members/filter-test.js so the suite runs, then run the tests and either fix
failing tests (adapting selectors, test setup, or stubs referenced inside the
describe block) or, if a specific case truly must be skipped, change only that
individual it(...) to it.skip and add a linked follow-up issue ID in the test’s
comment; ensure you reference the top-level describe('Acceptance: Members
filtering', ...) and any failing nested tests when making fixes.

In `@ghost/admin/tests/acceptance/members/import-test.js`:
- Line 11: The test suite has been disabled via describe.skip in the Members
import acceptance test (describe.skip in members/import-test.js), which silences
all coverage; either re-enable the suite by changing describe.skip back to
describe so tests run, or if the suite is truly obsolete remove the entire
describe block; if re-enabling, update any assertions and route references
inside the suite (e.g., route transition expectations and controller/route
ownership checks within the tests) to match the new route ownership and paths so
the restored tests pass against the current implementation.

---

Nitpick comments:
In `@apps/admin/src/layout/app-sidebar/nav-content.tsx`:
- Around line 80-97: Extract the hardcoded 'members' string into a single
constant (e.g., MEMBERS_ROUTE) and use that constant wherever the literal is
used: replace the argument in useIsActiveLink({path: 'members', ...}) and the
membersRoute assignment (currently membersRoute = 'members'), and any other
occurrences in this file (e.g., references involving isMembersRouteActive or
membersNavActive) so all member-route logic references the new MEMBERS_ROUTE
constant consistently.
- Around line 91-93: Add a focused regression test for the legacy active-route
fallback used by membersNavActive: exercise the branch where
isMembersRouteActive is false so the code falls back to
routing.isRouteActive(LEGACY_MEMBERS_ACTIVE_ROUTES), and assert the Members item
remains highlighted when routing.isRouteActive returns true; also include cases
where isMembersRouteActive is true but either hasActiveMemberView or
membersExpanded cause the expression to resolve false to ensure the original
Ember-only detail/new/activity screens remain covered. Mock or stub
routing.isRouteActive and render the component (or call the selector) to assert
expected boolean outcomes for membersNavActive across these permutations.

In `@e2e/tests/admin/members/export.test.ts`:
- Around line 96-105: Create a shared test helper that centralizes the repeated
export assertions: move the checks referencing membersPage.exportMembers()
results (suggestedFilename, content), extractDownloadedContentSpecifics(content)
outputs (contentIds, contentTimestamps), and assertExportedMembers(content,
MEMBERS_FIXTURE) into one function (e.g., assertExportedMembersMetadata or
verifyExportDownload) and call it from both test sites; the helper should assert
contentIds and contentTimestamps lengths equal MEMBERS_FIXTURE.length and that
suggestedFilename startsWith 'members' and endsWith '.csv', then replace the
duplicated assertions in the tests with a single call to this new helper.

In `@ghost/admin/app/routes/member.js`:
- Around line 57-65: The comment "Make sure we clear" is incomplete—update it to
briefly explain what and why is being cleared: when isExiting is true, we're
resetting transient navigation state on the controller (clearing backPath and
directlyFromAnalytics) and clearing postAnalytics if present to avoid leaking
state between member route visits; modify the comment above the conditional that
references isExiting and controller.postAnalytics (the block that sets backPath,
directlyFromAnalytics, and postAnalytics to null/false) to a concise sentence
like "Clear transient navigation and analytics state when exiting the route to
avoid carrying state into the next visit."

In `@ghost/admin/tests/acceptance/members-test.js`:
- Line 11: The test suite is entirely disabled by using describe.skip for the
'Acceptance: Members Test' suite; change describe.skip to describe to re-enable
the acceptance tests in members-test.js, and if certain individual specs are
truly obsolete mark those with it.skip or remove them instead of skipping the
whole suite (locate the top-level describe.skip('Acceptance: Members Test', ...)
and update it accordingly).
🪄 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: e61c4aa8-7850-4d7f-b1e9-5ea6a1d99938

📥 Commits

Reviewing files that changed from the base of the PR and between 54eaf84 and c1efdf6.

⛔ Files ignored due to path filters (1)
  • ghost/core/test/e2e-api/admin/__snapshots__/config.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (44)
  • apps/admin-x-settings/src/components/settings/advanced/labs/private-features.tsx
  • apps/admin/src/layout/app-sidebar/nav-content.tsx
  • apps/admin/src/members-route-gate.tsx
  • apps/admin/src/members-route.test.tsx
  • apps/admin/src/members-route.tsx
  • apps/admin/src/routes.tsx
  • apps/posts/src/views/members/components/members-actions.tsx
  • apps/posts/src/views/members/components/members-list-item.tsx
  • apps/posts/src/views/members/components/members-list.tsx
  • apps/posts/src/views/members/member-detail-hash.ts
  • apps/posts/src/views/members/members.tsx
  • apps/posts/test/unit/views/members/members-actions.test.tsx
  • apps/posts/test/unit/views/members/members-list.test.ts
  • e2e/helpers/pages/admin/members/member-details-page.ts
  • e2e/tests/admin/analytics/post-analytics/growth.test.ts
  • e2e/tests/admin/members-legacy/disable-commenting.test.ts
  • e2e/tests/admin/members-legacy/filter-actions.test.ts
  • e2e/tests/admin/members-legacy/impersonation.test.ts
  • e2e/tests/admin/members-legacy/import.test.ts
  • e2e/tests/admin/members-legacy/member-activity-events.test.ts
  • e2e/tests/admin/members-legacy/members.test.ts
  • e2e/tests/admin/members-legacy/stripe-webhooks.test.ts
  • e2e/tests/admin/members/bulk-actions.test.ts
  • e2e/tests/admin/members/export.test.ts
  • e2e/tests/admin/members/list.test.ts
  • e2e/tests/admin/members/multiselect-filters.test.ts
  • e2e/tests/admin/members/saved-views.test.ts
  • e2e/tests/admin/members/search-and-filter.test.ts
  • e2e/tests/admin/members/tier-filter-search.test.ts
  • e2e/tests/admin/members/virtual-window.test.ts
  • ghost/admin/app/components/dashboard/onboarding-checklist.hbs
  • ghost/admin/app/components/editor/publish-options/publish-type.hbs
  • ghost/admin/app/components/posts-list/list-item.hbs
  • ghost/admin/app/controllers/member.js
  • ghost/admin/app/router.js
  • ghost/admin/app/routes/member.js
  • ghost/admin/app/routes/members.js
  • ghost/admin/app/services/feature.js
  • ghost/admin/app/templates/member.hbs
  • ghost/admin/tests/acceptance/authentication-test.js
  • ghost/admin/tests/acceptance/members-test.js
  • ghost/admin/tests/acceptance/members/filter-test.js
  • ghost/admin/tests/acceptance/members/import-test.js
  • ghost/core/core/shared/labs.js
💤 Files with no reviewable changes (18)
  • e2e/tests/admin/members/saved-views.test.ts
  • e2e/tests/admin/members/search-and-filter.test.ts
  • apps/admin-x-settings/src/components/settings/advanced/labs/private-features.tsx
  • e2e/tests/admin/members/virtual-window.test.ts
  • apps/admin/src/members-route-gate.tsx
  • ghost/admin/app/router.js
  • e2e/tests/admin/members-legacy/impersonation.test.ts
  • ghost/admin/app/routes/members.js
  • e2e/tests/admin/members/tier-filter-search.test.ts
  • apps/admin/src/routes.tsx
  • ghost/admin/app/services/feature.js
  • e2e/tests/admin/members-legacy/disable-commenting.test.ts
  • e2e/tests/admin/members-legacy/members.test.ts
  • e2e/tests/admin/members-legacy/import.test.ts
  • e2e/tests/admin/members-legacy/filter-actions.test.ts
  • e2e/tests/admin/members/bulk-actions.test.ts
  • ghost/core/core/shared/labs.js
  • e2e/tests/admin/members-legacy/member-activity-events.test.ts

Comment on lines +54 to +56
if (this.backPath?.startsWith('/members')) {
return this.backPath;
}
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.

⚠️ Potential issue | 🟡 Minor

Tighten backPath validation to avoid invalid route fallthrough.

Line 54 uses startsWith('/members'), which also accepts removed/non-list paths like /members-forward.... That can send delete/breadcrumb navigation to stale routes if back is manipulated or old links are used.

Suggested fix
-        if (this.backPath?.startsWith('/members')) {
+        if (this.backPath?.match(/^\/members(?:$|\?)/)) {
             return this.backPath;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/admin/app/controllers/member.js` around lines 54 - 56, The current
check this.backPath?.startsWith('/members') is too permissive and can match
unintended routes like '/members-forward'; tighten validation by matching only
the exact /members route or subpaths (e.g. use a strict test like
/^\/members(?:$|\/)/ or normalize and compare path segments) before returning
this.backPath so stale or manipulated back links cannot fall through; update the
conditional around this.backPath to use that stricter pattern (reference:
this.backPath and the startsWith check).

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
Removed redundant nav wiring, simplified the member detail path helper naming, and dropped the stale members-route e2e case without changing runtime behavior.
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)
apps/admin/src/layout/app-sidebar/nav-content.tsx (1)

80-80: Optional: centralize the "members" route literal.

Using one constant for the route path would reduce drift risk between active-state checks and link targets.

♻️ Suggested refactor
+const MEMBERS_ROUTE_PATH = 'members';
 const LEGACY_MEMBERS_ACTIVE_ROUTES = ['member', 'member.new', 'members-activity'];

-const isMembersRouteActive = useIsActiveLink({path: 'members', activeOnSubpath: true});
+const isMembersRouteActive = useIsActiveLink({path: MEMBERS_ROUTE_PATH, activeOnSubpath: true});

 ...
-    to="members"
+    to={MEMBERS_ROUTE_PATH}
 ...
-    to="members"
+    to={MEMBERS_ROUTE_PATH}

Also applies to: 183-197

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

In `@apps/admin/src/layout/app-sidebar/nav-content.tsx` at line 80, The "members"
route string is repeated (e.g., in the isMembersRouteActive useIsActiveLink call
and elsewhere around lines 183-197), which risks drift; extract that literal
into a single constant (e.g., MEMBERS_ROUTE or MEMBERS_PATH) and replace all
occurrences where the route is referenced (for active-state checks like
isMembersRouteActive and any Link/Href targets) so both use the same identifier;
update import/exports if needed so the constant is shared where used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/admin/src/layout/app-sidebar/nav-content.tsx`:
- Line 80: The "members" route string is repeated (e.g., in the
isMembersRouteActive useIsActiveLink call and elsewhere around lines 183-197),
which risks drift; extract that literal into a single constant (e.g.,
MEMBERS_ROUTE or MEMBERS_PATH) and replace all occurrences where the route is
referenced (for active-state checks like isMembersRouteActive and any Link/Href
targets) so both use the same identifier; update import/exports if needed so the
constant is shared where used.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 115fe09e-99b1-4d52-8702-3a5d5594054d

📥 Commits

Reviewing files that changed from the base of the PR and between c1efdf6 and 77b9413.

📒 Files selected for processing (6)
  • apps/admin/src/layout/app-sidebar/nav-content.tsx
  • apps/posts/src/views/members/components/members-list-item.tsx
  • apps/posts/src/views/members/components/members-list.tsx
  • apps/posts/src/views/members/member-detail-hash.ts
  • apps/posts/test/unit/views/members/members-list.test.ts
  • e2e/tests/admin/members/list.test.ts
✅ Files skipped from review due to trivial changes (3)
  • apps/posts/test/unit/views/members/members-list.test.ts
  • apps/posts/src/views/members/member-detail-hash.ts
  • apps/posts/src/views/members/components/members-list.tsx

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
Migrated the dropped React import flow and retained legacy member-detail coverage, and tightened bulk-action coverage so the filtered-members behavior still has an active browser test.
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)
e2e/tests/admin/members/import.test.ts (1)

16-31: Optional: clean up temporary CSV files after test execution.

The temp file created around Line 29–Line 30 is never removed. Wrapping import steps in try/finally with unlinkSync(csvPath) would avoid local/CI temp-dir buildup over time.

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

In `@e2e/tests/admin/members/import.test.ts` around lines 16 - 31, The test
creates a temp CSV via tmpdir() and writeFileSync into csvPath but never deletes
it; wrap the import and assertions that use csvPath (the block around the import
steps in import.test.ts) in a try/finally and call unlinkSync(csvPath) in the
finally to ensure cleanup; reference csvPath, writeFileSync and tmpdir() to
locate the creation and add unlinkSync(csvPath) to the finally block so temp
files are removed even if the test fails.
🤖 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/members/import.test.ts`:
- Around line 16-31: The test creates a temp CSV via tmpdir() and writeFileSync
into csvPath but never deletes it; wrap the import and assertions that use
csvPath (the block around the import steps in import.test.ts) in a try/finally
and call unlinkSync(csvPath) in the finally to ensure cleanup; reference
csvPath, writeFileSync and tmpdir() to locate the creation and add
unlinkSync(csvPath) to the finally block so temp files are removed even if the
test fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 661ddbaa-1ca4-4f55-b780-933798c60b03

📥 Commits

Reviewing files that changed from the base of the PR and between 77b9413 and 4a25fdb.

📒 Files selected for processing (3)
  • e2e/tests/admin/members-legacy/members.test.ts
  • e2e/tests/admin/members/bulk-actions.test.ts
  • e2e/tests/admin/members/import.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • e2e/tests/admin/members-legacy/members.test.ts
  • e2e/tests/admin/members/bulk-actions.test.ts

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 2026

E2E Tests Failed

To view the Playwright test report locally, run:

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

ref https://linear.app/ghost/issue/BER-3361/remove-feature-flag-release
Updated the Playwright import modal helper to match the shipped React import dialog instead of the old Ember data-test selectors so the restored browser coverage exercises the real UI.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

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