@coinbase/onchaintestkit
Version:
End-to-end testing toolkit for blockchain applications, powered by Playwright
212 lines (211 loc) • 10.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NotificationPage = exports.NotificationPageType = void 0;
const utils_1 = require("../../../../utils");
const spendingCap_1 = require("../../pages/NotificationPage/actions/spendingCap");
const actions_1 = require("./actions");
var NotificationPageType;
(function (NotificationPageType) {
NotificationPageType["SpendingCap"] = "spending-cap";
NotificationPageType["Signature"] = "signature";
NotificationPageType["Transaction"] = "transaction";
NotificationPageType["RemoveSpendCap"] = "remove-spend-cap";
})(NotificationPageType || (exports.NotificationPageType = NotificationPageType = {}));
// Constants for MetaMask notification page
const NOTIFICATION_PAGE_PATH = "notification.html";
const DEFAULT_VIEWPORT = { width: 360, height: 580 };
class NotificationPage {
constructor(page) {
this.page = page;
}
/**
* Helper method to get notification page URL
*/
getNotificationUrl(extensionId) {
return `chrome-extension://${extensionId}/${NOTIFICATION_PAGE_PATH}`;
}
/**
* Helper method to wait for notification page
*/
async getNotificationPage(extensionId) {
return (0, utils_1.waitForPage)(this.page.context(), this.getNotificationUrl(extensionId), DEFAULT_VIEWPORT);
}
async connectToDapp(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await (0, actions_1.connectToDapp)(notificationPage);
}
async approveNewNetwork(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.network.approveNewNetwork(notificationPage);
}
async rejectNewNetwork(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.network.rejectNewNetwork(notificationPage);
}
async approveSwitchNetwork(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.network.approveSwitchNetwork(notificationPage);
}
async rejectSwitchNetwork(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.network.rejectSwitchNetwork(notificationPage);
}
async approveAddNetwork(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.network.approveNewNetwork(notificationPage);
}
async rejectAddNetwork(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.network.rejectNewNetwork(notificationPage);
}
async confirmTransaction(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.transaction.confirm(notificationPage);
}
async rejectTransaction(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.transaction.reject(notificationPage);
}
async approveTokenPermission(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.approvePermission.approve(notificationPage);
}
async rejectTokenPermission(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.approvePermission.reject(notificationPage);
}
async confirmSpendingCapRemoval(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await spendingCap_1.spendingCapRemoval.confirm(notificationPage);
}
async rejectSpendingCapRemoval(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await spendingCap_1.spendingCapRemoval.reject(notificationPage);
}
async addNewToken(extensionId) {
const notificationPage = await this.getNotificationPage(extensionId);
await actions_1.token.addNew(notificationPage);
}
async identifyNotificationType(extensionId, globalTimeout = 15000, checkTimeout = 10000) {
// Get the notification page and wait for it to load fully
const notificationPage = await this.getNotificationPage(extensionId);
// Give the page an extra moment to fully render and stabilize
await notificationPage.waitForTimeout(500);
// Simple checks that should work
const checks = [
{ type: NotificationPageType.SpendingCap, text: "Spending cap request" },
{ type: NotificationPageType.Signature, text: "Signature request" },
{ type: NotificationPageType.Transaction, text: "Network fee" },
{ type: NotificationPageType.RemoveSpendCap, text: "Remove Permission" },
];
// Immediately log the full page content for comparison
void (async () => {
try {
const pageContent = (await notificationPage.textContent("body"))?.substring(0, 100) ?? "";
console.log("Page content at start of detection:", pageContent);
// For each check, log if its text is present in the content
checks.forEach(({ type, text }) => {
const isPresent = pageContent.includes(text);
console.log(`Check for "${text}" (${type}): ${isPresent ? "FOUND in content" : "NOT FOUND in content"}`);
});
}
catch (error) {
console.error("Error capturing initial page content:", error);
}
})();
// Create timeout ID for cleanup
let timeoutId;
// Create a promise that will reject after the global timeout
const timeoutPromise = new Promise((_, reject) => {
timeoutId = setTimeout(() => {
// Use an IIFE to capture page content, but properly void the promise
void (function captureDebugInfo() {
const capturePromise = (async () => {
try {
// Only capture info if page is still available
if (notificationPage.isClosed()) {
console.log("Page already closed, skipping debug capture");
return;
}
// When timeout occurs, log the entire page content to help debugging
const pageContent = (await notificationPage.textContent("body"))?.substring(0, 100) ?? "";
console.log("Global timeout reached. Page content:", pageContent);
// Take a screenshot for visual debugging
await notificationPage.screenshot({
path: "notification-timeout.png",
});
console.log("Screenshot saved as notification-timeout.png");
// Debug each selector specifically
for (const { type, text } of checks) {
try {
// Try to get the element even if not visible
const element = notificationPage.getByText(text, {
exact: false,
});
const count = await element.count();
const isVisible = count > 0
? await element.isVisible().catch(() => false)
: false;
console.log(`Selector debug for "${text}" (${type}): count=${count}, visible=${isVisible}`);
}
catch (error) {
console.error(`Error checking selector for "${text}":`, error);
}
}
}
catch (error) {
console.error("Error capturing page content on timeout:", error);
}
})();
// Explicitly void the promise to satisfy linter
void capturePromise;
})();
reject(new Error("Timeout waiting for notification type"));
}, globalTimeout);
});
// Create a promise that resolves with the first matching notification type
const checkTypePromise = new Promise((resolve, _reject) => {
// Check each notification type with debug logging
checks.forEach(({ type, text }) => {
void (async () => {
try {
const selector = notificationPage.getByText(text, {
exact: false,
});
// Log when we start checking each selector
console.log(`Starting check for "${text}" (${type})`);
// Wait for the text to be visible with individual timeout
const isVisible = await selector
.isVisible({ timeout: checkTimeout })
.catch((error) => {
console.log(`Selector for "${text}" timed out with error:`, error.message);
return false;
});
if (isVisible) {
console.log(`Found notification type: ${type} with text: "${text}"`);
resolve(type);
}
else {
console.log(`Selector for "${text}" didn't match any visible elements`);
}
}
catch (error) {
console.error(`Error checking type ${type}:`, error);
}
})();
});
});
try {
// Race between finding a match and the global timeout
const result = await Promise.race([checkTypePromise, timeoutPromise]);
return result;
}
finally {
// Always clear the timeout to prevent it from running after page is closed
if (timeoutId) {
clearTimeout(timeoutId);
}
}
}
}
exports.NotificationPage = NotificationPage;