API监听和WebSocket监听移至注入的js脚本
This commit is contained in:
parent
e73b03b4f2
commit
6aecdb17d6
|
@ -1,10 +1,8 @@
|
|||
import { test as base, TestInfo } from "@playwright/test";
|
||||
import { test as base, expect, TestInfo } from "@playwright/test";
|
||||
import type {
|
||||
Browser,
|
||||
BrowserContext,
|
||||
Page,
|
||||
Response,
|
||||
WebSocket,
|
||||
} from "playwright-core";
|
||||
import PagesInstance from "./PagesInstance";
|
||||
|
||||
|
@ -23,7 +21,7 @@ async function newContext(
|
|||
context: BrowserContext;
|
||||
close: (testInfo: TestInfo) => Promise<void>;
|
||||
}> {
|
||||
const pages = [];
|
||||
let pages: Page[] = [];
|
||||
const video = testInfo.project.use.video;
|
||||
const videoMode = normalizeVideoMode(video);
|
||||
const captureVideo = shouldCaptureVideo(videoMode, testInfo);
|
||||
|
@ -36,10 +34,12 @@ async function newContext(
|
|||
}
|
||||
: {};
|
||||
const context = await browser.newContext(videoOptions);
|
||||
await test.step("DeleteFromTheHtmlreport-监听", async () => {
|
||||
context.on("response", (data) => ListenResponse(data));
|
||||
context.on("page", (page) => onPage(pages, page));
|
||||
});
|
||||
context.on("dialog", async (dialog) => {
|
||||
const message = dialog.message();
|
||||
await dialog.accept();
|
||||
expect.soft(message, { message: "API报错:" + message }).not.toContain("failInfo")
|
||||
})
|
||||
context.on("page", (page) => pages.push(page));
|
||||
|
||||
// 使用MutationObserver监听DOM变化,结合PerformanceObserver获取最后一次响应的返回时间,以达到loading时禁止点击输入等操作.
|
||||
await context.addInitScript({
|
||||
|
@ -111,75 +111,6 @@ function shouldCaptureVideo(videoMode: string, testInfo: TestInfo): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
interface WSMessage {
|
||||
message: {
|
||||
subject?: string;
|
||||
content?: string;
|
||||
};
|
||||
}
|
||||
|
||||
async function ListenWebScoket(page: Page, ws: WebSocket): Promise<void> {
|
||||
const wsmsg = await new Promise((resolve) => {
|
||||
ws.on("framereceived", (event) => {
|
||||
console.log(event.payload);
|
||||
resolve(event.payload);
|
||||
});
|
||||
});
|
||||
// Extract subject and content from wsmsg if it contains message with subject or content
|
||||
let subject = "",
|
||||
content = "";
|
||||
if (wsmsg && typeof wsmsg === "object" && (wsmsg as WSMessage).message) {
|
||||
const message = (wsmsg as WSMessage).message;
|
||||
subject = message.subject || "";
|
||||
content = message.content || "";
|
||||
// remove html tag
|
||||
content = content.replace(/<\/?[^>]+(>|$)/g, "");
|
||||
}
|
||||
let popup = page
|
||||
.locator(
|
||||
".c7n-notification-notice:has(.c7n-notification-notice-icon:not(.icon))"
|
||||
)
|
||||
.locator("visible=true");
|
||||
if (subject) {
|
||||
popup = popup.filter({ hasText: subject });
|
||||
}
|
||||
if (content) {
|
||||
for (const char of content) {
|
||||
popup = popup.filter({ hasText: char });
|
||||
}
|
||||
}
|
||||
await popup.evaluate((node) => (node.style.display = "none"));
|
||||
}
|
||||
|
||||
async function ListenResponse(response: Response): Promise<void> {
|
||||
await test.step("DeleteFromTheHtmlreport-监听", async () => {
|
||||
if (!response.url().includes("https://cdn-")) {
|
||||
if (response.status() === 403) {
|
||||
console.log("Response status code is 403");
|
||||
} else if (
|
||||
response.status() === 200 &&
|
||||
(await response.headerValue("Content-Type")) === "application/json"
|
||||
) {
|
||||
try {
|
||||
const resJson = await response.json();
|
||||
if (resJson.failed) {
|
||||
console.log(resJson.message);
|
||||
}
|
||||
} catch (e) {
|
||||
// Silent catch empty videos.
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function onPage(pages: Array<Page>, page: Page) {
|
||||
pages.push(page);
|
||||
await test.step("DeleteFromTheHtmlreport-监听", async () => {
|
||||
page.on("websocket", (ws) => ListenWebScoket(page, ws));
|
||||
});
|
||||
}
|
||||
|
||||
type Accounts = {
|
||||
user_1: PagesInstance;
|
||||
user_2: PagesInstance;
|
||||
|
|
|
@ -129,7 +129,7 @@ var ajaxHooker = (function () {
|
|||
emptyFn,
|
||||
errorFn
|
||||
);
|
||||
} catch {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
});
|
||||
ajaxHooker.filter([
|
||||
{
|
||||
url: /^https:\/\/(test|demo)\.cloudlong.cn/,
|
||||
url: /^https:\/\/(oc-test|demo)\.cloudlong.cn/,
|
||||
async: true,
|
||||
},
|
||||
]);
|
||||
|
@ -42,6 +42,12 @@
|
|||
document.body.appendChild(mask);
|
||||
}
|
||||
request.response = (res) => {
|
||||
if (res.status === 403){
|
||||
win.alert("API:" + res.finalUrl + "-----failInfo:Response status is 403");
|
||||
}else if(res.json && res.json.hasOwnProperty("failed"))
|
||||
{
|
||||
win.alert("API:" + res.finalUrl + "-----failInfo:" + res.json.message);
|
||||
}
|
||||
if (
|
||||
win.apiCounter === 0 &&
|
||||
document.getElementById("networkIdleMask")
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// 观察DOM变化,对新增的按钮等进行disable或hidden,同时获取loading元素数量
|
||||
const domObserver = new MutationObserver((mutationsList) => {
|
||||
// listenElementsClassName中元素出现style.display属性将被设置为none,且不会被恢复,防止此类元素出现影响UI自动化操作其他元素
|
||||
// 如需判断页面中存在这些这些元素,只需playwrigh locator.waitFor("attached")即可.
|
||||
const listenElementsClassName = ["c7n-notification-notice request"];
|
||||
// 临时被禁用,网络结束后启用的元素
|
||||
const findAllElementsNeedToDisable = (element) => [
|
||||
...(element.tagName === "BUTTON" && !element.disabled
|
||||
? [(element.disabled = true && element)]
|
||||
|
@ -17,15 +21,22 @@ const domObserver = new MutationObserver((mutationsList) => {
|
|||
let elementsToRestore = [];
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === "childList") {
|
||||
if (mutation.target instanceof HTMLElement && mutation.target.classList) {
|
||||
if (mutation.addedNodes.length > 0) {
|
||||
const disabledElements = Array.from(
|
||||
mutation.addedNodes || []
|
||||
).flatMap(findAllElementsNeedToDisable);
|
||||
const { target, addedNodes } = mutation;
|
||||
if (target instanceof HTMLElement && target.classList && addedNodes.length > 0) {
|
||||
const disabledElements = Array.from(addedNodes || []).flatMap(findAllElementsNeedToDisable);
|
||||
elementsToRestore = elementsToRestore.concat(disabledElements);
|
||||
addedNodes.forEach((addedNode) => {
|
||||
if (typeof addedNode.className === 'string') {
|
||||
for (const className of listenElementsClassName) {
|
||||
if (addedNode.className.includes(className)) {
|
||||
addedNode.style.display = "none";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// 当目前无loading,且最后一次网络请求结束timeOut时间以上,恢复元素状态.
|
||||
if (elementsToRestore.length > 0) {
|
||||
|
|
Loading…
Reference in New Issue