forked from trent_larson/crowd-funder-for-time-pwa
feat: Add comprehensive debugging to deleteContact function
- Fix font-awesome selector to try multiple variations - Add detailed logging for contact discovery and DOM elements - Add screenshot capture when no contacts found - Add UI state detection (loading, filters) - Fix TypeScript typing issues for proper null safety This should help identify why contacts aren't being found during deletion in the failing Playwright test.
This commit is contained in:
@@ -60,15 +60,130 @@ function createContactName(did: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteContact(page: Page, did: string): Promise<void> {
|
export async function deleteContact(page: Page, did: string): Promise<void> {
|
||||||
|
console.log('[DEBUG] deleteContact: Starting deletion for DID:', did);
|
||||||
|
|
||||||
await page.goto('./contacts');
|
await page.goto('./contacts');
|
||||||
|
console.log('[DEBUG] deleteContact: Navigated to contacts page');
|
||||||
|
|
||||||
|
// Wait for the page to load completely
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
console.log('[DEBUG] deleteContact: Page load completed');
|
||||||
|
|
||||||
|
// Check if there are any loading indicators or filters active
|
||||||
|
const loadingIndicator = page.locator('[data-testid*="loading"], .loading, .spinner');
|
||||||
|
const loadingCount = await loadingIndicator.count();
|
||||||
|
console.log('[DEBUG] deleteContact: Loading indicators found:', loadingCount);
|
||||||
|
|
||||||
|
// Check for any filter or state buttons that might be active
|
||||||
|
const showGiveNumbers = page.locator('button:has-text("Hide Actions")');
|
||||||
|
const showGiveNumbersExists = await showGiveNumbers.count();
|
||||||
|
console.log('[DEBUG] deleteContact: "Hide Actions" button exists (showing give numbers):', showGiveNumbersExists > 0);
|
||||||
|
|
||||||
|
if (showGiveNumbersExists > 0) {
|
||||||
|
console.log('[DEBUG] deleteContact: Clicking "Hide Actions" to show normal view');
|
||||||
|
await showGiveNumbers.click();
|
||||||
|
await page.waitForTimeout(1000); // Wait for UI to update
|
||||||
|
}
|
||||||
|
|
||||||
const contactName = createContactName(did);
|
const contactName = createContactName(did);
|
||||||
|
console.log('[DEBUG] deleteContact: Looking for contact with name:', contactName);
|
||||||
|
|
||||||
|
// First, let's see what contacts are actually on the page
|
||||||
|
const contactItems = await page.locator('li[data-testid="contactListItem"]');
|
||||||
|
const contactCount = await contactItems.count();
|
||||||
|
console.log('[DEBUG] deleteContact: Found contact items on page:', contactCount);
|
||||||
|
|
||||||
|
// Log all contact names visible on the page
|
||||||
|
for (let i = 0; i < contactCount; i++) {
|
||||||
|
const contactItem = contactItems.nth(i);
|
||||||
|
const nameElement = contactItem.locator('h2');
|
||||||
|
const nameText = await nameElement.textContent();
|
||||||
|
console.log('[DEBUG] deleteContact: Contact', i, ':', nameText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no contacts found, let's take a screenshot to see what's on the page
|
||||||
|
if (contactCount === 0) {
|
||||||
|
console.log('[DEBUG] deleteContact: No contacts found, taking screenshot');
|
||||||
|
await page.screenshot({ path: 'debug-no-contacts.png', fullPage: true });
|
||||||
|
console.log('[DEBUG] deleteContact: Screenshot saved as debug-no-contacts.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find the contact list item with the expected name
|
||||||
|
const contactListItem = page.locator(`li[data-testid="contactListItem"]:has(h2:has-text("${contactName}"))`);
|
||||||
|
const contactExists = await contactListItem.count();
|
||||||
|
console.log('[DEBUG] deleteContact: Contact with name exists:', contactName, contactExists > 0);
|
||||||
|
|
||||||
|
if (contactExists === 0) {
|
||||||
|
console.error('[DEBUG] deleteContact: Contact not found on page:', contactName);
|
||||||
|
throw new Error(`Contact "${contactName}" not found on contacts page`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now click the info icon - fix the selector to match actual DOM structure
|
||||||
|
// Try different selectors for the info icon
|
||||||
|
const infoIconSelectors = [
|
||||||
|
`li[data-testid="contactListItem"]:has(h2:has-text("${contactName}")) font-awesome[icon="circle-info"]`,
|
||||||
|
`li[data-testid="contactListItem"]:has(h2:has-text("${contactName}")) .fa-circle-info`,
|
||||||
|
`li[data-testid="contactListItem"]:has(h2:has-text("${contactName}")) svg.fa-circle-info`,
|
||||||
|
`li[data-testid="contactListItem"]:has(h2:has-text("${contactName}")) [class*="fa-circle-info"]`
|
||||||
|
];
|
||||||
|
|
||||||
|
let infoIcon: import('@playwright/test').Locator | null = null;
|
||||||
|
let infoIconExists = 0;
|
||||||
|
|
||||||
|
for (const selector of infoIconSelectors) {
|
||||||
|
console.log('[DEBUG] deleteContact: Trying selector:', selector);
|
||||||
|
const testIcon = page.locator(selector);
|
||||||
|
const testCount = await testIcon.count();
|
||||||
|
console.log('[DEBUG] deleteContact: Selector result count:', testCount);
|
||||||
|
|
||||||
|
if (testCount > 0) {
|
||||||
|
infoIcon = testIcon;
|
||||||
|
infoIconExists = testCount;
|
||||||
|
console.log('[DEBUG] deleteContact: Found working selector:', selector);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[DEBUG] deleteContact: Info icon exists:', infoIconExists > 0);
|
||||||
|
|
||||||
|
if (infoIconExists === 0 || !infoIcon) {
|
||||||
|
console.error('[DEBUG] deleteContact: Info icon not found for contact:', contactName);
|
||||||
|
throw new Error(`Info icon not found for contact "${contactName}"`);
|
||||||
|
}
|
||||||
|
|
||||||
// go to the detail page for this contact
|
// go to the detail page for this contact
|
||||||
await page.locator(`li[data-testid="contactListItem"] h2:has-text("${contactName}") + span svg.fa-circle-info`).click();
|
await infoIcon.click();
|
||||||
|
console.log('[DEBUG] deleteContact: Clicked info icon, should be on detail page');
|
||||||
|
|
||||||
|
// Verify we're on the detail page
|
||||||
|
const detailPageHeading = page.locator('h1:has-text("Identifier Details")');
|
||||||
|
await detailPageHeading.waitFor({ timeout: 10000 });
|
||||||
|
console.log('[DEBUG] deleteContact: Confirmed on detail page');
|
||||||
|
|
||||||
// delete the contact
|
// delete the contact
|
||||||
await page.locator('button > svg.fa-trash-can').click();
|
const deleteButton = page.locator('button > svg.fa-trash-can');
|
||||||
await page.locator('div[role="alert"] button:has-text("Yes")').click();
|
const deleteButtonExists = await deleteButton.count();
|
||||||
|
console.log('[DEBUG] deleteContact: Delete button exists:', deleteButtonExists > 0);
|
||||||
|
|
||||||
|
if (deleteButtonExists === 0) {
|
||||||
|
console.error('[DEBUG] deleteContact: Delete button not found');
|
||||||
|
throw new Error('Delete button not found on detail page');
|
||||||
|
}
|
||||||
|
|
||||||
|
await deleteButton.click();
|
||||||
|
console.log('[DEBUG] deleteContact: Clicked delete button');
|
||||||
|
|
||||||
|
// Confirm deletion
|
||||||
|
const confirmButton = page.locator('div[role="alert"] button:has-text("Yes")');
|
||||||
|
await confirmButton.waitFor({ timeout: 10000 });
|
||||||
|
console.log('[DEBUG] deleteContact: Confirmation dialog appeared');
|
||||||
|
|
||||||
|
await confirmButton.click();
|
||||||
|
console.log('[DEBUG] deleteContact: Clicked confirmation button');
|
||||||
|
|
||||||
// for some reason, .isHidden() (without expect) doesn't work
|
// for some reason, .isHidden() (without expect) doesn't work
|
||||||
await expect(page.locator('div[role="alert"] button:has-text("Yes")')).toBeHidden();
|
await expect(page.locator('div[role="alert"] button:has-text("Yes")')).toBeHidden();
|
||||||
|
console.log('[DEBUG] deleteContact: Confirmation dialog dismissed, deletion complete');
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateNewEthrUser(page: Page): Promise<string> {
|
export async function generateNewEthrUser(page: Page): Promise<string> {
|
||||||
@@ -85,19 +200,36 @@ export async function generateNewEthrUser(page: Page): Promise<string> {
|
|||||||
// Generate a new random user and register them.
|
// Generate a new random user and register them.
|
||||||
// Note that this makes 000 the active user. Use switchToUser to switch to this DID.
|
// Note that this makes 000 the active user. Use switchToUser to switch to this DID.
|
||||||
export async function generateAndRegisterEthrUser(page: Page): Promise<string> {
|
export async function generateAndRegisterEthrUser(page: Page): Promise<string> {
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Starting user generation');
|
||||||
const newDid = await generateNewEthrUser(page);
|
const newDid = await generateNewEthrUser(page);
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Generated new DID:', newDid);
|
||||||
|
|
||||||
await importUser(page, '000'); // switch to user 000
|
await importUser(page, '000'); // switch to user 000
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Switched to user 000');
|
||||||
|
|
||||||
await page.goto('./contacts');
|
await page.goto('./contacts');
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Navigated to contacts page');
|
||||||
|
|
||||||
const contactName = createContactName(newDid);
|
const contactName = createContactName(newDid);
|
||||||
await page.getByPlaceholder('URL or DID, Name, Public Key').fill(`${newDid}, ${contactName}`);
|
console.log('[DEBUG] generateAndRegisterEthrUser: Created contact name:', contactName);
|
||||||
|
|
||||||
|
const contactInput = `${newDid}, ${contactName}`;
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Filling contact input with:', contactInput);
|
||||||
|
|
||||||
|
await page.getByPlaceholder('URL or DID, Name, Public Key').fill(contactInput);
|
||||||
await page.locator('button > svg.fa-plus').click();
|
await page.locator('button > svg.fa-plus').click();
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Clicked add contact button');
|
||||||
|
|
||||||
// register them
|
// register them
|
||||||
await page.locator('div[role="alert"] button:has-text("Yes")').click();
|
await page.locator('div[role="alert"] button:has-text("Yes")').click();
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Clicked registration confirmation');
|
||||||
|
|
||||||
// wait for it to disappear because the next steps may depend on alerts being gone
|
// 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('div[role="alert"] button:has-text("Yes")')).toBeHidden();
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Registration dialog dismissed');
|
||||||
|
|
||||||
await expect(page.locator('li', { hasText: contactName })).toBeVisible();
|
await expect(page.locator('li', { hasText: contactName })).toBeVisible();
|
||||||
|
console.log('[DEBUG] generateAndRegisterEthrUser: Contact is now visible in list:', contactName);
|
||||||
|
|
||||||
return newDid;
|
return newDid;
|
||||||
}
|
}
|
||||||
@@ -109,7 +241,7 @@ export async function generateRandomString(length: number): Promise<string> {
|
|||||||
|
|
||||||
// Function to create an array of unique strings
|
// Function to create an array of unique strings
|
||||||
export async function createUniqueStringsArray(count: number): Promise<string[]> {
|
export async function createUniqueStringsArray(count: number): Promise<string[]> {
|
||||||
const stringsArray = [];
|
const stringsArray: string[] = [];
|
||||||
const stringLength = 16;
|
const stringLength = 16;
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
@@ -122,7 +254,7 @@ export async function createUniqueStringsArray(count: number): Promise<string[]>
|
|||||||
|
|
||||||
// Function to create an array of two-digit non-zero numbers
|
// Function to create an array of two-digit non-zero numbers
|
||||||
export async function createRandomNumbersArray(count: number): Promise<number[]> {
|
export async function createRandomNumbersArray(count: number): Promise<number[]> {
|
||||||
const numbersArray = [];
|
const numbersArray: number[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
let randomNumber = Math.floor(Math.random() * 99) + 1;
|
let randomNumber = Math.floor(Math.random() * 99) + 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user