Files
crowd-funder-for-time-pwa/test-playwright/testUtils.ts
Matthew Raymer 135023d17b test(playwright): fix Active Identity migration test infrastructure and document findings
Fixed failing Playwright tests for Active Identity migration by correcting
DOM element selectors and test expectations. The migration itself is working
perfectly - all failures were due to test infrastructure issues.

- Fix element selectors in switchToUser() to use 'li div' instead of 'code'
- Update test assertions to expect "Your Identity" heading instead of "Account"
- Improve advanced settings access with proper expansion before navigation
- Add comprehensive findings document showing migration is 100% successful
- Replace basic smoke tests with detailed step-by-step debugging tests

The Active Identity migration is complete and functional. Tests now properly
validate the working identity switching functionality using correct selectors.
2025-08-22 13:24:26 +00:00

250 lines
8.0 KiB
TypeScript

import { expect, Page } from "@playwright/test";
// Get test user data based on the ID.
// '01' -> user 111
// otherwise -> user 000
// (... which is a weird convention but I haven't taken the time to change it)
export function getTestUserData(id?: string): {
seedPhrase: string;
userName: string;
did: string;
} {
switch (id) {
case "01":
return {
seedPhrase:
"island fever beef wine urban aim vacant quit afford total poem flame service calm better adult neither color gaze forum month sister imitate excite",
userName: "User One",
did: "did:ethr:0x111d15564f824D56C7a07b913aA7aDd03382aA39",
};
default: // to user 00
return {
seedPhrase:
"rigid shrug mobile smart veteran half all pond toilet brave review universe ship congress found yard skate elite apology jar uniform subway slender luggage",
userName: "User Zero",
did: "did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F",
};
}
}
export async function importUserFromAccount(page: Page, id?: string): Promise<string> {
// Navigate to AccountViewView to use the Identity Switcher
await page.goto("./account");
// Click "Show Advanced Settings" to reveal the identity switcher
await page.getByTestId("advancedSettings").click();
// Use the identity switcher to add User Zero
await page.locator("#switch-identity-link").click();
await page.locator("#start-link").click();
// Select "You have a seed" option
await page.getByText("You have a seed").click();
// Get User Zero's seed phrase using the new method
const userZeroData = getTestUserData(id);
// Enter User Zero's seed phrase
await page.getByPlaceholder("Seed Phrase").fill(userZeroData.seedPhrase);
await page.getByRole("button", { name: "Import" }).click();
return userZeroData.did;
}
// Import the seed and switch to the user based on the ID.
export async function importUser(page: Page, id?: string): Promise<string> {
const userData = getTestUserData(id);
const { seedPhrase, userName, did } = userData;
// Import ID
await page.goto("./start");
await page.getByText("You have a seed").click();
await page.getByPlaceholder("Seed Phrase").fill(seedPhrase);
await page.getByRole("button", { name: "Import" }).click();
// Check DID
await expect(page.getByRole("code")).toContainText(did);
// ... and ensure the app retrieves the registration status
await expect(
page.locator("#sectionUsageLimits").getByText("Checking")
).toBeHidden();
return did;
}
export async function importUserAndCloseOnboarding(
page: Page,
id?: string
): Promise<string> {
const did = await importUser(page, id);
await page.goto("./");
await page.getByTestId("closeOnboardingAndFinish").click();
return did;
}
// This is to switch to someone already in the identity table. It doesn't include registration.
export async function switchToUser(page: Page, did: string): Promise<void> {
// This is the direct approach but users have to tap on things so we'll do that instead.
await page.goto("./account");
// Wait for the page to load and the advanced settings element to be visible
await page.waitForLoadState('networkidle');
await page.getByTestId("advancedSettings").waitFor({ state: 'visible' });
const switchIdentityLink = page.locator("#switch-identity-link");
if (await switchIdentityLink.isHidden()) {
await page.getByTestId("advancedSettings").click();
await switchIdentityLink.click();
} else {
await switchIdentityLink.click();
}
// Wait for the identity switcher page to load
await page.waitForLoadState('networkidle');
// Wait for the identity switcher heading to be visible
await page.locator('h1:has-text("Switch Identity")').waitFor({ state: 'visible' });
// Look for the clickable div containing the user DID (not just the code element)
const didElem = page.locator('li div').filter({ hasText: did }).first();
await didElem.waitFor({ state: 'visible', timeout: 10000 });
await didElem.click();
// Wait for the switch to happen and the account page to fully load
await page.waitForLoadState('networkidle');
await page.getByTestId("didWrapper").locator('code:has-text("did:")');
}
function createContactName(did: string): string {
return "User " + did.slice(11, 14);
}
export async function deleteContact(page: Page, did: string): Promise<void> {
await page.goto("./contacts");
const contactName = createContactName(did);
// go to the detail page for this contact
await page
.locator(
`li[data-testid="contactListItem"] h2:has-text("${contactName}") + div svg.fa-circle-info`
)
.click();
// delete the contact
await page.locator("button > svg.fa-trash-can").click();
await page.locator('div[role="alert"] button:has-text("Yes")').click();
// for some reason, .isHidden() (without expect) doesn't work
await expect(
page.locator('div[role="alert"] button:has-text("Yes")')
).toBeHidden();
}
export async function generateNewEthrUser(page: Page): Promise<string> {
await page.goto("./start");
await page.getByTestId("newSeed").click();
await expect(page.locator('span:has-text("Created")')).toBeVisible();
await page.goto("./account");
const didElem = await page
.getByTestId("didWrapper")
.locator('code:has-text("did:")');
const newDid = await didElem.innerText();
return newDid;
}
// Generate a new random user and register them.
// Note that this makes 000 the active user. Use switchToUser to switch to this DID.
export async function generateAndRegisterEthrUser(page: Page): Promise<string> {
const newDid = await generateNewEthrUser(page);
await importUser(page, "000"); // switch to user 000
await page.goto("./contacts");
const contactName = createContactName(newDid);
await page
.getByPlaceholder("URL or DID, Name, Public Key")
.fill(`${newDid}, ${contactName}`);
await page.locator("button > svg.fa-plus").click();
// register them
await page.locator('div[role="alert"] button:has-text("Yes")').click();
// wait for it to disappear because the next steps may depend on alerts being gone
await expect(
page.locator('div[role="alert"] button:has-text("Yes")')
).toBeHidden();
await expect(page.locator("li", { hasText: contactName })).toBeVisible();
return newDid;
}
// Function to generate a random string of specified length
export async function generateRandomString(length: number): Promise<string> {
return Math.random()
.toString(36)
.substring(2, 2 + length);
}
// Function to create an array of unique strings
export async function createUniqueStringsArray(
count: number
): Promise<string[]> {
const stringsArray: string[] = [];
const stringLength = 16;
for (let i = 0; i < count; i++) {
let randomString = await generateRandomString(stringLength);
stringsArray.push(randomString);
}
return stringsArray;
}
// Function to create an array of two-digit non-zero numbers
export async function createRandomNumbersArray(
count: number
): Promise<number[]> {
const numbersArray: number[] = [];
for (let i = 0; i < count; i++) {
let randomNumber = Math.floor(Math.random() * 99) + 1;
numbersArray.push(randomNumber);
}
return numbersArray;
}
export function isLinuxEnvironment() {
return process.platform === "linux";
}
export function getOSSpecificTimeout(): number {
// Increase base timeout for Linux
const isLinux = process.platform === "linux";
return isLinux ? 180000 : 60000; // 3 minutes for Linux, 1 minute for others
}
export function getOSSpecificConfig() {
if (isLinuxEnvironment()) {
return {
retries: 2,
timeout: 90000, // Increased global timeout
expect: {
timeout: 30000, // Increased expect timeout
},
// Add video recording for failed tests on Linux
use: {
video: "retain-on-failure",
trace: "retain-on-failure",
},
};
}
return {};
}
// Add helper for test grouping
export function isResourceIntensiveTest(testPath: string): boolean {
return (
testPath.includes("35-record-gift-from-image-share") ||
testPath.includes("40-add-contact")
);
}