Skip to content

Instantly share code, notes, and snippets.

@gravitylow
Created April 3, 2026 03:21
Show Gist options
  • Select an option

  • Save gravitylow/c404d461ade92e6cb061877c8a8c45af to your computer and use it in GitHub Desktop.

Select an option

Save gravitylow/c404d461ade92e6cb061877c8a8c45af to your computer and use it in GitHub Desktop.
cursed-playwright-lambda.ts
import { Handler } from "aws-lambda";
import {Client, Guest, Invitation, InvitationFlags, MealChoice, RSVP} from "wedding-client";
import {chromium as playwright, ConsoleMessage, Page, Request} from "playwright-core";
import chromium from "@sparticuz/chromium";
import {expect} from "@playwright/test";
import * as fs from "node:fs";
import {PutObjectCommand, S3Client} from "@aws-sdk/client-s3";
import {Metrics, MetricUnit} from "@aws-lambda-powertools/metrics";
const s3Client = new S3Client();
interface TestContext {
testRunId: string,
client: Client,
page: Page,
invitation: Invitation,
firstGuest: Guest,
secondGuest: Guest,
plusOne: Guest,
}
// From https://github.com/mattdsteele/spot-tracker-tracker/blob/main/pizza-function/src/lambda.ts#L7-L46
const chromeArgs = [
"--disable-background-networking",
"--disable-background-timer-throttling",
"--disable-backgrounding-occluded-windows",
"--disable-breakpad",
"--disable-client-side-phishing-detection",
"--disable-component-update",
"--disable-default-apps",
"--disable-dev-shm-usage",
"--disable-domain-reliability",
"--disable-extensions",
"--disable-features=AudioServiceOutOfProcess",
"--disable-hang-monitor",
"--disable-ipc-flooding-protection",
"--disable-notifications",
"--disable-offer-store-unmasked-wallet-cards",
"--disable-popup-blocking",
"--disable-print-preview",
"--disable-prompt-on-repost",
"--disable-renderer-backgrounding",
"--disable-setuid-sandbox",
"--disable-speech-api",
"--disable-sync",
"--metrics-recording-only",
"--mute-audio",
"--no-default-browser-check",
"--no-first-run",
"--no-pings",
"--no-sandbox",
"--no-zygote",
"--password-store=basic",
"--single-process",
];
export const handler: Handler = async (event: any, context): Promise<any> => {
console.log(event, context);
const tests = [
testLoginPageUnsuccessful,
testBypassLoginPage,
testLogin,
testNavbarLinks,
testRegistry,
testRsvp,
];
const testProps = await setup();
const startTime = new Date().getTime();
const metrics = new Metrics({
namespace: 'wedding_website',
serviceName: 'canary',
});
console.log('Test run ID: ', testProps.testRunId);
try {
let failedTests = [];
for (const test of tests) {
console.log(`Running test: ${test.name}`);
const result = await runTest(test, testProps);
if (result) {
console.log(`Test passed: ${test.name}`);
} else {
console.log(`Test FAILED: ${test.name}`);
failedTests.push(test);
}
}
if (failedTests.length > 0) {
console.log(`One or more tests FAILED: ${failedTests.map(test => test.name).join(', ')}`);
} else {
console.log('Success!!1!');
}
const endTime = new Date().getTime();
await uploadVideos(testProps.testRunId);
metrics.addMetric('failedTestCount', MetricUnit.Count, failedTests.length);
metrics.addMetric('totalTime', MetricUnit.Milliseconds, endTime - startTime);
metrics.addMetric('fault', MetricUnit.Count, 0);
} catch (e) {
metrics.addMetric('fault', MetricUnit.Count, 1);
console.error('Uncaught error in test run', e);
} finally {
metrics.publishStoredMetrics();
await tearDown(testProps.client, testProps.invitation.invitationId);
}
};
async function setup(): Promise<any> {
if (!fs.existsSync('/tmp/output')){
fs.mkdirSync('/tmp/output');
}
const client = new Client({ endpointPrefix: `${process.env.API_URL}/api/` });
const testRunId = crypto.randomUUID();
const createInviteResponse = await client.createInvitation({
invitationName: testRunId,
lastName: testRunId,
address: '123 Test Ln',
houseNumber: '123',
flags: [InvitationFlags.TestAccount],
guests: [
{
guestName: 'First Guest',
primaryGuest: true,
},
{
guestName: 'Second Guest',
primaryGuest: true,
},
{
guestDescription: 'Plus One',
primaryGuest: false,
}
]
});
const invitation = createInviteResponse.invitation!;
const firstGuest = createInviteResponse.guests!.find(guest => guest.guestName == 'First Guest')!;
const secondGuest = createInviteResponse.guests!.find(guest => guest.guestName == 'Second Guest')!;
const plusOne = createInviteResponse.guests!.find(guest => guest.guestDescription == 'Plus One')!;
console.log(`Test setup: invitationId = ${invitation.invitationId}, lastName = ${invitation.lastNameLowercase}, houseNumber = ${invitation.houseNumber}`)
return {
testRunId,
client,
invitation,
firstGuest,
secondGuest,
plusOne,
};
}
async function tearDown(client: Client, invitationId: string) {
console.log('Tearing down test setup');
await client.deleteInvitation({ invitationId: invitationId }).then(() => {
console.log('Teardown complete');
}).catch(err => {
console.error('Error in test teardown', err);
})
}
async function uploadVideos(testRunId: string) {
const fileNames = fs.readdirSync('/tmp/output');
for (const file of fileNames) {
console.log('Uploading ', file);
const Key = `${testRunId}/${file}`;
const Body = fs.readFileSync(`/tmp/output/${file}`);
const putObjectCommand = new PutObjectCommand({
Bucket: process.env.TEST_BUCKET_NAME,
Body,
Key,
});
const result = await s3Client.send(putObjectCommand);
console.log(result);
}
}
async function runTest(test: Function, testProps: any) {
const metrics = new Metrics({
namespace: 'wedding_website',
serviceName: 'canary',
});
metrics.addDimension('testName', test.name);
const setupStartTime = new Date().getTime();
const browser = await playwright.launch({
args: [
...chromium.args,
...chromeArgs,
],
executablePath: await chromium.executablePath(),
});
const browserContext = await browser.newContext();
const page = await browserContext.newPage();
const logs: ConsoleMessage[] = [];
const errors: Error[] = [];
const failedRequests: Request[] = [];
page.on('console', msg => logs.push(msg));
page.on('pageerror', err => errors.push(err));
page.on('requestfailed', req => failedRequests.push(req));
const testStartTime = new Date().getTime();
try {
await test({
...testProps,
page,
});
metrics.addMetric('testFailed', MetricUnit.Count, 0);
metrics.addMetric('testSuccess', MetricUnit.Count, 1);
return true;
} catch (err) {
console.error(`Error in test: ${test.name}`, err);
console.log('Logs:');
for (const log of logs) {
console.log(log);
}
console.log('Errors:');
for (const error of errors) {
console.log(error);
}
console.log('Failed requests:');
for (const failedReq of failedRequests) {
console.log(failedReq);
}
try {
await page.screenshot({
path: `/tmp/output/${test.name}.png`,
});
console.log(`Saved screenshot to /tmp/${test.name}.png`);
} catch (e) {
console.warn("Couldn't save screenshot", e);
}
metrics.addMetric('testFailed', MetricUnit.Count, 1);
metrics.addMetric('testSuccess', MetricUnit.Count, 0);
return false;
} finally {
const testEndTime = new Date().getTime();
metrics.addMetric('testSetupTime', MetricUnit.Milliseconds, testStartTime - setupStartTime);
metrics.addMetric('testRunTime', MetricUnit.Milliseconds, testEndTime - testStartTime);
metrics.publishStoredMetrics();
await browser.close();
}
}
const login = async ({page, invitation}: TestContext) => {
await page.goto(`https://${process.env.WEBSITE_HOSTNAME}/rsvp`);
// Should get forwarded to the login page
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/login?next=%2Frsvp`);
// Fill in required information
await page.getByRole('textbox', { name: 'Your last name' }).fill(invitation.lastNameLowercase);
await page.getByRole('textbox', { name: 'House number on your' }).fill(invitation.houseNumber);
// Enter button is now enabled
const enterButton = page.getByRole('button');
await expect(enterButton).toBeEnabled();
// Click enter button
await enterButton.click();
// Enter button should be disabled while loading
await expect(enterButton).not.toBeEnabled();
// There should not be an error
await expect(page.locator('.chakra-alert__root')).not.toBeVisible();
// Should get logged in and forwarded to the RSVP page
await page.waitForURL(`https://${process.env.WEBSITE_HOSTNAME}/rsvp`);
// await page.waitForFunction(() => window.location.href.includes('...'))
}
const testLoginPageUnsuccessful = async ({page}: TestContext) => {
if (process.env.DEMO) {
// Demo website will let any combination of user + house number in
return;
}
await page.goto(`https://${process.env.WEBSITE_HOSTNAME}`);
// Should get forwarded to the login page
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/login`);
await expect(page.getByRole('heading', {name: 'Enter your information to'})).toBeVisible();
// No error initially
await expect(page.locator('.chakra-alert__root')).not.toBeVisible();
// Enter button should be disabled initially
const enterButton = page.getByRole('button');
await expect(enterButton).toBeDisabled();
// Fill in required information
await page.getByRole('textbox', {name: 'Your last name'}).fill('Test');
await page.getByRole('textbox', {name: 'House number on your'}).fill('123');
// Enter button is now enabled
await expect(enterButton).toBeEnabled();
// Click enter button
await enterButton.click();
// Enter button should be disabled while loading
await expect(enterButton).not.toBeEnabled();
// Wait for button to become enabled again
await expect(enterButton).toBeEnabled();
// There should be an error
await expect(page.locator('.chakra-alert__root')).toBeVisible();
}
const testBypassLoginPage = async ({page, invitation}: TestContext) => {
await page.goto(`https://${process.env.WEBSITE_HOSTNAME}/rsvp?invitationId=${invitation.invitationId}`);
// Should get logged in and forwarded to the RSVP page
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/rsvp`);
}
const testLogin = async (context: TestContext) => {
await login(context);
}
const testNavbarLinks = async (context: TestContext) => {
await login(context);
const { page } = context;
await page.getByRole('link', { name: 'Our Story' }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/our-story`);
await page.getByRole('link', { name: 'Wedding Party', exact: true }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/wedding-party`);
await page.getByRole('link', { name: 'Registry' }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/registry`);
await page.getByRole('link', { name: 'RSVP' }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/rsvp`);
await page.getByRole('link', { name: 'Location Info' }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/location`);
await page.getByRole('link', { name: 'FAQ' }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/faq`);
}
const testRegistry = async (context: TestContext) => {
await login(context);
const { page } = context;
await page.goto(`https://${process.env.WEBSITE_HOSTNAME}/registry`);
// Gifts should be visible
await expect(page.getByText('Checked Bags')).toBeVisible();
await page.getByRole('link', { name: 'Checked Bags' }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/registry/item/checked-bags`);
await expect(page.getByRole('spinbutton', { name: 'Quantity' })).toBeVisible();
await expect(page.getByRole('button', { name: 'increment value' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Add to Cart' })).toBeVisible();
await expect(page.getByRole('button', { name: 'View Cart' })).not.toBeVisible();
await page.getByRole('button', { name: 'increment value' }).click();
await page.getByRole('button', { name: 'Add to Cart' }).click();
await expect(page.getByRole('button', { name: 'View Cart' })).toBeVisible();
await page.getByRole('button', { name: 'View Cart' }).click();
await expect(page).toHaveURL(`https://${process.env.WEBSITE_HOSTNAME}/registry/cart`);
await expect(page.getByRole('heading', { name: 'Registry Cart (2 items)' })).toBeVisible();
await expect(page.getByText('Total')).toBeVisible();
await page.getByLabel('Select quantity').selectOption('3');
await expect(page.getByRole('heading', { name: 'Registry Cart (3 items)' })).toBeVisible();
}
const testRsvp = async (context: TestContext) => {
const { page, client, invitation, firstGuest, secondGuest, plusOne } = context;
await login(context);
await page.goto(`https://${process.env.WEBSITE_HOSTNAME}/rsvp`);
// Elements we want to inspect
const firstGuestCard = await page.getByTestId(`guest-card-${firstGuest.guestId}`);
const secondGuestCard = await page.getByTestId(`guest-card-${secondGuest.guestId}`);
const plusOneCard = await page.getByTestId(`guest-card-${plusOne.guestId}`);
const firstGuestHeading = await page.getByRole('heading', { name: 'First Guest' });
const secondGuestHeading = await page.getByRole('heading', { name: 'Second Guest' });
const plusOneGuestHeading = await page.getByText('Plus One');
const rsvpButton = await page.getByRole('button', { name: 'Send RSVP' });
const updateRsvpButton = await page.getByRole('button', { name: 'Update RSVP' });
await expect(firstGuestCard).not.toBeVisible();
await expect(secondGuestCard).not.toBeVisible();
await expect(plusOneCard).not.toBeVisible();
await expect(firstGuestHeading).not.toBeVisible();
await expect(secondGuestHeading).not.toBeVisible();
await expect(plusOneGuestHeading).not.toBeVisible();
await expect(rsvpButton).not.toBeVisible();
await expect(updateRsvpButton).not.toBeVisible();
// RSVP should be empty
const rsvpInput = page.getByRole('combobox', { name: 'Your RSVP' });
await expect(rsvpInput).toBeVisible();
// Set RSVP to yes
await page.getByRole('combobox', { name: 'Your RSVP' }).click();
await page.getByRole('option', { name: 'Yes! We will attend' }).click();
// Guest RSVPs and RSVP button should appear
await expect(firstGuestCard).toBeVisible();
await expect(secondGuestCard).toBeVisible();
await expect(plusOneCard).toBeVisible();
await expect(firstGuestHeading).toBeVisible();
await expect(secondGuestHeading).toBeVisible();
await expect(plusOneGuestHeading).toBeVisible();
await expect(rsvpButton).toBeVisible();
// Give the plus one a name
await page.getByRole('button', { name: 'edit' }).click();
await page.getByRole('textbox', { name: 'editable input' }).fill('The King of England');
await page.getByRole('button', { name: 'submit' }).click();
// Now RSVP for them
await expect(plusOneCard.getByRole('combobox', { name: 'RSVP' })).not.toBeDisabled();
// Meal choice is disabled until they RSVP Yes
await expect(plusOneCard.getByRole('combobox', { name: 'Meal Choice' })).toBeDisabled();
await plusOneCard.getByRole('combobox', { name: 'RSVP' }).click();
await page.getByRole('option', { name: 'Attending' }).click();
// Attempting to RSVP should fail with a bunch of errors
await rsvpButton.click();
await expect(page.getByText('Error')).toBeVisible();
await expect(page.getByText('Please provide a meal choice for The King of England')).toBeVisible();
await expect(page.getByText('At least one guest must be attending')).toBeVisible();
// To avoid errors asserting on simultaneous error toasts, wait for 5 seconds
await page.waitForTimeout(5000);
// Add the meal choice for the plus one
await plusOneCard.getByRole('combobox', { name: 'Meal Choice' }).click();
await page.getByRole('option', { name: 'Whiffletree Farm Chicken' }).click();
// Now we are only prevented from RSVPing since no primary guest is attending
await rsvpButton.click();
await expect(page.getByText('Error')).toBeVisible();
await expect(page.getByText('At least one guest named on the invitation must be attending')).toBeVisible();
// Primary guests are awaiting RSVP
await expect(firstGuestCard.getByRole('combobox', { name: 'RSVP' })).not.toBeDisabled();
await expect(firstGuestCard.getByRole('combobox', { name: 'Meal Choice' })).toBeDisabled();
await expect(secondGuestCard.getByRole('combobox', { name: 'RSVP' })).not.toBeDisabled();
await expect(secondGuestCard.getByRole('combobox', { name: 'Meal Choice' })).toBeDisabled();
// RSVP yes, select meal, and add dietary restriction for the first guest
await firstGuestCard.getByRole('combobox', { name: 'RSVP' }).click();
await page.getByRole('option', { name: 'Attending' }).click();
await expect(firstGuestCard.getByRole('combobox', { name: 'Meal Choice' })).not.toBeDisabled();
await firstGuestCard.getByRole('combobox', { name: 'Meal Choice' }).click();
await page.getByRole('option', { name: 'Organic Seared Salmon' }).click();
await expect(firstGuestCard.getByRole('button', { name: 'Add Dietary Restriction' })).not.toBeDisabled();
await expect(firstGuestCard.getByRole('button', { name: 'Add Accommodation Request' })).not.toBeDisabled();
await firstGuestCard.getByRole('button', { name: 'Add Dietary Restriction' }).click();
await expect(page.getByTestId(`guest-dietary-restrictions-input-${firstGuest.guestId}`)).toBeVisible();
await page.getByTestId(`guest-dietary-restrictions-input-${firstGuest.guestId}`).fill('Pesca-Pescatarian');
// RSVP no for the second guest
await secondGuestCard.getByRole('combobox', { name: 'RSVP' }).click();
await page.getByRole('option', { name: 'Unable to attend' }).click();
await expect(secondGuestCard.getByRole('combobox', { name: 'Meal Choice' })).toBeDisabled();
await expect(secondGuestCard.getByRole('button', { name: 'Add Dietary Restriction' })).toBeDisabled();
await expect(secondGuestCard.getByRole('button', { name: 'Add Accommodation Request' })).toBeDisabled();
// Now can RSVP
await rsvpButton.click();
// Successful RSVP yes
await expect(page.getByText('Success')).toBeVisible();
await expect(page.getByText('Your RSVP has been updated.')).toBeVisible();
await expect(page.getByRole('heading', { name: 'You RSVP\'d YES for 2 guests!' })).toBeVisible();
await expect(page.getByRole('link', { name: 'day-of and travel info' })).toBeVisible()
await expect(page.getByText('Need to change your RSVP?')).toBeVisible();
await expect(page.getByRole('link', { name: 'wedding registry?' })).toBeVisible();
// To avoid errors asserting on simultaneous error toasts, wait for 5 seconds
await page.waitForTimeout(5000);
// Verify server-side state
const invitationUpdate1 = await client.getInvitation({
invitationId: invitation.invitationId
});
expect(invitationUpdate1.invitation!.rsvp).toBe(RSVP.Yes);
expect(invitationUpdate1.invitation!.attendingGuestsCount).toBe(2);
expect(invitationUpdate1.invitation!.lastRsvpTimestamp).toBeDefined();
expect(invitationUpdate1.guests!.find(guest => guest.guestId == firstGuest.guestId)!.rsvp).toBe(RSVP.Yes);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == firstGuest.guestId)!.mealChoice).toBe(MealChoice.Salmon);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == firstGuest.guestId)!.rsvpChangeCount).toBe(1);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == firstGuest.guestId)!.accommodationRequests).toBeUndefined();
expect(invitationUpdate1.guests!.find(guest => guest.guestId == firstGuest.guestId)!.dietaryRestrictions).toBe('Pesca-Pescatarian');
expect(invitationUpdate1.guests!.find(guest => guest.guestId == secondGuest.guestId)!.rsvp).toBe(RSVP.No);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == secondGuest.guestId)!.mealChoice).toBeUndefined();
expect(invitationUpdate1.guests!.find(guest => guest.guestId == secondGuest.guestId)!.rsvpChangeCount).toBe(1);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == secondGuest.guestId)!.accommodationRequests).toBeUndefined();
expect(invitationUpdate1.guests!.find(guest => guest.guestId == secondGuest.guestId)!.dietaryRestrictions).toBeUndefined();
expect(invitationUpdate1.guests!.find(guest => guest.guestId == plusOne.guestId)!.rsvp).toBe(RSVP.Yes);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == plusOne.guestId)!.guestName).toBe('The King of England');
expect(invitationUpdate1.guests!.find(guest => guest.guestId == plusOne.guestId)!.mealChoice).toBe(MealChoice.Chicken);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == plusOne.guestId)!.rsvpChangeCount).toBe(1);
expect(invitationUpdate1.guests!.find(guest => guest.guestId == plusOne.guestId)!.accommodationRequests).toBeUndefined();
expect(invitationUpdate1.guests!.find(guest => guest.guestId == plusOne.guestId)!.dietaryRestrictions).toBeUndefined();
// Reload the page
await page.goto(`https://${process.env.WEBSITE_HOSTNAME}/rsvp`);
// Result should persist
await expect(page.getByRole('heading', { name: 'You RSVP\'d YES for 2 guests!' })).toBeVisible();
// Change RSVP
await page.getByText('Need to change your RSVP?').click();
// Everything should be populated as before
await expect(page.getByRole('combobox', { name: 'Your RSVP' })).toContainText('Yes! We will attend');
await expect(firstGuestCard.getByRole('combobox', { name: 'RSVP' })).toContainText('Attending');
await expect(firstGuestCard.getByRole('combobox', { name: 'Meal Choice' })).toContainText('Organic Seared Salmon');
await expect(page.getByTestId(`guest-dietary-restrictions-input-${firstGuest.guestId}`)).toHaveValue('Pesca-Pescatarian');
await expect(page.getByTestId(`guest-accommodations-button-${firstGuest.guestId}`)).toBeEnabled();
await expect(page.getByTestId(`guest-accommodations-input-${firstGuest.guestId}`)).not.toBeVisible();
await expect(firstGuestCard.getByRole('button', { name: 'Add Dietary Restriction' })).not.toBeVisible();
await expect(secondGuestCard.getByRole('combobox', { name: 'RSVP' })).toContainText('Unable to attend');
await expect(secondGuestCard.getByRole('combobox', { name: 'Meal Choice' })).toBeDisabled();
await expect(page.getByTestId(`guest-dietary-restrictions-input-${secondGuest.guestId}`)).not.toBeVisible();
await expect(page.getByTestId(`guest-accommodations-input-${secondGuest.guestId}`)).not.toBeVisible();
await expect(page.getByTestId(`guest-accommodations-button-${secondGuest.guestId}`)).toBeDisabled();
await expect(secondGuestCard.getByRole('button', { name: 'Add Dietary Restriction' })).toBeDisabled();
await expect(plusOneCard.getByRole('combobox', { name: 'RSVP' })).toContainText('Attending');
await expect(plusOneCard.getByRole('combobox', { name: 'Meal Choice' })).toContainText('Whiffletree Farm Chicken');
await expect(page.getByTestId(`guest-dietary-restrictions-input-${plusOne.guestId}`)).not.toBeVisible();
await expect(page.getByTestId(`guest-accommodations-input-${plusOne.guestId}`)).not.toBeVisible();
await expect(page.getByTestId(`guest-accommodations-button-${plusOne.guestId}`)).toBeEnabled();
await expect(plusOneCard.getByRole('button', { name: 'Add Dietary Restriction' })).toBeEnabled();
// Change RSVP of second guest
await secondGuestCard.getByRole('combobox', { name: 'RSVP' }).click();
await page.getByRole('option', { name: 'Attending' }).click();
await expect(secondGuestCard.getByRole('combobox', { name: 'Meal Choice' })).not.toBeDisabled();
await secondGuestCard.getByRole('combobox', { name: 'Meal Choice' }).click();
await page.getByRole('option', { name: 'Chilly Hollow Vegetable Tasting' }).click();
await expect(secondGuestCard.getByRole('button', { name: 'Add Dietary Restriction' })).not.toBeDisabled();
await expect(secondGuestCard.getByRole('button', { name: 'Add Accommodation Request' })).not.toBeDisabled();
// Add an accommodation to the plus one
await page.getByTestId(`guest-accommodations-button-${plusOne.guestId}`).click();
await expect(page.getByTestId(`guest-accommodations-input-${plusOne.guestId}`)).toBeVisible();
await page.getByTestId(`guest-accommodations-input-${plusOne.guestId}`).fill('Red carpet please!');
// Update RSVP
await updateRsvpButton.click();
// Successful RSVP yes
await expect(page.getByText('Success')).toBeVisible();
await expect(page.getByText('Your RSVP has been updated.')).toBeVisible();
await expect(page.getByRole('heading', { name: 'You RSVP\'d YES for 3 guests!' })).toBeVisible();
await expect(page.getByText('Need to change your RSVP?')).toBeVisible();
// To avoid errors asserting on simultaneous error toasts, wait for 5 seconds
await page.waitForTimeout(5000);
// Verify server-side state
const invitationUpdate2 = await client.getInvitation({
invitationId: invitation.invitationId
});
expect(invitationUpdate2.invitation!.rsvp).toBe(RSVP.Yes);
expect(invitationUpdate2.invitation!.attendingGuestsCount).toBe(3);
expect(invitationUpdate2.invitation!.lastRsvpTimestamp).toBeDefined();
expect(invitationUpdate2.invitation!.lastRsvpTimestamp).toBeGreaterThan(invitationUpdate1.invitation!.lastRsvpTimestamp!);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == firstGuest.guestId)!.rsvp).toBe(RSVP.Yes);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == firstGuest.guestId)!.mealChoice).toBe(MealChoice.Salmon);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == firstGuest.guestId)!.rsvpChangeCount).toBe(2);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == firstGuest.guestId)!.accommodationRequests).toBeUndefined();
expect(invitationUpdate2.guests!.find(guest => guest.guestId == firstGuest.guestId)!.dietaryRestrictions).toBe('Pesca-Pescatarian');
expect(invitationUpdate2.guests!.find(guest => guest.guestId == secondGuest.guestId)!.rsvp).toBe(RSVP.Yes);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == secondGuest.guestId)!.mealChoice).toBe(MealChoice.VegetableTasting);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == secondGuest.guestId)!.rsvpChangeCount).toBe(2);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == secondGuest.guestId)!.accommodationRequests).toBeUndefined();
expect(invitationUpdate2.guests!.find(guest => guest.guestId == secondGuest.guestId)!.dietaryRestrictions).toBeUndefined();
expect(invitationUpdate2.guests!.find(guest => guest.guestId == plusOne.guestId)!.rsvp).toBe(RSVP.Yes);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == plusOne.guestId)!.guestName).toBe('The King of England');
expect(invitationUpdate2.guests!.find(guest => guest.guestId == plusOne.guestId)!.mealChoice).toBe(MealChoice.Chicken);
expect(invitationUpdate2.guests!.find(guest => guest.guestId == plusOne.guestId)!.rsvpChangeCount).toBe(2);
// TODO fix
// expect(invitationUpdate2.guests!.find(guest => guest.guestId == plusOne.guestId).accommodationRequests).toBe('Red carpet please!');
expect(invitationUpdate2.guests!.find(guest => guest.guestId == plusOne.guestId)!.dietaryRestrictions).toBeUndefined();
// Change RSVP
await page.getByText('Need to change your RSVP?').click();
// Set RSVP to no
await page.getByRole('combobox', { name: 'Your RSVP' }).click();
await page.getByRole('option', { name: 'Regretfully, we are unable to' }).click();
// Button to add a message should become visible
await expect(page.getByRole('button', { name: 'Here' })).toBeVisible();
await page.getByRole('button', { name: 'Here' }).click();
await expect(page.getByRole('textbox', { name: 'Add a message to the Bride' })).toBeVisible();
await page.getByRole('textbox', { name: 'Add a message to the Bride' }).fill('Maybe next time!');
// Update RSVP
await updateRsvpButton.click();
// Successful RSVP no
await expect(page.getByRole('heading', { name: 'You RSVP\'d no' })).toBeVisible();
await expect(page.getByText('Need to change your RSVP?')).toBeVisible();
// Verify server-side state
const invitationUpdate3 = await client.getInvitation({
invitationId: invitation.invitationId
});
expect(invitationUpdate3.invitation!.rsvp).toBe(RSVP.No);
expect(invitationUpdate3.invitation!.attendingGuestsCount).toBe(0);
expect(invitationUpdate3.invitation!.lastRsvpTimestamp).toBeDefined();
expect(invitationUpdate3.invitation!.lastRsvpTimestamp).toBeGreaterThan(invitationUpdate2.invitation!.lastRsvpTimestamp!);
expect(invitationUpdate3.guests!.find(guest => guest.guestId == firstGuest.guestId)!.rsvp).toBe(RSVP.No);
expect(invitationUpdate3.guests!.find(guest => guest.guestId == firstGuest.guestId)!.rsvpChangeCount).toBe(3);
expect(invitationUpdate3.guests!.find(guest => guest.guestId == secondGuest.guestId)!.rsvp).toBe(RSVP.No);
expect(invitationUpdate3.guests!.find(guest => guest.guestId == secondGuest.guestId)!.rsvpChangeCount).toBe(3);
expect(invitationUpdate3.guests!.find(guest => guest.guestId == plusOne.guestId)!.rsvp).toBe(RSVP.No);
expect(invitationUpdate3.guests!.find(guest => guest.guestId == plusOne.guestId)!.rsvpChangeCount).toBe(3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment