@ -80,7 +80,7 @@
* /
* /
import { test , expect } from '@playwright/test' ;
import { test , expect } from '@playwright/test' ;
import { UNNAMED_ENTITY_NAME } from '../src/constants/entities' ;
import { UNNAMED_ENTITY_NAME } from '../src/constants/entities' ;
import { importUser } from './testUtils' ;
import { importUser , retryWaitForLoadState , retryWaitForSelector , retryClick , getNetworkIdleTimeout , getElementWaitTimeout } from './testUtils' ;
test ( 'Record something given' , async ( { page } ) = > {
test ( 'Record something given' , async ( { page } ) = > {
// Generate a random string of a few characters
// Generate a random string of a few characters
@ -101,63 +101,12 @@ test('Record something given', async ({ page }) => {
// Record something given
// Record something given
await page . goto ( './' ) ;
await page . goto ( './' ) ;
await page . getByTestId ( 'closeOnboardingAndFinish' ) . click ( ) ;
await page . getByTestId ( 'closeOnboardingAndFinish' ) . click ( ) ;
// Wait for dialog to be hidden or removed - try multiple approaches
try {
// Simple dialog handling - just wait for it to be gone
// First try: wait for overlay to disappear
await page . waitForFunction ( ( ) = > {
await page . waitForFunction ( ( ) = > {
return ! document . querySelector ( '.dialog-overlay' ) ;
return document . querySelector ( '.dialog-overlay' ) === null ;
} , { timeout : 5000 } ) ;
} , { timeout : 5000 } ) ;
} catch ( error ) {
// Check if page is still available before second attempt
try {
await page . waitForLoadState ( 'domcontentloaded' , { timeout : 2000 } ) ;
// Second try: wait for dialog to be hidden
await page . waitForFunction ( ( ) = > {
const overlay = document . querySelector ( '.dialog-overlay' ) as HTMLElement ;
return overlay && overlay . style . display === 'none' ;
} , { timeout : 5000 } ) ;
} catch ( pageError ) {
// If page is closed, just continue - the dialog is gone anyway
console . log ( 'Page closed during dialog wait, continuing...' ) ;
}
}
// Check if page is still available before proceeding
try {
await page . waitForLoadState ( 'domcontentloaded' , { timeout : 2000 } ) ;
} catch ( error ) {
// If page is closed, we can't continue - this is a real error
throw new Error ( 'Page closed unexpectedly during test' ) ;
}
// Force close any remaining dialog overlay
try {
await page . evaluate ( ( ) = > {
const overlay = document . querySelector ( '.dialog-overlay' ) as HTMLElement ;
if ( overlay ) {
overlay . style . display = 'none' ;
overlay . remove ( ) ;
}
} ) ;
} catch ( error ) {
// If this fails, continue anyway
console . log ( 'Could not force close dialog, continuing...' ) ;
}
// Wait for page to stabilize after potential navigation
try {
await page . waitForLoadState ( 'networkidle' , { timeout : 5000 } ) ;
} catch ( error ) {
// If networkidle times out, that's okay - just continue
console . log ( 'Network not idle, continuing anyway...' ) ;
}
// Wait for page to be ready for interaction
try {
await page . waitForFunction ( ( ) = > {
return document . readyState === 'complete' &&
! document . querySelector ( '.dialog-overlay' ) ;
} , { timeout : 5000 } ) ;
} catch ( error ) {
// If this fails, continue anyway
console . log ( 'Page not ready, continuing anyway...' ) ;
}
await page . getByRole ( 'button' , { name : 'Person' } ) . click ( ) ;
await page . getByRole ( 'button' , { name : 'Person' } ) . click ( ) ;
await page . getByRole ( 'listitem' ) . filter ( { hasText : UNNAMED_ENTITY_NAME } ) . locator ( 'svg' ) . click ( ) ;
await page . getByRole ( 'listitem' ) . filter ( { hasText : UNNAMED_ENTITY_NAME } ) . locator ( 'svg' ) . click ( ) ;
await page . getByPlaceholder ( 'What was given' ) . fill ( finalTitle ) ;
await page . getByPlaceholder ( 'What was given' ) . fill ( finalTitle ) ;
@ -168,10 +117,25 @@ test('Record something given', async ({ page }) => {
// Refresh home view and check gift
// Refresh home view and check gift
await page . goto ( './' ) ;
await page . goto ( './' ) ;
const item = await page . locator ( 'li:first-child' ) . filter ( { hasText : finalTitle } ) ;
await item . locator ( '[data-testid="circle-info-link"]' ) . click ( ) ;
// Use adaptive timeout and retry logic for load-sensitive operations
await retryWaitForLoadState ( page , 'networkidle' , { timeout : getNetworkIdleTimeout ( ) } ) ;
// Resilient approach - verify the gift appears in activity feed
await retryWaitForLoadState ( page , 'networkidle' , { timeout : getNetworkIdleTimeout ( ) } ) ;
// Wait for activity items and verify our gift appears
await retryWaitForSelector ( page , 'ul#listLatestActivity li' , { timeout : getElementWaitTimeout ( ) } ) ;
// Verify the gift we just recorded appears in the activity feed
await expect ( page . getByText ( finalTitle , { exact : false } ) ) . toBeVisible ( ) ;
// Click the specific gift item
const item = page . locator ( 'li:first-child' ) . filter ( { hasText : finalTitle } ) ;
await retryClick ( page , item . locator ( '[data-testid="circle-info-link"]' ) ) ;
await expect ( page . getByRole ( 'heading' , { name : 'Verifiable Claim Details' } ) ) . toBeVisible ( ) ;
await expect ( page . getByRole ( 'heading' , { name : 'Verifiable Claim Details' } ) ) . toBeVisible ( ) ;
await expect ( page . getByText ( finalTitle , { exact : true } ) ) . toBeVisible ( ) ;
// Verify we're viewing the specific gift we recorded
await expect ( page . getByText ( finalTitle , { exact : false } ) ) . toBeVisible ( ) ;
const page1Promise = page . waitForEvent ( 'popup' ) ;
const page1Promise = page . waitForEvent ( 'popup' ) ;
// expand the Details section to see the extended details
// expand the Details section to see the extended details
await page . getByRole ( 'heading' , { name : 'Details' , exact : true } ) . click ( ) ;
await page . getByRole ( 'heading' , { name : 'Details' , exact : true } ) . click ( ) ;