feat(sdk): 身份与环境上下文模块
- identity.ts: 访客/会话 ID(30min 空闲轮换),localStorage 异常统一内存降级不冒泡(spec §4.5 红线) - context.ts: buildEnvContext/parseUtm/sanitizeUrl/pageContext;参数黑名单与 server URL_PARAM_DROP_PATTERNS 同源(整键精确匹配、大小写不敏感、保留空值) - 测试 21 过(含隐私模式降级、Edg 先于 Chrome、微信 UA 判定、iPad-Mobile 规格顺序锁定) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import { getVisitorId, getSessionId, touchActivity } from "../src/identity";
|
||||
|
||||
describe("identity", () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("visitor_id 持久化且格式正确", () => {
|
||||
const v = getVisitorId();
|
||||
expect(v).toBe(getVisitorId());
|
||||
expect(v).toMatch(/^[0-9a-f-]{36}$/);
|
||||
});
|
||||
|
||||
it("30 分钟无活动切新会话;窗口内 touch 续期", () => {
|
||||
const s1 = getSessionId();
|
||||
vi.advanceTimersByTime(10 * 60_000);
|
||||
touchActivity();
|
||||
vi.advanceTimersByTime(10 * 60_000);
|
||||
expect(getSessionId()).toBe(s1); // 20min 内有活动 → 同会话
|
||||
vi.advanceTimersByTime(31 * 60_000); // 再过 31min 无活动
|
||||
expect(getSessionId()).not.toBe(s1);
|
||||
});
|
||||
|
||||
it("localStorage 抛异常时内存降级不冒泡且功能可用", () => {
|
||||
// 探测确认:vitest happy-dom 环境下 window === globalThis,且 localStorage
|
||||
// 是 window 上的自有可配置 accessor——spy 其 getter 即可让模块内裸
|
||||
// localStorage 引用在访问时抛异常(等效隐私模式/禁存储)。
|
||||
const spy = vi.spyOn(window, "localStorage", "get").mockImplementation(() => {
|
||||
throw new DOMException("denied");
|
||||
});
|
||||
|
||||
const v = getVisitorId();
|
||||
expect(v).toMatch(/^[0-9a-f-]{36}$/);
|
||||
const s = getSessionId();
|
||||
expect(s).toMatch(/^[0-9a-f-]{36}$/);
|
||||
expect(getSessionId()).toBe(s); // 纯内存降级下会话仍连续
|
||||
expect(() => touchActivity()).not.toThrow();
|
||||
|
||||
// 还原后(内存态无法迁移到 localStorage 是预期)混用两套存储不抛
|
||||
spy.mockRestore();
|
||||
expect(() => getSessionId()).not.toThrow();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user