mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-12 17:22:38 +02:00
8.4 KiB
8.4 KiB
Multi-Tab, Window & Popup Testing
This file covers single-user scenarios with multiple browser tabs, windows, and popups. For multi-user collaboration testing (multiple users interacting simultaneously), see multi-user.md.
Table of Contents
Popup Handling
Basic Popup
test("handle popup window", async ({ page }) => {
await page.goto("/");
// Start waiting for popup before triggering it
const popupPromise = page.waitForEvent("popup");
await page.getByRole("button", { name: "Open Support Chat" }).click();
const popup = await popupPromise;
// Wait for popup to load
await popup.waitForLoadState();
// Interact with popup
await popup.getByLabel("Message").fill("Need help");
await popup.getByRole("button", { name: "Send" }).click();
await expect(popup.getByText("Message sent")).toBeVisible();
// Close popup
await popup.close();
});
Popup with Authentication
test("popup login flow", async ({ page }) => {
await page.goto("/dashboard");
const popupPromise = page.waitForEvent("popup");
await page.getByRole("button", { name: "Connect Account" }).click();
const popup = await popupPromise;
await popup.waitForLoadState();
// Complete login in popup
await popup.getByLabel("Email").fill("user@example.com");
await popup.getByLabel("Password").fill("password123");
await popup.getByRole("button", { name: "Log In" }).click();
// Popup should close automatically after auth
await popup.waitForEvent("close");
// Main page should reflect connected state
await expect(page.getByText("Account connected")).toBeVisible();
});
Handle Blocked Popups
test("handle popup blocker", async ({ page }) => {
await page.goto("/share");
// Listen for console messages about blocked popup
page.on("console", (msg) => {
if (msg.text().includes("popup blocked")) {
console.log("Popup was blocked");
}
});
const popupPromise = page.waitForEvent("popup").catch(() => null);
await page.getByRole("button", { name: "Share to Twitter" }).click();
const popup = await popupPromise;
if (!popup) {
// Popup blocked - app should show fallback
await expect(page.getByText("Copy share link instead")).toBeVisible();
}
});
New Tab Navigation
Link Opens in New Tab
test("external link opens in new tab", async ({ page, context }) => {
await page.goto("/resources");
// Wait for new page in context
const pagePromise = context.waitForEvent("page");
await page.getByRole("link", { name: "Documentation" }).click();
const newPage = await pagePromise;
await newPage.waitForLoadState();
expect(newPage.url()).toContain("docs.example.com");
await expect(newPage.getByRole("heading", { level: 1 })).toBeVisible();
// Original page still there
expect(page.url()).toContain("/resources");
await newPage.close();
});
Intercept New Tab
test("prevent new tab for testing", async ({ page }) => {
await page.goto("/links");
// Remove target="_blank" to keep navigation in same tab
await page.evaluate(() => {
document.querySelectorAll('a[target="_blank"]').forEach((a) => {
a.removeAttribute("target");
});
});
// Now link opens in same tab
await page.getByRole("link", { name: "External Site" }).click();
// Can test the destination page
await expect(page).toHaveURL(/external-site\.com/);
});
OAuth Flows
Google OAuth Popup
test("Google OAuth login", async ({ page }) => {
await page.goto("/login");
const popupPromise = page.waitForEvent("popup");
await page.getByRole("button", { name: "Sign in with Google" }).click();
const popup = await popupPromise;
await popup.waitForLoadState();
// Handle Google's OAuth flow
await popup.getByLabel("Email or phone").fill("test@gmail.com");
await popup.getByRole("button", { name: "Next" }).click();
await popup.getByLabel("Enter your password").fill("password");
await popup.getByRole("button", { name: "Next" }).click();
// Wait for redirect back and popup close
await popup.waitForEvent("close");
// Verify logged in on main page
await expect(page.getByText("Welcome, Test User")).toBeVisible();
});
Mock OAuth (Recommended)
test("mock OAuth flow", async ({ page, context }) => {
// Mock the OAuth callback instead of real flow
await page.route("**/auth/callback**", async (route) => {
// Simulate successful OAuth
const url = new URL(route.request().url());
url.searchParams.set("code", "mock-auth-code");
await route.fulfill({
status: 302,
headers: { Location: "/dashboard" },
});
});
// Mock token exchange
await page.route("**/api/auth/token", (route) =>
route.fulfill({
json: {
access_token: "mock-token",
user: { name: "Test User", email: "test@example.com" },
},
}),
);
await page.goto("/login");
await page.getByRole("button", { name: "Sign in with Google" }).click();
// Should redirect to dashboard without actual OAuth
await expect(page).toHaveURL("/dashboard");
await expect(page.getByText("Welcome, Test User")).toBeVisible();
});
OAuth Fixture
For comprehensive OAuth mocking patterns (fixtures, multiple providers, SAML SSO), see third-party.md. This section focuses on popup window handling mechanics for OAuth flows.
Multiple Windows
Test Across Multiple Windows
test("sync between windows", async ({ context }) => {
// Open two pages
const page1 = await context.newPage();
const page2 = await context.newPage();
await page1.goto("/dashboard");
await page2.goto("/dashboard");
// Make change in first window
await page1.getByRole("button", { name: "Add Item" }).click();
await page1.getByLabel("Name").fill("New Item");
await page1.getByRole("button", { name: "Save" }).click();
// Should sync to second window (if app supports real-time sync)
await expect(page2.getByText("New Item")).toBeVisible({ timeout: 10000 });
});
Different Users in Different Windows
For multi-user collaboration patterns (admin/user interactions, real-time collaboration, role-based testing, concurrent actions), see multi-user.md. This file focuses on single-user scenarios with multiple tabs/windows/popups.
Tab Coordination
Switch Between Tabs
test("manage multiple tabs", async ({ context }) => {
const page1 = await context.newPage();
await page1.goto("/editor");
const page2 = await context.newPage();
await page2.goto("/preview");
// Edit in first tab
await page1.bringToFront();
await page1.getByLabel("Content").fill("Hello World");
// Check preview in second tab
await page2.bringToFront();
await page2.reload(); // If preview needs refresh
await expect(page2.getByText("Hello World")).toBeVisible();
});
Close All Tabs Except One
test("cleanup tabs after test", async ({ context }) => {
const mainPage = await context.newPage();
await mainPage.goto("/");
// Open several popups during test
for (let i = 0; i < 3; i++) {
const popup = await context.newPage();
await popup.goto(`/popup/${i}`);
}
// Close all except main page
for (const page of context.pages()) {
if (page !== mainPage) {
await page.close();
}
}
expect(context.pages()).toHaveLength(1);
});
Anti-Patterns to Avoid
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Not waiting for popup | Race condition | Use waitForEvent("popup") before trigger |
| Testing real OAuth | Slow, flaky, needs credentials | Mock OAuth endpoints |
| Assuming popup opens | May be blocked | Handle both open and blocked cases |
| Not closing extra pages | Resource leak | Close pages in cleanup |
Related References
- Authentication: See fixtures-hooks.md for auth patterns
- Network: See network-advanced.md for mocking OAuth