test
Some checks failed
test / Run tests (push) Failing after 6s
build / Build (push) Failing after 9s
Some checks failed
test / Run tests (push) Failing after 6s
build / Build (push) Failing after 9s
This commit is contained in:
parent
c2219db73e
commit
fd2aba4286
@ -56,7 +56,6 @@
|
|||||||
"@types/serviceworker": "^0.0.120",
|
"@types/serviceworker": "^0.0.120",
|
||||||
"@unocss/postcss": "0.65.0-beta.2",
|
"@unocss/postcss": "0.65.0-beta.2",
|
||||||
"@vitest/coverage-v8": "2.1.4",
|
"@vitest/coverage-v8": "2.1.4",
|
||||||
"@webext-core/fake-browser": "^1.3.2",
|
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"compression-webpack-plugin": "^11.1.0",
|
"compression-webpack-plugin": "^11.1.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
@ -66,6 +65,7 @@
|
|||||||
"fake-indexeddb": "^6.0.0",
|
"fake-indexeddb": "^6.0.0",
|
||||||
"globals": "^15.14.0",
|
"globals": "^15.14.0",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^25.0.1",
|
||||||
|
"mock-xmlhttprequest": "^8.4.1",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.4.49",
|
||||||
"postcss-loader": "^8.1.1",
|
"postcss-loader": "^8.1.1",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
|
3
packages/chrome-extension-mock/README.md
Normal file
3
packages/chrome-extension-mock/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# mock一个chrome扩展环境
|
||||||
|
> 只针对自己的项目做了一些简单的封装,如果有需要可以自己修改
|
||||||
|
|
32
packages/chrome-extension-mock/cookies.ts
Normal file
32
packages/chrome-extension-mock/cookies.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
export default class Cookies {
|
||||||
|
getAllCookieStores(
|
||||||
|
callback: (cookieStores: chrome.cookies.CookieStore[]) => void
|
||||||
|
) {
|
||||||
|
callback([
|
||||||
|
{
|
||||||
|
id: "0",
|
||||||
|
tabIds: [1],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mockGetAll?: (
|
||||||
|
details: chrome.cookies.GetAllDetails,
|
||||||
|
callback: (cookies: chrome.cookies.Cookie[]) => void
|
||||||
|
) => void | undefined;
|
||||||
|
|
||||||
|
getAll(
|
||||||
|
details: chrome.cookies.GetAllDetails,
|
||||||
|
callback: (cookies: chrome.cookies.Cookie[]) => void
|
||||||
|
): void {
|
||||||
|
this.mockGetAll?.(details, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
set(details: chrome.cookies.SetDetails, callback?: () => void): void {
|
||||||
|
callback?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(details: chrome.cookies.Details, callback?: () => void): void {
|
||||||
|
callback?.();
|
||||||
|
}
|
||||||
|
}
|
38
packages/chrome-extension-mock/declarativ_net_request.ts
Normal file
38
packages/chrome-extension-mock/declarativ_net_request.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export default class DeclarativeNetRequest {
|
||||||
|
HeaderOperation = {
|
||||||
|
APPEND: "append",
|
||||||
|
SET: "set",
|
||||||
|
REMOVE: "remove",
|
||||||
|
};
|
||||||
|
|
||||||
|
RuleActionType = {
|
||||||
|
BLOCK: "block",
|
||||||
|
REDIRECT: "redirect",
|
||||||
|
ALLOW: "allow",
|
||||||
|
UPGRADE_SCHEME: "upgradeScheme",
|
||||||
|
MODIFY_HEADERS: "modifyHeaders",
|
||||||
|
ALLOW_ALL_REQUESTS: "allowAllRequests",
|
||||||
|
};
|
||||||
|
|
||||||
|
ResourceType = {
|
||||||
|
MAIN_FRAME: "main_frame",
|
||||||
|
SUB_FRAME: "sub_frame",
|
||||||
|
STYLESHEET: "stylesheet",
|
||||||
|
SCRIPT: "script",
|
||||||
|
IMAGE: "image",
|
||||||
|
FONT: "font",
|
||||||
|
OBJECT: "object",
|
||||||
|
XMLHTTPREQUEST: "xmlhttprequest",
|
||||||
|
PING: "ping",
|
||||||
|
CSP_REPORT: "csp_report",
|
||||||
|
MEDIA: "media",
|
||||||
|
WEBSOCKET: "websocket",
|
||||||
|
OTHER: "other",
|
||||||
|
};
|
||||||
|
|
||||||
|
updateSessionRules() {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
5
packages/chrome-extension-mock/downloads.ts
Normal file
5
packages/chrome-extension-mock/downloads.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export default class Downloads {
|
||||||
|
download(_: any, callback: Function) {
|
||||||
|
callback && callback();
|
||||||
|
}
|
||||||
|
}
|
9
packages/chrome-extension-mock/i18n.ts
Normal file
9
packages/chrome-extension-mock/i18n.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default class I18n {
|
||||||
|
getUILanguage() {
|
||||||
|
return "zh-CN";
|
||||||
|
}
|
||||||
|
|
||||||
|
getAcceptLanguages(callback: (lngs: string[]) => void) {
|
||||||
|
callback(["zh-CN"]);
|
||||||
|
}
|
||||||
|
}
|
26
packages/chrome-extension-mock/index.ts
Normal file
26
packages/chrome-extension-mock/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Cookies from "./cookies";
|
||||||
|
import Downloads from "./downloads";
|
||||||
|
import Notifications from "./notifications";
|
||||||
|
import Runtime from "./runtime";
|
||||||
|
import MockTab from "./tab";
|
||||||
|
import WebRequest from "./web_reqeuest";
|
||||||
|
import Storage from "./storage";
|
||||||
|
import I18n from "./i18n";
|
||||||
|
import DeclarativeNetRequest from "./declarativ_net_request";
|
||||||
|
|
||||||
|
const chromeMock = {
|
||||||
|
tabs: new MockTab(),
|
||||||
|
runtime: new Runtime(),
|
||||||
|
webRequest: new WebRequest(),
|
||||||
|
notifications: new Notifications(),
|
||||||
|
downloads: new Downloads(),
|
||||||
|
cookies: new Cookies(),
|
||||||
|
storage: new Storage(),
|
||||||
|
i18n: new I18n(),
|
||||||
|
declarativeNetRequest: new DeclarativeNetRequest(),
|
||||||
|
init() {},
|
||||||
|
};
|
||||||
|
// @ts-ignore
|
||||||
|
global.chrome = chromeMock;
|
||||||
|
|
||||||
|
export default chromeMock;
|
64
packages/chrome-extension-mock/notifications.ts
Normal file
64
packages/chrome-extension-mock/notifications.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
export default class Notifications {
|
||||||
|
notification: Map<string, boolean> = new Map();
|
||||||
|
|
||||||
|
onClosedHandler?: (id: string, byUser: boolean) => void;
|
||||||
|
|
||||||
|
onClosed = {
|
||||||
|
addListener: (
|
||||||
|
callback: (notificationId: string, byUser: boolean) => void
|
||||||
|
) => {
|
||||||
|
this.onClosedHandler = callback;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
onButtonClickedHandler?: (id: string, index: number) => void;
|
||||||
|
|
||||||
|
onButtonClicked = {
|
||||||
|
addListener: (
|
||||||
|
callback: (notificationId: string, buttonIndex: number) => void
|
||||||
|
) => {
|
||||||
|
this.onButtonClickedHandler = callback;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mockClickButton(id: string, index: number) {
|
||||||
|
this.onButtonClickedHandler?.(id, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickedHandler?: (id: string) => void;
|
||||||
|
|
||||||
|
onClicked = {
|
||||||
|
addListener: (callback: (notificationId: string) => void) => {
|
||||||
|
this.onClickedHandler = callback;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
create(
|
||||||
|
options: chrome.notifications.NotificationOptions,
|
||||||
|
callback?: (id: string) => void
|
||||||
|
) {
|
||||||
|
const id = Math.random().toString();
|
||||||
|
this.notification.set(id, true);
|
||||||
|
if (callback) {
|
||||||
|
callback(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(id: string) {
|
||||||
|
if (!this.notification.has(id)) {
|
||||||
|
throw new Error("notification not found");
|
||||||
|
}
|
||||||
|
this.notification.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(id: string) {
|
||||||
|
if (!this.notification.has(id)) {
|
||||||
|
throw new Error("notification not found");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mockClick(id: string) {
|
||||||
|
this.onClickedHandler?.(id);
|
||||||
|
}
|
||||||
|
}
|
62
packages/chrome-extension-mock/runtime.ts
Normal file
62
packages/chrome-extension-mock/runtime.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
type Port = chrome.runtime.Port & {
|
||||||
|
setTargetPort: (port: chrome.runtime.Port) => void;
|
||||||
|
messageListener: Array<(message: any) => void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Runtime {
|
||||||
|
connectListener: Array<(port: chrome.runtime.Port) => void> = [];
|
||||||
|
|
||||||
|
onConnect = {
|
||||||
|
addListener: (callback: (port: chrome.runtime.Port) => void) => {
|
||||||
|
this.connectListener.push(callback);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Port(connectInfo?: chrome.runtime.ConnectInfo) {
|
||||||
|
const messageListener: Array<(message: any) => void> = [];
|
||||||
|
let targetPort: Port;
|
||||||
|
return {
|
||||||
|
setTargetPort(port: Port) {
|
||||||
|
targetPort = port;
|
||||||
|
},
|
||||||
|
messageListener,
|
||||||
|
name: connectInfo?.name || "",
|
||||||
|
sender: {
|
||||||
|
tab: {
|
||||||
|
id: 1,
|
||||||
|
} as unknown as chrome.tabs.Tab,
|
||||||
|
url: window.location.href,
|
||||||
|
},
|
||||||
|
postMessage(message: any) {
|
||||||
|
messageListener.forEach((callback) => {
|
||||||
|
callback(message);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onMessage: {
|
||||||
|
addListener(callback: (message: any) => void) {
|
||||||
|
targetPort.messageListener.push(callback);
|
||||||
|
},
|
||||||
|
} as unknown as chrome.events.Event<(message: any) => void>,
|
||||||
|
onDisconnect: {
|
||||||
|
addListener() {
|
||||||
|
// do nothing
|
||||||
|
},
|
||||||
|
} as unknown as chrome.events.Event<() => void>,
|
||||||
|
} as unknown as Port;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(connectInfo?: chrome.runtime.ConnectInfo) {
|
||||||
|
const port = this.Port(connectInfo);
|
||||||
|
const targetPort = this.Port(connectInfo);
|
||||||
|
targetPort.setTargetPort(port);
|
||||||
|
port.setTargetPort(targetPort);
|
||||||
|
this.connectListener.forEach((callback) => {
|
||||||
|
callback(targetPort);
|
||||||
|
});
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
getURL(path: string) {
|
||||||
|
return `${window.location.href}${path}`;
|
||||||
|
}
|
||||||
|
}
|
33
packages/chrome-extension-mock/storage.ts
Normal file
33
packages/chrome-extension-mock/storage.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
export default class Storage {
|
||||||
|
sync = new CrhomeStorage();
|
||||||
|
local = new CrhomeStorage();
|
||||||
|
session = new CrhomeStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CrhomeStorage {
|
||||||
|
data: any = {};
|
||||||
|
|
||||||
|
get(key: string, callback: (data: any) => void) {
|
||||||
|
if (key === null) {
|
||||||
|
callback(this.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback({ [key]: this.data[key] });
|
||||||
|
}
|
||||||
|
|
||||||
|
set(data: any, callback: () => void) {
|
||||||
|
this.data = Object.assign(this.data, data);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(keys: string | string[], callback: () => void) {
|
||||||
|
if (typeof keys === "string") {
|
||||||
|
delete this.data[keys];
|
||||||
|
} else {
|
||||||
|
keys.forEach((key) => {
|
||||||
|
delete this.data[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
28
packages/chrome-extension-mock/tab.ts
Normal file
28
packages/chrome-extension-mock/tab.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import EventEmitter from "eventemitter3";
|
||||||
|
|
||||||
|
export default class MockTab {
|
||||||
|
hook = new EventEmitter();
|
||||||
|
|
||||||
|
query() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
resolve([]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
create(createProperties: chrome.tabs.CreateProperties, callback?: (tab: chrome.tabs.Tab) => void) {
|
||||||
|
this.hook.emit("create", createProperties);
|
||||||
|
callback?.({
|
||||||
|
id: 1,
|
||||||
|
} as chrome.tabs.Tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(tabId: number) {
|
||||||
|
this.hook.emit("remove", tabId);
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemoved = {
|
||||||
|
addListener: (callback: any) => {
|
||||||
|
this.hook.addListener("remove", callback);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
59
packages/chrome-extension-mock/web_reqeuest.ts
Normal file
59
packages/chrome-extension-mock/web_reqeuest.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
export default class WebRequest {
|
||||||
|
sendHeader?: (
|
||||||
|
details: chrome.webRequest.WebRequestHeadersDetails
|
||||||
|
) => chrome.webRequest.BlockingResponse | void;
|
||||||
|
|
||||||
|
mockXhr(xhr: any): any {
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
const _this = this;
|
||||||
|
// eslint-disable-next-line func-names
|
||||||
|
return function () {
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
const ret = new xhr();
|
||||||
|
const header: chrome.webRequest.HttpHeader[] = [];
|
||||||
|
ret.setRequestHeader = (k: string, v: string) => {
|
||||||
|
header.push({
|
||||||
|
name: k,
|
||||||
|
value: v,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const oldSend = ret.send.bind(ret);
|
||||||
|
ret.send = (data: any) => {
|
||||||
|
header.push({
|
||||||
|
name: "cookie",
|
||||||
|
value: "website=example.com",
|
||||||
|
});
|
||||||
|
const resp = _this.sendHeader?.({
|
||||||
|
method: ret.method,
|
||||||
|
url: ret.url,
|
||||||
|
requestHeaders: header,
|
||||||
|
initiator: chrome.runtime.getURL(""),
|
||||||
|
} as chrome.webRequest.WebRequestHeadersDetails) as chrome.webRequest.BlockingResponse;
|
||||||
|
resp.requestHeaders?.forEach((h) => {
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
ret._authorRequestHeaders!.addHeader(h.name, h.value);
|
||||||
|
});
|
||||||
|
oldSend(data);
|
||||||
|
};
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeSendHeaders = {
|
||||||
|
addListener: (callback: any) => {
|
||||||
|
this.sendHeader = callback;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
onHeadersReceived = {
|
||||||
|
addListener: () => {
|
||||||
|
// TODO
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
onCompleted = {
|
||||||
|
addListener: () => {
|
||||||
|
// TODO
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
61
packages/message/mock_message.ts
Normal file
61
packages/message/mock_message.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import EventEmitter from "eventemitter3";
|
||||||
|
import { Message, MessageConnect, MessageSend } from "./server";
|
||||||
|
|
||||||
|
export class MockMessageConnect implements MessageConnect {
|
||||||
|
constructor(protected EE: EventEmitter) {}
|
||||||
|
|
||||||
|
onMessage(callback: (data: any) => void): void {
|
||||||
|
this.EE.on("message", (data: any) => {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(data: any): void {
|
||||||
|
this.EE.emit("message", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(): void {
|
||||||
|
this.EE.emit("disconnect");
|
||||||
|
}
|
||||||
|
|
||||||
|
onDisconnect(callback: () => void): void {
|
||||||
|
this.EE.on("disconnect", callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MockMessageSend implements MessageSend {
|
||||||
|
constructor(
|
||||||
|
protected EE: EventEmitter,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
connect(data: any): Promise<MessageConnect> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const EE = new EventEmitter();
|
||||||
|
const con = new MockMessageConnect(EE);
|
||||||
|
this.EE.emit("connect", data, con);
|
||||||
|
resolve(con);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(data: any): Promise<any> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.EE.emit("message", data, (resp: any) => {
|
||||||
|
resolve(resp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MockMessage extends MockMessageSend implements Message {
|
||||||
|
onConnect(callback: (data: any, con: MessageConnect) => void): void {
|
||||||
|
this.EE.on("connect", (data: any, con: MessageConnect) => {
|
||||||
|
callback(data, con);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage(callback: (data: any, sendResponse: (data: any) => void) => void): void {
|
||||||
|
this.EE.on("message", (data: any, sendResponse: (data: any) => void) => {
|
||||||
|
callback(data, sendResponse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
19
pnpm-lock.yaml
generated
19
pnpm-lock.yaml
generated
@ -123,9 +123,6 @@ importers:
|
|||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 2.1.4
|
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))
|
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:
|
autoprefixer:
|
||||||
specifier: ^10.4.20
|
specifier: ^10.4.20
|
||||||
version: 10.4.20(postcss@8.4.49)
|
version: 10.4.20(postcss@8.4.49)
|
||||||
@ -153,6 +150,9 @@ importers:
|
|||||||
jsdom:
|
jsdom:
|
||||||
specifier: ^25.0.1
|
specifier: ^25.0.1
|
||||||
version: 25.0.1
|
version: 25.0.1
|
||||||
|
mock-xmlhttprequest:
|
||||||
|
specifier: ^8.4.1
|
||||||
|
version: 8.4.1
|
||||||
postcss:
|
postcss:
|
||||||
specifier: ^8.4.49
|
specifier: ^8.4.49
|
||||||
version: 8.4.49
|
version: 8.4.49
|
||||||
@ -1612,9 +1612,6 @@ packages:
|
|||||||
'@webassemblyjs/wast-printer@1.14.1':
|
'@webassemblyjs/wast-printer@1.14.1':
|
||||||
resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==}
|
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':
|
'@xtuc/ieee754@1.2.0':
|
||||||
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
|
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
|
||||||
|
|
||||||
@ -3165,6 +3162,10 @@ packages:
|
|||||||
mlly@1.7.3:
|
mlly@1.7.3:
|
||||||
resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==}
|
resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==}
|
||||||
|
|
||||||
|
mock-xmlhttprequest@8.4.1:
|
||||||
|
resolution: {integrity: sha512-2ORxRN+h40+3/Ylw9LKOtYGfQIoX6grGQlmbvMKqaeZ5/l7oeMvqdJxyG/ax3Poy7VbqMTADI6BwTmO7u10Wrw==}
|
||||||
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
||||||
monaco-editor@0.52.2:
|
monaco-editor@0.52.2:
|
||||||
resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
|
resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
|
||||||
|
|
||||||
@ -5946,10 +5947,6 @@ snapshots:
|
|||||||
'@webassemblyjs/ast': 1.14.1
|
'@webassemblyjs/ast': 1.14.1
|
||||||
'@xtuc/long': 4.2.2
|
'@xtuc/long': 4.2.2
|
||||||
|
|
||||||
'@webext-core/fake-browser@1.3.2':
|
|
||||||
dependencies:
|
|
||||||
lodash.merge: 4.6.2
|
|
||||||
|
|
||||||
'@xtuc/ieee754@1.2.0': {}
|
'@xtuc/ieee754@1.2.0': {}
|
||||||
|
|
||||||
'@xtuc/long@4.2.2': {}
|
'@xtuc/long@4.2.2': {}
|
||||||
@ -7815,6 +7812,8 @@ snapshots:
|
|||||||
pkg-types: 1.2.1
|
pkg-types: 1.2.1
|
||||||
ufo: 1.5.4
|
ufo: 1.5.4
|
||||||
|
|
||||||
|
mock-xmlhttprequest@8.4.1: {}
|
||||||
|
|
||||||
monaco-editor@0.52.2: {}
|
monaco-editor@0.52.2: {}
|
||||||
|
|
||||||
mrmime@1.0.1: {}
|
mrmime@1.0.1: {}
|
||||||
|
@ -9,7 +9,7 @@ export interface CacheStorage {
|
|||||||
export class ExtCache implements CacheStorage {
|
export class ExtCache implements CacheStorage {
|
||||||
get(key: string): Promise<any> {
|
get(key: string): Promise<any> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.storage.local.get(key, (value) => {
|
chrome.storage.session.get(key, (value) => {
|
||||||
resolve(value[key]);
|
resolve(value[key]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -17,7 +17,7 @@ export class ExtCache implements CacheStorage {
|
|||||||
|
|
||||||
set(key: string, value: any): Promise<void> {
|
set(key: string, value: any): Promise<void> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.storage.local.set(
|
chrome.storage.session.set(
|
||||||
{
|
{
|
||||||
[key]: value,
|
[key]: value,
|
||||||
},
|
},
|
||||||
@ -30,7 +30,7 @@ export class ExtCache implements CacheStorage {
|
|||||||
|
|
||||||
has(key: string): Promise<boolean> {
|
has(key: string): Promise<boolean> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.storage.local.get(key, (value) => {
|
chrome.storage.session.get(key, (value) => {
|
||||||
resolve(value[key] !== undefined);
|
resolve(value[key] !== undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -38,7 +38,7 @@ export class ExtCache implements CacheStorage {
|
|||||||
|
|
||||||
del(key: string): Promise<void> {
|
del(key: string): Promise<void> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.storage.local.remove(key, () => {
|
chrome.storage.session.remove(key, () => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -46,7 +46,7 @@ export class ExtCache implements CacheStorage {
|
|||||||
|
|
||||||
list(): Promise<string[]> {
|
list(): Promise<string[]> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.storage.local.get(null, (value) => {
|
chrome.storage.session.get(null, (value) => {
|
||||||
resolve(Object.keys(value));
|
resolve(Object.keys(value));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
import "fake-indexeddb/auto";
|
|
||||||
import { DAO, db } from "./dao";
|
|
||||||
import { LoggerDAO } from "./logger";
|
|
||||||
import migrate from "../migrate";
|
|
||||||
|
|
||||||
migrate();
|
|
||||||
|
|
||||||
interface Test {
|
|
||||||
id: number;
|
|
||||||
data: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
db.version(17).stores({ test: "++id,data" });
|
|
||||||
|
|
||||||
class testDAO extends DAO<Test> {
|
|
||||||
public tableName = "test";
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.table = db.table(this.tableName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("dao", () => {
|
|
||||||
const dao = new testDAO();
|
|
||||||
it("测试save", async () => {
|
|
||||||
expect(await dao.save({ id: 0, data: "ok1" })).toEqual(1);
|
|
||||||
|
|
||||||
expect(await dao.save({ id: 0, data: "ok" })).toEqual(2);
|
|
||||||
|
|
||||||
expect(await dao.save({ id: 2, data: "ok2" })).toEqual(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("测试find", async () => {
|
|
||||||
expect(await dao.findOne({ id: 1 })).toEqual({ id: 1, data: "ok1" });
|
|
||||||
expect(await dao.findById(2)).toEqual({ id: 2, data: "ok2" });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("测试list", async () => {
|
|
||||||
expect(await dao.list({ id: 1 })).toEqual([{ id: 1, data: "ok1" }]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("测试delete", async () => {
|
|
||||||
expect(await dao.delete({ id: 1 })).toEqual(1);
|
|
||||||
expect(await dao.findById(1)).toEqual(undefined);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("model", () => {
|
|
||||||
const logger = new LoggerDAO();
|
|
||||||
it("save", async () => {
|
|
||||||
expect(
|
|
||||||
await logger.save({
|
|
||||||
id: 0,
|
|
||||||
level: "info",
|
|
||||||
message: "ok",
|
|
||||||
label: {},
|
|
||||||
createtime: new Date().getTime(),
|
|
||||||
})
|
|
||||||
).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,6 +1,6 @@
|
|||||||
import { Group, MessageConnect } from "@Packages/message/server";
|
import { Group, MessageConnect } from "@Packages/message/server";
|
||||||
|
|
||||||
export class GMApi {
|
export default class GMApi {
|
||||||
constructor(private group: Group) {}
|
constructor(private group: Group) {}
|
||||||
|
|
||||||
xmlHttpRequest(params: GMSend.XHRDetails, con: MessageConnect | null) {
|
xmlHttpRequest(params: GMSend.XHRDetails, con: MessageConnect | null) {
|
||||||
|
@ -6,7 +6,7 @@ import { WindowMessage } from "@Packages/message/window_message";
|
|||||||
import { ExtensionMessageSend } from "@Packages/message/extension_message";
|
import { ExtensionMessageSend } from "@Packages/message/extension_message";
|
||||||
import { ServiceWorkerClient } from "../service_worker/client";
|
import { ServiceWorkerClient } from "../service_worker/client";
|
||||||
import { sendMessage } from "@Packages/message/client";
|
import { sendMessage } from "@Packages/message/client";
|
||||||
import { GMApi } from "./gm_api";
|
import GMApi from "./gm_api";
|
||||||
|
|
||||||
// offscreen环境的管理器
|
// offscreen环境的管理器
|
||||||
export class OffscreenManager {
|
export class OffscreenManager {
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import LoggerCore from "@App/app/logger/core";
|
import LoggerCore from "@App/app/logger/core";
|
||||||
import Logger from "@App/app/logger/logger";
|
import Logger from "@App/app/logger/logger";
|
||||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
||||||
import { Group, MessageConnect, MessageSender } from "@Packages/message/server";
|
import { Group, MessageConnect, MessageSend, MessageSender } from "@Packages/message/server";
|
||||||
import { ValueService } from "@App/app/service/service_worker/value";
|
import { ValueService } from "@App/app/service/service_worker/value";
|
||||||
import PermissionVerify from "./permission_verify";
|
import PermissionVerify from "./permission_verify";
|
||||||
import { ServiceWorkerMessageSend } from "@Packages/message/window_message";
|
|
||||||
import { connect } from "@Packages/message/client";
|
import { connect } from "@Packages/message/client";
|
||||||
import Cache, { incr } from "@App/app/cache";
|
import Cache, { incr } from "@App/app/cache";
|
||||||
import { unsafeHeaders } from "@App/runtime/utils";
|
import { unsafeHeaders } from "@App/runtime/utils";
|
||||||
@ -35,7 +34,7 @@ export default class GMApi {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private group: Group,
|
private group: Group,
|
||||||
private sender: ServiceWorkerMessageSend,
|
private sender: MessageSend,
|
||||||
private value: ValueService
|
private value: ValueService
|
||||||
) {
|
) {
|
||||||
this.logger = LoggerCore.logger().with({ service: "runtime/gm_api" });
|
this.logger = LoggerCore.logger().with({ service: "runtime/gm_api" });
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Server } from "@Packages/message/server";
|
import { Server } from "@Packages/message/server";
|
||||||
import { MessageQueue } from "@Packages/message/message_queue";
|
import { MessageQueue } from "@Packages/message/message_queue";
|
||||||
import { ScriptService } from "./script";
|
import { ScriptService } from "./script";
|
||||||
import { ExtensionMessage } from "@Packages/message/extension_message";
|
|
||||||
import { ResourceService } from "./resource";
|
import { ResourceService } from "./resource";
|
||||||
import { ValueService } from "./value";
|
import { ValueService } from "./value";
|
||||||
import { RuntimeService } from "./runtime";
|
import { RuntimeService } from "./runtime";
|
||||||
@ -11,11 +10,11 @@ export type InstallSource = "user" | "system" | "sync" | "subscribe" | "vscode";
|
|||||||
|
|
||||||
// service worker的管理器
|
// service worker的管理器
|
||||||
export default class ServiceWorkerManager {
|
export default class ServiceWorkerManager {
|
||||||
private api: Server = new Server(new ExtensionMessage());
|
constructor(
|
||||||
|
private api: Server,
|
||||||
private mq: MessageQueue = new MessageQueue(this.api);
|
private mq: MessageQueue,
|
||||||
|
private sender: ServiceWorkerMessageSend
|
||||||
private sender: ServiceWorkerMessageSend = new ServiceWorkerMessageSend();
|
) {}
|
||||||
|
|
||||||
async initManager() {
|
async initManager() {
|
||||||
this.api.on("preparationOffscreen", async () => {
|
this.api.on("preparationOffscreen", async () => {
|
||||||
@ -32,79 +31,5 @@ export default class ServiceWorkerManager {
|
|||||||
script.init();
|
script.init();
|
||||||
const runtime = new RuntimeService(this.api.group("runtime"), this.sender, this.mq, value);
|
const runtime = new RuntimeService(this.api.group("runtime"), this.sender, this.mq, value);
|
||||||
runtime.init();
|
runtime.init();
|
||||||
|
|
||||||
// 测试xhr
|
|
||||||
// setTimeout(() => {
|
|
||||||
// chrome.tabs.query(
|
|
||||||
// {
|
|
||||||
// url: chrome.runtime.getURL("src/offscreen.html"),
|
|
||||||
// },
|
|
||||||
// (result) => {
|
|
||||||
// console.log(result);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// }, 2000);
|
|
||||||
// group.on("testGmApi", () => {
|
|
||||||
// console.log(chrome.runtime.getURL("src/offscreen.html"));
|
|
||||||
// return new Promise((resolve) => {
|
|
||||||
// chrome.tabs.query({}, (tabs) => {
|
|
||||||
// const excludedTabIds: number[] = [];
|
|
||||||
// tabs.forEach((tab) => {
|
|
||||||
// if (tab.id) {
|
|
||||||
// excludedTabIds.push(tab.id);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// chrome.declarativeNetRequest.updateSessionRules(
|
|
||||||
// {
|
|
||||||
// removeRuleIds: [100],
|
|
||||||
// addRules: [
|
|
||||||
// {
|
|
||||||
// id: 100,
|
|
||||||
// priority: 1,
|
|
||||||
// action: {
|
|
||||||
// type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS,
|
|
||||||
// requestHeaders: [
|
|
||||||
// {
|
|
||||||
// header: "cookie",
|
|
||||||
// operation: chrome.declarativeNetRequest.HeaderOperation.SET,
|
|
||||||
// value: "test=1234314",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// header: "origin",
|
|
||||||
// operation: chrome.declarativeNetRequest.HeaderOperation.SET,
|
|
||||||
// value: "https://learn.scriptcat.org",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// header: "user-agent",
|
|
||||||
// operation: chrome.declarativeNetRequest.HeaderOperation.SET,
|
|
||||||
// value: "test",
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// condition: {
|
|
||||||
// resourceTypes: [chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST],
|
|
||||||
// urlFilter: "^https://scriptcat.org/zh-CN$",
|
|
||||||
// excludedTabIds: excludedTabIds,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// () => {
|
|
||||||
// resolve(1);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// chrome.webRequest.onHeadersReceived.addListener(
|
|
||||||
// (details) => {
|
|
||||||
// console.log(details);
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// urls: ["<all_urls>"],
|
|
||||||
// types: ["xmlhttprequest"],
|
|
||||||
// },
|
|
||||||
// ["responseHeaders", "extraHeaders"]
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import { MessageQueue } from "@Packages/message/message_queue";
|
import { MessageQueue } from "@Packages/message/message_queue";
|
||||||
import { ScriptEnableCallbackValue } from "./client";
|
import { ScriptEnableCallbackValue } from "./client";
|
||||||
import { Group } from "@Packages/message/server";
|
import { Group, MessageSend } from "@Packages/message/server";
|
||||||
import { Script, SCRIPT_STATUS_ENABLE, SCRIPT_TYPE_NORMAL, ScriptAndCode, ScriptDAO } from "@App/app/repo/scripts";
|
import { Script, SCRIPT_STATUS_ENABLE, SCRIPT_TYPE_NORMAL, ScriptAndCode, ScriptDAO } from "@App/app/repo/scripts";
|
||||||
import { ValueService } from "./value";
|
import { ValueService } from "./value";
|
||||||
import GMApi from "./gm_api";
|
import GMApi from "./gm_api";
|
||||||
import { ServiceWorkerMessageSend } from "@Packages/message/window_message";
|
|
||||||
|
|
||||||
export class RuntimeService {
|
export class RuntimeService {
|
||||||
scriptDAO: ScriptDAO = new ScriptDAO();
|
scriptDAO: ScriptDAO = new ScriptDAO();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private group: Group,
|
private group: Group,
|
||||||
private sender: ServiceWorkerMessageSend,
|
private sender: MessageSend,
|
||||||
private mq: MessageQueue,
|
private mq: MessageQueue,
|
||||||
private value: ValueService
|
private value: ValueService
|
||||||
) {}
|
) {}
|
||||||
|
@ -1,37 +1,27 @@
|
|||||||
import { formatTime, nextTime, ltever, checkSilenceUpdate } from "./utils";
|
import { describe, test, expect, it } from "vitest";
|
||||||
|
import { nextTime, ltever, checkSilenceUpdate } from "./utils";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
describe("nextTime", () => {
|
describe("nextTime", () => {
|
||||||
test("每分钟表达式", () => {
|
test("每分钟表达式", () => {
|
||||||
expect(nextTime("* * * * *")).toEqual(
|
expect(nextTime("* * * * *")).toEqual(dayjs(new Date()).add(1, "minute").format("YYYY-MM-DD HH:mm:00"));
|
||||||
dayjs(new Date()).add(1, "minute").format("YYYY-MM-DD HH:mm:00")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
test("每分钟一次表达式", () => {
|
test("每分钟一次表达式", () => {
|
||||||
expect(nextTime("once * * * *")).toEqual(
|
expect(nextTime("once * * * *")).toEqual(
|
||||||
dayjs(new Date())
|
dayjs(new Date()).add(1, "minute").format("YYYY-MM-DD HH:mm 每分钟运行一次")
|
||||||
.add(1, "minute")
|
|
||||||
.format("YYYY-MM-DD HH:mm 每分钟运行一次")
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test("每小时一次表达式", () => {
|
test("每小时一次表达式", () => {
|
||||||
expect(nextTime("* once * * *")).toEqual(
|
expect(nextTime("* once * * *")).toEqual(dayjs(new Date()).add(1, "hour").format("YYYY-MM-DD HH 每小时运行一次"));
|
||||||
dayjs(new Date()).add(1, "hour").format("YYYY-MM-DD HH 每小时运行一次")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
test("每天一次表达式", () => {
|
test("每天一次表达式", () => {
|
||||||
expect(nextTime("* * once * *")).toEqual(
|
expect(nextTime("* * once * *")).toEqual(dayjs(new Date()).add(1, "day").format("YYYY-MM-DD 每天运行一次"));
|
||||||
dayjs(new Date()).add(1, "day").format("YYYY-MM-DD 每天运行一次")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
test("每月一次表达式", () => {
|
test("每月一次表达式", () => {
|
||||||
expect(nextTime("* * * once *")).toEqual(
|
expect(nextTime("* * * once *")).toEqual(dayjs(new Date()).add(1, "month").format("YYYY-MM 每月运行一次"));
|
||||||
dayjs(new Date()).add(1, "month").format("YYYY-MM 每月运行一次")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
test("每星期一次表达式", () => {
|
test("每星期一次表达式", () => {
|
||||||
expect(nextTime("* * * * once")).toEqual(
|
expect(nextTime("* * * * once")).toEqual(dayjs(new Date()).add(1, "week").format("YYYY-MM-DD 每星期运行一次"));
|
||||||
dayjs(new Date()).add(1, "week").format("YYYY-MM-DD 每星期运行一次")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Metadata } from "@App/app/repo/scripts";
|
||||||
import { CronTime } from "cron";
|
import { CronTime } from "cron";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
@ -186,3 +187,27 @@ export function openInCurrentTab(url: string) {
|
|||||||
export function isDebug() {
|
export function isDebug() {
|
||||||
return process.env.NODE_ENV === "development";
|
return process.env.NODE_ENV === "development";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查订阅规则是否改变,是否能够静默更新
|
||||||
|
export function checkSilenceUpdate(oldMeta: Metadata, newMeta: Metadata): boolean {
|
||||||
|
// 判断connect是否改变
|
||||||
|
const oldConnect: { [key: string]: boolean } = {};
|
||||||
|
const newConnect: { [key: string]: boolean } = {};
|
||||||
|
oldMeta.connect &&
|
||||||
|
oldMeta.connect.forEach((val) => {
|
||||||
|
oldConnect[val] = true;
|
||||||
|
});
|
||||||
|
newMeta.connect &&
|
||||||
|
newMeta.connect.forEach((val) => {
|
||||||
|
newConnect[val] = true;
|
||||||
|
});
|
||||||
|
// 老的里面没有新的就需要用户确认了
|
||||||
|
const keys = Object.keys(newConnect);
|
||||||
|
for (let i = 0; i < keys.length; i += 1) {
|
||||||
|
const key = keys[i];
|
||||||
|
if (!oldConnect[key]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import initTestEnv from "@App/pkg/utils/test_utils";
|
|
||||||
import { ScriptRunResouce } from "@App/app/repo/scripts";
|
import { ScriptRunResouce } from "@App/app/repo/scripts";
|
||||||
import ExecScript from "./exec_script";
|
import ExecScript from "./exec_script";
|
||||||
import { compileScript, compileScriptCode } from "./utils";
|
import { compileScript, compileScriptCode } from "./utils";
|
||||||
import { ExtVersion } from "@App/app/const";
|
import { ExtVersion } from "@App/app/const";
|
||||||
|
import initTestEnv from "@Tests/utils";
|
||||||
|
|
||||||
initTestEnv();
|
initTestEnv();
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { fakeBrowser } from "@webext-core/fake-browser";
|
import { beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { it } from "node:test";
|
import { initTestEnv } from "@Tests/utils";
|
||||||
import initTestEnv from "@Tests/utils";
|
|
||||||
import { beforeEach, describe, expect } from "vitest";
|
|
||||||
|
|
||||||
initTestEnv();
|
initTestEnv();
|
||||||
|
// serviceWorker环境
|
||||||
|
|
||||||
|
beforeAll(() => {});
|
||||||
|
|
||||||
describe("GM xhr", () => {
|
describe("GM xhr", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// See https://webext-core.aklinker1.io/fake-browser/reseting-state
|
// See https://webext-core.aklinker1.io/fake-browser/reseting-state
|
||||||
fakeBrowser.reset();
|
|
||||||
});
|
});
|
||||||
it("1", async () => {
|
it("123123", async () => {
|
||||||
expect(1).toBe(2);
|
expect(1).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,10 @@ import migrate from "./app/migrate";
|
|||||||
import LoggerCore from "./app/logger/core";
|
import LoggerCore from "./app/logger/core";
|
||||||
import DBWriter from "./app/logger/db_writer";
|
import DBWriter from "./app/logger/db_writer";
|
||||||
import { LoggerDAO } from "./app/repo/logger";
|
import { LoggerDAO } from "./app/repo/logger";
|
||||||
|
import { ExtensionMessage } from "@Packages/message/extension_message";
|
||||||
|
import { Server } from "@Packages/message/server";
|
||||||
|
import { MessageQueue } from "@Packages/message/message_queue";
|
||||||
|
import { ServiceWorkerMessageSend } from "@Packages/message/window_message";
|
||||||
|
|
||||||
const OFFSCREEN_DOCUMENT_PATH = "src/offscreen.html";
|
const OFFSCREEN_DOCUMENT_PATH = "src/offscreen.html";
|
||||||
|
|
||||||
@ -51,7 +55,8 @@ async function main() {
|
|||||||
});
|
});
|
||||||
loggerCore.logger().debug("service worker start");
|
loggerCore.logger().debug("service worker start");
|
||||||
// 初始化管理器
|
// 初始化管理器
|
||||||
const manager = new ServiceWorkerManager();
|
const server = new Server(new ExtensionMessage());
|
||||||
|
const manager = new ServiceWorkerManager(server, new MessageQueue(server), new ServiceWorkerMessageSend());
|
||||||
manager.initManager();
|
manager.initManager();
|
||||||
// 初始化沙盒环境
|
// 初始化沙盒环境
|
||||||
await setupOffscreenDocument();
|
await setupOffscreenDocument();
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
// <root>/__mocks__/webextension-polyfill.ts
|
|
||||||
export { fakeBrowser as default } from "@webext-core/fake-browser";
|
|
55
tests/utils.test.ts
Normal file
55
tests/utils.test.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { describe, expect, it, vitest } from "vitest";
|
||||||
|
import { initTestEnv, initTestGMApi } from "./utils";
|
||||||
|
import GMApi from "@App/runtime/content/gm_api";
|
||||||
|
import { randomUUID } from "crypto";
|
||||||
|
import { newMockXhr } from "mock-xmlhttprequest";
|
||||||
|
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
||||||
|
|
||||||
|
initTestEnv();
|
||||||
|
|
||||||
|
describe("测试GMApi环境", async () => {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
await new ScriptDAO().save(script);
|
||||||
|
const gmApi = new GMApi(msg);
|
||||||
|
//@ts-ignore
|
||||||
|
gmApi.scriptRes = {
|
||||||
|
uuid: script.uuid,
|
||||||
|
};
|
||||||
|
const mockXhr = newMockXhr();
|
||||||
|
mockXhr.onSend = async (request) => {
|
||||||
|
return request.respond(200, {}, "example");
|
||||||
|
};
|
||||||
|
global.XMLHttpRequest = mockXhr;
|
||||||
|
it("test GM xhr", async () => {
|
||||||
|
const onload = vitest.fn();
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
gmApi.GM_xmlhttpRequest({
|
||||||
|
url: "https://scriptcat.org/zh-CN",
|
||||||
|
onload: (res) => {
|
||||||
|
console.log(res);
|
||||||
|
resolve(res);
|
||||||
|
onload(res);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
expect(onload).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -3,8 +3,15 @@ import LoggerCore from "@App/app/logger/core";
|
|||||||
import DBWriter from "@App/app/logger/db_writer";
|
import DBWriter from "@App/app/logger/db_writer";
|
||||||
import migrate from "@App/app/migrate";
|
import migrate from "@App/app/migrate";
|
||||||
import { LoggerDAO } from "@App/app/repo/logger";
|
import { LoggerDAO } from "@App/app/repo/logger";
|
||||||
|
import { MockMessage } from "@Packages/message/mock_message";
|
||||||
|
import { Message, Server } from "@Packages/message/server";
|
||||||
|
import { MessageQueue } from "@Packages/message/message_queue";
|
||||||
|
import { ValueService } from "@App/app/service/service_worker/value";
|
||||||
|
import GMApi from "@App/app/service/service_worker/gm_api";
|
||||||
|
import OffscreenGMApi from "@App/app/service/offscreen/gm_api";
|
||||||
|
import EventEmitter from "eventemitter3";
|
||||||
|
|
||||||
export default function initTestEnv() {
|
export function initTestEnv() {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (global.initTest) {
|
if (global.initTest) {
|
||||||
return;
|
return;
|
||||||
@ -42,3 +49,27 @@ export default function initTestEnv() {
|
|||||||
});
|
});
|
||||||
logger.logger().debug("test start");
|
logger.logger().debug("test start");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initTestGMApi(): Message {
|
||||||
|
const wsEE = new EventEmitter();
|
||||||
|
const wsMessage = new MockMessage(wsEE);
|
||||||
|
const osEE = new EventEmitter();
|
||||||
|
const osMessage = new MockMessage(osEE);
|
||||||
|
|
||||||
|
const serviceWorkerServer = new Server(wsMessage);
|
||||||
|
const mq = new MessageQueue(serviceWorkerServer);
|
||||||
|
const valueService = new ValueService(serviceWorkerServer.group("value"), mq);
|
||||||
|
const swGMApi = new GMApi(serviceWorkerServer.group("runtime"), osMessage, valueService);
|
||||||
|
|
||||||
|
valueService.init();
|
||||||
|
swGMApi.start();
|
||||||
|
|
||||||
|
// offscreen
|
||||||
|
const offscreenServer = new Server(osMessage);
|
||||||
|
const osGMApi = new OffscreenGMApi(offscreenServer.group("gmApi"));
|
||||||
|
osGMApi.init();
|
||||||
|
|
||||||
|
return wsMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initTestOffscreen() {}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import { vi } from "vitest";
|
import chromeMock from "@Packages/chrome-extension-mock";
|
||||||
|
|
||||||
vi.mock("webextension-polyfill");
|
chromeMock.init();
|
||||||
|
@ -10,6 +10,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
|
environment: "jsdom",
|
||||||
// List setup file
|
// List setup file
|
||||||
setupFiles: ["./tests/vitest.setup.ts"],
|
setupFiles: ["./tests/vitest.setup.ts"],
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user