test(admin): cover saveSettings round-trip + restart persistence (#7819)#7820
Conversation
…er#7819) The admin saveSettings socket had zero direct backend coverage and the e2e 'restart works' test only checked the page renders after restart — neither catches a deployment that resets settings.json on restart, nor the user-visible workflow that triggered ether#7819 (add a top-level plugin block via Raw, save, watch it disappear). Adds three backend specs for the saveSettings socket: - payload is written byte-for-byte to settings.settingsFilename - augmenting existing JSON with a new top-level block round-trips through the next load reply - /* */ comments survive the write path Adds one e2e spec mirroring the ether#7819 workflow: open Raw, prepend an ep_oauth-shaped top-level block, save, restartEtherpad(), re-login, confirm the block is still in Raw and surfaces as its own Form-view section ('Ep oauth' from humanize()). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
Review Summary by QodoAdd admin settings persistence tests for issue #7819
WalkthroughsDescription• Add backend specs for saveSettings socket covering round-trip persistence • Verify payload writes byte-for-byte to disk and survives server restart • Add e2e test mirroring #7819 workflow: add plugin block, save, restart, confirm persistence • Ensure comments and custom top-level blocks survive the write path Diagramflowchart LR
A["Admin saveSettings socket"] -->|"Backend specs"| B["Payload write verification"]
A -->|"Backend specs"| C["Round-trip JSON augmentation"]
A -->|"Backend specs"| D["Comment preservation"]
E["E2E restart workflow"] -->|"Add plugin block"| F["Save settings"]
F -->|"Restart server"| G["Verify persistence"]
G -->|"Check Raw view"| H["Confirm block survives"]
G -->|"Check Form view"| I["Verify humanized section"]
File Changes1. src/tests/backend/specs/admin/adminSettingsSave.ts
|
Code Review by Qodo
Context used 1. Missing settings cleanup guard
|
| // Restore — DO NOT rely on the next test's cleanup; the file is | ||
| // shared across the serial run and a custom ep_oauth block could | ||
| // poison anything that asserts the exact length of settings. | ||
| await page.getByTestId('mode-toggle-raw').click(); | ||
| await rawAfter.fill(original); | ||
| await saveSettings(page); | ||
| }); |
There was a problem hiding this comment.
1. Missing settings cleanup guard 🐞 Bug ☼ Reliability
The new Playwright restart-persistence test restores the original raw settings only at the end of the test body; if any assertion fails before the restore, the injected ep_oauth block remains persisted and can break subsequent serial admin settings tests that assume a clean settings file.
Agent Prompt
### Issue description
The test `#7819 custom top-level block survives server restart` mutates the shared settings file and only restores it at the very end. If the test fails (assertion/timeout/restart issues) before the restore block, the suite remains polluted and later tests in the same serial run can fail.
### Issue Context
This suite is configured to run serially, and the test itself notes the settings file is shared across the serial run.
### Fix Focus Areas
- src/tests/frontend-new/admin-spec/adminsettings.spec.ts[134-185]
### Suggested fix
Wrap the mutation + assertions in a `try { ... } finally { ... }` and move the restore logic into the `finally` so it executes even on failure.
Example sketch:
```ts
const original = await raw.inputValue();
let mutated = false;
try {
const augmented = ...;
mutated = true;
... assertions ...
} finally {
if (mutated) {
// best-effort restore
await page.goto('http://localhost:9001/admin/settings');
await page.getByTestId('mode-toggle-raw').click();
await page.getByTestId('settings-raw-textarea').fill(original);
await saveSettings(page);
}
}
```
(You can keep it minimal by reusing existing locators; the key is ensuring restore runs even when the test fails.)
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Summary
Closes the test gap exposed by #7819:
src/tests/backend/specs/admin/adminSettingsSave.ts, new) — 3 specs covering thesaveSettingssocket on/settings, which previously had zero direct test coverage. Asserts the payload is written byte-for-byte tosettings.settingsFilename, augmenting existing JSON with a new top-level block round-trips through the nextloadreply, and/* */comments survive the write path.src/tests/frontend-new/admin-spec/adminsettings.spec.ts) — adds#7819 custom top-level block survives server restart. The pre-existingrestart workstest never sets a custom value before restart, so a deployment that resetssettings.jsonon restart (Docker layer wipe, init-container template render, snap reseed) would pass it. The new test mirrors the workflow Can't add Github's settings for the plugin ep_oauth v11.0.28 - Etherpad 3.1.0 #7819 describes: open Raw, prepend anep_oauth-shaped block, save,restartEtherpad(), re-login, confirm the block is still in Raw and surfaces in Form view as its ownEp oauthsection.No production code changes — tests only.
Why the gap was there
The save path is dead simple —
fsp.writeFile(settings.settingsFilename, newSettings)— so it has felt "obviously correct" enough to skip. But that simplicity hides the actual #7819 failure mode: the deployment layer (not Etherpad) resets the file on restart, and the existing tests only restart the server without first putting a recoverable marker into the file. Now they do.Test plan
pnpm run ts-check(passes; no other lint job in CI)pnpm testtargetingtests/backend/specs/admin/— 35 passing, including the 3 new oneschromium-adminPlaywright project — the new e2e test exercises the restart path under the same conditions as the existingrestart workstest it sits beside🤖 Generated with Claude Code