Skip to content

fix(e2e): add test isolation for note-modal Slate editor tests#132

Merged
ryota-murakami merged 2 commits intomainfrom
fix/e2e-note-modal-isolation
Feb 18, 2026
Merged

fix(e2e): add test isolation for note-modal Slate editor tests#132
ryota-murakami merged 2 commits intomainfrom
fix/e2e-note-modal-isolation

Conversation

@ryota-murakami
Copy link
Contributor

@ryota-murakami ryota-murakami commented Feb 18, 2026

Summary

  • Add resetProjectInfoNotes() DB helper to reset note content to seed values
  • Call it in beforeEach for all 3 note-modal test describe blocks
  • Fixes shard 9 flakiness: the "save and persist" test writes content to DB, and subsequent tests (slash command, heading autoformat) inherited that state — making Ctrl+A+Backspace clear unreliable on slow CI runners

Root Cause

The Slate/Plate.js editor Ctrl+A selection doesn't reliably select all content in contenteditable elements on GitHub Actions runners, especially when the content includes rich text with multiple block nodes. Rather than fighting browser timing, reset the DB to a known state before each test.

Test plan

  • All 12 E2E shards pass (especially shard 9)
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (1282 tests)

Summary by CodeRabbit

  • Tests
    • Improved test reliability by seeding note content before each test and standardizing initialization across note-related suites, reducing intermittent failures.
    • Made editor empty-state checks more robust by validating placeholder visibility instead of raw text, improving resilience of note-editing, formatting, and command tests.

The note-modal tests were flaky on CI because the "save and persist"
test writes content to the DB, and subsequent tests (slash command,
heading autoformat) inherit that state. Ctrl+A+Backspace to clear
Slate editors is inherently unreliable on slow CI runners.

Fix: add resetProjectInfoNotes() helper that resets note fields to
seed values before each test, ensuring a known starting state.
@vercel
Copy link
Contributor

vercel bot commented Feb 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gitbox Ready Ready Preview, Comment Feb 18, 2026 7:51pm

Request Review

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

Adds a new e2e DB helper resetProjectInfoNotes() that seeds note values into projectinfo, and integrates it into the NoteModal test suite. Tests also adopt a polling-based editor-clear/assertion pattern to reliably detect the editor's placeholder state before interactions.

Changes

Cohort / File(s) Summary
Database seeding helper
e2e/helpers/db-query.ts
Adds exported resetProjectInfoNotes() which creates a local Supabase client, updates seed note values in projectinfo for specific IDs, and throws descriptive errors when updates fail or affect zero rows.
Note modal tests
e2e/logged-in/note-modal.spec.ts
Imports and calls resetProjectInfoNotes() in multiple beforeEach hooks; replaces fragile editor-clear checks with polling-based clear + placeholder visibility assertions across note editing, formatting, and slash-command tests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🌱 Seeds written, notes set right,
Tests wake steady after night.
Placeholders wait, editors clear,
CI hums along—no fear. ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding test isolation for note-modal Slate editor tests by resetting DB state between tests to fix flakiness.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/e2e-note-modal-isolation

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.

@morph-subagents
Copy link

🤖 Morph Preview Test

Looks like you hit your rate limits!

Please upgrade your limits here, or wait a few minutes and try again.

If you need help, reach out to support@morphllm.com.


Automated testing by Morph

@codecov-commenter
Copy link

codecov-commenter commented Feb 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.03%. Comparing base (44aa00c) to head (f781f9e).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #132   +/-   ##
=======================================
  Coverage   71.03%   71.03%           
=======================================
  Files         145      145           
  Lines        4381     4381           
  Branches     1148     1180   +32     
=======================================
  Hits         3112     3112           
  Misses       1248     1248           
  Partials       21       21           

☔ 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.

Copy link

@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/helpers/db-query.ts (1)

316-321: Optional: extract seed note values to avoid duplication with resetRepoCards().

