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:
parent
f62ae93e13
commit
643989989f
@ -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 |
@ -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}`);
|
||||
});
|
||||
});
|
||||
@ -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);
|
||||
});
|
||||
@ -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}`);
|
||||
// });
|
||||
// });
|
||||
@ -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();
|
||||
}
|
||||
});
|
||||
@ -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();
|
||||
// }
|
||||
// });
|
||||
});
|
||||
97
tests/proxy_admin_ui_tests/package-lock.json
generated
97
tests/proxy_admin_ui_tests/package-lock.json
generated
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
// },
|
||||
});
|
||||
@ -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("**/*");
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user