forked from trent_larson/crowd-funder-for-time-pwa
- Add detailed header documentation to playwright tests - Document test categories and flows - Add key selector documentation - Document state verification and alert handling - Include code examples and usage patterns - Add important checks and requirements The documentation helps developers understand the foundational tests that verify basic application functionality before running more complex test suites.
149 lines
5.9 KiB
TypeScript
149 lines
5.9 KiB
TypeScript
/**
|
|
* End-to-End Contact Management Tests
|
|
*
|
|
* Comprehensive test suite for Time Safari's contact management and gift recording features.
|
|
* Tests run sequentially to avoid state conflicts and API rate limits.
|
|
*
|
|
* Test Flow:
|
|
* 1. Contact Creation & Verification
|
|
* - Add contact using DID
|
|
* - Verify contact appears in list
|
|
* - Rename contact and verify change
|
|
* - Check contact appears in "Record Something" section
|
|
*
|
|
* 2. Gift Recording Flow
|
|
* - Generate unique gift details
|
|
* - Record gift to contact
|
|
* - Verify gift confirmation
|
|
* - Check gift appears in activity feed
|
|
*
|
|
* 3. Contact Import/Export Tests
|
|
* - Copy contact details to clipboard
|
|
* - Delete existing contact
|
|
* - Import contact from clipboard
|
|
* - Verify imported contact details
|
|
*
|
|
* Test Data Generation:
|
|
* - Gift titles: "Gift " + 16-char random string
|
|
* - Gift amounts: Random 1-99 value
|
|
* - Contact names: Predefined test values
|
|
* - DIDs: Uses test accounts (e.g., did:ethr:0x000...)
|
|
*
|
|
* Key Selectors:
|
|
* - Contact list: 'li[data-testid="contactListItem"]'
|
|
* - Gift recording: '#sectionRecordSomethingGiven'
|
|
* - Contact name: '[data-testid="contactName"] input'
|
|
* - Alert dialogs: 'div[role="alert"]'
|
|
*
|
|
* Timeouts & Retries:
|
|
* - Uses OS-specific timeouts (longer for Linux)
|
|
* - Implements retry logic for network operations
|
|
* - Waits for UI animations and state changes
|
|
*
|
|
* Alert Handling:
|
|
* - Closes onboarding dialogs
|
|
* - Handles registration prompts
|
|
* - Verifies alert dismissal
|
|
*
|
|
* State Requirements:
|
|
* - Clean database state
|
|
* - No existing contacts for test DIDs
|
|
* - Available API rate limits
|
|
*
|
|
* @example Basic contact addition
|
|
* ```typescript
|
|
* await page.goto('./contacts');
|
|
* await page.getByPlaceholder('URL or DID, Name, Public Key')
|
|
* .fill('did:ethr:0x000...., User Name');
|
|
* await page.locator('button > svg.fa-plus').click();
|
|
* ```
|
|
*/
|
|
import { test, expect } from '@playwright/test';
|
|
import { importUser } from './testUtils';
|
|
|
|
test('Create new project, then search for it', async ({ page }) => {
|
|
|
|
// Generate a random string of 16 characters
|
|
let randomString = Math.random().toString(36).substring(2, 18);
|
|
|
|
// In case the string is shorter than 16 characters, generate more characters until it is 16 characters long
|
|
while (randomString.length < 16) {
|
|
randomString += Math.random().toString(36).substring(2, 18);
|
|
}
|
|
const finalRandomString = randomString.substring(0, 16);
|
|
|
|
// Standard texts
|
|
const standardTitle = 'Idea ';
|
|
const standardDescription = 'Description of Idea ';
|
|
const standardEdit = ' EDITED';
|
|
const standardWebsite = 'https://example.com';
|
|
const editedWebsite = 'https://example.com/edited';
|
|
|
|
// Set dates
|
|
const today = new Date();
|
|
const oneMonthAhead = new Date(today.setDate(today.getDate() + 30));
|
|
const twoMonthsAhead = new Date(today.setDate(today.getDate() + 30));
|
|
const finalDate = oneMonthAhead.toISOString().split('T')[0];
|
|
const editedDate = twoMonthsAhead.toISOString().split('T')[0];
|
|
|
|
// Set times
|
|
const now = new Date();
|
|
const oneHourAhead = new Date(now.setHours(now.getHours() + 1));
|
|
const twoHoursAhead = new Date(now.setHours(now.getHours() + 1));
|
|
const finalHour = oneHourAhead.getHours().toString().padStart(2, '0');
|
|
const editedHour = twoHoursAhead.getHours().toString().padStart(2, '0');
|
|
const finalMinute = oneHourAhead.getMinutes().toString().padStart(2, '0');
|
|
const finalTime = `${finalHour}:${finalMinute}`;
|
|
const editedTime = `${editedHour}:${finalMinute}`;
|
|
|
|
// Combine texts with the random string
|
|
const finalTitle = standardTitle + finalRandomString;
|
|
const finalDescription = standardDescription + finalRandomString;
|
|
const editedTitle = finalTitle + standardEdit;
|
|
const editedDescription = finalDescription + standardEdit;
|
|
|
|
// Import user 00
|
|
await importUser(page, '00');
|
|
|
|
// Create new project
|
|
await page.goto('./projects');
|
|
// close onboarding, but not with a click to go to the main screen
|
|
await page.locator('div > svg.fa-xmark').click();
|
|
await page.locator('button > svg.fa-plus').click();
|
|
await page.getByPlaceholder('Idea Name').fill(finalTitle);
|
|
await page.getByPlaceholder('Description').fill(finalDescription);
|
|
await page.getByPlaceholder('Website').fill(standardWebsite);
|
|
await page.getByPlaceholder('Start Date').fill(finalDate);
|
|
await page.getByPlaceholder('Start Time').fill(finalTime);
|
|
await page.getByRole('button', { name: 'Save Project' }).click();
|
|
|
|
// Check texts
|
|
await expect(page.locator('h2')).toContainText(finalTitle);
|
|
await expect(page.locator('#Content')).toContainText(finalDescription);
|
|
|
|
// Search for newly-created project in /projects
|
|
await page.goto('./projects');
|
|
await expect(page.locator('ul#listProjects li').filter({ hasText: finalTitle })).toBeVisible();
|
|
|
|
// Search for newly-created project in /discover
|
|
await page.goto('./discover');
|
|
await page.getByPlaceholder('Search…').fill(finalRandomString);
|
|
await page.locator('#QuickSearch button').click();
|
|
await expect(page.locator('ul#listDiscoverResults li').filter({ hasText: finalTitle })).toBeVisible();
|
|
|
|
// Edit the project
|
|
await page.locator('a').filter({ hasText: finalTitle }).first().click();
|
|
await page.getByRole('button', { name: 'Edit' }).click();
|
|
await expect(page.getByPlaceholder('Idea Name')).toHaveValue(finalTitle); // Check that textfield value has loaded before proceeding
|
|
await page.getByPlaceholder('Idea Name').fill(editedTitle);
|
|
await page.getByPlaceholder('Description').fill(editedDescription);
|
|
await page.getByPlaceholder('Website').fill(editedWebsite);
|
|
await page.getByPlaceholder('Start Date').fill(editedDate);
|
|
await page.getByPlaceholder('Start Time').fill(editedTime);
|
|
await page.getByRole('button', { name: 'Save Project' }).click();
|
|
|
|
// Check edits
|
|
await expect(page.locator('h2')).toContainText(editedTitle);
|
|
await page.getByText('Read More').click();
|
|
await expect(page.locator('#Content')).toContainText(editedDescription);
|
|
}); |