Enhance architecture documentation and update project dependencies. Introduce new features for browser recording, page callables, and transform capabilities. Improve build scripts and permissions for better functionality.

This commit is contained in:
go0p
2026-07-23 15:16:50 +08:00
parent 726a97849b
commit c7891a6a9d
125 changed files with 25018 additions and 1675 deletions
+46 -10
View File
@@ -2,19 +2,55 @@ import { vi, describe, expect, it } from 'vitest';
vi.mock('wxt/browser', () => ({ browser: { declarativeNetRequest: {} } }));
import { buildUserAgentDnrRules } from './user-agent';
import {
buildUserAgentDnrRules, resolveUserAgent, userAgentHostname, validateUserAgent,
} from './user-agent';
import { BUILTIN_USER_AGENT_PROFILES } from './user-agent-profiles';
import type { UserAgentAssignment, UserAgentProfile } from '@/types/models';
describe('User-Agent DNR rules', () => {
it('normalizes domains and covers browser request resource types', () => {
const [rule] = buildUserAgentDnrRules([{
id: 'ua-1', name: 'Test', enabled: true, userAgent: 'Yakit-E2E/1.0', domains: ['https://*.example.test/path'],
}]);
expect(rule.condition.urlFilter).toBe('||example.test^');
const assignment: UserAgentAssignment = {
id: 'assignment-1', hostname: 'app.example.test', profileId: 'chrome-windows', createdAt: 1, updatedAt: 2,
};
describe('User-Agent site assignments', () => {
it('compiles one real request-header rule for each hostname', () => {
const [rule] = buildUserAgentDnrRules([assignment]);
expect(rule.condition.urlFilter).toBe('||app.example.test^');
expect(rule.condition.resourceTypes).toContain('websocket');
expect(rule.action).toMatchObject({ requestHeaders: [{ header: 'user-agent', operation: 'set', value: 'Yakit-E2E/1.0' }] });
expect(rule.action).toMatchObject({ requestHeaders: [{ header: 'user-agent', operation: 'set' }] });
});
it('ignores disabled rules', () => {
expect(buildUserAgentDnrRules([{ id: 'x', name: 'X', enabled: false, userAgent: 'x', domains: [] }])).toHaveLength(0);
it('deduplicates a hostname and ignores missing profiles', () => {
const rules = buildUserAgentDnrRules([
assignment,
{ ...assignment, id: 'assignment-2', profileId: 'safari-iphone', updatedAt: 3 },
{ ...assignment, id: 'missing', hostname: 'missing.example.test', profileId: 'missing' },
]);
expect(rules).toHaveLength(1);
expect(rules[0].action).toMatchObject({
requestHeaders: [{ value: BUILTIN_USER_AGENT_PROFILES.find((item) => item.id === 'safari-iphone')!.userAgent }],
});
});
it('resolves the effective profile for the current URL', () => {
expect(resolveUserAgent('https://app.example.test/path', [assignment], [], 'Browser/Default'))
.toMatchObject({ hostname: 'app.example.test', mode: 'override', profile: { id: 'chrome-windows' } });
expect(resolveUserAgent('https://other.example.test/', [assignment], [], 'Browser/Default'))
.toEqual({ hostname: 'other.example.test', mode: 'default', userAgent: 'Browser/Default' });
});
it('supports custom profiles and rejects unsafe header values', () => {
const custom: UserAgentProfile = {
id: 'custom-1', name: 'Custom', userAgent: 'Yakit-Test/1.0', category: 'custom', builtin: false,
};
expect(buildUserAgentDnrRules([{ ...assignment, profileId: custom.id }], [custom])[0].action)
.toMatchObject({ requestHeaders: [{ value: 'Yakit-Test/1.0' }] });
expect(validateUserAgent(' Safe-UA/1.0 ')).toBe('Safe-UA/1.0');
expect(() => validateUserAgent('Injected\r\nX-Test: yes')).toThrow('换行');
});
it('only accepts HTTP(S) targets', () => {
expect(userAgentHostname('http://127.0.0.1:8080/path')).toBe('127.0.0.1');
expect(() => userAgentHostname('chrome://extensions')).toThrow('HTTP');
});
});