Follow-up to molecule-core#2449 (which taught the platform to return 410 Gone for status='removed'). Without this branch the operator sees `get_workspace_info failed: HTTP 410 — workspace removed` and has to guess what to do — exactly the 2026-04-30 silent-fail UX hit on the hongmingwang tenant. The new code path: 1. Detect resp.status === 410 explicitly 2. Best-effort parse the body for id / removed_at / hint 3. Throw `Workspace <id> was deleted on the platform at <ts>. <hint>` The 410-message-formatting is extracted into a pure `formatRemovedWorkspaceError` helper so it can be unit-tested without mocking fetch + resolveWatching. Four new bun:test cases: - prefers platform-supplied id, removed_at, hint - falls back to local workspaceId + default hint when body is empty - tolerates null/undefined body (unparseable response) - omits ' at <ts>' clause when removed_at is missing Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
// Regression tests for getWorkspaceInfo's 410-handling — pinned via
|
|
// the formatRemovedWorkspaceError pure helper so the test doesn't
|
|
// need to mock fetch + resolveWatching just to read one string.
|
|
//
|
|
// molecule-core#2429 — without these tests, the "your workspace was
|
|
// deleted, re-onboard" message is a 4-line code path that an
|
|
// inattentive refactor could collapse back into the generic
|
|
// "HTTP 410" error we used to surface.
|
|
|
|
import { describe, expect, it } from 'bun:test'
|
|
import { formatRemovedWorkspaceError } from './server.ts'
|
|
|
|
describe('formatRemovedWorkspaceError — 410 Gone handling (#2429)', () => {
|
|
it('prefers the platform-supplied id, removed_at, and hint when present', () => {
|
|
const msg = formatRemovedWorkspaceError('local-fallback-id', {
|
|
id: 'real-uuid',
|
|
removed_at: '2026-04-30T12:00:00Z',
|
|
hint: 'Custom hint from the platform.',
|
|
})
|
|
expect(msg).toBe(
|
|
'Workspace real-uuid was deleted on the platform at 2026-04-30T12:00:00Z. Custom hint from the platform.',
|
|
)
|
|
})
|
|
|
|
it('falls back to the local workspaceId + default hint when body is empty', () => {
|
|
const msg = formatRemovedWorkspaceError('fallback-uuid', {})
|
|
expect(msg).toBe(
|
|
'Workspace fallback-uuid was deleted on the platform. Regenerate workspace + token from the canvas → Tokens tab.',
|
|
)
|
|
})
|
|
|
|
it('tolerates a null/undefined body (unparseable response)', () => {
|
|
expect(formatRemovedWorkspaceError('uuid', null)).toContain(
|
|
'Workspace uuid was deleted',
|
|
)
|
|
expect(formatRemovedWorkspaceError('uuid', undefined)).toContain(
|
|
'Regenerate workspace + token',
|
|
)
|
|
})
|
|
|
|
it('omits the timestamp clause when removed_at is missing', () => {
|
|
const msg = formatRemovedWorkspaceError('uuid', {
|
|
id: 'uuid',
|
|
hint: 'h',
|
|
})
|
|
expect(msg).not.toContain(' at ')
|
|
expect(msg).toBe('Workspace uuid was deleted on the platform. h')
|
|
})
|
|
})
|