scriptcat-mv3/tests/runtime/gm_api.test.ts
王一之 131f1bda40
Some checks failed
test / Run tests (push) Failing after 15s
build / Build (push) Failing after 22s
单测
2025-03-20 23:34:38 +08:00

204 lines
5.9 KiB
TypeScript

import { Script, ScriptDAO } from "@App/app/repo/scripts";
import GMApi from "@App/runtime/content/gm_api";
import chromeMock from "@Packages/chrome-extension-mock";
import { initTestEnv, initTestGMApi } from "@Tests/utils";
import { randomUUID } from "crypto";
import { newMockXhr } from "mock-xmlhttprequest";
import { beforeAll, describe, expect, it } from "vitest";
initTestEnv();
const msg = initTestGMApi();
const script: Script = {
uuid: randomUUID(),
name: "test",
metadata: {
grant: [
// gm xhr
"GM_xmlhttpRequest",
],
connect: ["example.com"],
},
namespace: "",
type: 1,
status: 1,
sort: 0,
runStatus: "running",
createtime: 0,
checktime: 0,
};
beforeAll(async () => {
await new ScriptDAO().save(script);
});
describe("GM xmlHttpRequest", () => {
const gmApi = new GMApi(msg);
//@ts-ignore
gmApi.scriptRes = {
uuid: script.uuid,
};
const mockXhr = newMockXhr();
mockXhr.onSend = async (request) => {
switch (request.url) {
case "https://www.example.com/":
return request.respond(200, {}, "example");
case window.location.href:
return request.respond(200, {}, "location");
case "https://example.com/json":
return request.respond(200, { "Content-Type": "application/json" }, JSON.stringify({ test: 1 }));
case "https://www.example.com/header":
if (request.requestHeaders.getHeader("x-nonce") !== "123456") {
return request.respond(403, {}, "bad");
}
return request.respond(200, {}, "header");
case "https://www.example.com/unsafeHeader":
if (
request.requestHeaders.getHeader("Origin") !== "https://example.com" ||
request.requestHeaders.getHeader("Cookie") !== "website=example.com"
) {
return request.respond(400, {}, "bad request");
}
return request.respond(200, { "Set-Cookie": "test=1" }, "unsafeHeader");
case "https://www.wexample.com/unsafeHeader/cookie":
if (request.requestHeaders.getHeader("Cookie") !== "test=1") {
return request.respond(400, {}, "bad request");
}
return request.respond(200, {}, "unsafeHeader/cookie");
}
if (request.method === "POST") {
switch (request.url) {
case "https://example.com/form":
if (request.body.get("blob")) {
return request.respond(
200,
{ "Content-Type": "text/html" },
// mock 一个blob对象
{
text: () => Promise.resolve("form"),
}
);
}
return request.respond(400, {}, "bad");
}
}
return request.respond(200, {}, "test");
};
global.XMLHttpRequest = mockXhr;
it("get", () => {
return new Promise<void>((resolve) => {
gmApi.GM_xmlhttpRequest({
url: "https://www.example.com",
onreadystatechange: (resp) => {
if (resp.readyState === 4 && resp.status === 200) {
expect(resp.responseText).toBe("example");
resolve();
}
},
});
});
});
it("post数据和blob", () => {
const form = new FormData();
form.append("blob", new Blob(["blob"], { type: "text/html" }));
return new Promise<void>((resolve) => {
gmApi.GM_xmlhttpRequest({
url: "https://example.com/form",
method: "POST",
data: form,
responseType: "blob",
onreadystatechange: async (resp) => {
if (resp.readyState === 4 && resp.status === 200) {
expect(resp.responseText).toBe("form");
expect(await (<Blob>resp.response).text()).toBe("form");
resolve();
}
},
});
});
});
// xml原版是没有responseText的,但是tampermonkey有,恶心的兼容性
it("json", async () => {
await new Promise<void>((resolve) => {
gmApi.GM_xmlhttpRequest({
url: "https://example.com/json",
method: "GET",
responseType: "json",
onload: (resp) => {
// @ts-ignore
expect(resp.response.test).toBe(1);
expect(resp.responseText).toBe('{"test":1}');
resolve();
},
});
});
// bad json
await new Promise<void>((resolve) => {
gmApi.GM_xmlhttpRequest({
url: "https://www.example.com/",
method: "GET",
responseType: "json",
onload: (resp) => {
expect(resp.response).toBeUndefined();
expect(resp.responseText).toBe("example");
resolve();
},
});
});
});
it("header", async () => {
await new Promise<void>((resolve) => {
gmApi.GM_xmlhttpRequest({
url: "https://www.example.com/header",
method: "GET",
headers: {
"x-nonce": "123456",
},
onload: (resp) => {
expect(resp.responseText).toBe("header");
resolve();
},
});
});
});
it("unsafeHeader", async () => {
global.XMLHttpRequest = chromeMock.webRequest.mockXhr(mockXhr);
// 模拟header
await new Promise<void>((resolve) => {
gmApi.GM_xmlhttpRequest({
url: "https://www.example.com/unsafeHeader",
method: "GET",
headers: {
Origin: "https://example.com",
},
onload: (resp) => {
expect(resp.responseText).toBe("unsafeHeader");
expect(resp.responseHeaders?.indexOf("set-cookie")).not.toBe(-1);
resolve();
},
});
});
});
it("unsafeHeader/cookie", async () => {
// global.XMLHttpRequest = chromeMock.webRequest.mockXhr(mockXhr);
// 模拟header
await new Promise<void>((resolve) => {
gmApi.GM_xmlhttpRequest({
url: "https://www.wexample.com/unsafeHeader/cookie",
method: "GET",
headers: {
Cookie: "test=1",
},
anonymous: true,
onload: (resp) => {
expect(resp.responseText).toBe("unsafeHeader/cookie");
resolve();
},
});
});
});
});