test: convert mocha this.timeout/this.skip to vitest in merged-from-develop admin specs

Three admin test files brought in by the develop merge (5afd466bb) still
used mocha-shape this.timeout/this.skip. Converts them to vi.setConfig
and ctx.skip per the pattern established in 95f753c80.
This commit is contained in:
SamTV12345 2026-05-25 12:01:37 +02:00
parent 5afd466bba
commit d8eeee8321
3 changed files with 48 additions and 30 deletions

View file

@ -1,6 +1,7 @@
'use strict';
import {strict as assert} from 'assert';
import {vi} from 'vitest';
import setCookieParser from 'set-cookie-parser';
import * as fs from 'fs';
import * as os from 'os';
@ -81,7 +82,7 @@ const ask = (socket: any, evt: string, payload: any, replyEvt: string) =>
socket.emit(evt, payload);
});
describe(__filename, function () {
describe(__filename, () => {
let socket: any;
let savedUsers: any;
let savedRequireAuthentication: boolean;
@ -92,9 +93,10 @@ describe(__filename, function () {
let savedSettingsFilename: any;
let tmpSettingsPath: string | null = null;
let setupCompleted = false;
let skipReason: string | null = null;
before(async function () {
this.timeout(60000);
before(async () => {
vi.setConfig({hookTimeout: 60000});
await common.init();
// The load handler bails with logger.error + early return if the
@ -125,13 +127,13 @@ describe(__filename, function () {
console.warn(
`[adminSettingsResolved] admin socket probe failed (${probe.reason}); ` +
'skipping suite — likely an authenticate-hook plugin rejecting test creds.');
this.skip();
skipReason = probe.reason;
return;
}
socket = probe.socket;
});
after(function () {
after(() => {
if (socket) socket.disconnect();
if (!setupCompleted) return;
if (savedDbPwd === undefined) delete settings.dbSettings.password;
@ -148,7 +150,8 @@ describe(__filename, function () {
settings.requireAuthentication = savedRequireAuthentication;
});
it('emits {results, resolved, flags}', async function () {
it('emits {results, resolved, flags}', async (ctx) => {
if (skipReason) return ctx.skip();
const reply: any = await ask(socket, 'load', null, 'settings');
assert.ok(reply, 'reply present');
assert.equal(typeof reply.results, 'string', 'raw file string');
@ -156,19 +159,22 @@ describe(__filename, function () {
assert.ok(reply.flags, 'flags present');
});
it('resolved reflects live in-memory values, not the file on disk', async function () {
it('resolved reflects live in-memory values, not the file on disk', async (ctx) => {
if (skipReason) return ctx.skip();
const reply: any = await ask(socket, 'load', null, 'settings');
assert.equal(reply.resolved.trustProxy, true,
'resolved should show the in-memory trustProxy');
});
it('resolved redacts secrets', async function () {
it('resolved redacts secrets', async (ctx) => {
if (skipReason) return ctx.skip();
const reply: any = await ask(socket, 'load', null, 'settings');
assert.equal(reply.resolved.dbSettings.password, '[REDACTED]');
assert.equal(reply.resolved.sessionKey, '[REDACTED]');
});
it('resolved is omitted when showSettingsInAdminPage is false', async function () {
it('resolved is omitted when showSettingsInAdminPage is false', async (ctx) => {
if (skipReason) return ctx.skip();
settings.showSettingsInAdminPage = false;
try {
const reply: any = await ask(socket, 'load', null, 'settings');

View file

@ -1,6 +1,7 @@
'use strict';
import {strict as assert} from 'assert';
import {vi} from 'vitest';
import setCookieParser from 'set-cookie-parser';
import * as fs from 'fs';
import * as os from 'os';
@ -97,7 +98,7 @@ const save = (socket: any, payload: string) =>
// disk byte-for-byte at settings.settingsFilename, and the subsequent
// `load` reply reflects the new file contents. We do NOT exercise
// runtime reload — that's reloadSettings()' job and is covered elsewhere.
describe(__filename, function () {
describe(__filename, () => {
let socket: any;
let savedUsers: any;
let savedRequireAuthentication: boolean;
@ -105,9 +106,10 @@ describe(__filename, function () {
let tmpSettingsPath: string | null = null;
let baselineContents: string;
let setupCompleted = false;
let skipReason: string | null = null;
before(async function () {
this.timeout(60000);
before(async () => {
vi.setConfig({hookTimeout: 60000});
await common.init();
savedSettingsFilename = settings.settingsFilename;
@ -134,13 +136,13 @@ describe(__filename, function () {
console.warn(
`[adminSettingsSave] admin socket probe failed (${probe.reason}); ` +
'skipping suite — likely an authenticate-hook plugin rejecting test creds.');
this.skip();
skipReason = probe.reason;
return;
}
socket = probe.socket;
});
after(function () {
after(() => {
if (socket) socket.disconnect();
if (!setupCompleted) return;
settings.settingsFilename = savedSettingsFilename;
@ -153,14 +155,15 @@ describe(__filename, function () {
});
// Reset to baseline between tests so each it() is independent — earlier
// suites in the same mocha run can leave behind state via shared sockets.
beforeEach(function () {
if (!tmpSettingsPath) this.skip();
// suites in the same run can leave behind state via shared sockets.
beforeEach((ctx) => {
if (!tmpSettingsPath) return ctx.skip();
fs.writeFileSync(tmpSettingsPath!, baselineContents);
});
it('saveSettings writes the payload byte-for-byte to settings.settingsFilename',
async function () {
async (ctx) => {
if (skipReason) return ctx.skip();
const payload = JSON.stringify({title: 'EtherpadWrittenViaSocket'}, null, 2);
const ack = await save(socket, payload);
assert.equal(ack.status, 'saved', 'saveprogress should be "saved"');
@ -173,7 +176,8 @@ describe(__filename, function () {
// one new top-level block (a plugin config). The block must persist on
// disk verbatim and reappear in the next `load` reply.
it('augmenting existing JSON with a new top-level plugin block round-trips',
async function () {
async (ctx) => {
if (skipReason) return ctx.skip();
const augmented = JSON.stringify({
title: 'Etherpad',
ip: '0.0.0.0',
@ -207,7 +211,8 @@ describe(__filename, function () {
// path must not normalize or strip them — the SPA test
// 'preserves /* */ comments after save round-trip' covers the UI side;
// this one covers the socket-level guarantee.
it('preserves /* */ comments in the written file', async function () {
it('preserves /* */ comments in the written file', async (ctx) => {
if (skipReason) return ctx.skip();
const withComment =
'/* persisted-marker-7819 */\n' +
JSON.stringify({title: 'Etherpad'}, null, 2);

View file

@ -9,6 +9,7 @@
// offset/limit slice, so `total` reflects the filtered universe.
import {strict as assert} from 'assert';
import {vi} from 'vitest';
import setCookieParser from 'set-cookie-parser';
const io = require('socket.io-client');
@ -86,19 +87,20 @@ const adminSocketWithProbe = async (budgetMs: number): Promise<{
return {ok: true, socket};
};
describe(__filename, function () {
describe(__filename, () => {
let socket: any;
let savedUsers: any;
let savedRequireAuthentication: boolean;
let setupCompleted = false;
let skipReason: string | null = null;
// Distinct per-suite tag so concurrent test runs / leftover pads from
// earlier suites don't pollute the filter assertions.
const tag = `padLoadFilter-${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
const emptyPadIds: string[] = [];
const editedPadIds: string[] = [];
before(async function () {
this.timeout(120000);
before(async () => {
vi.setConfig({hookTimeout: 120000});
await common.init();
savedUsers = settings.users;
@ -111,7 +113,7 @@ describe(__filename, function () {
`[padLoadFilter] admin socket probe failed (${probe.reason}); ` +
"skipping suite — likely an authenticate-hook plugin rejecting the test's " +
'admin credentials.');
this.skip();
skipReason = probe.reason;
return;
}
socket = probe.socket;
@ -132,7 +134,7 @@ describe(__filename, function () {
}
});
after(async function () {
after(async () => {
if (socket) socket.disconnect();
if (!setupCompleted) return;
// `savedUsers` may point at the same object that adminSocket mutated,
@ -150,7 +152,8 @@ describe(__filename, function () {
}
});
it('filter:"empty" returns only revisionNumber===0 pads from the full set', async function () {
it('filter:"empty" returns only revisionNumber===0 pads from the full set', async (ctx) => {
if (skipReason) return ctx.skip();
const res = await ask(socket, 'padLoad', {
pattern: tag, offset: 0, limit: 12, sortBy: 'padName',
ascending: true, filter: 'empty',
@ -162,7 +165,8 @@ describe(__filename, function () {
}
});
it('filter:"empty" with limit=2 still reports the correct total (regression: thm)', async function () {
it('filter:"empty" with limit=2 still reports the correct total (regression: thm)', async (ctx) => {
if (skipReason) return ctx.skip();
// The bug thm hit: clicking "empty" showed at most `limit` empties
// because filtering happened on the client AFTER pagination. The
// server now applies filter first, so total reflects the filtered
@ -175,7 +179,8 @@ describe(__filename, function () {
assert.equal(res.results.length, 2, `expected limit=2 page, got ${res.results.length} rows`);
});
it('filter omitted (older client) falls back to "all"', async function () {
it('filter omitted (older client) falls back to "all"', async (ctx) => {
if (skipReason) return ctx.skip();
const res = await ask(socket, 'padLoad', {
pattern: tag, offset: 0, limit: 12, sortBy: 'padName',
ascending: true,
@ -184,7 +189,8 @@ describe(__filename, function () {
`expected total=8 (5 empty + 3 edited), got ${JSON.stringify(res)}`);
});
it('filter:"all" matches the no-filter behaviour', async function () {
it('filter:"all" matches the no-filter behaviour', async (ctx) => {
if (skipReason) return ctx.skip();
const res = await ask(socket, 'padLoad', {
pattern: tag, offset: 0, limit: 12, sortBy: 'padName',
ascending: true, filter: 'all',
@ -192,7 +198,8 @@ describe(__filename, function () {
assert.equal(res.total, 8);
});
it('filter:"active" excludes pads with no active users', async function () {
it('filter:"active" excludes pads with no active users', async (ctx) => {
if (skipReason) return ctx.skip();
// No connected clients in this test, so every test pad has
// userCount === 0 → filter:"active" must return zero.
const res = await ask(socket, 'padLoad', {