chore(test): remove dead old Playwright e2e suite (#28632)

The Playwright suite under tests/proxy_admin_ui_tests/e2e_ui_tests/ is no
longer wired into CI (only test_*.py is globbed) and every active spec is
duplicated by ui/litellm-dashboard/e2e_tests/tests/ (login, auth redirect,
search users, internal user list). team_admin.spec.ts was entirely
commented out. Removing the directory plus its only-used-here playwright
config, package.json/lock, and utils/login.ts keeps the canonical suite
under ui/litellm-dashboard/e2e_tests/ as the single source of truth.
This commit is contained in:
ryan-crabbe-berri 2026-05-22 11:29:17 -07:00 committed by GitHub
parent f62ae93e13
commit 643989989f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 0 additions and 978 deletions

View File

@ -1,51 +0,0 @@
/*
Login to Admin UI
Basic UI Test
Click on all the tabs ensure nothing is broken
*/
import { test, expect } from "@playwright/test";
test("admin login test", async ({ page }) => {
// Go to the specified URL
await page.goto("http://localhost:4000/ui");
await page.waitForLoadState("networkidle");
await page.screenshot({ path: "test-results/login_before.png" });
// Enter "admin" in the username input field
await page.fill('input[placeholder="Enter your username"]', "admin");
// Enter "gm" in the password input field
await page.fill('input[placeholder="Enter your password"]', "gm");
page.screenshot({ path: "test-results/login_after_inputs.png" });
// Optionally, you can add an assertion to verify the login button is enabled
const loginButton = page.getByRole("button", { name: "Login" });
await expect(loginButton).toBeEnabled();
// Optionally, you can click the login button to submit the form
await loginButton.click();
const tabs = [
"Virtual Keys",
"Playground",
"Models",
"Usage",
"Teams",
"Internal User",
"Settings",
"Experimental",
"API Reference",
"AI Hub",
];
for (const tab of tabs) {
const tabElement = page.locator("span.ant-menu-title-content", {
hasText: tab,
});
await tabElement.click();
}
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@ -1,37 +0,0 @@
// tests/auth.spec.ts
import { test, expect } from "@playwright/test";
test.describe("Authentication Checks", () => {
test("should redirect unauthenticated user from a protected page", async ({
page,
}) => {
test.setTimeout(30000);
page.on("console", (msg) => console.log("PAGE LOG:", msg.text()));
const protectedPageUrl = "http://localhost:4000/ui?page=llm-playground";
const expectedRedirectUrl = "http://localhost:4000/ui/login/";
console.log(
`Attempting to navigate to protected page: ${protectedPageUrl}`
);
await page.goto(protectedPageUrl);
console.log(`Navigation initiated. Current URL: ${page.url()}`);
try {
await page.waitForURL(expectedRedirectUrl, { timeout: 10000 });
console.log(`Waited for URL. Current URL is now: ${page.url()}`);
} catch (error) {
console.error(
`Timeout waiting for URL: ${expectedRedirectUrl}. Current URL: ${page.url()}`
);
await page.screenshot({ path: "redirect-fail-screenshot.png" });
throw error;
}
await expect(page).toHaveURL(expectedRedirectUrl);
console.log(`Assertion passed: Page URL is ${expectedRedirectUrl}`);
});
});

View File

@ -1,222 +0,0 @@
/*
Search Users in Admin UI
E2E Test for user search functionality
Tests:
1. Navigate to Internal Users tab
2. Verify search input exists
3. Test search functionality
4. Verify results update
5. Test filtering by email, user ID, and SSO user ID
*/
import { test, expect } from "@playwright/test";
test("user search test", async ({ page }) => {
// Set a longer timeout for the entire test
test.setTimeout(60000);
// Enable console logging
page.on("console", (msg) => console.log("PAGE LOG:", msg.text()));
// Login first
await page.goto("http://localhost:4000/ui");
await page.waitForLoadState("networkidle");
console.log("Navigated to login page");
page.screenshot({ path: "test-results/search_users_before_login.png" });
// Wait for login form to be visible
await page.waitForSelector('input[placeholder="Enter your username"]', {
timeout: 10000,
});
console.log("Login form is visible");
await page.fill('input[placeholder="Enter your username"]', "admin");
await page.fill('input[placeholder="Enter your password"]', "gm");
console.log("Filled login credentials");
const loginButton = page.getByRole("button", { name: "Login" });
await expect(loginButton).toBeEnabled();
await loginButton.click();
console.log("Clicked login button");
// Wait for navigation to complete and dashboard to load
await page.waitForLoadState("networkidle");
console.log("Page loaded after login");
// Take a screenshot for debugging
await page.screenshot({ path: "after-login.png" });
console.log("Took screenshot after login");
// Try to find the Internal User tab with more debugging
console.log("Looking for Internal User tab...");
const internalUserTab = page.locator("span.ant-menu-title-content", {
hasText: "Internal User",
});
// Wait for the tab to be visible
await internalUserTab.waitFor({ state: "visible", timeout: 10000 });
console.log("Internal User tab is visible");
// Take another screenshot before clicking
await page.screenshot({ path: "before-tab-click.png" });
console.log("Took screenshot before tab click");
await internalUserTab.click();
console.log("Clicked Internal User tab");
// Wait for the page to load and table to be visible
await page.waitForSelector("tbody tr", { timeout: 30000 });
await page.waitForTimeout(2000); // Additional wait for table to stabilize
console.log("Table is visible");
// Take a final screenshot
await page.screenshot({ path: "after-tab-click.png" });
console.log("Took screenshot after tab click");
// Verify search input exists
const searchInput = page.locator('input[placeholder="Search by email..."]');
await expect(searchInput).toBeVisible();
console.log("Search input is visible");
// Test search functionality
const initialUserCount = await page.locator("tbody tr").count();
console.log(`Initial user count: ${initialUserCount}`);
// Perform a search
const testEmail = "test@";
await searchInput.fill(testEmail);
console.log("Filled search input");
// Wait for the debounced search to complete
await page.waitForTimeout(500);
console.log("Waited for debounce");
// Wait for the results count to update
await page.waitForFunction((initialCount) => {
const currentCount = document.querySelectorAll("tbody tr").length;
return currentCount !== initialCount;
}, initialUserCount);
console.log("Results updated");
const filteredUserCount = await page.locator("tbody tr").count();
console.log(`Filtered user count: ${filteredUserCount}`);
expect(filteredUserCount).toBeDefined();
// Clear the search
await searchInput.clear();
console.log("Cleared search");
await page.waitForTimeout(500);
console.log("Waited for debounce after clear");
await page.waitForFunction((initialCount) => {
const currentCount = document.querySelectorAll("tbody tr").length;
return currentCount === initialCount;
}, initialUserCount);
console.log("Results reset");
const resetUserCount = await page.locator("tbody tr").count();
console.log(`Reset user count: ${resetUserCount}`);
expect(resetUserCount).toBe(initialUserCount);
});
test("user filter test", async ({ page }) => {
// Set a longer timeout for the entire test
test.setTimeout(60000);
// Enable console logging
page.on("console", (msg) => console.log("PAGE LOG:", msg.text()));
// Login first
await page.goto("http://localhost:4000/ui");
await page.waitForLoadState("networkidle");
console.log("Navigated to login page");
// Wait for login form to be visible
await page.waitForSelector('input[placeholder="Enter your username"]', {
timeout: 10000,
});
console.log("Login form is visible");
await page.fill('input[placeholder="Enter your username"]', "admin");
await page.fill('input[placeholder="Enter your password"]', "gm");
console.log("Filled login credentials");
const loginButton = page.getByRole("button", { name: "Login" });
await expect(loginButton).toBeEnabled();
await loginButton.click();
console.log("Clicked login button");
// Wait for navigation to complete and dashboard to load
await page.waitForLoadState("networkidle");
console.log("Page loaded after login");
// Navigate to Internal Users tab
const internalUserTab = page.locator("span.ant-menu-title-content", {
hasText: "Internal User",
});
await internalUserTab.waitFor({ state: "visible", timeout: 10000 });
await internalUserTab.click();
console.log("Clicked Internal User tab");
// Wait for the page to load and table to be visible
await page.waitForSelector("tbody tr", { timeout: 30000 });
await page.waitForTimeout(2000); // Additional wait for table to stabilize
console.log("Table is visible");
// Get initial user count
const initialUserCount = await page.locator("tbody tr").count();
console.log(`Initial user count: ${initialUserCount}`);
// Click the filter button to show additional filters
const filterButton = page.getByRole("button", {
name: "Filters",
exact: true,
});
await filterButton.click();
console.log("Clicked filter button");
await page.waitForTimeout(500); // Wait for filters to appear
// Test user ID filter
const userIdInput = page.locator('input[placeholder="Filter by User ID"]');
await expect(userIdInput).toBeVisible();
console.log("User ID filter is visible");
await userIdInput.fill("user");
console.log("Filled user ID filter");
await page.waitForTimeout(1000);
const userIdFilteredCount = await page.locator("tbody tr").count();
console.log(`User ID filtered count: ${userIdFilteredCount}`);
expect(userIdFilteredCount).toBeLessThan(initialUserCount);
// Clear user ID filter
await userIdInput.clear();
await page.waitForTimeout(1000);
console.log("Cleared user ID filter");
// Test SSO user ID filter
const ssoUserIdInput = page.locator('input[placeholder="Filter by SSO ID"]');
await expect(ssoUserIdInput).toBeVisible();
console.log("SSO user ID filter is visible");
await ssoUserIdInput.fill("sso");
console.log("Filled SSO user ID filter");
await page.waitForTimeout(1000);
const ssoUserIdFilteredCount = await page.locator("tbody tr").count();
console.log(`SSO user ID filtered count: ${ssoUserIdFilteredCount}`);
expect(ssoUserIdFilteredCount).toBeLessThan(initialUserCount);
// Clear SSO user ID filter
await ssoUserIdInput.clear();
await page.waitForTimeout(5000);
console.log("Cleared SSO user ID filter");
// Verify count returns to initial after clearing all filters
const finalUserCount = await page.locator("tbody tr").count();
console.log(`Final user count: ${finalUserCount}`);
expect(finalUserCount).toBe(initialUserCount);
});

View File

@ -1,250 +0,0 @@
import { test, expect } from "@playwright/test";
import { loginToUI } from "../utils/login";
// test.describe("Invite User, Set Password, and Login", () => {
// let testEmail: string;
// const testPassword = "Password123!"; // Define a password
// const teamName1 = `team-invite-test-1-${Date.now()}`;
// const teamName2 = `team-invite-test-2-${Date.now()}`;
// const keyName1 = `key-${teamName1}`;
// const keyName2 = `key-${teamName2}`;
// test.beforeEach(async ({ page }) => {
// await loginToUI(page); // Login as admin first
// await page.goto("http://localhost:4000/ui?page=teams");
// // --- Create Team 1 ---
// await page.getByRole("button", { name: "+ Create New Team" }).click();
// await page
// .getByLabel("Team Name")
// .waitFor({ state: "visible", timeout: 5000 }); // Wait for label
// await page.getByLabel("Team Name").click();
// await page.getByLabel("Team Name").fill(teamName1);
// await page.getByRole("button", { name: "Create Team" }).click();
// // Wait for the modal to close or for a success message if applicable
// await expect(
// page.locator(".ant-modal-wrap").filter({ hasText: "Create New Team" })
// ).not.toBeVisible({ timeout: 10000 });
// console.log(`Created Team 1: ${teamName1}`);
// // --- Create Team 2 ---
// await page.getByRole("button", { name: "+ Create New Team" }).click();
// await page
// .getByLabel("Team Name")
// .waitFor({ state: "visible", timeout: 5000 }); // Wait for label
// await page.getByLabel("Team Name").click();
// await page.getByLabel("Team Name").fill(teamName2);
// await page.getByRole("button", { name: "Create Team" }).click();
// // Wait for the modal to close or for a success message if applicable
// await expect(
// page.locator(".ant-modal-wrap").filter({ hasText: "Create New Team" })
// ).not.toBeVisible({ timeout: 10000 });
// console.log(`Created Team 2: ${teamName2}`);
// // // Verify both teams are listed
// // await page.goto("http://localhost:4000/ui?page=teams"); // Refresh or ensure on teams page
// // await page.waitForTimeout(3000);
// await expect(page.getByText(teamName1)).toBeVisible({ timeout: 10000 });
// await expect(page.getByText(teamName2)).toBeVisible({ timeout: 10000 });
// // --- Navigate to Keys Page ---
// await page.goto("http://localhost:4000/ui?page=api-keys");
// await page.waitForTimeout(3000);
// await expect(
// page.getByRole("button", { name: "+ Create New Key" })
// ).toBeVisible(); // Wait for page load
// // --- Create Key for Team 1 ---
// await page.getByRole("button", { name: "+ Create New Key" }).click();
// const createKeyModal1 = page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Key Ownership" });
// await expect(createKeyModal1).toBeVisible();
// // Select Team 1
// await createKeyModal1
// .locator(".ant-select-selector >> input")
// .first()
// .click(); // Click to open team dropdown
// await createKeyModal1
// .locator(".ant-select-selector >> input")
// .first()
// .fill(teamName1);
// await page
// .locator(".ant-select-item-option")
// .filter({ hasText: teamName1 })
// .first()
// .click(); // Click specific team name
// // Enter Key Name 1
// await page.fill('input[id="key_alias"]', keyName1);
// // Click on models dropdown
// await page.locator("input#models").click();
// await page.waitForSelector(
// '.ant-select-item-option[title="All Team Models"]'
// );
// await page
// .locator('.ant-select-item-option[title="All Team Models"]')
// .click();
// // Click Create Key
// await createKeyModal1.getByRole("button", { name: "Create Key" }).click();
// // Close the Key Generated modal (which appears after successful creation)
// const keyGeneratedModal1 = page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Save your Key" });
// await expect(keyGeneratedModal1).toBeVisible({ timeout: 10000 });
// await keyGeneratedModal1.locator('button[aria-label="Close"]').click();
// await expect(keyGeneratedModal1).not.toBeVisible(); // Wait for close
// console.log(`Created Key 1: ${keyName1} for Team: ${teamName1}`);
// // --- Create Key for Team 2 ---
// await page.getByRole("button", { name: "+ Create New Key" }).click();
// const createKeyModal2 = page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Key Ownership" });
// await expect(createKeyModal2).toBeVisible();
// // Select Team 2
// await createKeyModal2
// .locator(".ant-select-selector >> input")
// .first()
// .click(); // Click to open team dropdown
// await page
// .locator(".ant-select-item-option")
// .filter({ hasText: teamName2 })
// .click(); // Click specific team name
// // Enter Key Name 2
// await page.fill('input[id="key_alias"]', keyName2);
// // Click on models dropdown
// await page.locator("input#models").click();
// await page.waitForSelector(
// '.ant-select-item-option[title="All Team Models"]'
// );
// await page
// .locator('.ant-select-item-option[title="All Team Models"]')
// .click();
// // Click Create Key
// await createKeyModal2.getByRole("button", { name: "Create Key" }).click();
// // Close the Key Generated modal
// const keyGeneratedModal2 = page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Save your Key" });
// await expect(keyGeneratedModal2).toBeVisible({ timeout: 10000 });
// await keyGeneratedModal2.locator('button[aria-label="Close"]').click();
// await expect(keyGeneratedModal2).not.toBeVisible(); // Wait for close
// console.log(`Created Key 2: ${keyName2} for Team: ${teamName2}`);
// });
// test("Invite user, set password via link, and login", async ({ page }) => {
// // Navigate to Users page
// await page.goto("http://localhost:4000/ui?page=users");
// // Go to Internal User tab
// const internalUserTab = page.locator("span.ant-menu-title-content", {
// hasText: "Internal User",
// });
// await internalUserTab.waitFor({ state: "visible", timeout: 10000 });
// await internalUserTab.click();
// // --- Invite User Flow ---
// await page.getByRole("button", { name: "+ Invite User" }).click();
// // Wait for the invite user modal to be visible
// const inviteModal = page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Invite User" });
// await expect(inviteModal).toBeVisible();
// testEmail = `test-${Date.now()}@litellm.ai`; // Use a unique email
// // Assuming the email input is the first one with 'base-input' test id inside the modal
// await inviteModal.getByTestId("base-input").first().fill(testEmail);
// // Select Global Admin Role (or another appropriate role)
// const globalRoleLabel = inviteModal.getByLabel("Global Proxy Role");
// await globalRoleLabel.click();
// // Wait for the dropdown option to be visible before clicking
// const adminRoleOption = page.getByTitle("Admin (All Permissions)", {
// exact: true,
// });
// await adminRoleOption.waitFor({ state: "visible", timeout: 5000 });
// await adminRoleOption.click();
// // Select Team - Add explicit wait before clicking
// const teamIdLabel = inviteModal.getByLabel("Team ID");
// // Wait for the label associated with the Team ID select to be visible
// await teamIdLabel.waitFor({ state: "visible", timeout: 10000 }); // Increased timeout for safety
// await teamIdLabel.click();
// // Wait for the team name option to be visible in the dropdown
// const teamNameOption = page.getByText(teamName1, { exact: true });
// await teamNameOption.waitFor({ state: "visible", timeout: 5000 });
// await teamNameOption.click();
// // Create User
// await inviteModal.getByRole("button", { name: "Create User" }).click();
// // --- Capture Invitation Link ---
// const invitationModal = page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Invitation Link" });
// await expect(invitationModal).toBeVisible({ timeout: 15000 }); // Wait longer for modal
// // Locate the text element containing the URL more reliably
// const invitationUrl = await page
// .locator("div.flex.justify-between.pt-5.pb-2") // find the correct div
// .filter({ hasText: "Invitation Link" }) // find the div that has text "Invitation Link"
// .locator("p") // find all <p> inside that div
// .nth(1) // pick the second <p> (index 1)
// .innerText();
// // Close Invitation Link Modal
// await page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Invitation Link" })
// .locator('button[aria-label="Close"]')
// .click();
// // Close Invite User Modal
// await page
// .locator(".ant-modal-wrap")
// .filter({ hasText: "Invite User" })
// .locator('button[aria-label="Close"]')
// .click();
// // Open invite link as new page (simulate invited user)
// const context = await page.context()?.browser()?.newContext();
// const invitedUserPage = await context?.newPage();
// if (!invitedUserPage) {
// throw new Error("invitedUserPage is undefined");
// }
// await invitedUserPage?.goto(invitationUrl || "");
// //Insert new password
// await invitedUserPage?.fill("input#password", testPassword);
// //Click on submit
// await invitedUserPage?.getByRole("button", { name: "Sign Up" }).click();
// // // --- Verify Keys Created ---
// // await invitedUserPage?.waitForSelector("table");
// // // Verify keyName1 (associated with user's team) IS visible in the table
// // const keyTable = invitedUserPage.locator('table'); // Locate the table element
// // await expect(keyTable).toBeVisible({ timeout: 10000 }); // Ensure table exists
// // // Use getByText within the table scope to find the key name
// // await expect(keyTable.getByText(keyName1, { exact: true })).toBeVisible({ timeout: 10000 });
// // console.log(`Verified key ${keyName1} is visible for user ${testEmail}`);
// // // Verify keyName2 (associated with the *other* team) IS NOT visible
// // await expect(keyTable.getByText(keyName2, { exact: true })).not.toBeVisible();
// // console.log(`Verified key ${keyName2} is NOT visible for user ${testEmail}`);
// });
// });

View File

@ -1,72 +0,0 @@
/*
Test view internal user page
*/
import { test, expect } from "@playwright/test";
test("view internal user page", async ({ page }) => {
// Go to the specified URL
await page.goto("http://localhost:4000/ui");
await page.waitForLoadState("networkidle");
page.screenshot({ path: "test-results/view_internal_user_before_login.png" });
// Enter "admin" in the username input field
await page.fill('input[placeholder="Enter your username"]', "admin");
// Enter "gm" in the password input field
await page.fill('input[placeholder="Enter your password"]', "gm");
// Click the login button
const loginButton = page.getByRole("button", { name: "Login" });
await expect(loginButton).toBeEnabled();
await loginButton.click();
// Wait for the Internal User tab and click it
const tabElement = page.locator("span.ant-menu-title-content", {
hasText: "Internal User",
});
await tabElement.click();
// Wait for the table to load
await page.waitForSelector("tbody tr", { timeout: 10000 });
await page.waitForTimeout(2000); // Additional wait for table to stabilize
await page.waitForLoadState("networkidle");
// Test all expected fields are present
// Verify that the API Keys column is rendered for all users
// The UI renders badges in each row - we just verify the column structure exists
const rowCount = await page.locator("tbody tr").count();
expect(rowCount).toBeGreaterThan(0);
const userIdHeader = await page.locator("th", { hasText: "User ID" });
await expect(userIdHeader).toBeVisible({ timeout: 10000 });
// test pagination
// Wait for pagination controls to be visible
await page.waitForSelector(".flex.justify-between.items-center", {
timeout: 5000,
});
// Check if we're on the first page by looking at the results count
const resultsText =
(await page.locator(".text-sm.text-gray-700").textContent()) || "";
const isFirstPage = resultsText.includes("1 -");
if (isFirstPage) {
// On first page, previous button should be disabled
const prevButton = page.locator("button", { hasText: "Previous" });
await expect(prevButton).toBeDisabled();
}
// Next button should be enabled if there are more pages
const nextButton = page.locator("button", { hasText: "Next" });
const totalResults =
(await page.locator(".text-sm.text-gray-700").textContent()) || "";
const hasMorePages =
totalResults.includes("of") && !totalResults.includes("1 - 25 of 25");
if (hasMorePages) {
await expect(nextButton).toBeEnabled();
}
});

View File

@ -1,124 +0,0 @@
import { test, expect } from "@playwright/test";
import { loginToUI } from "../utils/login";
test.describe("User Info View", () => {
test("should display user info when clicking on user ID", async ({
page,
}) => {
await page.goto("http://localhost:4000/ui");
await page.waitForLoadState("networkidle");
page.screenshot({
path: "test-results/view_user_info_before_login.png",
});
// Enter "admin" in the username input field
await page.fill('input[placeholder="Enter your username"]', "admin");
page.screenshot({
path: "test-results/view_user_info_after_username_input.png",
});
// Enter "gm" in the password input field
await page.fill('input[placeholder="Enter your password"]', "gm");
page.screenshot({
path: "test-results/view_user_info_after_password_input.png",
});
// Click the login button
const loginButton = page.getByRole("button", { name: "Login" });
await expect(loginButton).toBeEnabled();
await loginButton.click();
page.screenshot({
path: "test-results/view_user_info_after_login_button_click.png",
});
// Wait for navigation to complete and dashboard to load
await page.waitForLoadState("networkidle");
const tabElement = page.locator("span.ant-menu-title-content", {
hasText: "Internal User",
});
await tabElement.click();
page.screenshot({
path: "test-results/view_user_info_after_internal_user_tab_click.png",
});
// Wait for loading state to disappear
await page.waitForSelector('text="🚅 Loading users..."', {
state: "hidden",
timeout: 10000,
});
page.screenshot({ path: "test-results/view_user_info_after_loading.png" });
// Wait for users table to load
await page.waitForSelector("table");
page.screenshot({
path: "test-results/view_user_info_after_table_load.png",
});
// Get the first user ID cell
const firstUserIdCell = page.locator(
"table tbody tr:first-child td:first-child"
);
const userId = await firstUserIdCell.textContent();
console.log("Found user ID:", userId);
// Click on the user ID
await firstUserIdCell.click();
await page.waitForLoadState("networkidle");
// Check for tabs
await expect(page.locator('button:has-text("Overview")')).toBeVisible({
timeout: 10000,
});
await expect(page.locator('button:has-text("Details")')).toBeVisible({
timeout: 10000,
});
// Switch to details tab
await page.locator('button:has-text("Details")').click();
// Check details section
await expect(page.locator("text=User ID")).toBeVisible();
await expect(page.locator("text=Email")).toBeVisible();
// Go back to users list
await page.locator('button:has-text("Back to Users")').click();
// Verify we're back on the users page
await expect(page.locator("table")).toBeVisible();
await expect(
page.locator('input[placeholder="Search by email..."]')
).toBeVisible();
});
// test("should handle user deletion", async ({ page }) => {
// // Wait for users table to load
// await page.waitForSelector("table");
// // Get the first user ID cell
// const firstUserIdCell = page.locator(
// "table tbody tr:first-child td:first-child"
// );
// const userId = await firstUserIdCell.textContent();
// // Click on the user ID
// await firstUserIdCell.click();
// // Wait for user info view to load
// await page.waitForSelector('h1:has-text("User")');
// // Click delete button
// await page.locator('button:has-text("Delete User")').click();
// // Confirm deletion in modal
// await page.locator('button:has-text("Delete")').click();
// // Verify success message
// await expect(page.locator("text=User deleted successfully")).toBeVisible();
// // Verify we're back on the users page
// await expect(page.locator('h1:has-text("Users")')).toBeVisible();
// // Verify user is no longer in the table
// if (userId) {
// await expect(page.locator(`text=${userId}`)).not.toBeVisible();
// }
// });
});

View File

@ -1,97 +0,0 @@
{
"name": "proxy_admin_ui_tests",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "proxy_admin_ui_tests",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.47.2",
"@types/node": "^22.5.5"
}
},
"node_modules/@playwright/test": {
"version": "1.56.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
"integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.56.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@types/node": {
"version": "22.19.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz",
"integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/playwright": {
"version": "1.56.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
"integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.56.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.56.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
}
}
}

View File

@ -1,14 +0,0 @@
{
"name": "proxy_admin_ui_tests",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "1.56.1",
"@types/node": "22.19.1"
}
}

View File

@ -1,84 +0,0 @@
import { defineConfig, devices } from '@playwright/test';
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './e2e_ui_tests',
testIgnore: ['**/tests/pass_through_tests/**', '../pass_through_tests/**/*'],
testMatch: '**/*.spec.ts', // Only run files ending in .spec.ts
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
timeout: 4*60*1000,
expect: {
timeout: 10 * 1000
}
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// url: 'http://127.0.0.1:3000',
// reuseExistingServer: !process.env.CI,
// },
});

View File

@ -1,27 +0,0 @@
import { Page, expect } from "@playwright/test";
export async function loginToUI(page: Page) {
// Login first
await page.goto("http://localhost:4000/ui");
await page.waitForLoadState("networkidle");
console.log("Navigated to login page");
page.screenshot({ path: "test-results/login_utils_before.png" });
// Wait for login form to be visible
await page.waitForSelector('input[placeholder="Enter your username"]', {
timeout: 10000,
});
console.log("Login form is visible");
await page.fill('input[placeholder="Enter your username"]', "admin");
await page.fill('input[placeholder="Enter your password"]', "gm");
console.log("Filled login credentials");
const loginButton = page.getByRole("button", { name: "Login" });
await expect(loginButton).toBeEnabled();
await loginButton.click();
console.log("Clicked login button");
// Wait for navigation to complete
await page.waitForURL("**/*");
}