Files
SnowLuma/packages/core/tests/webui/consent.test.ts
T
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

167 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import fs from 'fs';
import os from 'os';
import path from 'path';
import {
computeAgreementsVersion,
EULA_ACCEPT_ENV,
isConsentRequired,
loadAgreements,
parseAgreementMeta,
PRIVACY_ACCEPT_ENV,
recordConsent,
loadConsentRecord,
resolveEnvironmentConsent,
} from '@/webui/consent';
describe('computeAgreementsVersion', () => {
it('is deterministic for identical input', () => {
const docs = [
{ id: 'eula', text: 'A' },
{ id: 'privacy', text: 'B' },
];
expect(computeAgreementsVersion(docs)).toBe(computeAgreementsVersion(docs));
});
it('changes when any agreement TEXT changes (forces re-consent)', () => {
const before = computeAgreementsVersion([
{ id: 'eula', text: 'terms v1' },
{ id: 'privacy', text: 'privacy v1' },
]);
const after = computeAgreementsVersion([
{ id: 'eula', text: 'terms v2' }, // edited
{ id: 'privacy', text: 'privacy v1' },
]);
expect(after).not.toBe(before);
});
it('is independent of app version — same text => same version', () => {
// The function takes only doc id+text, never an app version, so an app
// upgrade with unchanged docs yields an identical version (stable consent).
const v1 = computeAgreementsVersion([{ id: 'eula', text: 'same' }]);
const v2 = computeAgreementsVersion([{ id: 'eula', text: 'same' }]);
expect(v1).toBe(v2);
});
it('is not fooled by id/text boundary shifting', () => {
const a = computeAgreementsVersion([{ id: 'eula', text: 'x' }]);
const b = computeAgreementsVersion([{ id: 'eu', text: 'lax' }]);
expect(a).not.toBe(b);
});
});
describe('parseAgreementMeta', () => {
it('pulls title / declared version / effective date from a bilingual doc', () => {
const text = [
'# SnowLuma 最终用户许可协议(EULA)/ End-User License Agreement',
'',
'- **生效日期 / Effective date:** 2026-06-19',
'- **版本 / Version:** 1.0',
'',
'正文…',
].join('\n');
const meta = parseAgreementMeta(text);
expect(meta.title).toBe('SnowLuma 最终用户许可协议(EULA)/ End-User License Agreement');
expect(meta.declaredVersion).toBe('1.0');
expect(meta.effectiveDate).toBe('2026-06-19');
});
it('degrades gracefully on empty text', () => {
expect(parseAgreementMeta('')).toEqual({
title: '',
declaredVersion: '',
effectiveDate: '',
});
});
});
describe('environment consent', () => {
it('requires explicit acceptance of both EULA and PRIVACY', () => {
expect(resolveEnvironmentConsent({})).toEqual({
eulaAccepted: false,
privacyAccepted: false,
accepted: false,
});
expect(resolveEnvironmentConsent({ [EULA_ACCEPT_ENV]: '1' })).toEqual({
eulaAccepted: true,
privacyAccepted: false,
accepted: false,
});
});
it('accepts trimmed, case-insensitive true values', () => {
expect(
resolveEnvironmentConsent({
[EULA_ACCEPT_ENV]: ' true ',
[PRIVACY_ACCEPT_ENV]: 'TRUE',
}).accepted,
).toBe(true);
});
it('fails fast on an invalid configured value', () => {
expect(() =>
resolveEnvironmentConsent({
[EULA_ACCEPT_ENV]: 'yes',
[PRIVACY_ACCEPT_ENV]: '1',
}),
).toThrow(`${EULA_ACCEPT_ENV} must be one of: 1, true, 0, false`);
});
});
describe('consent persistence', () => {
let tmp: string;
let cwd: string;
beforeEach(() => {
cwd = process.cwd();
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'snowluma-consent-'));
process.chdir(tmp);
});
afterEach(() => {
process.chdir(cwd);
fs.rmSync(tmp, { recursive: true, force: true });
});
it('records and reads back the accepted version', () => {
expect(loadConsentRecord()).toBeNull();
const rec = recordConsent('abc123');
expect(rec.version).toBe('abc123');
expect(Date.parse(rec.acceptedAt)).not.toBeNaN();
const loaded = loadConsentRecord();
expect(loaded?.version).toBe('abc123');
expect(fs.existsSync(path.join('config', 'consent.json'))).toBe(true);
});
it('staleness check: stored version != current => re-consent needed', () => {
recordConsent('old-version');
const stored = loadConsentRecord();
// mirrors isConsentRequired()'s comparison against the current version
expect(stored?.version !== 'new-version').toBe(true);
expect(stored?.version !== 'old-version').toBe(false);
});
it('environment consent unlocks without writing a permanent consent record', () => {
expect(
isConsentRequired({
[EULA_ACCEPT_ENV]: '1',
[PRIVACY_ACCEPT_ENV]: 'true',
}),
).toBe(false);
expect(loadConsentRecord()).toBeNull();
expect(isConsentRequired({ [EULA_ACCEPT_ENV]: '1' })).toBe(true);
});
it('stored consent still covers the current agreement version', () => {
recordConsent(loadAgreements().version);
expect(isConsentRequired({})).toBe(false);
});
it('ignores a malformed consent.json (treated as no consent)', () => {
fs.mkdirSync('config', { recursive: true });
fs.writeFileSync(path.join('config', 'consent.json'), '{ not json');
expect(loadConsentRecord()).toBeNull();
});
});