The four note strings defined here ('Important project notes here', 'Another repo notes', '', 'CLI tool documentation') are also inlined inside resetRepoCards() at its seedProjectInfos array. If a seed value changes, both places need updating.

♻️ Suggested extraction
+// Canonical seed note values — shared by resetProjectInfoNotes() and resetRepoCards()
+export const SEED_NOTES: Record<keyof typeof PROJECT_INFO_IDS, string> = {
+  projinfo1: 'Important project notes here',
+  projinfo2: 'Another repo notes',
+  projinfo3: '',
+  projinfo4: 'CLI tool documentation',
+} as const

 const seedNotes = [
-  { id: PROJECT_INFO_IDS.projinfo1, note: 'Important project notes here' },
-  { id: PROJECT_INFO_IDS.projinfo2, note: 'Another repo notes' },
-  { id: PROJECT_INFO_IDS.projinfo3, note: '' },
-  { id: PROJECT_INFO_IDS.projinfo4, note: 'CLI tool documentation' },
+  { id: PROJECT_INFO_IDS.projinfo1, note: SEED_NOTES.projinfo1 },
+  { id: PROJECT_INFO_IDS.projinfo2, note: SEED_NOTES.projinfo2 },
+  { id: PROJECT_INFO_IDS.projinfo3, note: SEED_NOTES.projinfo3 },
+  { id: PROJECT_INFO_IDS.projinfo4, note: SEED_NOTES.projinfo4 },
 ]

Then reference SEED_NOTES in resetRepoCards() as well.

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

In `@e2e/helpers/db-query.ts` around lines 316 - 321, The seed note strings are
duplicated between the local constant seedNotes and the array inside
resetRepoCards() (seedProjectInfos); extract the four note strings into a single
exported constant (e.g., SEED_NOTES) and replace both occurrences so
resetRepoCards() uses SEED_NOTES and the current seedNotes definition references
the same constant; update any imports/usages accordingly and keep identifiers
like seedNotes, resetRepoCards(), and seedProjectInfos in mind when making the
change.
🤖 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/db-query.ts`:
- Around line 316-321: The seed note strings are duplicated between the local
constant seedNotes and the array inside resetRepoCards() (seedProjectInfos);
extract the four note strings into a single exported constant (e.g., SEED_NOTES)
and replace both occurrences so resetRepoCards() uses SEED_NOTES and the current
seedNotes definition references the same constant; update any imports/usages
accordingly and keep identifiers like seedNotes, resetRepoCards(), and
seedProjectInfos in mind when making the change.

@github-actions
Copy link

github-actions bot commented Feb 18, 2026

🧪 E2E Coverage Report (Sharded: 12 parallel jobs)

Metric Coverage
Lines 94.39%
Functions 17.39%
Branches 16.96%
Statements 30.63%

📊 Full report available in workflow artifacts

When the Plate/Slate editor is empty, it renders a placeholder element
with data-slate-placeholder="true". textContent() captures this
placeholder text, causing the emptiness check to fail. Use placeholder
element visibility instead — a visible placeholder means the editor
is truly empty.
@morph-subagents
Copy link

🤖 Morph Preview Test

Looks like you hit your rate limits!

Please upgrade your limits here, or wait a few minutes and try again.

If you need help, reach out to support@morphllm.com.


Automated testing by Morph

Copy link

@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 (2)
e2e/logged-in/note-modal.spec.ts (2)

294-298: Bold test still uses waitForTimeout(300) — consider the polling pattern applied to heading/slash tests.

The heading autoformat (lines 542-551) and slash command (lines 244-253) tests use toPass() polling to confirm the placeholder is visible after clear. For consistency and CI resilience, the same guard could be applied here (and in the italic test at lines 588-591).

♻️ Proposed refactor
-    // Clear existing content and wait for Slate to process
-    await page.keyboard.press(`${MOD}+a`)
-    await page.keyboard.press('Backspace')
-    // eslint-disable-next-line playwright/no-wait-for-timeout
-    await page.waitForTimeout(300)
+    // Clear existing content — retry inside polling loop for CI resilience
+    await expect(async () => {
+      await page.keyboard.press(`${MOD}+a`)
+      await page.keyboard.press('Backspace')
+      const placeholder = editorContent.locator('[data-slate-placeholder="true"]')
+      await expect(placeholder).toBeVisible()
+    }).toPass({ timeout: 10000 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/logged-in/note-modal.spec.ts` around lines 294 - 298, Replace the brittle
fixed sleep after clearing Slate in the bold test (the block using
page.keyboard.press(`${MOD}+a`) and page.keyboard.press('Backspace')) with the
same toPass() polling pattern used by the heading autoformat and slash command
tests: remove the waitForTimeout(300) and instead call the toPass() helper to
poll until the editor placeholder (the same locator/assertion used in lines
~542-551 and ~244-253) becomes visible; apply the identical change to the italic
test (lines ~588-591) so both tests wait deterministically for Slate processing
rather than sleeping.

