You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
10 KiB
277 lines
10 KiB
import { expect, Page } from '@playwright/test';
|
|
|
|
// Import the seed and switch to the user 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 async function importUser(page: Page, id?: string): Promise<string> {
|
|
let seedPhrase, userName, did;
|
|
|
|
// Set seed phrase and DID based on user ID
|
|
switch(id) {
|
|
case '01':
|
|
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';
|
|
break;
|
|
default: // to user 00
|
|
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';
|
|
}
|
|
|
|
// 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('./identity-switcher');
|
|
|
|
await page.goto('./account');
|
|
await page.getByRole('heading', { name: 'Advanced' }).click();
|
|
await page.getByRole('link', { name: 'Switch Identifier' }).click();
|
|
const didElem = await page.locator(`code:has-text("${did}")`);
|
|
await didElem.isVisible();
|
|
await didElem.click();
|
|
// wait for the switch to happen and the account page to fully load
|
|
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, contactName: string) {
|
|
// Navigate to contacts page
|
|
await page.goto('./contacts');
|
|
|
|
// Wait for page to load completely
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Check if we need to hide the "Show Actions" view first
|
|
const loadingCount = await page.locator('.loading-indicator').count();
|
|
if (loadingCount > 0) {
|
|
await page.locator('.loading-indicator').first().waitFor({ state: 'hidden' });
|
|
}
|
|
|
|
// Check if "Hide Actions" button exists (meaning we're in the give numbers view)
|
|
const showGiveNumbersExists = await page.getByRole('button', { name: 'Hide Actions' }).count();
|
|
if (showGiveNumbersExists > 0) {
|
|
await page.getByRole('button', { name: 'Hide Actions' }).click();
|
|
}
|
|
|
|
// Look for the contact by name
|
|
const contactItems = page.locator('li[data-testid="contactListItem"]');
|
|
const contactCount = await contactItems.count();
|
|
|
|
// Debug: Print all contact names if no match found
|
|
if (contactCount === 0) {
|
|
await page.screenshot({ path: 'debug-no-contacts.png' });
|
|
throw new Error(`No contacts found on page. Screenshot saved as debug-no-contacts.png`);
|
|
}
|
|
|
|
// Check if our contact exists
|
|
const contactExists = await contactItems.filter({ hasText: contactName }).count();
|
|
if (contactExists === 0) {
|
|
// Try alternative selectors
|
|
const selectors = [
|
|
'li',
|
|
'div[data-testid="contactListItem"]',
|
|
'.contact-item',
|
|
'[data-testid*="contact"]'
|
|
];
|
|
|
|
for (const selector of selectors) {
|
|
const testCount = await page.locator(selector).filter({ hasText: contactName }).count();
|
|
if (testCount > 0) {
|
|
// Found working selector, use it
|
|
const contactItem = page.locator(selector).filter({ hasText: contactName }).first();
|
|
|
|
// Look for info icon or delete button
|
|
const infoIconExists = await contactItem.locator('svg.fa-info-circle').count();
|
|
if (infoIconExists > 0) {
|
|
await contactItem.locator('svg.fa-info-circle').click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Should now be on the contact detail page
|
|
await expect(page.getByText('Contact Details')).toBeVisible();
|
|
|
|
// Look for delete button
|
|
const deleteButtonExists = await page.getByRole('button', { name: 'Delete Contact' }).count();
|
|
if (deleteButtonExists > 0) {
|
|
await page.getByRole('button', { name: 'Delete Contact' }).click();
|
|
|
|
// Handle confirmation dialog
|
|
await expect(page.getByRole('button', { name: 'Yes, Delete' })).toBeVisible();
|
|
await page.getByRole('button', { name: 'Yes, Delete' }).click();
|
|
|
|
// Wait for dialog to close
|
|
await expect(page.getByRole('button', { name: 'Yes, Delete' })).toBeHidden();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new Error(`Contact "${contactName}" not found on contacts page`);
|
|
}
|
|
|
|
// Use the standard flow
|
|
const contactItem = contactItems.filter({ hasText: contactName }).first();
|
|
|
|
// Look for info icon
|
|
const infoIconExists = await contactItem.locator('svg.fa-info-circle').count();
|
|
if (infoIconExists > 0) {
|
|
await contactItem.locator('svg.fa-info-circle').click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Should now be on the contact detail page
|
|
await expect(page.getByText('Contact Details')).toBeVisible();
|
|
|
|
// Look for delete button
|
|
const deleteButtonExists = await page.getByRole('button', { name: 'Delete Contact' }).count();
|
|
if (deleteButtonExists > 0) {
|
|
await page.getByRole('button', { name: 'Delete Contact' }).click();
|
|
|
|
// Handle confirmation dialog
|
|
await expect(page.getByRole('button', { name: 'Yes, Delete' })).toBeVisible();
|
|
await page.getByRole('button', { name: 'Yes, Delete' }).click();
|
|
|
|
// Wait for dialog to close
|
|
await expect(page.getByRole('button', { name: 'Yes, Delete' })).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);
|
|
|
|
const contactInput = `${newDid}, ${contactName}`;
|
|
|
|
await page.getByPlaceholder('URL or DID, Name, Public Key').fill(contactInput);
|
|
await page.locator('button > svg.fa-plus').click();
|
|
|
|
// Wait for the contact to be added first
|
|
await expect(page.locator('li', { hasText: contactName })).toBeVisible();
|
|
|
|
// Wait longer for the registration alert to appear (it has a 1-second timeout)
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Check if the registration alert is present
|
|
const alertCount = await page.locator('div[role="alert"]').count();
|
|
|
|
if (alertCount > 0) {
|
|
// Check if this is a registration alert (contains "Yes" button)
|
|
const yesButtonCount = await page.locator('div[role="alert"] button:has-text("Yes")').count();
|
|
if (yesButtonCount > 0) {
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
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');
|
|
}
|
|
|