mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
* fix(collab): synchronize owner devices with overwrite consent * docs(collab): add owner device synchronization QA handoff * chore(collab): move delivery reports and screenshots to Plane * fix(collab): preserve owner pull fallback and ghost heal Generated-By: looper 0.16.1 (runner=fixer, agent=codex) * fix(collab): probe null owner heads for retractions Generated-By: looper 0.16.1 (runner=fixer, agent=codex) * fix(collab): preserve manual checks across coalescing Generated-By: looper 0.16.1 (runner=fixer, agent=codex) * feat(collab): hide update check behind a dismissed-version badge Show the header entry only when the owner skipped a cloud version, as a "Cloud update available" badge that re-opens the overwrite dialog. Rewrite the dialog description in plain product language. * fix(collab): clarify device sync copy and place entry before present * fix(collab): silence update reminders without automatic overwrite --------- Co-authored-by: Looper <looper@noreply.github.com> Co-authored-by: elifive555555 <296440099+elifive555555@users.noreply.github.com>
36 lines
2.3 KiB
TypeScript
36 lines
2.3 KiB
TypeScript
import { execFile } from 'node:child_process';
|
|
import http from 'node:http';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { promisify } from 'node:util';
|
|
import { expect, it } from 'vitest';
|
|
|
|
it('od collab shares the scoped check, acceptance, dismissal and preference API', async () => {
|
|
const received: Array<{ url: string; workspace: string | undefined; body: unknown }> = [];
|
|
const server = http.createServer((req, res) => {
|
|
let raw = '';
|
|
req.on('data', chunk => { raw += chunk; });
|
|
req.on('end', () => {
|
|
received.push({ url: req.url!, workspace: req.headers['x-od-workspace-id'] as string | undefined, body: JSON.parse(raw) });
|
|
res.setHeader('content-type', 'application/json');
|
|
res.end(JSON.stringify({ update: { state: 'up_to_date', latestVersion: 7, localVersion: 7, promptSuppressedUntil: null, updatedAt: 1 } }));
|
|
});
|
|
});
|
|
await new Promise<void>(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
const address = server.address();
|
|
if (!address || typeof address === 'string') throw new Error('missing server address');
|
|
const cli = fileURLToPath(new URL('../src/cli.ts', import.meta.url));
|
|
const tsx = fileURLToPath(new URL('../../../node_modules/tsx/dist/cli.mjs', import.meta.url));
|
|
try {
|
|
for (const args of [['check'], ['accept', '--version', '7'], ['dismiss', '--version', '7', '--dont-prompt-24h'], ['ask-again']]) {
|
|
const { stdout } = await promisify(execFile)(process.execPath, [tsx, cli, 'collab', args[0]!, 'p1', ...args.slice(1), '--daemon-url', `http://127.0.0.1:${address.port}`, '--workspace', 'w1', '--workspace-member', 'owner', '--json'], { timeout: 15_000 });
|
|
expect(JSON.parse(stdout).update.localVersion).toBe(7);
|
|
}
|
|
expect(received).toEqual([
|
|
{ url: '/api/projects/p1/collab/update', workspace: 'w1', body: { action: 'check', manual: true } },
|
|
{ url: '/api/projects/p1/collab/update', workspace: 'w1', body: { action: 'accept', version: 7, dontPromptFor24h: false } },
|
|
{ url: '/api/projects/p1/collab/update', workspace: 'w1', body: { action: 'dismiss', version: 7, dontPromptFor24h: true } },
|
|
{ url: '/api/projects/p1/collab/update', workspace: 'w1', body: { action: 'reset-preference' } },
|
|
]);
|
|
} finally { await new Promise<void>(resolve => server.close(() => resolve())); }
|
|
}, 60_000);
|