516-518: Navigation duplicated in test bodies — consider centralising in beforeEach.

Unlike the other two describe blocks, this beforeEach skips page.goto() / waitForLoadState('networkidle'), so both tests repeat that boilerplate individually (lines 523-525 and 570-572). As per coding guidelines, networkidle should be the standard wait strategy for page loads — centralising it in beforeEach is consistent with that and the rest of the file.

♻️ Proposed refactor
-  test.beforeEach(async () => {
-    await resetProjectInfoNotes()
-  })
+  test.beforeEach(async ({ page }) => {
+    await resetProjectInfoNotes()
+    await page.goto(BOARD_URL)
+    await page.waitForLoadState('networkidle')
+  })

Then remove the duplicated goto/waitForLoadState lines from each test body (lines 523-525 and 570-572).

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

In `@e2e/logged-in/note-modal.spec.ts` around lines 516 - 518, The tests in this
describe block call resetProjectInfoNotes in test.beforeEach but do not navigate
to the app; two tests duplicate page.goto(...) and
page.waitForLoadState('networkidle') in their bodies—move the navigation into
the describe block's test.beforeEach so it runs after resetProjectInfoNotes
(i.e., call page.goto(...) and await page.waitForLoadState('networkidle') in the
same beforeEach), then remove the duplicated page.goto/page.waitForLoadState
lines from the two tests to centralise navigation and use the standard
networkidle wait strategy; look for test.beforeEach, resetProjectInfoNotes, and
the page.goto/page.waitForLoadState('networkidle') calls to update.
🤖 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/logged-in/note-modal.spec.ts`:
- Around line 294-298: Replace the brittle fixed sleep after clearing Slate in
the bold test (the block using page.keyboard.press(`${MOD}+a`) and
page.keyboard.press('Backspace')) with the same toPass() polling pattern used by
the heading autoformat and slash command tests: remove the waitForTimeout(300)
and instead call the toPass() helper to poll until the editor placeholder (the
same locator/assertion used in lines ~542-551 and ~244-253) becomes visible;
apply the identical change to the italic test (lines ~588-591) so both tests
wait deterministically for Slate processing rather than sleeping.
- Around line 516-518: The tests in this describe block call
resetProjectInfoNotes in test.beforeEach but do not navigate to the app; two
tests duplicate page.goto(...) and page.waitForLoadState('networkidle') in their
bodies—move the navigation into the describe block's test.beforeEach so it runs
after resetProjectInfoNotes (i.e., call page.goto(...) and await
page.waitForLoadState('networkidle') in the same beforeEach), then remove the
duplicated page.goto/page.waitForLoadState lines from the two tests to
centralise navigation and use the standard networkidle wait strategy; look for
test.beforeEach, resetProjectInfoNotes, and the
page.goto/page.waitForLoadState('networkidle') calls to update.

@ryota-murakami ryota-murakami merged commit 2d67f41 into main Feb 18, 2026
38 of 46 checks passed
@ryota-murakami ryota-murakami deleted the fix/e2e-note-modal-isolation branch February 18, 2026 20:28
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.

2 participants

Comments