Files
WebDrop/web/src/core-bridge/worker/resourceMetadata.test.ts
T
justme 4b8d0b5a5f
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful
feat(web): discord-style chat, members pane, invitations and optimistic send [CI]
- chat: left-aligned discord-style messages with grouped senders, hover
  actions, an auto-growing composer and file cards
- send: render messages and files locally first and replace the
  placeholder when the worker publishes the real item; failures keep the
  text with a retry action
- navigation: space rail plus a flatter channel list with the space name
  header and collapsible groups
- members: right pane tabs (files / members) grouped by online, offline
  and pending users, with a prominent invite action and a top bar shortcut
- notifications: toast host for invite results; invitees get a toast with
  an accept action, and the invitation payload now carries the space name
  and inviter inside the encrypted grant
- users over devices: drop device names, the device list and device
  rename/release; senders show the account (guests show as guest) and the
  share panel only keeps links
- follow contract 7.0.0 (max_members, members_used, members_full, /join)
- docs: ui-design and frontend updated for the new layout and concepts
2026-10-14 22:19:25 +08:00

30 lines
1.9 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { isOfflineFailure } from './resourceMetadata';
import { toPublishedFile } from './fileCatalog';
import { exportResource } from './accountVault';
import type { FileItem } from '../types';
import type { SavedResource } from '../database';
describe('resource and rendering boundaries', () => {
it('does not treat authorization, tampering or contract errors as offline cache hits', () => {
expect(isOfflineFailure(new Error('网络连接失败'))).toBe(true);
expect(isOfflineFailure(Object.assign(new Error('forbidden'), { status: 403 }))).toBe(false);
expect(isOfflineFailure(new Error('api_contract_mismatch'))).toBe(false);
expect(isOfflineFailure(new Error('bad_meta'))).toBe(false);
});
it('publishes only resource metadata, excluding UI state and download counters', () => {
const item: FileItem = { id: 'a', threadId: 'channel', kind: 'file', name: 'secret.txt', mime: 'text/plain', size: 10, ts: 1,
gated: true, remaining: 5, preview: 'text', state: { kind: 'receiving', progress: 0.2 }, unseen: true, versions: [] };
const wire = toPublishedFile(item);
expect(wire.name).toBe('secret.txt');
for (const field of ['state', 'preview', 'remaining', 'versions', 'unseen']) expect(wire).not.toHaveProperty(field);
});
it('never synchronizes draft content or server structure snapshots inside the key vault', () => {
const resource: SavedResource = { id: 'a', kind: 'share', mode: 'enc', role: 'owner', link: 'key', createdAt: 1, expiresAt: 2,
endpointSecret: new Uint8Array(32), maxMembers: 0, draftItems: [], manifestEntries: [],
workspaceMetadata: { structure: { revision: 1, channels: [], groups: [], folders: [], locations: [] }, people: [] } };
const exported = exportResource(resource);
for (const field of ['draftItems', 'manifestEntries', 'workspaceMetadata', 'endpointSecret']) expect(exported).not.toHaveProperty(field);
});
});