Skip to content
Open
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
13 changes: 12 additions & 1 deletion src/app/service/extension/extension_env.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { extensionEnv, getExtensionUserAgentData } from "./extension_env";
import { extensionEnv, getExtensionEnv, getExtensionUserAgentData } from "./extension_env";

describe("extensionEnv 常量", () => {
it("读取扩展上下文状态与 manifest 的 incognito 模式", () => {
Expand All @@ -10,6 +10,17 @@ describe("extensionEnv 常量", () => {
// userAgentData 为可选字段,常量初始化时不应填充
expect(extensionEnv.userAgentData).toBeUndefined();
});

it("chrome.extension 缺失时仍能初始化环境并默认非隐身", () => {
const originalExtension = (chrome as any).extension;
try {
delete (chrome as any).extension;
expect(() => getExtensionEnv()).not.toThrow();
expect(getExtensionEnv().inIncognitoContext).toBe(false);
} finally {
(chrome as any).extension = originalExtension;
}
});
});

describe("getExtensionUserAgentData", () => {
Expand Down
8 changes: 5 additions & 3 deletions src/app/service/extension/extension_env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ export type TExtensionEnv = {

type GMUserAgentData = typeof GM_info.userAgentData;

export const extensionEnv: TExtensionEnv = {
inIncognitoContext: chrome.extension.inIncognitoContext,
export const getExtensionEnv = (): TExtensionEnv => ({
inIncognitoContext: chrome.extension?.inIncognitoContext ?? false,
incognitoMode: chrome.runtime.getManifest().incognito,
} satisfies TExtensionEnv;
});

export const extensionEnv: TExtensionEnv = getExtensionEnv();

export const getExtensionUserAgentData = async (): Promise<GMUserAgentData | null> => {
// @ts-ignore
Expand Down
62 changes: 61 additions & 1 deletion src/app/service/service_worker/runtime.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { initTestEnv } from "@Tests/utils";
import { RuntimeService } from "./runtime";
import { vi, describe, it, expect, beforeEach, type MockedFunction } from "vitest";
import { vi, describe, it, expect, beforeEach, afterEach, type MockedFunction } from "vitest";
import { randomUUID } from "crypto";
import type { Script, ScriptRunResource } from "@App/app/repo/scripts";
import {
Expand Down Expand Up @@ -1192,3 +1192,63 @@ describe("MQ 事件处理效果(enableScripts / deleteScripts / sortedScripts
expect((runtime as any).cachedPatterns.has(uuid)).toBe(false);
});
});

describe("registerUserscripts 注册健康检查", () => {
let runtime: RuntimeService;
let originalScripting: unknown;

beforeEach(() => {
runtime = _createRuntimeContext().runtime;
originalScripting = (chrome as any).scripting;
(chrome as any).scripting = {
getRegisteredContentScripts: vi.fn().mockResolvedValue([{ id: "scriptcat-scripting" }]),
registerContentScripts: vi.fn().mockResolvedValue(undefined),
unregisterContentScripts: vi.fn().mockResolvedValue(undefined),
};
vi.spyOn(chrome.userScripts as any, "getScripts").mockResolvedValue([{ id: "scriptcat-inject" }]);
vi.spyOn(chrome.userScripts, "register").mockResolvedValue(undefined);
vi.spyOn(chrome.userScripts, "resetWorldConfiguration").mockResolvedValue(undefined);
vi.spyOn(runtime, "unregisterUserscripts").mockResolvedValue(undefined);
vi.spyOn(runtime as any, "getParticularScriptList").mockResolvedValue([]);
vi.spyOn(runtime as any, "getContentAndInjectScript").mockResolvedValue({ content: [], inject: [] });
runtime.isUserScriptsAvailable = true;
});

afterEach(async () => {
vi.restoreAllMocks();
await runtime.unregisterUserscripts();
(chrome as any).scripting = originalScripting;
});

const primeRegisteredState = async () => {
await runtime.registerUserscripts();
vi.clearAllMocks();
};

it("已注册用户脚本但 scripting 广播者丢失时重新注册", async () => {
await primeRegisteredState();
(chrome as any).scripting.getRegisteredContentScripts.mockResolvedValue([]);

await runtime.registerUserscripts();

expect(chrome.userScripts.getScripts).toHaveBeenCalledWith({ ids: ["scriptcat-inject"] });
expect((chrome as any).scripting.getRegisteredContentScripts).toHaveBeenCalledWith({
ids: ["scriptcat-scripting"],
});
expect(runtime.unregisterUserscripts).toHaveBeenCalled();
expect(chrome.userScripts.register).toHaveBeenCalled();
});

it("用户脚本和 scripting 广播者都在时跳过重复注册", async () => {
await primeRegisteredState();

await runtime.registerUserscripts();

expect(chrome.userScripts.getScripts).toHaveBeenCalledWith({ ids: ["scriptcat-inject"] });
expect((chrome as any).scripting.getRegisteredContentScripts).toHaveBeenCalledWith({
ids: ["scriptcat-scripting"],
});
expect(runtime.unregisterUserscripts).not.toHaveBeenCalled();
expect(chrome.userScripts.register).not.toHaveBeenCalled();
});
});
3 changes: 2 additions & 1 deletion src/app/service/service_worker/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,8 @@ export class RuntimeService {
// 异常情况
// 检查scriptcat-content和scriptcat-inject是否存在
const res = await chrome.userScripts.getScripts({ ids: ["scriptcat-inject"] });
if (res.length === 1) {
const contentScripts = await chrome.scripting.getRegisteredContentScripts({ ids: ["scriptcat-scripting"] });
if (res.length === 1 && contentScripts.length === 1) {
return;
}
// scriptcat-content/scriptcat-inject不存在的情况
Expand Down
Loading