Scert/frontend/src/test-support/mount.js

102 lines
2.9 KiB
JavaScript

import { createRenderer, nextTick } from "vue";
export const aliyunProvider = {
id: "aliyun",
name: "阿里云 DNS",
available: true,
credential_fields: [{ name: "access_key_id", label: "访问密钥", required: true }],
};
export function deferred() {
let resolve;
let reject;
const promise = new Promise((accept, fail) => {
resolve = accept;
reject = fail;
});
return { promise, resolve, reject };
}
export function verifiedResponse(token = "test-token") {
return Response.json({
verified: true,
credential_ref: "secret://test/only",
verification_token: token,
expires_at: new Date(Date.now() + 60000).toISOString(),
});
}
// 运行真实组合式逻辑和生命周期,不加载浏览器,也不连接 DNS 或业务数据库。
export async function mountComposable(t, factory, fetcher) {
const windowEvents = new EventTarget();
const intervals = new Map();
let nextIntervalID = 1;
let currentTime = Date.now();
const originals = new Map();
for (const [key, value] of Object.entries({
window: {
addEventListener: windowEvents.addEventListener.bind(windowEvents),
removeEventListener: windowEvents.removeEventListener.bind(windowEvents),
dispatchEvent: windowEvents.dispatchEvent.bind(windowEvents),
setInterval(callback) {
const intervalID = nextIntervalID;
nextIntervalID += 1;
intervals.set(intervalID, callback);
return intervalID;
},
clearInterval(intervalID) {
intervals.delete(intervalID);
},
location: { pathname: "/", search: "", hash: "", assign() {} },
history: { replaceState() {} },
setTimeout,
clearTimeout,
},
document: { body: { style: { overflow: "" } } },
})) {
originals.set(key, Object.getOwnPropertyDescriptor(globalThis, key));
Object.defineProperty(globalThis, key, { configurable: true, writable: true, value });
}
t.mock.method(Date, "now", () => currentTime);
t.mock.method(globalThis, "fetch", fetcher);
const renderer = createRenderer({
createComment: () => ({}),
insert() {},
remove() {},
parentNode: () => null,
nextSibling: () => null,
});
let state;
const app = renderer.createApp({
setup() {
state = factory();
return () => null;
},
});
app.mount({});
let mounted = true;
const unmount = () => {
if (mounted) app.unmount();
mounted = false;
};
t.after(() => {
unmount();
for (const [key, descriptor] of originals) {
if (descriptor) Object.defineProperty(globalThis, key, descriptor);
else delete globalThis[key];
}
});
await new Promise((resolve) => setImmediate(resolve));
await nextTick();
return {
state,
unmount,
runIntervals() {
for (const callback of [...intervals.values()]) callback();
},
advanceTime(milliseconds) {
currentTime += milliseconds;
},
};
}