diff --git a/package.json b/package.json index b74568e..9141c48 100644 --- a/package.json +++ b/package.json @@ -56,12 +56,14 @@ "@types/serviceworker": "^0.0.120", "@unocss/postcss": "0.65.0-beta.2", "@vitest/coverage-v8": "2.1.4", + "@webext-core/fake-browser": "^1.3.2", "autoprefixer": "^10.4.20", "compression-webpack-plugin": "^11.1.0", "cross-env": "^7.0.3", "eslint": "^9.19.0", "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-hooks": "^5.1.0", + "fake-indexeddb": "^6.0.0", "globals": "^15.14.0", "jsdom": "^25.0.1", "postcss": "^8.4.49", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df6fb12..12dd8dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -123,6 +123,9 @@ importers: '@vitest/coverage-v8': specifier: 2.1.4 version: 2.1.4(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1)(terser@5.36.0)) + '@webext-core/fake-browser': + specifier: ^1.3.2 + version: 1.3.2 autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.49) @@ -141,6 +144,9 @@ importers: eslint-plugin-react-hooks: specifier: ^5.1.0 version: 5.1.0(eslint@9.20.1(jiti@1.21.6)) + fake-indexeddb: + specifier: ^6.0.0 + version: 6.0.0 globals: specifier: ^15.14.0 version: 15.15.0 @@ -923,46 +929,55 @@ packages: resolution: {integrity: sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.24.4': resolution: {integrity: sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.24.4': resolution: {integrity: sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.24.4': resolution: {integrity: sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.24.4': resolution: {integrity: sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.24.4': resolution: {integrity: sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.24.4': resolution: {integrity: sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.24.4': resolution: {integrity: sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.24.4': resolution: {integrity: sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.24.4': resolution: {integrity: sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==} @@ -1027,6 +1042,7 @@ packages: resolution: {integrity: sha512-K2u/fPUmKujlKSWL3q2zaUu8/6ZK/bOGKcqJSib8jdanQQ/GFKwKtPAFOOa/vvqbzhDocqKOobFR10FhgJqCHg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rspack/binding-linux-arm64-musl@1.0.14': resolution: {integrity: sha512-qgybhxI/nnoa8CUz7zKTC0Oh37NZt9uRxsSV7+ZYrfxqbrVCoNVuutPpY724uUHy1M6W34kVEm1uT1N4Ka5cZg==} @@ -1038,6 +1054,7 @@ packages: resolution: {integrity: sha512-mgovdzGb6cH9hQsjTyzDbfZWCPhTcoHcLro1P7UbiqcLPMDJp/k3Io9xV2/EJhaDA1aynIdq7XfY0fuk4+6Irw==} cpu: [arm64] os: [linux] + libc: [musl] '@rspack/binding-linux-x64-gnu@1.0.14': resolution: {integrity: sha512-5vzaDRw3/sGKo3ax/1cU3/cxqNjajwlt2LU288vXNe1/n8oe/pcDfYcTugpOe/A1DqzadanudJszLpFcKsaFtQ==} @@ -1049,6 +1066,7 @@ packages: resolution: {integrity: sha512-542lwJzB1RMGuVdBdA3cOWTlmL9okpOppHUBWcNCjmJM+9zTI+0jwjVe8HaqOqtuR8XzNsoCwT9QonU/GLcuhg==} cpu: [x64] os: [linux] + libc: [glibc] '@rspack/binding-linux-x64-musl@1.0.14': resolution: {integrity: sha512-4U6QD9xVS1eGme52DuJr6Fg/KdcUfJ+iKwH49Up460dZ/fLvGylnVGA+V0mzPlKi8gfy7NwFuYXZdu3Pwi1YYg==} @@ -1060,6 +1078,7 @@ packages: resolution: {integrity: sha512-dJromiREDcTWqzfCOI5y1IVoYmUnCv7vCp63AEq0+13fJJdk7+pcNN3VV2jOKpk9VECSvjg1c01wl+UzXAXFMw==} cpu: [x64] os: [linux] + libc: [musl] '@rspack/binding-win32-arm64-msvc@1.0.14': resolution: {integrity: sha512-SjeYw7qqRHYZ5RPClu+ffKZsShQdU3amA1OwC3M0AS6dbfEcji8482St3Y8Z+QSzYRapCEZij9LMM/9ypEhISg==} @@ -1593,6 +1612,9 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@webext-core/fake-browser@1.3.2': + resolution: {integrity: sha512-jFyPWWz+VkHAC9DRIiIPOyu6X/KlC8dYqSKweHz6tsDb86QawtVgZSpYcM+GOQBlZc5DHFo92jJ7cIq4uBnU0A==} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -2380,6 +2402,10 @@ packages: resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} engines: {node: '>= 0.10.0'} + fake-indexeddb@6.0.0: + resolution: {integrity: sha512-YEboHE5VfopUclOck7LncgIqskAqnv4q0EWbYCaxKKjAvO93c+TJIaBuGy8CBFdbg9nKdpN3AuPRwVBJ4k7NrQ==} + engines: {node: '>=18'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -5920,6 +5946,10 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@webext-core/fake-browser@1.3.2': + dependencies: + lodash.merge: 4.6.2 + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -7004,6 +7034,8 @@ snapshots: transitivePeerDependencies: - supports-color + fake-indexeddb@6.0.0: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.2: diff --git a/src/app/logger/core.ts b/src/app/logger/core.ts index dfd7cac..dde1e40 100644 --- a/src/app/logger/core.ts +++ b/src/app/logger/core.ts @@ -39,7 +39,7 @@ export default class LoggerCore { this.labels = config.labels || {}; // 获取日志debug等级, 如果是开发环境, 则默认为trace if (process.env.NODE_ENV === "development") { - this.debug = "trace"; + this.debug = "debug"; } if (!LoggerCore.instance) { LoggerCore.instance = this; diff --git a/src/app/service/offscreen/gm_api.ts b/src/app/service/offscreen/gm_api.ts index 834d9fd..b37ce80 100644 --- a/src/app/service/offscreen/gm_api.ts +++ b/src/app/service/offscreen/gm_api.ts @@ -13,6 +13,7 @@ export class GMApi { } } xhr.onload = function () { + console.log(xhr.getAllResponseHeaders()); con?.sendMessage({ action: "onload", data: { diff --git a/src/app/service/sandbox/runtime.ts b/src/app/service/sandbox/runtime.ts index 9fb6740..e8b6207 100644 --- a/src/app/service/sandbox/runtime.ts +++ b/src/app/service/sandbox/runtime.ts @@ -83,6 +83,7 @@ export class Runtime { return this.execScript(script); } else { // 定时脚本加入定时任务 + await this.stopCronJob(script.uuid); return this.crontabScript(script); } } diff --git a/src/app/service/service_worker/gm_api.ts b/src/app/service/service_worker/gm_api.ts index fc2ee79..786ca45 100644 --- a/src/app/service/service_worker/gm_api.ts +++ b/src/app/service/service_worker/gm_api.ts @@ -148,10 +148,17 @@ export default class GMApi { } params.headers["X-Scriptcat-GM-XHR-Request-Id"] = requestId.toString(); await this.buildDNRRule(requestId, request.params[0]); + let responseHeader = ""; // 等待response - this.gmXhrHeadersReceived.addListener("headersReceived:" + requestId, (details) => { - console.log("处理", details); - }); + this.gmXhrHeadersReceived.addListener( + "headersReceived:" + requestId, + (details: chrome.webRequest.WebResponseHeadersDetails) => { + details.responseHeaders?.forEach((header) => { + responseHeader += header.name + ": " + header.value + "\n"; + }); + console.log("处理", details, responseHeader); + } + ); // 再发送到offscreen, 处理请求 const offscreenCon = await connect(this.sender, "gmApi/xmlHttpRequest", request.params[0]); offscreenCon.onMessage((msg) => { diff --git a/src/runtime/content/gm_api.ts b/src/runtime/content/gm_api.ts index 11f95a4..bece83b 100644 --- a/src/runtime/content/gm_api.ts +++ b/src/runtime/content/gm_api.ts @@ -219,6 +219,9 @@ export default class GMApi { let connect: MessageConnect; this.connect("GM_xmlhttpRequest", [param]).then((con) => { connect = con; + con.onMessage((data) => { + console.log("data", data); + }); }); return { diff --git a/src/runtime/content/utils.test.ts b/src/runtime/content/utils.test.ts index 3e53a42..4b221de 100644 --- a/src/runtime/content/utils.test.ts +++ b/src/runtime/content/utils.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from "vitest"; import { init, proxyContext, writables } from "./utils"; describe("proxy context", () => { diff --git a/src/runtime/gm_api.test.ts b/src/runtime/gm_api.test.ts new file mode 100644 index 0000000..f856815 --- /dev/null +++ b/src/runtime/gm_api.test.ts @@ -0,0 +1,16 @@ +import { fakeBrowser } from "@webext-core/fake-browser"; +import { it } from "node:test"; +import initTestEnv from "@Tests/utils"; +import { beforeEach, describe, expect } from "vitest"; + +initTestEnv(); + +describe("GM xhr", () => { + beforeEach(() => { + // See https://webext-core.aklinker1.io/fake-browser/reseting-state + fakeBrowser.reset(); + }); + it("1", async () => { + expect(1).toBe(2); + }); +}); diff --git a/tests/__mock__/webextension-polyfill.ts b/tests/__mock__/webextension-polyfill.ts new file mode 100644 index 0000000..afc6d53 --- /dev/null +++ b/tests/__mock__/webextension-polyfill.ts @@ -0,0 +1,2 @@ +// /__mocks__/webextension-polyfill.ts +export { fakeBrowser as default } from "@webext-core/fake-browser"; diff --git a/tests/utils.ts b/tests/utils.ts new file mode 100644 index 0000000..a090b0a --- /dev/null +++ b/tests/utils.ts @@ -0,0 +1,44 @@ +import "fake-indexeddb/auto"; +import LoggerCore from "@App/app/logger/core"; +import DBWriter from "@App/app/logger/db_writer"; +import migrate from "@App/app/migrate"; +import { LoggerDAO } from "@App/app/repo/logger"; + +export default function initTestEnv() { + // @ts-ignore + if (global.initTest) { + return; + } + // @ts-ignore + global.initTest = true; + + const OldBlob = Blob; + // @ts-ignore + global.Blob = function Blob(data, options) { + const blob = new OldBlob(data, options); + blob.text = () => { + return Promise.resolve(data[0]); + }; + blob.arrayBuffer = () => { + return new Promise((resolve) => { + const str = data[0]; + const buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节 + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i += 1) { + bufView[i] = str.charCodeAt(i); + } + resolve(buf); + }); + }; + return blob; + }; + + migrate(); + + const logger = new LoggerCore({ + level: "debug", + writer: new DBWriter(new LoggerDAO()), + labels: { env: "test" }, + }); + logger.logger().debug("test start"); +} diff --git a/tests/vitest.setup.ts b/tests/vitest.setup.ts new file mode 100644 index 0000000..325a079 --- /dev/null +++ b/tests/vitest.setup.ts @@ -0,0 +1,3 @@ +import { vi } from "vitest"; + +vi.mock("webextension-polyfill"); diff --git a/tsconfig.json b/tsconfig.json index cdf0b66..6bd3ee6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,12 +24,16 @@ ], "@Packages/*": [ "packages/*" + ], + "@Tests/*": [ + "tests/*" ] }, }, "include": [ "src", - "packages" + "packages", + "tests" ], "ts-node": { "compilerOptions": { diff --git a/vitest.config.ts b/vitest.config.ts index 6c90798..337ad5b 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,7 +1,16 @@ +import path from "path"; import { defineConfig } from "vitest/config"; export default defineConfig({ + resolve: { + alias: { + "@App": path.resolve(__dirname, "./src"), + "@Packages": path.resolve(__dirname, "./packages"), + "@Tests": path.resolve(__dirname, "./tests"), + }, + }, test: { - // ... + // List setup file + setupFiles: ["./tests/vitest.setup.ts"], }, });