Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions e2e/keep-alive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@ const HEARTBEAT_VALIDATION_WINDOW_MS = 31_000;

const openRuntimeSettings = async (context: Parameters<typeof openOptionsPage>[0], extensionId: string) => {
const page = await openOptionsPage(context, extensionId);
await page
.getByTestId("view-toggle")
.or(page.getByTestId("mobile-search"))
.first()
.waitFor({ state: "visible", timeout: 30_000 });
await page.goto(`chrome-extension://${extensionId}/src/options.html#/settings`);
await expect(page.getByTestId("setting-page")).toBeVisible({ timeout: 20_000 });
return page;
try {
await page
.getByTestId("view-toggle")
.or(page.getByTestId("mobile-search"))
.first()
.waitFor({ state: "visible", timeout: 30_000 });
await page.goto(`chrome-extension://${extensionId}/src/options.html#/settings`);
await expect(page.getByTestId("setting-page")).toBeVisible({ timeout: 20_000 });
return page;
} catch (error) {
if (!page.isClosed()) await page.close();
throw error;
}
};

type CdpTargetMessage = {
Expand Down
6 changes: 6 additions & 0 deletions src/pages/components/use-is-mobile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ function stubMatchMedia(initialMatches: boolean, matchesOnSubscribe?: boolean) {
}

describe("useIsMobile 视口断点", () => {
it("视口 < 768px 时返回 true", () => {
stubMatchMedia(true);
const { result } = renderHook(() => useIsMobile());
expect(result.current).toBe(true);
});

it("监听 change 事件,视口变化时更新返回值", () => {
const mql = stubMatchMedia(false);
const { result } = renderHook(() => useIsMobile());
Expand Down
24 changes: 22 additions & 2 deletions src/pages/install/useInstallData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ describe("assembleInstallView 组装安装视图", () => {

describe("useInstallData 数据流编排", () => {
afterEach(() => {
vi.restoreAllMocks();
vi.clearAllMocks();
window.history.replaceState({}, "", "/install.html");
});
Expand Down Expand Up @@ -249,7 +250,7 @@ describe("useInstallData 数据流编排", () => {
expect(state.view.oldCode).toBe("// old code");
});

describe("安装成功后离开安装页:独立新标签应关闭,网页链接接管的原标签应返回上一页", () => {
describe("安装成功后离开安装页:独立新标签应关闭,同标签内被重定向而来应返回上一页", () => {
const setupReady = async (paramOptions: Record<string, unknown> = {}) => {
window.history.replaceState({}, "", "/install.html?uuid=u1");
const metadata = { name: ["示例脚本"], version: ["1.0.0"], match: ["https://e.com/*"] };
Expand Down Expand Up @@ -294,13 +295,32 @@ describe("useInstallData 数据流编排", () => {

await act(async () => {
await result.current.install();
// leaveInstallPage 延后到 install() 里 300ms 的 setTimeout 再叠一帧 rAF 才真正执行,多等一点确保已触发
await new Promise((r) => setTimeout(r, 320));
});

expect(backSpy).toHaveBeenCalledOnce();
expect(closeSpy).not.toHaveBeenCalled();
});

it("byWebRequest 的直接 URL 入口应把来源标记传给脚本匹配", async () => {
window.history.replaceState({}, "", "/install.html?byWebRequest=1&url=https://e.com/x.user.js");
const metadata = { name: ["示例脚本"], version: ["1.0.0"], match: ["https://e.com/*"] };
(fetchScriptBody as Mock).mockResolvedValue("// code");
(parseMetadata as Mock).mockReturnValue(metadata);
(prepareScriptByCode as Mock).mockResolvedValue({ script: makeAction(metadata) });

const { result } = renderHook(() => useInstallData());
await waitFor(() => expect(result.current.state.status).toBe("ready"));

expect(prepareScriptByCode).toHaveBeenCalledWith(
"// code",
"https://e.com/x.user.js",
undefined,
false,
undefined,
{ byWebRequest: true }
);
});
});

it("?skill= 时读取技能数据进入 skill 状态", async () => {
Expand Down
4 changes: 3 additions & 1 deletion src/pages/install/useInstallData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,9 @@ export function useInstallData(): UseInstallData {
});
const metadata = parseMetadata(code);
if (!metadata) throw new Error(t("install:script_info_load_failed"));
await loadFromInfo(buildScriptInfo(uuidv4(), code, parsed.href, metadata), false, {});
await loadFromInfo(buildScriptInfo(uuidv4(), code, parsed.href, metadata), false, {
byWebRequest: byWebRequestRef.current,
});
} else if (fid) {
const handle = await loadHandle(fid);
if (!handle) throw new Error(t("install:script_info_load_failed"));
Expand Down
23 changes: 23 additions & 0 deletions src/pkg/utils/skill-zip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,27 @@ description: 淘宝购物助手
expect(toolMeta!.params[0].name).toBe("pageType");
expect(toolMeta!.params[1].name).toBe("tabId");
});

it("嵌套目录 ZIP 的完整流程:解析 → 验证 SKILL.md → 验证 SkillScript", async () => {
const zipData = await createTestZip({
"taobao-skill/SKILL.md": `---\nname: nested-skill\ndescription: 嵌套目录测试\n---\n嵌套 Skill 提示词。`,
"taobao-skill/scripts/extract.js": VALID_SKILLSCRIPT_CODE,
"taobao-skill/references/guide.txt": "使用指南内容",
});

const zipResult = await parseSkillZip(zipData);

const parsed = parseSkillMd(zipResult.skillMd);
expect(parsed).not.toBeNull();
expect(parsed!.metadata.name).toBe("nested-skill");

expect(zipResult.scripts).toHaveLength(1);
const toolMeta = parseSkillScriptMetadata(zipResult.scripts[0].code);
expect(toolMeta).not.toBeNull();
expect(toolMeta!.name).toBe("taobao_extract");

expect(zipResult.references).toHaveLength(1);
expect(zipResult.references[0].name).toBe("guide.txt");
expect(zipResult.references[0].content).toBe("使用指南内容");
});
});
Loading