TTeamDesk 学习手册

tests/drafts.test.ts

此代码来自构建时的仓库快照。修改源码后重新构建即可更新。

ts
import { describe, expect, it } from 'vitest';
import { createDraftStore, draftKey } from '@/stores/drafts';
import { ticketSearchParsers } from '@/features/tickets/url-state';

const memoryStorage = () => {
  const data = new Map<string, string>();
  return {
    getItem: (key: string) => data.get(key) ?? null,
    setItem: (key: string, value: string) => {
      data.set(key, value);
    },
    removeItem: (key: string) => {
      data.delete(key);
    },
  };
};
describe('草稿隔离与恢复', () => {
  it('同账号刷新恢复草稿,其他团队、工单和账号不串用', async () => {
    const storage = memoryStorage();
    const first = createDraftStore('user-a', storage);
    await first.persist.rehydrate();
    first
      .getState()
      .save(draftKey('team-a', 'ticket-a'), { text: '未发送内容' });
    first.getState().save(draftKey('team-b', 'new'), {
      ticket: { title: '', description: '尚未写完', priority: 'NORMAL' },
    });
    const refresh = createDraftStore('user-a', storage);
    await refresh.persist.rehydrate();
    expect(refresh.getState().drafts[draftKey('team-a', 'ticket-a')].text).toBe(
      '未发送内容',
    );
    expect(
      refresh.getState().drafts[draftKey('team-a', 'ticket-b')],
    ).toBeUndefined();
    expect(
      refresh.getState().drafts[draftKey('team-b', 'new')].ticket?.description,
    ).toBe('尚未写完');
    const other = createDraftStore('user-b', storage);
    await other.persist.rehydrate();
    expect(other.getState().drafts).toEqual({});
    refresh.getState().remove(draftKey('team-a', 'ticket-a'));
    expect(refresh.getState().drafts[draftKey('team-b', 'new')]).toBeDefined();
    refresh.persist.clearStorage();
    const logout = createDraftStore('user-a', storage);
    await logout.persist.rehydrate();
    expect(logout.getState().drafts).toEqual({});
  });
  it('损坏的存储不会恢复成草稿', async () => {
    const storage = memoryStorage();
    storage.setItem(
      'teamdesk-drafts:user-a',
      JSON.stringify({ state: { drafts: { bad: { text: 123 } } }, version: 0 }),
    );
    const store = createDraftStore('user-a', storage);
    await store.persist.rehydrate();
    expect(store.getState().drafts).toEqual({});
  });
});
describe('URL 参数边界', () => {
  it('无效分页和枚举回落默认值,合法链接可恢复', () => {
    expect(ticketSearchParsers.page.parse('-1')).toBeNull();
    expect(ticketSearchParsers.page.parse('1.5')).toBeNull();
    expect(ticketSearchParsers.pageSize.parse('999')).toBeNull();
    expect(ticketSearchParsers.status.parse('INVALID')).toBeNull();
    expect(ticketSearchParsers.page.parse('2')).toBe(2);
    expect(ticketSearchParsers.status.parse('OPEN')).toBe('OPEN');
    expect(ticketSearchParsers.assignment.parse('mine')).toBe('mine');
  });
});

搜索教程

输入关键词,搜索全部章节。

阅读设置

外观
正文字号

从一张工单出发,读懂数据如何流转。

设置与进度仅保存在当前浏览器。