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.
286 lines
9.8 KiB
286 lines
9.8 KiB
/**
|
|
* Initial State and Basic Functionality Tests
|
|
*
|
|
* Core test suite that validates fundamental application features and initial state handling.
|
|
* These tests run first to ensure basic functionality before more complex tests.
|
|
*
|
|
* Test Categories:
|
|
* 1. Activity Feed
|
|
* - Verifies server connectivity
|
|
* - Tests infinite scroll loading
|
|
* - Checks initial 10 activities load
|
|
* - Validates additional activity loading
|
|
*
|
|
* 2. Discovery Features
|
|
* - Tests project listing
|
|
* - Verifies infinite scroll
|
|
* - Checks project card rendering
|
|
*
|
|
* 3. Account State
|
|
* - Validates initial no-ID state
|
|
* - Tests ID generation flow
|
|
* - Verifies registration notices
|
|
* - Checks account detail display
|
|
*
|
|
* 4. Contact Sharing
|
|
* - Tests name setting functionality
|
|
* - Validates clipboard operations
|
|
* - Checks sharing UI elements
|
|
* - Verifies alert handling
|
|
*
|
|
* 5. User Registration
|
|
* - Tests User 0's ability to register others
|
|
* - Validates gift recording after registration
|
|
* - Checks contact deletion
|
|
* - Verifies deleted contact handling
|
|
*
|
|
* Key Selectors:
|
|
* - Activity list: 'ul#listLatestActivity li'
|
|
* - Discover list: 'ul#listDiscoverResults li'
|
|
* - Account notices: '#noticeBeforeShare', '#noticeBeforeAnnounce'
|
|
* - Identity details: '#sectionIdentityDetails code.truncate'
|
|
*
|
|
* State Verification:
|
|
* - Checks empty ID state
|
|
* - Verifies ID generation
|
|
* - Validates alert presence/dismissal
|
|
* - Confirms navigation state
|
|
*
|
|
* Alert Handling:
|
|
* - Closes onboarding dialogs
|
|
* - Verifies alert content
|
|
* - Checks alert dismissal
|
|
* - Validates alert transitions
|
|
*
|
|
* Important Checks:
|
|
* - Server connectivity
|
|
* - Data loading
|
|
* - UI state transitions
|
|
* - Error conditions
|
|
* - Clipboard operations
|
|
*
|
|
* @example Checking activity feed
|
|
* ```typescript
|
|
* await page.goto('./');
|
|
* await page.getByTestId('closeOnboardingAndFinish').click();
|
|
* await expect(page.locator('ul#listLatestActivity li:nth-child(10)'))
|
|
* .toBeVisible();
|
|
* ```
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test';
|
|
import { deleteContact, generateAndRegisterEthrUser, importUser, importUserAndCloseOnboarding } from './testUtils';
|
|
|
|
test('Check activity feed - check that server is running', async ({ page }) => {
|
|
// Load app homepage
|
|
await page.goto('./');
|
|
await page.getByTestId('closeOnboardingAndFinish').click();
|
|
|
|
// Check that initial 10 activities have been loaded
|
|
await expect(page.locator('ul#listLatestActivity li:nth-child(10)')).toBeVisible();
|
|
|
|
// Scroll down a bit to trigger loading additional activities
|
|
await page.locator('ul#listLatestActivity li:nth-child(50)').scrollIntoViewIfNeeded();
|
|
});
|
|
|
|
test('Check discover results', async ({ page }) => {
|
|
// Load Discover view
|
|
await page.goto('./discover');
|
|
|
|
// Check that initial 10 projects have been loaded
|
|
await expect(page.locator('ul#listDiscoverResults li.border-b:nth-child(10)')).toBeVisible();
|
|
|
|
// Scroll down a bit to trigger loading additional projects
|
|
await page.locator('ul#listDiscoverResults li.border-b:nth-child(20)').scrollIntoViewIfNeeded();
|
|
});
|
|
|
|
test('Check no-ID messaging in account', async ({ page }) => {
|
|
// Load account view
|
|
await page.goto('./account');
|
|
|
|
// Check 'someone must register you' notice
|
|
await expect(page.locator('#noticeBeforeShare')).toBeVisible();
|
|
|
|
// Check 'a friend needs to register you' notice
|
|
await expect(page.locator('#noticeBeforeAnnounce')).toBeVisible();
|
|
|
|
// Check that there is no ID
|
|
await expect(page.locator('#sectionIdentityDetails code.truncate')).toBeEmpty();
|
|
});
|
|
|
|
test('Check ability to share contact', async ({ page }) => {
|
|
// Load Discover view
|
|
await page.goto('./discover');
|
|
|
|
// Check that initial 10 projects have been loaded
|
|
await expect(page.locator('ul#listDiscoverResults li.border-b:nth-child(10)')).toBeVisible();
|
|
|
|
// Scroll down a bit to trigger loading additional projects
|
|
await page.locator('ul#listDiscoverResults li.border-b:nth-child(20)').scrollIntoViewIfNeeded();
|
|
});
|
|
|
|
test('Check ID generation', async ({ page }) => {
|
|
// Load Account view
|
|
await page.goto('./account');
|
|
|
|
// Check that ID is empty
|
|
await expect(page.locator('#sectionIdentityDetails code.truncate')).toBeEmpty();
|
|
|
|
// Load homepage to trigger ID generation (?)
|
|
await page.goto('./');
|
|
|
|
// Wait for activity feed to start loading, as a delay
|
|
await expect(page.locator('ul#listLatestActivity li:nth-child(10)')).toBeVisible();
|
|
|
|
// Check 'someone must register you' notice
|
|
await expect(page.getByText('To share, someone must register you.')).toBeVisible();
|
|
|
|
// Go back to Account view
|
|
await page.goto('./account');
|
|
|
|
// Check that ID is now generated
|
|
await expect(page.locator('#sectionIdentityDetails code.truncate')).toContainText('did:ethr:');
|
|
});
|
|
|
|
|
|
test('Check setting name & sharing info', async ({ page }) => {
|
|
// Do NOT import a user; start with a fresh, unregistered user state
|
|
|
|
function now() {
|
|
return new Date().toISOString();
|
|
}
|
|
|
|
// Start by loading the homepage and looking for the onboarding notice and button
|
|
await page.goto('./');
|
|
|
|
// Wait for page to fully load and check for overlays
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Loop to close all visible overlays/dialogs before proceeding
|
|
for (let i = 0; i < 5; i++) {
|
|
const overlayCount = await page.locator('.dialog-overlay').count();
|
|
if (overlayCount === 0) break;
|
|
|
|
// Try to close the overlay with various known close button texts
|
|
const closeButtons = [
|
|
"That's enough help, thanks.",
|
|
'Close',
|
|
'Cancel',
|
|
'Dismiss',
|
|
'Got it',
|
|
'OK'
|
|
];
|
|
|
|
let closed = false;
|
|
for (const buttonText of closeButtons) {
|
|
const button = page.getByRole('button', { name: buttonText });
|
|
if (await button.count() > 0) {
|
|
await button.click();
|
|
closed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If no text button found, try the close icon (xmark)
|
|
if (!closed) {
|
|
const closeIcon = page.locator('.fa-xmark, .fa-times, [aria-label*="close"], [aria-label*="Close"]');
|
|
if (await closeIcon.count() > 0) {
|
|
await closeIcon.first().click();
|
|
closed = true;
|
|
}
|
|
}
|
|
|
|
if (!closed) break;
|
|
|
|
// Wait a bit for the overlay to close
|
|
await page.waitForTimeout(500);
|
|
}
|
|
|
|
await expect(page.getByText('someone must register you.')).toBeVisible();
|
|
|
|
// Click the "Show them" button
|
|
await page.getByRole('button', { name: 'Show them' }).click();
|
|
|
|
// Wait for the "Set Your Name" dialog to appear
|
|
await expect(page.getByText('Set Your Name')).toBeVisible();
|
|
|
|
// Fill in the name
|
|
await page.getByRole('textbox').fill('Test User');
|
|
|
|
// Click Save
|
|
await page.getByRole('button', { name: 'Save' }).click();
|
|
|
|
// Wait for the choice dialog to appear
|
|
await expect(page.getByText('We will share some other way')).toBeVisible();
|
|
|
|
// Click "We will share some other way"
|
|
await page.getByRole('button', { name: 'We will share some other way' }).click();
|
|
|
|
// Wait up to 10 seconds for the heading
|
|
await expect(page.getByRole('heading', { name: 'Share Your Contact Info' })).toBeVisible({ timeout: 10000 });
|
|
|
|
// Click the Copy to Clipboard button
|
|
await expect(page.getByRole('button', { name: 'Copy contact information to clipboard' })).toBeVisible({ timeout: 10000 });
|
|
await page.getByRole('button', { name: 'Copy contact information to clipboard' }).click();
|
|
|
|
// Wait for either the notification or navigation to contacts
|
|
await Promise.race([
|
|
expect(page.getByText('contact info was copied')).toBeVisible({ timeout: 10000 }),
|
|
expect(page.getByText('your contacts')).toBeVisible({ timeout: 10000 })
|
|
]);
|
|
});
|
|
|
|
test('Confirm test API setting (may fail if you are running your own Time Safari)', async ({ page }, testInfo) => {
|
|
// Load account view
|
|
await page.goto('./account');
|
|
await page.getByRole('heading', { name: 'Advanced' }).click();
|
|
|
|
// look into the config file: if it starts Time Safari, it might say which server it should set by default
|
|
const webServer = testInfo.config.webServer;
|
|
const endorserWords = webServer?.command.split(' ');
|
|
const ENDORSER_ENV_NAME = 'VITE_DEFAULT_ENDORSER_API_SERVER';
|
|
const endorserTerm = endorserWords?.find(word => word.startsWith(ENDORSER_ENV_NAME + '='));
|
|
const endorserTermInConfig = endorserTerm?.substring(ENDORSER_ENV_NAME.length + 1);
|
|
|
|
const endorserServer = endorserTermInConfig || 'https://test-api.endorser.ch';
|
|
await expect(page.locator('#apiServerInput')).toHaveValue(endorserServer);
|
|
});
|
|
|
|
test('Check User 0 can register a random person', async ({ page }) => {
|
|
await importUser(page, '00');
|
|
const newDid = await generateAndRegisterEthrUser(page);
|
|
expect(newDid).toContain('did:ethr:');
|
|
|
|
await page.goto('./');
|
|
await page.getByTestId('closeOnboardingAndFinish').click();
|
|
|
|
// Click the "Person" button to open the gift recording dialog
|
|
await page.getByRole('button', { name: 'Person' }).click();
|
|
|
|
// In the dialog, click on "Unnamed" to select it as the giver
|
|
await page.getByRole('heading', { name: 'Unnamed' }).first().click();
|
|
|
|
await page.getByPlaceholder('What was given').fill('Gave me access!');
|
|
await page.getByRole('button', { name: 'Sign & Send' }).click();
|
|
await expect(page.getByText('That gift was recorded.')).toBeVisible();
|
|
// now ensure that alert goes away
|
|
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
|
|
await expect(page.getByText('That gift was recorded.')).toBeHidden();
|
|
|
|
// now delete the contact to test that pages still do reasonable things
|
|
await deleteContact(page, newDid);
|
|
// go the activity page for this new person
|
|
await page.goto('./did/' + encodeURIComponent(newDid));
|
|
// maybe replace by: const popupPromise = page.waitForEvent('popup');
|
|
let error;
|
|
try {
|
|
await page.waitForSelector('div[role="alert"]', { timeout: 2000 });
|
|
error = new Error('Error alert should not show.');
|
|
} catch (error) {
|
|
// success
|
|
} finally {
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
});
|
|
|