cloud-drive-renamer/tests/unit/platform-detection.test.ts
Zain 1176d08224 feat(onedrive): 新增 OneDrive 个人版支持,更新第 13 个平台文案与键盘隔离
新增 OneDrive 个人版适配器、MAIN 桥接、名称校验与冲突检测、目录身份与分页遍历。同步更新三语简介、商店素材、仓库描述及
manifest 域名注册。修复面板键盘冒泡至宿主页面的隔离与工具栏 Escape 作用域。修正 OneDrive 同步结果语义为手动刷新提示,
避免误报同步失败。补全对应单测与浏览器验收脚本。
2026-09-27 17:31:44 +08:00

444 行
14 KiB
TypeScript

/**
* 平台检测单元测试
* 验证统一的平台检测工具函数正确识别个人网盘和分享链接
*/
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { detectPlatformFromUrl, isQuarkShareLink, QUARK_SHARE_LINK_PATTERNS } from '../../src/utils/platform-detector';
import { detectPlatform } from '../../src/content/index';
import { logger } from '../../src/utils/logger';
// Mock logger 模块
vi.mock('../../src/utils/logger', async (importOriginal) => {
const actual = await importOriginal<typeof import('../../src/utils/logger')>();
return {
...actual,
logger: {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
},
};
});
describe('Platform Detection - Unified Utils', () => {
beforeEach(() => {
// 重置所有 mock
vi.clearAllMocks();
});
describe('isQuarkShareLink() - Share Link Pattern Detection', () => {
it('should detect basic share link pattern', () => {
expect(isQuarkShareLink('/s/abc123xyz')).toBe(true);
});
it('should detect share link with trailing slash', () => {
expect(isQuarkShareLink('/s/abc123xyz/')).toBe(true);
});
it('should detect share link with nested path', () => {
expect(isQuarkShareLink('/s/share/folder')).toBe(true);
});
it('should return false for personal storage path', () => {
expect(isQuarkShareLink('/list')).toBe(false);
expect(isQuarkShareLink('/list/all')).toBe(false);
expect(isQuarkShareLink('/settings')).toBe(false);
});
it('should handle null pathname defensively', () => {
expect(isQuarkShareLink(null)).toBe(false);
});
it('should handle undefined pathname defensively', () => {
expect(isQuarkShareLink(undefined)).toBe(false);
});
it('should handle empty string', () => {
expect(isQuarkShareLink('')).toBe(false);
});
it('should use configurable patterns from constant', () => {
// 验证函数使用了导出的常量
expect(QUARK_SHARE_LINK_PATTERNS).toContain('/s/');
});
});
describe('detectPlatformFromUrl() - Unified Detection Logic', () => {
describe('Quark Drive - Personal Storage', () => {
it('should detect personal file list page', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/list#/list/all',
'/list'
);
expect(result).toBe('quark');
});
it('should detect personal folder page', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/list#/list/folder/12345',
'/list'
);
expect(result).toBe('quark');
});
it('should detect personal recent files page', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/list#/recent',
'/list'
);
expect(result).toBe('quark');
});
it('should detect settings page', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/settings',
'/settings'
);
expect(result).toBe('quark');
});
});
describe('Quark Drive - Share Links (Should Return null)', () => {
it('should return null for basic share link', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/s/abc123xyz',
'/s/abc123xyz'
);
expect(result).toBeNull();
});
it('should return null for share link with password', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/s/abc123xyz?pwd=1234',
'/s/abc123xyz'
);
expect(result).toBeNull();
});
it('should return null for share link with hash fragment', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/s/xyz789#/folder',
'/s/xyz789'
);
expect(result).toBeNull();
});
it('should return null for share link with query parameters', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/s/shared123?from=mobile&source=qr',
'/s/shared123'
);
expect(result).toBeNull();
});
it('should handle pathname with trailing slash', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/s/test123/',
'/s/test123/'
);
expect(result).toBeNull();
});
it('should handle nested share path', () => {
const result = detectPlatformFromUrl(
'https://pan.quark.cn/s/share/folder',
'/s/share/folder'
);
expect(result).toBeNull();
});
});
describe('Auto pathname extraction (when pathname not provided)', () => {
it('should extract pathname from URL for personal storage', () => {
const result = detectPlatformFromUrl('https://pan.quark.cn/list#/list/all');
expect(result).toBe('quark');
});
it('should extract pathname from URL for share link', () => {
const result = detectPlatformFromUrl('https://pan.quark.cn/s/abc123xyz');
expect(result).toBeNull();
});
});
describe('Other Platforms - Unchanged Behavior', () => {
it('should detect UC Drive from drive.uc.cn', () => {
const result = detectPlatformFromUrl(
'https://drive.uc.cn/#/list/all',
'/'
);
expect(result).toBe('uc');
});
it('should detect UC Drive from pan.uc.cn', () => {
const result = detectPlatformFromUrl(
'https://pan.uc.cn/#/list/all/abc123-folder',
'/'
);
expect(result).toBe('uc');
});
it('should detect 115 Drive on supported netdisk page', () => {
const result = detectPlatformFromUrl(
'https://115.com/storage/netdisk?mode=wangpan&cid=folder115',
'/storage/netdisk'
);
expect(result).toBe('115');
});
it('should detect 115 Drive entry pages so the floating button can initialize before SPA navigation', () => {
const result = detectPlatformFromUrl(
'https://115.com/',
'/'
);
expect(result).toBe('115');
});
it('should ignore unsupported 115 pages', () => {
const result = detectPlatformFromUrl(
'https://115.com/account/settings',
'/account/settings'
);
expect(result).toBeNull();
});
it('should detect 123 Drive on yun.123pan.cn file pages', () => {
const result = detectPlatformFromUrl(
'https://yun.123pan.cn/?remember=yes&homeFilePath=31611662',
'/'
);
expect(result).toBe('123');
});
it('should ignore 123Pan product homepage', () => {
const result = detectPlatformFromUrl(
'https://www.123pan.com/',
'/'
);
expect(result).toBeNull();
});
it('should detect CMCC Drive', () => {
const result = detectPlatformFromUrl(
'https://yun.139.com/w/#/main',
'/w/'
);
expect(result).toBe('cmcc');
});
it('should detect CMCC Drive on the SPA index route', () => {
const result = detectPlatformFromUrl(
'https://yun.139.com/w/#/index',
'/w/'
);
expect(result).toBe('cmcc');
});
it('should detect CMCC Drive on the app entry before hash routing is ready', () => {
const result = detectPlatformFromUrl(
'https://yun.139.com/w/',
'/w/'
);
expect(result).toBe('cmcc');
});
it('should detect Woozooo Drive on the top-level file manager page', () => {
const result = detectPlatformFromUrl(
'https://pc.woozooo.com/mydisk.php',
'/mydisk.php'
);
expect(result).toBe('woozooo');
});
it('should detect Woozooo Drive on the same-origin file iframe page', () => {
const result = detectPlatformFromUrl(
'https://pc.woozooo.com/mydisk.php?item=files&action=index&u=484561',
'/mydisk.php'
);
expect(result).toBe('woozooo');
});
it('should detect Xunlei Drive', () => {
const result = detectPlatformFromUrl(
'https://pan.xunlei.com/',
'/'
);
expect(result).toBe('xunlei');
});
it('should detect Esurfing Drive entry page before navigating into file lists', () => {
const result = detectPlatformFromUrl(
'https://cloud.189.cn/web/main/',
'/web/main/'
);
expect(result).toBe('esurfing');
});
it('should detect Esurfing Drive', () => {
const result = detectPlatformFromUrl(
'https://cloud.189.cn/web/main/file/folder/folder189',
'/web/main/file/folder/folder189'
);
expect(result).toBe('esurfing');
});
it('should detect Aliyun Drive', () => {
const result = detectPlatformFromUrl(
'https://www.aliyundrive.com/drive/file/all',
'/drive/file/all'
);
expect(result).toBe('aliyun');
});
it('should detect Baidu Drive', () => {
const result = detectPlatformFromUrl(
'https://pan.baidu.com/disk/home',
'/disk/home'
);
expect(result).toBe('baidu');
});
it('should detect GuangyaPan on the hash-routed SPA home page', () => {
const result = detectPlatformFromUrl(
'https://www.guangyapan.com/#/home/all',
'/'
);
expect(result).toBe('guangyapan');
});
it('should detect GuangyaPan on the root entry before hash routing initializes', () => {
const result = detectPlatformFromUrl(
'https://www.guangyapan.com/',
'/'
);
expect(result).toBe('guangyapan');
});
it('should not detect GuangyaPan on the API domain', () => {
const result = detectPlatformFromUrl(
'https://api.guangyapan.com/userres/v1/file/get_file_list',
'/userres/v1/file/get_file_list'
);
expect(result).toBeNull();
});
it('should not detect GuangyaPan on the auth domain', () => {
const result = detectPlatformFromUrl(
'https://account.guangyapan.com/',
'/'
);
expect(result).toBeNull();
});
it('should detect WKBrowser cloud drive on pan.wkbrowser.com', () => {
const result = detectPlatformFromUrl(
'https://pan.wkbrowser.com/main?category=all',
'/main'
);
expect(result).toBe('wkbrowser');
});
it('should detect WKBrowser on root login entry', () => {
const result = detectPlatformFromUrl(
'https://pan.wkbrowser.com/',
'/'
);
expect(result).toBe('wkbrowser');
});
it('should not detect WKBrowser on the API domain', () => {
const result = detectPlatformFromUrl(
'https://api.wkbrowser.com/netdisk/user_file/filter_file',
'/netdisk/user_file/filter_file'
);
expect(result).toBeNull();
});
it('detects OneDrive Personal only on the supported My files route and exact host', () => {
expect(detectPlatformFromUrl('https://onedrive.live.com/my?viewid=abc', '/my')).toBe('onedrive');
expect(detectPlatformFromUrl('https://onedrive.live.com/my/', '/my/')).toBe('onedrive');
expect(detectPlatformFromUrl('https://onedrive.live.com/photos', '/photos')).toBeNull();
expect(detectPlatformFromUrl('https://login.onedrive.live.com/my', '/my')).toBeNull();
expect(detectPlatformFromUrl('http://onedrive.live.com/my', '/my')).toBeNull();
});
it('should return null for unsupported platform', () => {
const result = detectPlatformFromUrl(
'https://example.com/',
'/'
);
expect(result).toBeNull();
});
});
describe('Edge Cases - Robustness', () => {
it('should handle malformed URL gracefully', () => {
const result = detectPlatformFromUrl('not-a-valid-url');
expect(result).toBeNull();
});
it('should handle empty pathname', () => {
const result = detectPlatformFromUrl('https://pan.quark.cn/', '');
expect(result).toBe('quark');
});
});
});
describe('detectPlatform() - Content Script Integration', () => {
beforeEach(() => {
// 重置 window.location mock
delete (window as any).location;
});
it('should detect personal storage and not log warning', () => {
Object.defineProperty(window, 'location', {
value: {
href: 'https://pan.quark.cn/list#/list/all',
pathname: '/list'
},
writable: true,
configurable: true
});
const result = detectPlatform();
expect(result).toBe('quark');
expect(logger.warn).not.toHaveBeenCalled();
});
it('should detect share link and log warning', () => {
Object.defineProperty(window, 'location', {
value: {
href: 'https://pan.quark.cn/s/abc123xyz',
pathname: '/s/abc123xyz'
},
writable: true,
configurable: true
});
const result = detectPlatform();
expect(result).toBeNull();
expect(logger.warn).toHaveBeenCalledWith(
'Quark share link detected, extension disabled for share pages'
);
});
it('should return null for unsupported platform without warning', () => {
Object.defineProperty(window, 'location', {
value: {
href: 'https://example.com/',
pathname: '/'
},
writable: true,
configurable: true
});
const result = detectPlatform();
expect(result).toBeNull();
expect(logger.warn).not.toHaveBeenCalled();
});
});
});