From dc6d4009c7199962361d1bbe8c11e373259417dd Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 29 Apr 2026 17:47:06 +0100 Subject: [PATCH 01/35] test: centralise locators and refactor tests --- .../tests/submit/addressValidation.spec.js | 77 +++++----- .../tests/submit/formValidation.spec.js | 51 +++---- .../internationalAddressesValidation.spec.js | 46 +++--- .../submit/marketingPreferencesData.spec.js | 7 +- .../marketingPreferencesValidation.spec.js | 64 ++++---- .../tests/submit/postcodeLookup.spec.js | 40 ++--- playwright-staging/tests/submit/sorry.spec.js | 5 +- .../tests/submit/successRedirect.spec.js | 7 +- .../tests/submit/validFormSubmission.spec.js | 9 +- .../tests/update/formValidation.spec.js | 140 ++++++------------ .../update/giftaidDeclarationOptions.spec.js | 21 +-- .../internationalAddressesValidation.spec.js | 35 ++--- playwright-staging/tests/update/sorry.spec.js | 5 +- .../update/updateSuccessRedirect.spec.js | 3 +- .../tests/update/validFormSubmission.spec.js | 11 +- playwright-staging/tests/utils/locators.js | 74 +++++++++ 16 files changed, 331 insertions(+), 264 deletions(-) create mode 100644 playwright-staging/tests/utils/locators.js diff --git a/playwright-staging/tests/submit/addressValidation.spec.js b/playwright-staging/tests/submit/addressValidation.spec.js index 1a574546..3a448d12 100644 --- a/playwright-staging/tests/submit/addressValidation.spec.js +++ b/playwright-staging/tests/submit/addressValidation.spec.js @@ -1,6 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); +const { selectors } = require('../utils/locators'); test.describe('Address validation @sanity @nightly-sanity', () => { @@ -8,60 +9,68 @@ test.describe('Address validation @sanity @nightly-sanity', () => { // Navigate to the giftaid page await page.goto(process.env.BASE_URL, { timeout: 30000 }); await page.waitForLoadState('domcontentloaded'); - await page.locator('#field-label--giftaid').click(); - await page.locator('#field-input--mobile').fill('07123456789'); - await page.locator('input#field-input--firstname').fill('test'); - await page.locator('input#field-input--lastname').fill('user'); + await page.locator(selectors.giftaid.option).click(); + await page.locator(selectors.formFields.mobile).fill('07123456789'); + await page.locator(selectors.formFields.firstName).fill('test'); + await page.locator(selectors.formFields.lastName).fill('user'); }); test('empty postcode should show error message', async ({ page }) => { - await page.locator('input#field-input--postcode').fill(''); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter your postcode'); + await page.locator(selectors.formFields.postcode).fill(''); + await page.locator(selectors.formFields.submitButton).click(); + await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter your postcode'); await page.close(); }); test('invalid postcodes should show error messages', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('12SE17TP'); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - await page.locator('input#field-input--postcode').fill('comic relief'); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - await page.locator('input#field-input--postcode').fill('cro 7tp'); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); + await page.locator(selectors.formFields.postcode).fill('12SE17TP'); + await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); + + await page.locator(selectors.formFields.postcode).fill('comic relief'); + await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); + + await page.locator(selectors.formFields.postcode).fill('cro 7tp'); + await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); + await page.close(); }); test('enter postcode but submit without selecting address should show error message', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('SE1 7TP'); - await page.locator('#postcode_button').click(); - await expect(page.locator('#field-select--addressSelect')).toBeVisible(); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div#field-error--addressSelect > span')).toHaveText('Please select your address'); + await page.locator(selectors.formFields.postcode).fill('SE1 7TP'); + await page.locator(selectors.formFields.postcodeLookup).click(); + await expect(page.locator(selectors.address.addressSelect)).toBeVisible(); + + await page.locator(selectors.formFields.submitButton).click(); + await expect(page.locator(selectors.errorMessages.addressSelect)).toHaveText('Please select your address'); + await page.close(); }); test('clicking on manual address link should show address fields', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('SE1 7TP'); - await expect(page.locator('a[aria-describedby=field-error--addressDetails]')).toBeVisible(); - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await expect(page.locator('#field-input--address1')).toBeVisible(); - await expect(page.locator('#field-input--address2')).toBeVisible(); - await expect(page.locator('#field-input--address3')).toBeVisible(); - await expect(page.locator('#field-input--town')).toBeVisible(); - await expect(page.locator('select#field-select--country')).toBeVisible(); + await page.locator(selectors.formFields.postcode).fill('SE1 7TP'); + await expect(page.locator(selectors.address.manualAddressLink)).toBeVisible(); + + await page.locator(selectors.address.manualAddressLink).click(); + await expect(page.locator(selectors.address.address1)).toBeVisible(); + await expect(page.locator(selectors.address.address2)).toBeVisible(); + await expect(page.locator(selectors.address.address3)).toBeVisible(); + await expect(page.locator(selectors.address.town)).toBeVisible(); + await expect(page.locator(selectors.address.country)).toBeVisible(); + await page.close(); }); test('validate address fields', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('SE1 7TP'); - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - + await page.locator(selectors.formFields.postcode).fill('SE1 7TP'); + await page.locator(selectors.address.manualAddressLink).click(); + // Should see error message for address1 when inout with special characters is entered - await page.locator('#field-input--address1').fill('@£%3dComic Relief'); - await expect(page.locator('#field-error--address1 > span')).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); - await page.locator('#field-input--town').fill(' Comic Relief'); - await expect(page.locator('#field-error--town > span')).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); - + await page.locator(selectors.address.address1).fill('@£%3dComic Relief'); + await expect(page.locator(selectors.errorMessages.address1)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); + + await page.locator(selectors.address.town).fill(' Comic Relief'); + await expect(page.locator(selectors.errorMessages.town)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); + await page.close(); }); }); diff --git a/playwright-staging/tests/submit/formValidation.spec.js b/playwright-staging/tests/submit/formValidation.spec.js index 636e110f..6e14762a 100644 --- a/playwright-staging/tests/submit/formValidation.spec.js +++ b/playwright-staging/tests/submit/formValidation.spec.js @@ -2,6 +2,7 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { Commands } = require('../utils/commands'); +const { selectors } = require('../utils/locators'); test.describe('Form validation @sanity @nightly-sanity', () => { @@ -9,7 +10,7 @@ test.describe('Form validation @sanity @nightly-sanity', () => { // Navigate to the giftaid page await page.goto(process.env.BASE_URL, { timeout: 30000 }); await page.waitForLoadState('domcontentloaded'); - await page.locator('#field-label--giftaid').click(); + await page.locator(selectors.giftaid.option).click(); }); test('Validate mobile number field', async ({ page }) => { @@ -24,59 +25,59 @@ test.describe('Form validation @sanity @nightly-sanity', () => { ]; for (let testCase of mobileTestCases) { - await page.locator('#field-input--mobile').fill(''); // Clear the field before each test - await page.locator('#field-input--mobile').type(testCase.input, { delay: 100 }); - await expect(page.locator('div#field-error--mobile > span')).toHaveText(testCase.error); + await page.locator(selectors.formFields.mobile).fill(''); // Clear the field before each test + await page.locator(selectors.formFields.mobile).type(testCase.input, { delay: 100 }); + await expect(page.locator(selectors.errorMessages.mobile)).toHaveText(testCase.error); } // Validate correct mobile number - await page.locator('#field-input--mobile').fill(''); // Ensure the field is cleared and filled with valid data + await page.locator(selectors.formFields.mobile).fill(''); // Ensure the field is cleared and filled with valid data await commands.populateFormFields(page, { mobile: '07123456789' }); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div > h1')).toHaveText('Thank you, test!'); + await page.locator(selectors.formFields.submitButton).click(); + await expect(page.locator(selectors.sorry.heading)).toHaveText('Thank you, test!'); }); test('validate first name field', async ({ page }) => { const commands = new Commands(page); // First name with invalid characters - await page.locator('#field-input--firstname').fill('Test^$%£'); - await expect(page.locator('div#field-error--firstname')).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); + await page.locator(selectors.formFields.firstName).fill('Test^$%£'); + await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); // First name with just a space - await page.locator('#field-input--firstname').fill(' '); - await expect(page.locator('div#field-error--firstname')).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); + await page.locator(selectors.formFields.firstName).fill(' '); + await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); // First name with alphanumeric characters - await page.locator('#field-input--firstname').fill('123Test'); - await expect(page.locator('div#field-error--firstname')).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); + await page.locator(selectors.formFields.firstName).fill('123Test'); + await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); // Validate correct first name - await page.locator('#field-input--firstname').fill(''); + await page.locator(selectors.formFields.firstName).fill(''); await commands.populateFormFields(page, { firstName: 'testFirstname' }); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div > h1')).toHaveText('Thank you, testFirstname!'); + await page.locator(selectors.formFields.submitButton).click(); + await expect(page.locator(selectors.sorry.heading)).toHaveText('Thank you, testFirstname!'); }); test('validate last name field', async ({ page }) => { const commands = new Commands(page); // Last name with invalid characters - await page.locator('#field-input--lastname').fill('Test^$%£'); - await expect(page.locator('div#field-error--lastname > span')).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); + await page.locator(selectors.formFields.lastName).fill('Test^$%£'); + await expect(page.locator(selectors.errorMessages.lastName)).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); // Last name with just a space - await page.locator('#field-input--lastname').fill(' '); - await expect(page.locator('div#field-error--lastname > span')).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); + await page.locator(selectors.formFields.lastName).fill(' '); + await expect(page.locator(selectors.errorMessages.lastName)).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); // Last name with alphanumeric characters (valid case) - await page.locator('#field-input--lastname').fill('123Test'); - expect(await page.locator('div#field-error--lastname > span').count()).toEqual(0); + await page.locator(selectors.formFields.lastName).fill('123Test'); + expect(await page.locator(selectors.errorMessages.lastName).count()).toEqual(0); // Validate correct last name - await page.locator('#field-input--lastname').fill(''); + await page.locator(selectors.formFields.lastName).fill(''); await commands.populateFormFields(page); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, test!'); + await page.locator(selectors.formFields.submitButton).click(); + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); }); }); diff --git a/playwright-staging/tests/submit/internationalAddressesValidation.spec.js b/playwright-staging/tests/submit/internationalAddressesValidation.spec.js index f2823116..630cd7cc 100644 --- a/playwright-staging/tests/submit/internationalAddressesValidation.spec.js +++ b/playwright-staging/tests/submit/internationalAddressesValidation.spec.js @@ -2,6 +2,7 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { Commands } = require('../utils/commands'); +const { selectors } = require('../utils/locators'); test.describe('International addresses validation @sanity @nightly-sanity', () => { test('selecting a non-UK country and entering a non-UK postcode should submit the form', async ({ page }) => { @@ -12,33 +13,44 @@ test.describe('International addresses validation @sanity @nightly-sanity', () = await page.waitForLoadState('domcontentloaded'); // Click to activate the form and fill in default values - await page.click('#field-label--giftaid'); - await page.fill('#field-input--mobile', '07123456789'); - await page.fill('input#field-input--firstname', 'test'); - await page.fill('input#field-input--lastname', 'user'); - await page.fill('input#field-input--postcode', '30916-395'); // Non-UK postcode + await page.click(selectors.giftaid.option); + await page.fill(selectors.formFields.mobile, '07123456789'); + await page.fill(selectors.formFields.firstName, 'test'); + await page.fill(selectors.formFields.lastName, 'user'); + await page.fill(selectors.formFields.postcode, '30916-395'); // Non-UK postcode // Verify error message for UK postcode requirement - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); + await expect(page.locator(selectors.errorMessages.postcode)).toContainText( + 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); // Fill in address details - await page.click('a[aria-describedby=field-error--addressDetails]'); - await page.fill('#field-input--address1', '219 Beacon St'); - await page.fill('#field-input--address2', 'Winder'); - await page.fill('input#field-input--town', 'GA'); - + await page.click(selectors.address.manualAddressLink); + await page.fill(selectors.address.address1, '219 Beacon St'); + await page.fill(selectors.address.address2, 'Winder'); + await page.fill(selectors.address.town, 'GA'); + // Select a random non-UK country - const countries = await page.$$eval('select#field-select--country > option', options => options.map(option => option.value)); + const countries = await page.$$eval(selectors.address.countryOptions, options => + options + .map(option => option.value) + .filter(value => value && value !== 'GB') + ); + const randomCountryCode = countries[Math.floor(Math.random() * countries.length)]; - await page.selectOption('select[name="country"]', { value: randomCountryCode }); + await page.selectOption(selectors.address.countryByName, { value: randomCountryCode }); // Verify that postcode error is resolved after country change - await expect(page.locator('div#field-error--postcode > span')).not.toBeVisible(); + await expect(page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); // Submit the form and ensure no errors are shown for international address - await commands.selectMarketingPrefs(page); // Assuming this handles checkbox interactions - await page.click('button[type=submit]'); - await expect(page.locator('div.success-wrapper--inner h1')).toContainText('Thank you, test!'); + await commands.selectMarketingPrefs(page); + + await Promise.all([ + page.waitForNavigation(), + page.click(selectors.formFields.submitButton), + ]); + + await expect(page.locator(selectors.success.heading)).toContainText('Thank you, test!'); await page.close(); }); diff --git a/playwright-staging/tests/submit/marketingPreferencesData.spec.js b/playwright-staging/tests/submit/marketingPreferencesData.spec.js index 19fcd7ca..56c0dc2a 100644 --- a/playwright-staging/tests/submit/marketingPreferencesData.spec.js +++ b/playwright-staging/tests/submit/marketingPreferencesData.spec.js @@ -3,6 +3,7 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { Commands } = require('../utils/commands'); const { MarketingPrefsVerify } = require('../utils/marketingPrefsVerify'); +const { selectors } = require('../utils/locators'); const Chance = require('chance'); const chance = new Chance(); @@ -24,7 +25,7 @@ test('Verify giftaid marketing preferences data in contact-store @sanity @nightl // Navigate to the giftaid page await page.goto(process.env.BASE_URL, { timeout: 30000 }); await page.waitForLoadState('load'); - await page.locator('#field-label--giftaid').click(); + await page.locator(selectors.giftaid.option).click(); // Populate all input fields using Commands class await commands.populateFormFields(page, { @@ -35,10 +36,10 @@ test('Verify giftaid marketing preferences data in contact-store @sanity @nightl await commands.selectMarketingPrefs(page, { email, phone }); // Submit the form - await page.locator('button[type=submit]').click(); + await page.locator(selectors.formFields.submitButton).click(); // Verify success message - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText(`Thank you, ${firstName}!`); + await expect(page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); // Retrieve and verify marketing preferences data const mpData = await MarketingPrefsVerify.get(email); diff --git a/playwright-staging/tests/submit/marketingPreferencesValidation.spec.js b/playwright-staging/tests/submit/marketingPreferencesValidation.spec.js index f7fe5c6e..f1448bb8 100644 --- a/playwright-staging/tests/submit/marketingPreferencesValidation.spec.js +++ b/playwright-staging/tests/submit/marketingPreferencesValidation.spec.js @@ -2,6 +2,7 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { Commands } = require('../utils/commands'); +const { selectors } = require('../utils/locators'); const Chance = require('chance'); const chance = new Chance(); @@ -15,62 +16,67 @@ test.describe('Marketing preferences validation @sanity @nightly-sanity', () => const commands = new Commands(page); await page.goto(process.env.BASE_URL, { timeout: 30000 }); await page.waitForLoadState('domcontentloaded'); - await page.click('#field-label--giftaid'); + await page.click(selectors.giftaid.option); await commands.populateFormFields(page); }); - + test('clicking and unclicking marketing prefs options should submit the giftaid form', async ({ page }) => { // Interact with marketing preferences - const marketingOptions = ['[aria-label="field-label--Email--Email"]', '[aria-label="field-label--Phone--Phone"]', '[aria-label="field-label--Text--SMS"]']; + const marketingOptions = [ + selectors.marketingPreferences.options.email, + selectors.marketingPreferences.options.phone, + selectors.marketingPreferences.options.text, + ]; + for (const option of marketingOptions) { await page.click(option); expect(await page.locator(option).isChecked()).toBeTruthy(); } - + // Enter email and phone to validate the form can still submit - await expect(page.locator('input#field-input--email')).toBeVisible(); - await page.fill('input#field-input--email', email); - await expect(page.locator('input#field-input--phone')).toBeVisible(); - await page.fill('input#field-input--phone', phone); - + await expect(page.locator(selectors.marketingPreferences.fields.email)).toBeVisible(); + await page.fill(selectors.marketingPreferences.fields.email, email); + await expect(page.locator(selectors.marketingPreferences.fields.phone)).toBeVisible(); + await page.fill(selectors.marketingPreferences.fields.phone, phone); + // Submit the form - await page.click('button[type=submit]'); - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, test!'); + await page.click(selectors.formFields.submitButton); + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); }); test('Validate email marketing preference field', async ({ page }) => { - await page.click('[aria-label="field-label--Email--Email"]'); - await page.fill('input#field-input--email', email); + await page.click(selectors.marketingPreferences.options.email); + await page.fill(selectors.marketingPreferences.fields.email, email); // Clear and check for error - await page.fill('input#field-input--email', ''); - await expect(page.locator('#field-error--email')).toHaveText('Please fill in your email address'); + await page.fill(selectors.marketingPreferences.fields.email, ''); + await expect(page.locator(selectors.errorMessages.email)).toHaveText('Please fill in your email address'); // Input invalid email and check for error - await page.fill('input#field-input--email', 'example@£$^&email.com'); - await expect(page.locator('#field-error--email')).toHaveText('Please fill in a valid email address'); + await page.fill(selectors.marketingPreferences.fields.email, 'example@£$^&email.com'); + await expect(page.locator(selectors.errorMessages.email)).toHaveText('Please fill in a valid email address'); // Re-enter valid email and submit - await page.fill('input#field-input--email', email); - await page.click('button[type=submit]'); - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, test!'); + await page.fill(selectors.marketingPreferences.fields.email, email); + await page.click(selectors.formFields.submitButton); + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); }); test('Validate phone marketing preference field', async ({ page }) => { - await page.click('[aria-label="field-label--Phone--Phone"]'); - await page.fill('input#field-input--phone', phone); + await page.click(selectors.marketingPreferences.options.phone); + await page.fill(selectors.marketingPreferences.fields.phone, phone); // Clear and check for error - await page.fill('input#field-input--phone', ''); - await expect(page.locator('div#field-error--phone > span')).toHaveText('Please fill in your phone number'); + await page.fill(selectors.marketingPreferences.fields.phone, ''); + await expect(page.locator(selectors.errorMessages.phone)).toHaveText('Please fill in your phone number'); // Input invalid phone number and check for error - await page.fill('input#field-input--phone', '0208569424'); - await expect(page.locator('div#field-error--phone > span')).toHaveText('Please fill in a valid UK phone number, with no spaces'); + await page.fill(selectors.marketingPreferences.fields.phone, '0208569424'); + await expect(page.locator(selectors.errorMessages.phone)).toHaveText('Please fill in a valid UK phone number, with no spaces'); // Re-enter valid phone number and submit - await page.fill('input#field-input--phone', phone); - await page.click('button[type=submit]'); - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, test!'); + await page.fill(selectors.marketingPreferences.fields.phone, phone); + await page.click(selectors.formFields.submitButton); + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); }); }); diff --git a/playwright-staging/tests/submit/postcodeLookup.spec.js b/playwright-staging/tests/submit/postcodeLookup.spec.js index 740c4b52..10b1b577 100644 --- a/playwright-staging/tests/submit/postcodeLookup.spec.js +++ b/playwright-staging/tests/submit/postcodeLookup.spec.js @@ -1,16 +1,17 @@ // @ts-check const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); +const { selectors } = require('../utils/locators'); test.describe('Postcode validation @sanity @nightly-sanity', () => { test.beforeEach(async ({ page }) => { await page.goto(process.env.BASE_URL, { timeout: 30000 }); await page.waitForLoadState('domcontentloaded'); - await page.click('#field-label--giftaid'); - await page.fill('#field-input--mobile', '07123456789'); - await page.fill('input#field-input--firstname', 'test'); - await page.fill('input#field-input--lastname', 'user'); + await page.click(selectors.giftaid.option); + await page.fill(selectors.formFields.mobile, '07123456789'); + await page.fill(selectors.formFields.firstName, 'test'); + await page.fill(selectors.formFields.lastName, 'user'); }); test('Postcode formatting errors', async ({ page }) => { @@ -20,30 +21,31 @@ test.describe('Postcode validation @sanity @nightly-sanity', () => { ]; for (const { code, message } of postcodes) { - await page.fill('input#field-input--postcode', code); - await expect(page.locator('div#field-error--postcode > span')).toBeVisible(); - await expect(page.locator('div#field-error--postcode > span')).toContainText(message); + await page.fill(selectors.formFields.postcode, code); + await expect(page.locator(selectors.errorMessages.postcode)).toBeVisible(); + await expect(page.locator(selectors.errorMessages.postcode)).toContainText(message); } + await page.close(); }); test('enter valid UK postcode using postcode lookup should be able to submit the form', async ({ page }) => { - await page.fill('input#field-input--postcode', 'SE1 7TP'); - await page.click('#postcode_button'); + await page.fill(selectors.formFields.postcode, 'SE1 7TP'); + await page.click(selectors.formFields.postcodeLookup); - if (await page.isVisible('#field-select--addressSelect')) { - await page.selectOption('select#field-select--addressSelect', { label: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }); - await expect(page.locator('input#field-input--postcode')).toHaveValue('SE1 7TP'); + if (await page.isVisible(selectors.address.addressSelect)) { + await page.selectOption(selectors.address.addressSelect, { label: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }); + await expect(page.locator(selectors.formFields.postcode)).toHaveValue('SE1 7TP'); } else { - await page.click('a[aria-describedby=field-error--addressDetails]'); - await page.fill('#field-input--address1', 'COMIC RELIEF'); - await page.fill('#field-input--address2', 'CAMELFORD HOUSE 87-90'); - await page.fill('#field-input--address3', 'ALBERT EMBANKMENT'); - await page.fill('#field-input--town', 'LONDON'); + await page.click(selectors.address.manualAddressLink); + await page.fill(selectors.address.address1, 'COMIC RELIEF'); + await page.fill(selectors.address.address2, 'CAMELFORD HOUSE 87-90'); + await page.fill(selectors.address.address3, 'ALBERT EMBANKMENT'); + await page.fill(selectors.address.town, 'LONDON'); } - await page.click('button[type=submit]'); - await expect(page.locator('div.success-wrapper--inner h1')).toContainText('Thank you,\n' + 'test!'); + await page.click(selectors.formFields.submitButton); + await expect(page.locator(selectors.success.heading)).toContainText('Thank you,\n' + 'test!'); await page.close(); }); diff --git a/playwright-staging/tests/submit/sorry.spec.js b/playwright-staging/tests/submit/sorry.spec.js index c331d787..ea1f603d 100644 --- a/playwright-staging/tests/submit/sorry.spec.js +++ b/playwright-staging/tests/submit/sorry.spec.js @@ -1,18 +1,19 @@ // @ts-check const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); +const { selectors } = require('../utils/locators'); test('Accessing giftaid sorry page should show the sorry message @sanity @nightly-sanity', async ({ page }) => { // Go directly to the "sorry" page appended to the base URL await page.goto(`${process.env.BASE_URL}sorry`, { timeout: 30000 }); // Wait for the main header to be loaded and visible on the page - const header = page.locator('div > h1'); + const header = page.locator(selectors.sorry.heading); await expect(header).toBeVisible(); await expect(header).toContainText('Sorry!'); // Verify that the first paragraph under the div > div is visible - const firstParagraph = page.locator('div > div > p:nth-child(1)'); + const firstParagraph = page.locator(selectors.sorry.firstParagraph); await expect(firstParagraph).toBeVisible(); await page.close(); diff --git a/playwright-staging/tests/submit/successRedirect.spec.js b/playwright-staging/tests/submit/successRedirect.spec.js index 686b980c..cda8625f 100644 --- a/playwright-staging/tests/submit/successRedirect.spec.js +++ b/playwright-staging/tests/submit/successRedirect.spec.js @@ -1,6 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); +const { selectors } = require('../utils/locators'); test('Accessing success page should redirect to giftaid homepage @sanity @nightly-sanity', async ({ page }) => { // Navigate directly to the success page and expect a redirect @@ -8,13 +9,13 @@ test('Accessing success page should redirect to giftaid homepage @sanity @nightl await page.waitForLoadState('domcontentloaded'); // Check if the expected header title is present, which indicates a successful redirect - const headerTitle = page.locator('h1.giftaid-title'); + const headerTitle = page.locator(selectors.homepage.heading); await expect(headerTitle).toBeVisible(); await expect(headerTitle).toContainText('Giftaid it'); // Verify the presence of key elements on the redirected homepage - await expect(page.locator('#field-label--giftaid')).toBeVisible(); - await expect(page.locator('#field-input--mobile')).toBeVisible(); + await expect(page.locator(selectors.giftaid.option)).toBeVisible(); + await expect(page.locator(selectors.formFields.mobile)).toBeVisible(); await page.close(); }); diff --git a/playwright-staging/tests/submit/validFormSubmission.spec.js b/playwright-staging/tests/submit/validFormSubmission.spec.js index d9264b86..863a3a08 100644 --- a/playwright-staging/tests/submit/validFormSubmission.spec.js +++ b/playwright-staging/tests/submit/validFormSubmission.spec.js @@ -2,6 +2,7 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { Commands } = require('../utils/commands'); +const { selectors } = require('../utils/locators'); test('Valid giftaid submission @sanity @nightly-sanity', async ({ page }) => { const commands = new Commands(page); @@ -11,7 +12,7 @@ test('Valid giftaid submission @sanity @nightly-sanity', async ({ page }) => { await page.waitForLoadState('domcontentloaded'); // Click the Giftaid checkbox - await page.click('#field-label--giftaid'); + await page.click(selectors.giftaid.option); // Populate all the form fields with valid inputs await commands.populateFormFields(page); @@ -21,12 +22,12 @@ test('Valid giftaid submission @sanity @nightly-sanity', async ({ page }) => { // Submit the form and wait for the navigation to ensure the submission goes through await Promise.all([ - page.waitForNavigation(), // This ensures that the navigation happens before the check - page.click('button[type=submit]') + page.waitForNavigation(), + page.click(selectors.formFields.submitButton), ]); // Check for the thank you message to confirm successful submission - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, test!'); + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); await page.close(); }); diff --git a/playwright-staging/tests/update/formValidation.spec.js b/playwright-staging/tests/update/formValidation.spec.js index 0c71fe80..c0d3a2ba 100644 --- a/playwright-staging/tests/update/formValidation.spec.js +++ b/playwright-staging/tests/update/formValidation.spec.js @@ -5,62 +5,63 @@ const { Commands } = require('../utils/commands'); const { v4: uuidv4 } = require('uuid'); const Chance = require('chance'); const chance = new Chance(); +const { selectors } = require('../utils/locators'); test.describe('Giftaid Update form validation @sanity @nightly-sanity', () => { let commands; - + test.beforeEach(async ({ page }) => { commands = new Commands(page); // Navigate to the Giftaid Update form await page.goto(`${process.env.BASE_URL}update`, { timeout: 30000 }); await page.waitForLoadState('domcontentloaded'); }); - + test('empty input fields should show error messages', async ({ page }) => { // Submit the form without filling out any fields - await page.click('button[type=submit]'); - + await page.click(selectors.formFields.submitButton); + // Check for the error messages associated with each field - await expect(page.locator('div#field-error--firstname > span')).toHaveText('Please fill in your first name'); - await expect(page.locator('div#field-error--lastname > span')).toHaveText('Please fill in your last name'); - await expect(page.locator('div#field-error--email > span')).toHaveText('Please fill in your email address'); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter your postcode'); - await expect(page.locator('div#field-error--addressDetails > span')).toHaveText('Please fill in your address'); - await expect(page.locator('div#field-error--giftAidClaimChoice > span')).toHaveText('This field is required'); + await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('Please fill in your first name'); + await expect(page.locator(selectors.errorMessages.lastName)).toHaveText('Please fill in your last name'); + await expect(page.locator(selectors.errorMessages.email)).toHaveText('Please fill in your email address'); + await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter your postcode'); + await expect(page.locator(selectors.errorMessages.addressDetails)).toHaveText('Please fill in your address'); + await expect(page.locator(selectors.errorMessages.giftAidClaimChoice)).toHaveText('This field is required'); await page.close(); }); - + test('Validate first name field on Giftaid update form', async ({ page }) => { const commands = new Commands(page); - + // Set up different first name test cases const firstNameTestCases = [ { input: 'Test^$%£', error: "This field only accepts alphabetic characters and ' -" }, // Test for invalid characters { input: ' ', error: "This field only accepts alphabetic characters and ' -" }, // Test for space as input { input: '123Test', error: "This field only accepts alphabetic characters and ' -" } // Test for alphanumeric input ]; - + for (let testCase of firstNameTestCases) { - await page.fill('#field-input--firstname', testCase.input); + await page.fill(selectors.formFields.firstName, testCase.input); if (testCase.input) { await page.keyboard.press('Enter'); // Trigger validation by clicking submit button } - await expect(page.locator('#field-error--firstname')).toHaveText(testCase.error); + await expect(page.locator(selectors.errorMessages.firstName)).toHaveText(testCase.error); } - + // Test for a valid first name - await page.fill('#field-input--firstname', ''); // clear firstname field + await page.fill(selectors.formFields.firstName, ''); // clear firstname field await commands.populateUpdateFormFields(page, { firstName: 'John' }); - await page.click('#giftAidClaimChoice>div:nth-child(2)>label'); // Select yes for declaration - await page.click('button[type=submit]'); // Submit the form - - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, John!'); + await page.click(selectors.giftAidClaimChoice.yes); // Select yes for declaration + await page.click(selectors.formFields.submitButton); // Submit the form + + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, John!'); await page.close(); }); - + test('Validate email field on giftaid update form', async ({ page }) => { const commands = new Commands(page); - + // Set up different email test cases const emailTestCases = [ { input: 'test@comic$relief.com', error: 'Please fill in a valid email address', visible: true }, @@ -69,27 +70,27 @@ test.describe('Giftaid Update form validation @sanity @nightly-sanity', () => { { input: 'te$%^st@comicrelief.com', error: '', visible: false }, { input: 'Test0-9!#$%&\'*+/=?^_{|}~-@comicrelief_9-8.com.uk', error: 'Please fill in a valid email address', visible: true } ]; - + for (let testCase of emailTestCases) { - await page.fill('input#field-input--email', ''); // clear the email field before entering the test cases input - await page.fill('input#field-input--email', testCase.input); + await page.fill(selectors.marketingPreferences.fields.email, ''); // clear the email field before entering the test cases input + await page.fill(selectors.marketingPreferences.fields.email, testCase.input); await page.keyboard.press('Enter'); // Trigger validation by clicking the submit button if (testCase.visible) { - await expect(page.locator('div#field-error--email > span')).toBeVisible(); - await expect(page.locator('div#field-error--email > span')).toHaveText(testCase.error); + await expect(page.locator(selectors.errorMessages.email)).toBeVisible(); + await expect(page.locator(selectors.errorMessages.email)).toHaveText(testCase.error); } else { - await expect(page.locator('div#field-error--email > span')).not.toBeVisible(); + await expect(page.locator(selectors.errorMessages.email)).not.toBeVisible(); } } - + // Test for a valid email const validEmail = `giftaid-update-staging-${chance.email()}`; - await page.fill('input#field-input--email', ''); // clear email field + await page.fill(selectors.marketingPreferences.fields.email, ''); // clear email field await commands.populateUpdateFormFields(page, { email: validEmail }); - await page.click('#giftAidClaimChoice>div:nth-child(3)>label'); // Select no for declaration - await page.click('button[type=submit]'); // Submit the form - - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thanks for letting us know'); + await page.click(selectors.giftAidClaimChoice.no); // Select no for declaration + await page.click(selectors.formFields.submitButton); // Submit the form + + await expect(page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); await page.close(); }); @@ -112,70 +113,23 @@ test.describe('Giftaid Update form validation @sanity @nightly-sanity', () => { { input: '07123456789', valid: true }, { input: '07340707252', valid: true }, ]; - + for (let testCase of mobileTestCases) { - await page.locator('#field-input--mobile').fill(''); // Clear the field before each test - await page.locator('#field-input--mobile').type(testCase.input, { delay: 100 }); + await page.locator(selectors.formFields.mobile).fill(''); // Clear the field before each test + await page.locator(selectors.formFields.mobile).type(testCase.input, { delay: 100 }); if (testCase.valid) { - await expect(page.locator('div#field-error--mobile > span')).not.toBeVisible(); + await expect(page.locator(selectors.errorMessages.mobile)).not.toBeVisible(); } else { - await expect(page.locator('div#field-error--mobile > span')).toHaveText(testCase.error); - } + await expect(page.locator(selectors.errorMessages.mobile)).toHaveText(testCase.error); + } } // Validate correct mobile number - await page.locator('#field-input--mobile').fill(''); // Ensure the field is cleared and filled with valid data + await page.locator(selectors.formFields.mobile).fill(''); // Ensure the field is cleared and filled with valid data await commands.populateUpdateFormFields(page, { lastName: 'test', mobile: mobile }); - await page.click('#giftAidClaimChoice>div:nth-child(2)>label'); // Select yes for declaration - await page.click('button[type=submit]'); // Submit the form - - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, test!'); - }); - - test('Postcode validation and form submission', async ({ page }) => { - // Define postcodes and expected error messages - const postcodes = [ - { input: 'S E 1 7 T P', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, - { input: 'SE$%TP', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, - { input: 'cro 7tp', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' } - ]; - - // Test for each invalid postcode - for (const postcode of postcodes) { - await page.fill('input#field-input--postcode', ''); - await page.type('input#field-input--postcode', postcode.input); - await expect(page.locator('div#field-error--postcode > span')).toBeVisible(); - await expect(page.locator('div#field-error--postcode > span')).toHaveText(postcode.error); - } - - // Test for a valid postcode and subsequent form submission - await page.fill('input#field-input--postcode', 'SE1 7TP'); - await page.click('#postcode_button'); - - // Checking whether address selection is available or if manual entry is needed - if (await page.locator('#field-select--addressSelect').isVisible()) { - // Select the first address if available - const options = await page.$$eval('#field-select--addressSelect option', options => options.map(option => option.value)); - await page.selectOption('#field-select--addressSelect', options[1]); - await page.click('button[type=submit]'); - } else { - // Fallback to manual address input if no selection is available - await page.click('a[aria-describedby=field-error--addressDetails]'); - await page.fill('#field-input--address1', 'COMIC RELIEF'); - await page.fill('#field-input--address2', 'CAMELFORD HOUSE 87-90'); - await page.fill('#field-input--address3', 'ALBERT EMBANKMENT'); - await page.fill('input#field-input--town', 'LONDON'); - await page.click('button[type=submit]'); - } - - await page.locator('input#field-input--firstname').fill('test'); - await page.locator('input#field-input--lastname').fill(chance.last()); - await page.locator('input#field-input--email').fill(`giftaid-update-staging-${chance.email()}`); - await page.fill('input#field-input--postcode', 'SE1 7TP'); - await page.click('#giftAidClaimChoice>div:nth-child(2)>label'); // Select yes for declaration - await page.click('button[type=submit]'); // Submit the form - - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thank you, test!'); - await page.close(); + await page.click(selectors.giftAidClaimChoice.yes); // Select yes for declaration + await page.click(selectors.formFields.submitButton); // Submit the form + + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); }); }); diff --git a/playwright-staging/tests/update/giftaidDeclarationOptions.spec.js b/playwright-staging/tests/update/giftaidDeclarationOptions.spec.js index 397ba1f1..7e9a3443 100644 --- a/playwright-staging/tests/update/giftaidDeclarationOptions.spec.js +++ b/playwright-staging/tests/update/giftaidDeclarationOptions.spec.js @@ -2,6 +2,7 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { Commands } = require('../utils/commands'); +const { selectors } = require('../utils/locators'); test('Validate Giftaid declaration claim selections @sanity @nightly-sanity', async ({ page }) => { const commands = new Commands(page); @@ -10,20 +11,20 @@ test('Validate Giftaid declaration claim selections @sanity @nightly-sanity', as // Populate fields and submit the form to get to the Giftaid declaration part await commands.populateUpdateFormFields(page); - await page.locator('button[type=submit]').click(); + await page.locator(selectors.formFields.submitButton).click(); // Select 'Yes' for Giftaid declaration and verify it is selected - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - expect(await page.locator('#giftAidClaimChoice>div:nth-child(2)>input').isChecked()).toBeTruthy(); - expect(await page.locator('#giftAidClaimChoice>div:nth-child(3)>input').isChecked()).toBeFalsy(); + await page.locator(selectors.giftAidClaimChoice.yes).click(); + expect(await page.locator(selectors.giftAidClaimChoice.yesInput).isChecked()).toBeTruthy(); + expect(await page.locator(selectors.giftAidClaimChoice.noInput).isChecked()).toBeFalsy(); // Select 'No' for Giftaid declaration and verify it is selected - await page.locator('#giftAidClaimChoice>div:nth-child(3)>label').click(); - expect(await page.locator('#giftAidClaimChoice>div:nth-child(3)>input').isChecked()).toBeTruthy(); - expect(await page.locator('#giftAidClaimChoice>div:nth-child(2)>input').isChecked()).toBeFalsy(); - - await page.locator('button[type=submit]').click(); - await expect(page.locator('div.success-wrapper--inner h1')).toHaveText('Thanks for letting us know'); + await page.locator(selectors.giftAidClaimChoice.no).click(); + expect(await page.locator(selectors.giftAidClaimChoice.noInput).isChecked()).toBeTruthy(); + expect(await page.locator(selectors.giftAidClaimChoice.yesInput).isChecked()).toBeFalsy(); + + await page.locator(selectors.formFields.submitButton).click(); + await expect(page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); await page.close(); }); diff --git a/playwright-staging/tests/update/internationalAddressesValidation.spec.js b/playwright-staging/tests/update/internationalAddressesValidation.spec.js index 9f64900d..5f0c3361 100644 --- a/playwright-staging/tests/update/internationalAddressesValidation.spec.js +++ b/playwright-staging/tests/update/internationalAddressesValidation.spec.js @@ -2,6 +2,7 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { v4: uuidv4 } = require('uuid'); +const { selectors } = require('../utils/locators'); test.describe('International addresses validation on update form @sanity @nightly-sanity', () => { test('selecting a non-UK country and entering a non-UK postcode should submit the update form', async ({ page }) => { @@ -11,42 +12,42 @@ test.describe('International addresses validation on update form @sanity @nightl // fill in all input fields // await page.locator('input#field-input--transactionId').fill(transactionId); - await page.locator('#field-input--firstname').fill('test'); - await page.locator('#field-input--lastname').fill('test lastname'); - await page.locator('input#field-input--email').fill('giftaid-staging-@email.sls.comicrelief.com'); + await page.locator(selectors.formFields.firstName).fill('test'); + await page.locator(selectors.formFields.lastName).fill('test lastname'); + await page.locator(selectors.marketingPreferences.fields.email).fill('giftaid-staging-@email.sls.comicrelief.com'); // enter a non-UK postcode and attempt to validate it - await page.locator('input#field-input--postcode').fill('30916-395'); - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); + await page.locator(selectors.formFields.postcode).fill('30916-395'); + await expect(page.locator(selectors.errorMessages.postcode)).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); // manually enter international address details - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await page.locator('#field-input--address1').fill('219 Beacon St'); - await page.locator('#field-input--address2').fill('Winder'); - await page.locator('#field-input--address3').fill('Park Ridge'); - await page.locator('#field-input--town').fill('GA'); + await page.locator(selectors.address.manualAddressLink).click(); + await page.locator(selectors.address.address1).fill('219 Beacon St'); + await page.locator(selectors.address.address2).fill('Winder'); + await page.locator(selectors.address.address3).fill('Park Ridge'); + await page.locator(selectors.address.town).fill('GA'); // Select a random country from the dropdown (excluding UK to simulate international address) - const countryOptions = await page.$$eval('select#field-select--country>option', options => - options.map(option => option.value).filter(value => value !== 'GB') + const countryOptions = await page.$$eval(selectors.address.countryOptions, options => + options.map(option => option.value).filter(value => value && value !== 'GB') ); const randomCountryCode = countryOptions[Math.floor(Math.random() * countryOptions.length)]; - await page.locator('select[name="country"]').selectOption({ value: randomCountryCode }); + await page.locator(selectors.address.countryByName).selectOption({ value: randomCountryCode }); // Wait for the form to adjust to the selected country await page.waitForTimeout(2000); // When an international country is selected, the postcode error for UK format should not show anymore - await expect(page.locator('div#field-error--postcode > span')).not.toBeVisible(); + await expect(page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); // Select yes for giftaid declaration to complete the form - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); + await page.locator(selectors.giftAidClaimChoice.yes).click(); // Submitting the form with valid international details - await page.locator('button[type=submit]').click(); + await page.locator(selectors.formFields.submitButton).click(); // Thank you message on success page - await expect(page.locator('div.success-wrapper--inner h1')).toContainText('Thank you, test!'); + await expect(page.locator(selectors.success.heading)).toContainText('Thank you, test!'); await page.close(); }); diff --git a/playwright-staging/tests/update/sorry.spec.js b/playwright-staging/tests/update/sorry.spec.js index e52df692..a75a367a 100644 --- a/playwright-staging/tests/update/sorry.spec.js +++ b/playwright-staging/tests/update/sorry.spec.js @@ -1,6 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); +const { selectors } = require('../utils/locators'); test('Accessing giftaid update sorry page should show the sorry message @sanity @nightly-sanity', async ({ page }) => { // Navigate to the 'Sorry' page of giftaid update form @@ -8,11 +9,11 @@ test('Accessing giftaid update sorry page should show the sorry message @sanity await page.waitForLoadState('domcontentloaded'); // Check for the 'Sorry' message header - const headerText = await page.locator('div > h1').textContent(); + const headerText = await page.locator(selectors.sorry.heading).textContent(); expect(headerText).toContain('Sorry!'); // Verify the sorry message - const sorryMessage = await page.locator('div > div > p:nth-child(1)').isVisible(); + const sorryMessage = await page.locator(selectors.sorry.firstParagraph).isVisible(); expect(sorryMessage).toBeTruthy(); await page.close(); diff --git a/playwright-staging/tests/update/updateSuccessRedirect.spec.js b/playwright-staging/tests/update/updateSuccessRedirect.spec.js index 098bb7b0..d03deae1 100644 --- a/playwright-staging/tests/update/updateSuccessRedirect.spec.js +++ b/playwright-staging/tests/update/updateSuccessRedirect.spec.js @@ -1,6 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); +const { selectors } = require('../utils/locators'); test.describe('Success page redirect @sanity @nightly-sanity', () => { test('Accessing success page should redirect to giftaid update homepage', async ({ page }) => { @@ -9,7 +10,7 @@ test.describe('Success page redirect @sanity @nightly-sanity', () => { await page.waitForLoadState('domcontentloaded'); // Confirm the page has the expected Giftaid title after redirection - const pageTitle = await page.locator('h1[class="giftaid-title"]').textContent(); + const pageTitle = await page.locator(selectors.homepage.heading).textContent(); expect(pageTitle).toContain('Giftaid it'); await page.close(); diff --git a/playwright-staging/tests/update/validFormSubmission.spec.js b/playwright-staging/tests/update/validFormSubmission.spec.js index dcfc71f7..05cc99be 100644 --- a/playwright-staging/tests/update/validFormSubmission.spec.js +++ b/playwright-staging/tests/update/validFormSubmission.spec.js @@ -2,8 +2,9 @@ const { expect } = require('@playwright/test'); const { test } = require('../../browserstack'); const { Commands } = require('../utils/commands'); +const { selectors } = require('../utils/locators'); -test('Valid giftaid update submission @sanity @nightly-sanity', async ({ page }) => { +test.only('Valid giftaid update submission @sanity @nightly-sanity', async ({ page }) => { const commands = new Commands(page); // Navigate to the Giftaid update page @@ -14,11 +15,11 @@ test('Valid giftaid update submission @sanity @nightly-sanity', async ({ page }) await commands.populateUpdateFormFields(page); // Select 'Yes' for GiftAid declaration - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - + await page.locator(selectors.giftAidClaimChoice.yes).click(); + // Submit the form and validate the thank you message - await page.locator('button[type=submit]').click(); - await expect(page.locator('div.success-wrapper--inner h1')).toContainText('Thank you, test!'); + await page.locator(selectors.formFields.submitButton).click(); + await expect(page.locator(selectors.success.heading)).toContainText('Thank you, test!'); await page.close(); }); diff --git a/playwright-staging/tests/utils/locators.js b/playwright-staging/tests/utils/locators.js new file mode 100644 index 00000000..547c9297 --- /dev/null +++ b/playwright-staging/tests/utils/locators.js @@ -0,0 +1,74 @@ +const selectors = { + giftaid: { + option: '#field-label--giftaid', + }, + + homepage: { + heading: 'h1.giftaid-title', + }, + + giftAidClaimChoice: { + yes: '#giftAidClaimChoice>div:nth-child(2)>label', + no: '#giftAidClaimChoice>div:nth-child(3)>label', + yesInput: '#giftAidClaimChoice>div:nth-child(2)>input', + noInput: '#giftAidClaimChoice>div:nth-child(3)>input', + }, + + formFields: { + mobile: '#field-input--mobile', + firstName: 'input#field-input--firstname', + lastName: 'input#field-input--lastname', + postcode: 'input#field-input--postcode', + postcodeLookup: '#postcode_button', + submitButton: 'button[type=submit]', + }, + + address: { + manualAddressLink: 'a[aria-describedby=field-error--addressDetails]', + addressSelect: '#field-select--addressSelect', + address1: '#field-input--address1', + address2: '#field-input--address2', + address3: '#field-input--address3', + town: '#field-input--town', + country: 'select#field-select--country', + countryByName: 'select[name="country"]', + countryDropdown: 'select#field-select--country', + countryOptions: 'select#field-select--country > option', + }, + + marketingPreferences: { + options: { + email: '[aria-label="field-label--Email--Email"]', + phone: '[aria-label="field-label--Phone--Phone"]', + text: '[aria-label="field-label--Text--SMS"]', + }, + fields: { + email: 'input#field-input--email', + phone: 'input#field-input--phone', + }, + }, + + errorMessages: { + mobile: 'div#field-error--mobile > span', + firstName: 'div#field-error--firstname > span', + lastName: 'div#field-error--lastname > span', + email: '#field-error--email > span', + phone: 'div#field-error--phone > span', + postcode: 'div#field-error--postcode > span', + addressSelect: 'div#field-error--addressSelect > span', + address1: '#field-error--address1 > span', + town: '#field-error--town > span', + addressDetails: 'div#field-error--addressDetails > span', + giftAidClaimChoice: 'div#field-error--giftAidClaimChoice > span', + }, + + success: { + heading: 'div.success-wrapper--inner h1', + }, + sorry: { + heading: 'div > h1', + firstParagraph: 'div > div > p:nth-child(1)', + }, +}; + +module.exports = { selectors }; From e9062b1535986aa24541d7e99fbd7a310e427500 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 29 Apr 2026 18:02:54 +0100 Subject: [PATCH 02/35] test: add test that's been removed --- .../tests/update/formValidation.spec.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/playwright-staging/tests/update/formValidation.spec.js b/playwright-staging/tests/update/formValidation.spec.js index c0d3a2ba..90242887 100644 --- a/playwright-staging/tests/update/formValidation.spec.js +++ b/playwright-staging/tests/update/formValidation.spec.js @@ -132,4 +132,51 @@ test.describe('Giftaid Update form validation @sanity @nightly-sanity', () => { await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); }); + + test('Postcode validation and form submission', async ({ page }) => { + // Define postcodes and expected error messages + const postcodes = [ + { input: 'S E 1 7 T P', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, + { input: 'SE$%TP', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, + { input: 'cro 7tp', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' } + ]; + + // Test for each invalid postcode + for (const postcode of postcodes) { + await page.fill(selectors.formFields.postcode, ''); + await page.type(selectors.formFields.postcode, postcode.input); + await expect(page.locator(selectors.errorMessages.postcode)).toBeVisible(); + await expect(page.locator(selectors.errorMessages.postcode)).toHaveText(postcode.error); + } + + // Test for a valid postcode and subsequent form submission + await page.fill(selectors.formFields.postcode, 'SE1 7TP'); + await page.click(selectors.formFields.postcodeLookup); + + // Checking whether address selection is available or if manual entry is needed + if (await page.locator(selectors.address.addressSelect).isVisible()) { + // Select the first address if available + const options = await page.$$eval(selectors.address.addressSelectOptions, options => options.map(option => option.value)); + await page.selectOption(selectors.address.addressSelect, options[1]); + await page.click(selectors.formFields.submitButton); + } else { + // Fallback to manual address input if no selection is available + await page.click(selectors.address.manualAddressLink); + await page.fill(selectors.address.address1, 'COMIC RELIEF'); + await page.fill(selectors.address.address2, 'CAMELFORD HOUSE 87-90'); + await page.fill(selectors.address.address3, 'ALBERT EMBANKMENT'); + await page.fill(selectors.address.town, 'LONDON'); + await page.click(selectors.formFields.submitButton); + } + + await page.locator(selectors.formFields.firstName).fill('test'); + await page.locator(selectors.formFields.lastName).fill(chance.last()); + await page.locator(selectors.marketingPreferences.fields.email).fill(`giftaid-update-staging-${chance.email()}`); + await page.fill(selectors.formFields.postcode, 'SE1 7TP'); + await page.click(selectors.giftAidClaimChoice.yes); // Select yes for declaration + await page.click(selectors.formFields.submitButton); // Submit the form + + await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); + await page.close(); + }); }); From 6a524f73ea98ea6e7f657104f1bbaa28d74a8148 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 30 Apr 2026 15:57:45 +0100 Subject: [PATCH 03/35] test: write first test in cucumber --- playwright-staging/browserstack.js | 2 +- playwright-staging/config/cucumber.js | 13 + playwright-staging/package.json | 5 +- .../submit/addressValidation.spec.js | 4 +- .../submit/formValidation.spec.js | 6 +- .../internationalAddressesValidation.spec.js | 6 +- .../submit/marketingPreferencesData.spec.js | 8 +- .../marketingPreferencesValidation.spec.js | 6 +- .../submit/postcodeLookup.spec.js | 4 +- .../tests/{ => features}/submit/sorry.spec.js | 4 +- .../submit/successRedirect.spec.js | 4 +- .../submit/validFormSubmission.feature | 11 + .../update/formValidation.spec.js | 6 +- .../update/giftaidDeclarationOptions.spec.js | 6 +- .../internationalAddressesValidation.spec.js | 4 +- .../tests/{ => features}/update/sorry.spec.js | 4 +- .../update/updateSuccessRedirect.spec.js | 4 +- .../update/validFormSubmission.spec.js | 6 +- .../submit/giftaidSubmission.steps.js | 31 + .../tests/submit/validFormSubmission.spec.js | 33 - playwright-staging/tests/support/hooks.js | 78 ++ playwright-staging/tests/support/world.js | 12 + playwright-staging/yarn.lock | 742 +++++++++++++++++- 23 files changed, 927 insertions(+), 72 deletions(-) create mode 100644 playwright-staging/config/cucumber.js rename playwright-staging/tests/{ => features}/submit/addressValidation.spec.js (97%) rename playwright-staging/tests/{ => features}/submit/formValidation.spec.js (96%) rename playwright-staging/tests/{ => features}/submit/internationalAddressesValidation.spec.js (93%) rename playwright-staging/tests/{ => features}/submit/marketingPreferencesData.spec.js (90%) rename playwright-staging/tests/{ => features}/submit/marketingPreferencesValidation.spec.js (95%) rename playwright-staging/tests/{ => features}/submit/postcodeLookup.spec.js (95%) rename playwright-staging/tests/{ => features}/submit/sorry.spec.js (87%) rename playwright-staging/tests/{ => features}/submit/successRedirect.spec.js (89%) create mode 100644 playwright-staging/tests/features/submit/validFormSubmission.feature rename playwright-staging/tests/{ => features}/update/formValidation.spec.js (98%) rename playwright-staging/tests/{ => features}/update/giftaidDeclarationOptions.spec.js (89%) rename playwright-staging/tests/{ => features}/update/internationalAddressesValidation.spec.js (96%) rename playwright-staging/tests/{ => features}/update/sorry.spec.js (87%) rename playwright-staging/tests/{ => features}/update/updateSuccessRedirect.spec.js (86%) rename playwright-staging/tests/{ => features}/update/validFormSubmission.spec.js (83%) create mode 100644 playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js delete mode 100644 playwright-staging/tests/submit/validFormSubmission.spec.js create mode 100644 playwright-staging/tests/support/hooks.js create mode 100644 playwright-staging/tests/support/world.js diff --git a/playwright-staging/browserstack.js b/playwright-staging/browserstack.js index 1ea622eb..04725a9e 100644 --- a/playwright-staging/browserstack.js +++ b/playwright-staging/browserstack.js @@ -1,7 +1,7 @@ require('dotenv').config(); const base = require('@playwright/test'); -const clientPlaywrightVersion = require('@playwright/test/package.json').version; // "1.50.0" +const clientPlaywrightVersion = require('@playwright/test/package.json').version; // "1.56.1" // BrowserStack Specific Capabilities. const caps = { diff --git a/playwright-staging/config/cucumber.js b/playwright-staging/config/cucumber.js new file mode 100644 index 00000000..b9cbbc51 --- /dev/null +++ b/playwright-staging/config/cucumber.js @@ -0,0 +1,13 @@ +module.exports = { + default: { + paths: ['tests/features/**/*.feature'], + require: [ + 'tests/support/**/*.js', + 'tests/step-definitions/**/*.js', + ], + format: ['progress', 'summary'], + // Use 'pretty' locally for readable step-by-step output. + // On CI keep the output minimal to avoid noisy logs. + publishQuiet: true, + }, +}; diff --git a/playwright-staging/package.json b/playwright-staging/package.json index 82272c49..ac585018 100644 --- a/playwright-staging/package.json +++ b/playwright-staging/package.json @@ -8,6 +8,7 @@ "devDependencies": { "@comicrelief/data-models": "^1.29.6", "@comicrelief/test-utils": "^1.5.15", + "@cucumber/cucumber": "^12.8.2", "@playwright/test": "1.56.1", "axios": "^0.21.1", "chance": "^1.1.7", @@ -16,6 +17,8 @@ "uuid": "8.3.2" }, "scripts": { - "test:sanity": "FORCE_COLOR=1 playwright test --grep '@sanity'" + "test:sanity": "FORCE_COLOR=1 playwright test --grep '@sanity'", + "test:cucumber": "FORCE_COLOR=1 cucumber-js --config config/cucumber.js", + "test:cucumber:sanity": "FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'" } } diff --git a/playwright-staging/tests/submit/addressValidation.spec.js b/playwright-staging/tests/features/submit/addressValidation.spec.js similarity index 97% rename from playwright-staging/tests/submit/addressValidation.spec.js rename to playwright-staging/tests/features/submit/addressValidation.spec.js index 3a448d12..3656b6f5 100644 --- a/playwright-staging/tests/submit/addressValidation.spec.js +++ b/playwright-staging/tests/features/submit/addressValidation.spec.js @@ -1,7 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { selectors } = require('../../utils/locators'); test.describe('Address validation @sanity @nightly-sanity', () => { diff --git a/playwright-staging/tests/submit/formValidation.spec.js b/playwright-staging/tests/features/submit/formValidation.spec.js similarity index 96% rename from playwright-staging/tests/submit/formValidation.spec.js rename to playwright-staging/tests/features/submit/formValidation.spec.js index 6e14762a..c7892b81 100644 --- a/playwright-staging/tests/submit/formValidation.spec.js +++ b/playwright-staging/tests/features/submit/formValidation.spec.js @@ -1,8 +1,8 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { Commands } = require('../../utils/commands'); +const { selectors } = require('../../utils/locators'); test.describe('Form validation @sanity @nightly-sanity', () => { diff --git a/playwright-staging/tests/submit/internationalAddressesValidation.spec.js b/playwright-staging/tests/features/submit/internationalAddressesValidation.spec.js similarity index 93% rename from playwright-staging/tests/submit/internationalAddressesValidation.spec.js rename to playwright-staging/tests/features/submit/internationalAddressesValidation.spec.js index 630cd7cc..ee9febd9 100644 --- a/playwright-staging/tests/submit/internationalAddressesValidation.spec.js +++ b/playwright-staging/tests/features/submit/internationalAddressesValidation.spec.js @@ -1,8 +1,8 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { Commands } = require('../../utils/commands'); +const { selectors } = require('../../utils/locators'); test.describe('International addresses validation @sanity @nightly-sanity', () => { test('selecting a non-UK country and entering a non-UK postcode should submit the form', async ({ page }) => { diff --git a/playwright-staging/tests/submit/marketingPreferencesData.spec.js b/playwright-staging/tests/features/submit/marketingPreferencesData.spec.js similarity index 90% rename from playwright-staging/tests/submit/marketingPreferencesData.spec.js rename to playwright-staging/tests/features/submit/marketingPreferencesData.spec.js index 56c0dc2a..324be16b 100644 --- a/playwright-staging/tests/submit/marketingPreferencesData.spec.js +++ b/playwright-staging/tests/features/submit/marketingPreferencesData.spec.js @@ -1,9 +1,9 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); -const { MarketingPrefsVerify } = require('../utils/marketingPrefsVerify'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { Commands } = require('../../utils/commands'); +const { MarketingPrefsVerify } = require('../../utils/marketingPrefsVerify'); +const { selectors } = require('../../utils/locators'); const Chance = require('chance'); const chance = new Chance(); diff --git a/playwright-staging/tests/submit/marketingPreferencesValidation.spec.js b/playwright-staging/tests/features/submit/marketingPreferencesValidation.spec.js similarity index 95% rename from playwright-staging/tests/submit/marketingPreferencesValidation.spec.js rename to playwright-staging/tests/features/submit/marketingPreferencesValidation.spec.js index f1448bb8..ad9b341a 100644 --- a/playwright-staging/tests/submit/marketingPreferencesValidation.spec.js +++ b/playwright-staging/tests/features/submit/marketingPreferencesValidation.spec.js @@ -1,8 +1,8 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { Commands } = require('../../utils/commands'); +const { selectors } = require('../../utils/locators'); const Chance = require('chance'); const chance = new Chance(); diff --git a/playwright-staging/tests/submit/postcodeLookup.spec.js b/playwright-staging/tests/features/submit/postcodeLookup.spec.js similarity index 95% rename from playwright-staging/tests/submit/postcodeLookup.spec.js rename to playwright-staging/tests/features/submit/postcodeLookup.spec.js index 10b1b577..1268a83d 100644 --- a/playwright-staging/tests/submit/postcodeLookup.spec.js +++ b/playwright-staging/tests/features/submit/postcodeLookup.spec.js @@ -1,7 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { selectors } = require('../../utils/locators'); test.describe('Postcode validation @sanity @nightly-sanity', () => { diff --git a/playwright-staging/tests/submit/sorry.spec.js b/playwright-staging/tests/features/submit/sorry.spec.js similarity index 87% rename from playwright-staging/tests/submit/sorry.spec.js rename to playwright-staging/tests/features/submit/sorry.spec.js index ea1f603d..ffc54748 100644 --- a/playwright-staging/tests/submit/sorry.spec.js +++ b/playwright-staging/tests/features/submit/sorry.spec.js @@ -1,7 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { selectors } = require('../../utils/locators'); test('Accessing giftaid sorry page should show the sorry message @sanity @nightly-sanity', async ({ page }) => { // Go directly to the "sorry" page appended to the base URL diff --git a/playwright-staging/tests/submit/successRedirect.spec.js b/playwright-staging/tests/features/submit/successRedirect.spec.js similarity index 89% rename from playwright-staging/tests/submit/successRedirect.spec.js rename to playwright-staging/tests/features/submit/successRedirect.spec.js index cda8625f..0dac4165 100644 --- a/playwright-staging/tests/submit/successRedirect.spec.js +++ b/playwright-staging/tests/features/submit/successRedirect.spec.js @@ -1,7 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { selectors } = require('../../utils/locators'); test('Accessing success page should redirect to giftaid homepage @sanity @nightly-sanity', async ({ page }) => { // Navigate directly to the success page and expect a redirect diff --git a/playwright-staging/tests/features/submit/validFormSubmission.feature b/playwright-staging/tests/features/submit/validFormSubmission.feature new file mode 100644 index 00000000..75d2a36a --- /dev/null +++ b/playwright-staging/tests/features/submit/validFormSubmission.feature @@ -0,0 +1,11 @@ +@sanity @nightly-sanity +Feature: Giftaid submission + + Scenario: Submit Giftaid form with valid details + Given I am on the Giftaid page + When I select Giftaid + And I complete the Giftaid form with valid details + And I select marketing preferences + And I submit the Giftaid form + Then I should see the Giftaid thank you message + diff --git a/playwright-staging/tests/update/formValidation.spec.js b/playwright-staging/tests/features/update/formValidation.spec.js similarity index 98% rename from playwright-staging/tests/update/formValidation.spec.js rename to playwright-staging/tests/features/update/formValidation.spec.js index 90242887..e6194fae 100644 --- a/playwright-staging/tests/update/formValidation.spec.js +++ b/playwright-staging/tests/features/update/formValidation.spec.js @@ -1,11 +1,11 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); +const { test } = require('../../../browserstack'); +const { Commands } = require('../../utils/commands'); const { v4: uuidv4 } = require('uuid'); const Chance = require('chance'); const chance = new Chance(); -const { selectors } = require('../utils/locators'); +const { selectors } = require('../../utils/locators'); test.describe('Giftaid Update form validation @sanity @nightly-sanity', () => { let commands; diff --git a/playwright-staging/tests/update/giftaidDeclarationOptions.spec.js b/playwright-staging/tests/features/update/giftaidDeclarationOptions.spec.js similarity index 89% rename from playwright-staging/tests/update/giftaidDeclarationOptions.spec.js rename to playwright-staging/tests/features/update/giftaidDeclarationOptions.spec.js index 7e9a3443..ee684b48 100644 --- a/playwright-staging/tests/update/giftaidDeclarationOptions.spec.js +++ b/playwright-staging/tests/features/update/giftaidDeclarationOptions.spec.js @@ -1,8 +1,8 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { Commands } = require('../../utils/commands'); +const { selectors } = require('../../utils/locators'); test('Validate Giftaid declaration claim selections @sanity @nightly-sanity', async ({ page }) => { const commands = new Commands(page); diff --git a/playwright-staging/tests/update/internationalAddressesValidation.spec.js b/playwright-staging/tests/features/update/internationalAddressesValidation.spec.js similarity index 96% rename from playwright-staging/tests/update/internationalAddressesValidation.spec.js rename to playwright-staging/tests/features/update/internationalAddressesValidation.spec.js index 5f0c3361..91ea0860 100644 --- a/playwright-staging/tests/update/internationalAddressesValidation.spec.js +++ b/playwright-staging/tests/features/update/internationalAddressesValidation.spec.js @@ -1,8 +1,8 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); +const { test } = require('../../../browserstack'); const { v4: uuidv4 } = require('uuid'); -const { selectors } = require('../utils/locators'); +const { selectors } = require('../../utils/locators'); test.describe('International addresses validation on update form @sanity @nightly-sanity', () => { test('selecting a non-UK country and entering a non-UK postcode should submit the update form', async ({ page }) => { diff --git a/playwright-staging/tests/update/sorry.spec.js b/playwright-staging/tests/features/update/sorry.spec.js similarity index 87% rename from playwright-staging/tests/update/sorry.spec.js rename to playwright-staging/tests/features/update/sorry.spec.js index a75a367a..6a08bc83 100644 --- a/playwright-staging/tests/update/sorry.spec.js +++ b/playwright-staging/tests/features/update/sorry.spec.js @@ -1,7 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { selectors } = require('../../utils/locators'); test('Accessing giftaid update sorry page should show the sorry message @sanity @nightly-sanity', async ({ page }) => { // Navigate to the 'Sorry' page of giftaid update form diff --git a/playwright-staging/tests/update/updateSuccessRedirect.spec.js b/playwright-staging/tests/features/update/updateSuccessRedirect.spec.js similarity index 86% rename from playwright-staging/tests/update/updateSuccessRedirect.spec.js rename to playwright-staging/tests/features/update/updateSuccessRedirect.spec.js index d03deae1..c0108805 100644 --- a/playwright-staging/tests/update/updateSuccessRedirect.spec.js +++ b/playwright-staging/tests/features/update/updateSuccessRedirect.spec.js @@ -1,7 +1,7 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { selectors } = require('../../utils/locators'); test.describe('Success page redirect @sanity @nightly-sanity', () => { test('Accessing success page should redirect to giftaid update homepage', async ({ page }) => { diff --git a/playwright-staging/tests/update/validFormSubmission.spec.js b/playwright-staging/tests/features/update/validFormSubmission.spec.js similarity index 83% rename from playwright-staging/tests/update/validFormSubmission.spec.js rename to playwright-staging/tests/features/update/validFormSubmission.spec.js index 05cc99be..eaa3ee94 100644 --- a/playwright-staging/tests/update/validFormSubmission.spec.js +++ b/playwright-staging/tests/features/update/validFormSubmission.spec.js @@ -1,8 +1,8 @@ // @ts-check const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); -const { selectors } = require('../utils/locators'); +const { test } = require('../../../browserstack'); +const { Commands } = require('../../utils/commands'); +const { selectors } = require('../../utils/locators'); test.only('Valid giftaid update submission @sanity @nightly-sanity', async ({ page }) => { const commands = new Commands(page); diff --git a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js new file mode 100644 index 00000000..06e5d74c --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js @@ -0,0 +1,31 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I am on the Giftaid page', async function () { + await this.page.goto(process.env.BASE_URL, { timeout: 30000 }); + await this.page.waitForLoadState('domcontentloaded'); +}); + +When('I select Giftaid', async function () { + await this.page.click(selectors.giftaid.option); +}); + +When('I complete the Giftaid form with valid details', async function () { + await this.commands.populateFormFields(this.page); +}); + +When('I select marketing preferences', async function () { + await this.commands.selectMarketingPrefs(this.page); +}); + +When('I submit the Giftaid form', async function () { + await Promise.all([ + this.page.waitForNavigation(), + this.page.click(selectors.formFields.submitButton), + ]); +}); + +Then('I should see the Giftaid thank you message', async function () { + await expect(this.page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); +}); diff --git a/playwright-staging/tests/submit/validFormSubmission.spec.js b/playwright-staging/tests/submit/validFormSubmission.spec.js deleted file mode 100644 index 863a3a08..00000000 --- a/playwright-staging/tests/submit/validFormSubmission.spec.js +++ /dev/null @@ -1,33 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../browserstack'); -const { Commands } = require('../utils/commands'); -const { selectors } = require('../utils/locators'); - -test('Valid giftaid submission @sanity @nightly-sanity', async ({ page }) => { - const commands = new Commands(page); - - // Navigate to the giftaid page - await page.goto(process.env.BASE_URL, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Click the Giftaid checkbox - await page.click(selectors.giftaid.option); - - // Populate all the form fields with valid inputs - await commands.populateFormFields(page); - - // Select marketing preferences as required - await commands.selectMarketingPrefs(page); - - // Submit the form and wait for the navigation to ensure the submission goes through - await Promise.all([ - page.waitForNavigation(), - page.click(selectors.formFields.submitButton), - ]); - - // Check for the thank you message to confirm successful submission - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); - - await page.close(); -}); diff --git a/playwright-staging/tests/support/hooks.js b/playwright-staging/tests/support/hooks.js new file mode 100644 index 00000000..9ead586d --- /dev/null +++ b/playwright-staging/tests/support/hooks.js @@ -0,0 +1,78 @@ +require('dotenv').config(); + +const { Before, After, Status, setDefaultTimeout } = require('@cucumber/cucumber'); +const { chromium } = require('@playwright/test'); +const { Commands } = require('../utils/commands'); + +setDefaultTimeout(300 * 1000); + +const clientPlaywrightVersion = require('@playwright/test/package.json').version; + +const caps = { + project: 'giftaid-react', + name: 'cucumber e2e tests', + browser: 'chrome', + browser_version: 'latest', + resolution: '1920x1080', + os: 'Windows', + os_version: '11', + 'browserstack.username': process.env.BROWSERSTACK_USERNAME, + 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, + 'client.playwrightVersion': clientPlaywrightVersion, + 'browserstack.playwrightVersion': clientPlaywrightVersion, + + // logs + 'browserstack.networkLogs': true, + 'browserstack.console': 'info', + 'browserstack.debug': true, + 'browserstack.idleTimeout': 300, +}; + +Before(async function (scenario) { + caps.name = scenario.pickle.name; + + this.browser = await chromium.connect({ + wsEndpoint: + `wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify(caps))}`, + }); + + this.context = await this.browser.newContext({ + viewport: null, + serviceWorkers: 'block', + }); + + this.page = await this.context.newPage(); + + // maximise window + const session = await this.context.newCDPSession(this.page); + const { windowId } = await session.send('Browser.getWindowForTarget'); + await session.send('Browser.setWindowBounds', { + windowId, + bounds: { windowState: 'maximized' }, + }); + + this.commands = new Commands(this.page); +}); + +After(async function (scenario) { + const testResult = { + action: 'setSessionStatus', + arguments: { + status: scenario.result?.status === Status.PASSED ? 'passed' : 'failed', + reason: scenario.result?.message || '', + }, + }; + + if (this.page) { + await this.page.evaluate(() => {}, `browserstack_executor: ${JSON.stringify(testResult)}`); + await this.page.close(); + } + + if (this.context) { + await this.context.close(); + } + + if (this.browser) { + await this.browser.close(); + } +}); diff --git a/playwright-staging/tests/support/world.js b/playwright-staging/tests/support/world.js new file mode 100644 index 00000000..ab3a2bc3 --- /dev/null +++ b/playwright-staging/tests/support/world.js @@ -0,0 +1,12 @@ +const { setWorldConstructor } = require('@cucumber/cucumber'); + +class CustomWorld { + constructor() { + this.browser = null; + this.context = null; + this.page = null; + this.commands = null; + } +} + +setWorldConstructor(CustomWorld); diff --git a/playwright-staging/yarn.lock b/playwright-staging/yarn.lock index 8a3061cc..1aae373d 100644 --- a/playwright-staging/yarn.lock +++ b/playwright-staging/yarn.lock @@ -2,6 +2,20 @@ # yarn lockfile v1 +"@babel/code-frame@^7.26.2": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" + integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== + dependencies: + "@babel/helper-validator-identifier" "^7.28.5" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + "@babel/runtime@^7.10.5": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" @@ -9,6 +23,11 @@ dependencies: regenerator-runtime "^0.13.11" +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + "@comicrelief/data-models@^1.29.6": version "1.65.0" resolved "https://registry.yarnpkg.com/@comicrelief/data-models/-/data-models-1.65.0.tgz#2641ed99e58edf426e15ec7c4d62c73676d94dcb" @@ -24,6 +43,142 @@ resolved "https://registry.yarnpkg.com/@comicrelief/test-utils/-/test-utils-1.5.15.tgz#48ee30ccfa44d220dabce8dd7e9bb43c8e043814" integrity sha512-XsShlQcGzHDv6FVlJLvWGDPdY4mgqFNWdw+dXlGFXCCiC2WCpVQzVdzdInOTfvCZZXLAHDTT+RaF+RZlj3VVRQ== +"@cucumber/ci-environment@13.0.0": + version "13.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/ci-environment/-/ci-environment-13.0.0.tgz#0a9c4e279814af864cd1591c4c16f284e14af39b" + integrity sha512-cs+3NzfNkGbcmHPddjEv4TKFiBpZRQ6WJEEufB9mw+ExS22V/4R/zpDSEG+fsJ/iSNCd6A2sATdY8PFOyY3YnA== + +"@cucumber/cucumber-expressions@19.0.0": + version "19.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber-expressions/-/cucumber-expressions-19.0.0.tgz#562c932b1e6808485e4a45bf9cbcc93cdc3b1d45" + integrity sha512-4FKoOQh2Uf6F6/Ln+1OxuK8LkTg6PyAqekhf2Ix8zqV2M54sH+m7XNJNLhOFOAW/t9nxzRbw2CcvXbCLjcvHZg== + dependencies: + regexp-match-indices "1.0.2" + +"@cucumber/cucumber@^12.8.2": + version "12.8.2" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber/-/cucumber-12.8.2.tgz#6f8ffbfdd5b135ce6625b8047c461721dc0cb4ec" + integrity sha512-IvprstODr0JYTtVG7CQbphN6AGRpzzAQ1EjG7TSumuS15uvVt0inWm8/9uzX8oJwEv5ReU7JruDFim4938omog== + dependencies: + "@cucumber/ci-environment" "13.0.0" + "@cucumber/cucumber-expressions" "19.0.0" + "@cucumber/gherkin" "38.0.0" + "@cucumber/gherkin-streams" "6.0.0" + "@cucumber/gherkin-utils" "11.0.0" + "@cucumber/html-formatter" "23.1.0" + "@cucumber/junit-xml-formatter" "0.13.3" + "@cucumber/message-streams" "4.1.1" + "@cucumber/messages" "32.3.1" + "@cucumber/pretty-formatter" "1.0.1" + "@cucumber/tag-expressions" "9.1.0" + assertion-error-formatter "^3.0.0" + capital-case "^1.0.4" + chalk "^4.1.2" + cli-table3 "0.6.5" + commander "^14.0.0" + debug "^4.3.4" + error-stack-parser "^2.1.4" + figures "^3.2.0" + glob "^13.0.0" + has-ansi "^4.0.1" + indent-string "^4.0.0" + is-installed-globally "^0.4.0" + is-stream "^2.0.0" + knuth-shuffle-seeded "^1.0.6" + lodash.merge "^4.6.2" + lodash.mergewith "^4.6.2" + luxon "3.7.2" + mkdirp "^3.0.0" + mz "^2.7.0" + progress "^2.0.3" + read-package-up "^12.0.0" + semver "7.7.4" + string-argv "0.3.1" + supports-color "^8.1.1" + type-fest "^4.41.0" + util-arity "^1.1.0" + yaml "^2.2.2" + yup "1.7.1" + +"@cucumber/gherkin-streams@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin-streams/-/gherkin-streams-6.0.0.tgz#51e78a333439c6ed3d9e731d69ad3729a749028a" + integrity sha512-HLSHMmdDH0vCr7vsVEURcDA4WwnRLdjkhqr6a4HQ3i4RFK1wiDGPjBGVdGJLyuXuRdJpJbFc6QxHvT8pU4t6jw== + dependencies: + commander "14.0.0" + source-map-support "0.5.21" + +"@cucumber/gherkin-utils@11.0.0": + version "11.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin-utils/-/gherkin-utils-11.0.0.tgz#167afa559978cf6fbe2b583d3d5f9e7c4741c28a" + integrity sha512-LJ+s4+TepHTgdKWDR4zbPyT7rQjmYIcukTwNbwNwgqr6i8Gjcmzf6NmtbYDA19m1ZFg6kWbFsmHnj37ZuX+kZA== + dependencies: + "@cucumber/gherkin" "^38.0.0" + "@cucumber/messages" "^32.0.0" + "@teppeis/multimaps" "3.0.0" + commander "14.0.2" + source-map-support "^0.5.21" + +"@cucumber/gherkin@38.0.0", "@cucumber/gherkin@^38.0.0": + version "38.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin/-/gherkin-38.0.0.tgz#6c74388f95694e4c92762aeddf3d5638dbedf540" + integrity sha512-duEXK+KDfQUzu3vsSzXjkxQ2tirF5PRsc1Xrts6THKHJO6mjw4RjM8RV+vliuDasmhhrmdLcOcM7d9nurNTJKw== + dependencies: + "@cucumber/messages" ">=31.0.0 <33" + +"@cucumber/html-formatter@23.1.0": + version "23.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/html-formatter/-/html-formatter-23.1.0.tgz#6b9f759f9d50355b0cb28edde3ad3580d91f7081" + integrity sha512-DcCSFoGs6jbwzXPgX1CwgJKEE+ZMcIEzq/0Memg0o24maNn9NJizBFHmoFWG4iv/OxHza+mvc+56cTHetfHndw== + +"@cucumber/junit-xml-formatter@0.13.3": + version "0.13.3" + resolved "https://registry.yarnpkg.com/@cucumber/junit-xml-formatter/-/junit-xml-formatter-0.13.3.tgz#a6ee049caa4afe9160f1514b8c65f24a00e71f42" + integrity sha512-w9ujOxiuKDtU6fLzJz+wp4Sgp5Xu6ba7ls00LHJccVmQU0Ba7zs+AHnv3iIgPjKZAQe1w8x93dr8Gaubh7Vqkg== + dependencies: + "@cucumber/query" "^15.0.1" + "@teppeis/multimaps" "^3.0.0" + luxon "^3.5.0" + xmlbuilder "^15.1.1" + +"@cucumber/message-streams@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@cucumber/message-streams/-/message-streams-4.1.1.tgz#d3a271e6f6c90a52d731fb3554a56c4c6b456d17" + integrity sha512-QCAntLajesWMyX+mZKrj63YghVAts7yKFlZe46XprLbdJZN0ddB+f/Mr9OnyWKC2DHhJ18jzCfKIFCaqpAmUxg== + dependencies: + mime "^3.0.0" + +"@cucumber/messages@32.3.1", "@cucumber/messages@>=31.0.0 <33", "@cucumber/messages@^32.0.0": + version "32.3.1" + resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-32.3.1.tgz#8c6990554c35fb9bcff0b7f09fe52ddfd479dbce" + integrity sha512-yNQq1KoXRYaEKrWMFmpUQX7TdeQuU9jeGgJAZ3dArTsC/T4NpJ6DnqaJIIgwPnz/wtQIQTNX7/h0rOuF5xY4qQ== + dependencies: + class-transformer "0.5.1" + reflect-metadata "0.2.2" + +"@cucumber/pretty-formatter@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/pretty-formatter/-/pretty-formatter-1.0.1.tgz#65d6c1df436920036a7bd02d08cb44d20e7af0ab" + integrity sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ== + dependencies: + ansi-styles "^5.0.0" + cli-table3 "^0.6.0" + figures "^3.2.0" + ts-dedent "^2.0.0" + +"@cucumber/query@^15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/query/-/query-15.0.1.tgz#91b701121ba95caf7d0e6d9de95041ec3396d297" + integrity sha512-FMfT3orJblRsOxvU2doECBvQmauizYlj+5JsM8atAKKPbnQTj7v2/OrnuykvQpfZNBf19DYbRq1e832vllRP/g== + dependencies: + "@teppeis/multimaps" "3.0.0" + lodash.sortby "^4.7.0" + +"@cucumber/tag-expressions@9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/tag-expressions/-/tag-expressions-9.1.0.tgz#5c63cf716b6d688f140d0e4c0cc858bfd5703618" + integrity sha512-bvHjcRFZ+J1TqIa9eFNO1wGHqwx4V9ZKV3hYgkuK/VahHx73uiP4rKV3JVrvWSMrwrFvJG6C8aEwnCWSvbyFdQ== + "@jridgewell/gen-mapping@^0.3.0": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" @@ -71,6 +226,16 @@ dependencies: playwright "1.56.1" +"@teppeis/multimaps@3.0.0", "@teppeis/multimaps@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@teppeis/multimaps/-/multimaps-3.0.0.tgz#bb9c3f8d569f589e548586fa0bbf423010ddfdc5" + integrity sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q== + +"@types/normalize-package-data@^2.4.4": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" + integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== + acorn@^8.5.0: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" @@ -83,11 +248,38 @@ ansi-colors@^1.0.1: dependencies: ansi-wrap "^0.1.0" +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" integrity sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw== +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -98,6 +290,15 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== +assertion-error-formatter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz#be9c8825dee6a8a6c72183d915912d9b57d5d265" + integrity sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ== + dependencies: + diff "^4.0.1" + pad-right "^0.2.2" + repeat-string "^1.6.1" + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -110,11 +311,40 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" +balanced-match@^4.0.2: + version "4.0.4" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" + integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== + +brace-expansion@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" + integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== + dependencies: + balanced-match "^4.0.2" + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chance@^1.1.7: version "1.1.10" resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.10.tgz#97aa50acaeb810ae293330a9e2b138ee3d49daf2" @@ -122,6 +352,20 @@ chance@^1.1.7: dependencies: gulp-uglify-es "^3.0.0" +class-transformer@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +cli-table3@0.6.5, cli-table3@^0.6.0: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + clone-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" @@ -146,6 +390,33 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.0.tgz#f244fc74a92343514e56229f16ef5c5e22ced5e9" + integrity sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA== + +commander@14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.2.tgz#b71fd37fe4069e4c3c7c13925252ada4eba14e8e" + integrity sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ== + +commander@^14.0.0: + version "14.0.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.3.tgz#425d79b48f9af82fcd9e4fc1ea8af6c5ec07bbc2" + integrity sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw== + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -156,11 +427,40 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +debug@^4.3.4: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +diff@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.4.tgz#7a6dbfda325f25f07517e9b518f897c08332e07d" + integrity sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ== + dotenv@^8.0.0: version "8.6.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-stack-parser@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== + dependencies: + stackframe "^1.3.4" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" @@ -174,6 +474,18 @@ faker@^5.5.3: resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== +figures@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +find-up-simple@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/find-up-simple/-/find-up-simple-1.0.1.tgz#18fb90ad49e45252c4d7fca56baade04fa3fca1e" + integrity sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ== + fn-name@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c" @@ -189,6 +501,22 @@ fsevents@2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +glob@^13.0.0: + version "13.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d" + integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw== + dependencies: + minimatch "^10.2.2" + minipass "^7.1.3" + path-scurry "^2.0.2" + +global-dirs@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" + integrity sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA== + dependencies: + ini "2.0.0" + gulp-uglify-es@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/gulp-uglify-es/-/gulp-uglify-es-3.0.0.tgz#00466e0e3b0486057c552b8b0d3e326791f2f832" @@ -200,11 +528,45 @@ gulp-uglify-es@^3.0.0: vinyl "^2.2.1" vinyl-sourcemaps-apply "^0.2.1" +has-ansi@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-4.0.1.tgz#f216a8c8d7b129e490dc15f4a62cc1cdb9603ce8" + integrity sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A== + dependencies: + ansi-regex "^4.1.0" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hosted-git-info@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-9.0.2.tgz#b38c8a802b274e275eeeccf9f4a1b1a0a8557ada" + integrity sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg== + dependencies: + lru-cache "^11.1.0" + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +index-to-position@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/index-to-position/-/index-to-position-1.2.0.tgz#c800eb34dacf4dbf96b9b06c7eb78d5f704138b4" + integrity sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw== + inherits@^2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" @@ -212,6 +574,24 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-installed-globally@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -219,6 +599,11 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -229,21 +614,152 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +knuth-shuffle-seeded@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz#01f1b65733aa7540ee08d8b0174164d22081e4e1" + integrity sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg== + dependencies: + seed-random "~2.2.0" + lodash-es@^4.17.11: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^11.0.0, lru-cache@^11.1.0: + version "11.3.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.3.5.tgz#29047d348c0b2793e3112a01c739bb7c6d855637" + integrity sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw== + +luxon@3.7.2, luxon@^3.5.0: + version "3.7.2" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.7.2.tgz#d697e48f478553cca187a0f8436aff468e3ba0ba" + integrity sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew== + +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + +minimatch@^10.2.2: + version "10.2.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" + integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== + dependencies: + brace-expansion "^5.0.5" + +minipass@^7.1.2, minipass@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" + integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== + +mkdirp@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +normalize-package-data@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-8.0.0.tgz#bdce7ff2d6ba891b853e179e45a5337766e304a7" + integrity sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ== + dependencies: + hosted-git-info "^9.0.0" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + o-stream@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/o-stream/-/o-stream-0.3.0.tgz#204d27bc3fb395164507d79b381e91752e8daedc" integrity sha512-gbzl6qCJZ609x/M2t25HqCYQagFzWYCtQ84jcuObGr+V8D1Am4EVubkF4J+XFs6ukfiv96vNeiBb8FrbbMZYiQ== +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +pad-right@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/pad-right/-/pad-right-0.2.2.tgz#6fbc924045d244f2a2a244503060d3bfc6009774" + integrity sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g== + dependencies: + repeat-string "^1.5.2" + +parse-json@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-8.3.0.tgz#88a195a2157025139a2317a4f2f9252b61304ed5" + integrity sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ== + dependencies: + "@babel/code-frame" "^7.26.2" + index-to-position "^1.1.0" + type-fest "^4.39.1" + +path-scurry@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85" + integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + playwright-core@1.56.1: version "1.56.1" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.56.1.tgz#24a66481e5cd33a045632230aa2c4f0cb6b1db3d" @@ -278,11 +794,41 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +progress@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + property-expr@^2.0.2: version "2.0.5" resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== +property-expr@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" + integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== + +read-package-up@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/read-package-up/-/read-package-up-12.0.0.tgz#7ae889586f397b7a291ca59ce08caf7e9f68a61c" + integrity sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw== + dependencies: + find-up-simple "^1.0.1" + read-pkg "^10.0.0" + type-fest "^5.2.0" + +read-pkg@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-10.1.0.tgz#eff31c7e505a4995a85c5af017b3dc413745431c" + integrity sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg== + dependencies: + "@types/normalize-package-data" "^2.4.4" + normalize-package-data "^8.0.0" + parse-json "^8.3.0" + type-fest "^5.4.4" + unicorn-magic "^0.4.0" + readable-stream@^2.3.5: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" @@ -296,16 +842,38 @@ readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" +reflect-metadata@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== + regenerator-runtime@^0.13.11: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regexp-match-indices@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz#cf20054a6f7d5b3e116a701a7b00f82889d10da6" + integrity sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ== + dependencies: + regexp-tree "^0.1.11" + +regexp-tree@^0.1.11: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== + replace-ext@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" @@ -316,7 +884,17 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -source-map-support@~0.5.20: +seed-random@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/seed-random/-/seed-random-2.2.0.tgz#2a9b19e250a817099231a5b99a4daf80b7fbed54" + integrity sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ== + +semver@7.7.4, semver@^7.3.5: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + +source-map-support@0.5.21, source-map-support@^0.5.21, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -334,6 +912,51 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.23" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz#b069e687b1291a32f126893ed76a27a745ee2133" + integrity sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw== + +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== + +string-argv@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== + +string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -341,11 +964,37 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + synchronous-promise@^2.0.13: version "2.0.17" resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.17.tgz#38901319632f946c982152586f2caf8ddc25c032" integrity sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g== +tagged-tag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tagged-tag/-/tagged-tag-1.0.0.tgz#a0b5917c2864cba54841495abfa3f6b13edcf4d6" + integrity sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng== + terser@^5.7.1: version "5.16.5" resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.5.tgz#1c285ca0655f467f92af1bbab46ab72d1cb08e5a" @@ -356,11 +1005,74 @@ terser@^5.7.1: commander "^2.20.0" source-map-support "~0.5.20" +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +tiny-case@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" + integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== + toposort@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== +ts-dedent@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" + integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== + +tslib@^2.0.3: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +type-fest@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + +type-fest@^4.39.1, type-fest@^4.41.0: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + +type-fest@^5.2.0, type-fest@^5.4.4: + version "5.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-5.6.0.tgz#502f7a003b7309e96a7e17052cc2ab2c7e5c7a31" + integrity sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA== + dependencies: + tagged-tag "^1.0.0" + +unicorn-magic@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.4.0.tgz#78c6a090fd6d07abd2468b83b385603e00dfdb24" + integrity sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw== + +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" + +util-arity@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/util-arity/-/util-arity-1.1.0.tgz#59d01af1fdb3fede0ac4e632b0ab5f6ce97c9330" + integrity sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA== + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -371,6 +1083,14 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + vinyl-sourcemaps-apply@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" @@ -390,6 +1110,26 @@ vinyl@^2.2.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" +xmlbuilder@^15.1.1: + version "15.1.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" + integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== + +yaml@^2.2.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.3.tgz#a0d6bd2efb3dd03c59370223701834e60409bd7d" + integrity sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg== + +yup@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/yup/-/yup-1.7.1.tgz#4c47c6bb367df08d4bc597f8c4c4f5fc4277f6ab" + integrity sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw== + dependencies: + property-expr "^2.0.5" + tiny-case "^1.0.3" + toposort "^2.0.2" + type-fest "^2.19.0" + yup@^0.29.3: version "0.29.3" resolved "https://registry.yarnpkg.com/yup/-/yup-0.29.3.tgz#69a30fd3f1c19f5d9e31b1cf1c2b851ce8045fea" From 5bb625d5b7f034a6b4a47bddf5f8dc298d82b100 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Fri, 1 May 2026 16:53:49 +0100 Subject: [PATCH 04/35] test: convert submit dir tests into Gherkin and add step definitions --- .../features/submit/addressValidation.feature | 43 ++++++++++ .../features/submit/addressValidation.spec.js | 76 ----------------- .../features/submit/formValidation.feature | 55 ++++++++++++ .../features/submit/formValidation.spec.js | 83 ------------------- .../internationalAddressesValidation.feature | 15 ++++ .../internationalAddressesValidation.spec.js | 57 ------------- .../submit/marketingPreferencesData.feature | 11 +++ .../submit/marketingPreferencesData.spec.js | 64 -------------- .../marketingPreferencesValidation.feature | 35 ++++++++ .../marketingPreferencesValidation.spec.js | 82 ------------------ .../features/submit/postcodeLookup.feature | 23 +++++ .../features/submit/postcodeLookup.spec.js | 52 ------------ .../tests/features/submit/sorry.feature | 7 ++ .../tests/features/submit/sorry.spec.js | 20 ----- .../features/submit/successRedirect.feature | 10 +++ .../features/submit/successRedirect.spec.js | 21 ----- .../common/giftaidCommon.steps.js | 15 ++++ .../submit/addressValidation.steps.js | 48 +++++++++++ .../submit/formValidation.steps.js | 48 +++++++++++ .../submit/giftaidSubmission.steps.js | 15 ---- .../internationalAddressValidation.steps.js | 35 ++++++++ .../marketingPreferencesContactStore.steps.js | 69 +++++++++++++++ .../marketingPreferencesValidation.steps.js | 70 ++++++++++++++++ .../submit/postcodeValidation.steps.js | 39 +++++++++ .../submit/sorryPage.steps.js | 18 ++++ .../submit/successRedirect.steps.js | 26 ++++++ 26 files changed, 567 insertions(+), 470 deletions(-) create mode 100644 playwright-staging/tests/features/submit/addressValidation.feature delete mode 100644 playwright-staging/tests/features/submit/addressValidation.spec.js create mode 100644 playwright-staging/tests/features/submit/formValidation.feature delete mode 100644 playwright-staging/tests/features/submit/formValidation.spec.js create mode 100644 playwright-staging/tests/features/submit/internationalAddressesValidation.feature delete mode 100644 playwright-staging/tests/features/submit/internationalAddressesValidation.spec.js create mode 100644 playwright-staging/tests/features/submit/marketingPreferencesData.feature delete mode 100644 playwright-staging/tests/features/submit/marketingPreferencesData.spec.js create mode 100644 playwright-staging/tests/features/submit/marketingPreferencesValidation.feature delete mode 100644 playwright-staging/tests/features/submit/marketingPreferencesValidation.spec.js create mode 100644 playwright-staging/tests/features/submit/postcodeLookup.feature delete mode 100644 playwright-staging/tests/features/submit/postcodeLookup.spec.js create mode 100644 playwright-staging/tests/features/submit/sorry.feature delete mode 100644 playwright-staging/tests/features/submit/sorry.spec.js create mode 100644 playwright-staging/tests/features/submit/successRedirect.feature delete mode 100644 playwright-staging/tests/features/submit/successRedirect.spec.js create mode 100644 playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/addressValidation.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/formValidation.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/sorryPage.steps.js create mode 100644 playwright-staging/tests/step-definitions/submit/successRedirect.steps.js diff --git a/playwright-staging/tests/features/submit/addressValidation.feature b/playwright-staging/tests/features/submit/addressValidation.feature new file mode 100644 index 00000000..cacd5a43 --- /dev/null +++ b/playwright-staging/tests/features/submit/addressValidation.feature @@ -0,0 +1,43 @@ +@sanity @nightly-sanity @address-validation +Feature: Address validation + + Background: + Given I am on the Giftaid page + And I select Giftaid + And I enter supporter details + + Scenario: Empty postcode should show error message + When I clear the postcode field + And I submit the Giftaid form + Then I should see postcode error message "Please enter your postcode" + + Scenario Outline: Invalid postcodes should show error messages + When I enter postcode "" + Then I should see postcode error message "" + + Examples: + | postcode | message | + | 12SE17TP | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | comic relief | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | cro 7tp | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + + Scenario: Enter postcode but submit without selecting address should show error message + When I enter postcode "SE1 7TP" + And I search for the postcode + Then I should see the address dropdown + When I submit the Giftaid form + Then I should see address select error message "Please select your address" + + Scenario: Clicking on manual address link should show address fields + When I enter postcode "SE1 7TP" + Then I should see the manual address link + When I click the manual address link + Then I should see the manual address fields + + Scenario: Invalid address fields should show error messages + When I enter postcode "SE1 7TP" + And I click the manual address link + And I enter invalid address line 1 + Then I should see address line 1 error message + When I enter invalid town + Then I should see town error message diff --git a/playwright-staging/tests/features/submit/addressValidation.spec.js b/playwright-staging/tests/features/submit/addressValidation.spec.js deleted file mode 100644 index 3656b6f5..00000000 --- a/playwright-staging/tests/features/submit/addressValidation.spec.js +++ /dev/null @@ -1,76 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { selectors } = require('../../utils/locators'); - -test.describe('Address validation @sanity @nightly-sanity', () => { - - test.beforeEach(async ({ page }) => { - // Navigate to the giftaid page - await page.goto(process.env.BASE_URL, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - await page.locator(selectors.giftaid.option).click(); - await page.locator(selectors.formFields.mobile).fill('07123456789'); - await page.locator(selectors.formFields.firstName).fill('test'); - await page.locator(selectors.formFields.lastName).fill('user'); - }); - - test('empty postcode should show error message', async ({ page }) => { - await page.locator(selectors.formFields.postcode).fill(''); - await page.locator(selectors.formFields.submitButton).click(); - await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter your postcode'); - await page.close(); - }); - - test('invalid postcodes should show error messages', async ({ page }) => { - await page.locator(selectors.formFields.postcode).fill('12SE17TP'); - await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - await page.locator(selectors.formFields.postcode).fill('comic relief'); - await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - await page.locator(selectors.formFields.postcode).fill('cro 7tp'); - await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - await page.close(); - }); - - test('enter postcode but submit without selecting address should show error message', async ({ page }) => { - await page.locator(selectors.formFields.postcode).fill('SE1 7TP'); - await page.locator(selectors.formFields.postcodeLookup).click(); - await expect(page.locator(selectors.address.addressSelect)).toBeVisible(); - - await page.locator(selectors.formFields.submitButton).click(); - await expect(page.locator(selectors.errorMessages.addressSelect)).toHaveText('Please select your address'); - - await page.close(); - }); - - test('clicking on manual address link should show address fields', async ({ page }) => { - await page.locator(selectors.formFields.postcode).fill('SE1 7TP'); - await expect(page.locator(selectors.address.manualAddressLink)).toBeVisible(); - - await page.locator(selectors.address.manualAddressLink).click(); - await expect(page.locator(selectors.address.address1)).toBeVisible(); - await expect(page.locator(selectors.address.address2)).toBeVisible(); - await expect(page.locator(selectors.address.address3)).toBeVisible(); - await expect(page.locator(selectors.address.town)).toBeVisible(); - await expect(page.locator(selectors.address.country)).toBeVisible(); - - await page.close(); - }); - - test('validate address fields', async ({ page }) => { - await page.locator(selectors.formFields.postcode).fill('SE1 7TP'); - await page.locator(selectors.address.manualAddressLink).click(); - - // Should see error message for address1 when inout with special characters is entered - await page.locator(selectors.address.address1).fill('@£%3dComic Relief'); - await expect(page.locator(selectors.errorMessages.address1)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); - - await page.locator(selectors.address.town).fill(' Comic Relief'); - await expect(page.locator(selectors.errorMessages.town)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); - - await page.close(); - }); -}); diff --git a/playwright-staging/tests/features/submit/formValidation.feature b/playwright-staging/tests/features/submit/formValidation.feature new file mode 100644 index 00000000..f55c37ba --- /dev/null +++ b/playwright-staging/tests/features/submit/formValidation.feature @@ -0,0 +1,55 @@ +@sanity @nightly-sanity @form-validation +Feature: Giftaid form validation + + Background: + Given I am on the Giftaid page + And I select Giftaid + + Scenario Outline: Invalid mobile numbers should show error message + When I enter mobile number "" + Then I should see mobile error message "" + + Examples: + | mobile | message | + | 0712345678 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0712345678900 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0712 345 6789 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0780ab5694245 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + + Scenario: Valid mobile number should submit the form + When I complete the Giftaid form with mobile number "07123456789" + And I submit the Giftaid form + Then I should see the Giftaid thank you message + + Scenario Outline: Invalid first name values should show error message + When I enter first name "" + Then I should see first name error message "" + + Examples: + | firstName | message | + | Test^$%£ | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | + | SPACE | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | + | 123Test | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | + + Scenario: Valid first name should submit the form + When I complete the Giftaid form with first name "testFirstname" + And I submit the Giftaid form + Then I should see thank you message for "testFirstname" + + Scenario Outline: Invalid last name values should show error message + When I enter last name "" + Then I should see last name error message "" + + Examples: + | lastName | message | + | Test^$%£ | This field only accepts 25 alphanumeric characters and , . ( ) / & ' - starting with alphanumeric characters | + | SPACE | This field only accepts 25 alphanumeric characters and , . ( ) / & ' - starting with alphanumeric characters | + + Scenario: Alphanumeric last name should not show error message + When I enter last name "123Test" + Then I should not see last name error message + + Scenario: Valid last name should submit the form + When I complete the Giftaid form with valid details + And I submit the Giftaid form + Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/submit/formValidation.spec.js b/playwright-staging/tests/features/submit/formValidation.spec.js deleted file mode 100644 index c7892b81..00000000 --- a/playwright-staging/tests/features/submit/formValidation.spec.js +++ /dev/null @@ -1,83 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { Commands } = require('../../utils/commands'); -const { selectors } = require('../../utils/locators'); - -test.describe('Form validation @sanity @nightly-sanity', () => { - - test.beforeEach(async ({ page }) => { - // Navigate to the giftaid page - await page.goto(process.env.BASE_URL, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - await page.locator(selectors.giftaid.option).click(); - }); - - test('Validate mobile number field', async ({ page }) => { - const commands = new Commands(page); - - // Test cases for various mobile number validations - const mobileTestCases = [ - { input: '0712345678', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0712345678900', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0712 345 6789', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0780ab5694245', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - ]; - - for (let testCase of mobileTestCases) { - await page.locator(selectors.formFields.mobile).fill(''); // Clear the field before each test - await page.locator(selectors.formFields.mobile).type(testCase.input, { delay: 100 }); - await expect(page.locator(selectors.errorMessages.mobile)).toHaveText(testCase.error); - } - - // Validate correct mobile number - await page.locator(selectors.formFields.mobile).fill(''); // Ensure the field is cleared and filled with valid data - await commands.populateFormFields(page, { mobile: '07123456789' }); - await page.locator(selectors.formFields.submitButton).click(); - await expect(page.locator(selectors.sorry.heading)).toHaveText('Thank you, test!'); - }); - - test('validate first name field', async ({ page }) => { - const commands = new Commands(page); - - // First name with invalid characters - await page.locator(selectors.formFields.firstName).fill('Test^$%£'); - await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); - - // First name with just a space - await page.locator(selectors.formFields.firstName).fill(' '); - await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); - - // First name with alphanumeric characters - await page.locator(selectors.formFields.firstName).fill('123Test'); - await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); - - // Validate correct first name - await page.locator(selectors.formFields.firstName).fill(''); - await commands.populateFormFields(page, { firstName: 'testFirstname' }); - await page.locator(selectors.formFields.submitButton).click(); - await expect(page.locator(selectors.sorry.heading)).toHaveText('Thank you, testFirstname!'); - }); - - test('validate last name field', async ({ page }) => { - const commands = new Commands(page); - - // Last name with invalid characters - await page.locator(selectors.formFields.lastName).fill('Test^$%£'); - await expect(page.locator(selectors.errorMessages.lastName)).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); - - // Last name with just a space - await page.locator(selectors.formFields.lastName).fill(' '); - await expect(page.locator(selectors.errorMessages.lastName)).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); - - // Last name with alphanumeric characters (valid case) - await page.locator(selectors.formFields.lastName).fill('123Test'); - expect(await page.locator(selectors.errorMessages.lastName).count()).toEqual(0); - - // Validate correct last name - await page.locator(selectors.formFields.lastName).fill(''); - await commands.populateFormFields(page); - await page.locator(selectors.formFields.submitButton).click(); - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); - }); -}); diff --git a/playwright-staging/tests/features/submit/internationalAddressesValidation.feature b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature new file mode 100644 index 00000000..4e3f57c0 --- /dev/null +++ b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature @@ -0,0 +1,15 @@ +@sanity @nightly-sanity @international +Feature: International address validation + +Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the form +Given I am on the Giftaid page +And I select Giftaid +And I enter supporter details +When I enter a non UK postcode +Then I should see postcode validation error for UK format +When I enter international address details manually +And I select a non UK country +Then postcode error should disappear +When I select marketing preferences +And I submit the Giftaid form +Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/submit/internationalAddressesValidation.spec.js b/playwright-staging/tests/features/submit/internationalAddressesValidation.spec.js deleted file mode 100644 index ee9febd9..00000000 --- a/playwright-staging/tests/features/submit/internationalAddressesValidation.spec.js +++ /dev/null @@ -1,57 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { Commands } = require('../../utils/commands'); -const { selectors } = require('../../utils/locators'); - -test.describe('International addresses validation @sanity @nightly-sanity', () => { - test('selecting a non-UK country and entering a non-UK postcode should submit the form', async ({ page }) => { - const commands = new Commands(page); - - // Navigate to the giftaid page - await page.goto(process.env.BASE_URL, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Click to activate the form and fill in default values - await page.click(selectors.giftaid.option); - await page.fill(selectors.formFields.mobile, '07123456789'); - await page.fill(selectors.formFields.firstName, 'test'); - await page.fill(selectors.formFields.lastName, 'user'); - await page.fill(selectors.formFields.postcode, '30916-395'); // Non-UK postcode - - // Verify error message for UK postcode requirement - await expect(page.locator(selectors.errorMessages.postcode)).toContainText( - 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - // Fill in address details - await page.click(selectors.address.manualAddressLink); - await page.fill(selectors.address.address1, '219 Beacon St'); - await page.fill(selectors.address.address2, 'Winder'); - await page.fill(selectors.address.town, 'GA'); - - // Select a random non-UK country - const countries = await page.$$eval(selectors.address.countryOptions, options => - options - .map(option => option.value) - .filter(value => value && value !== 'GB') - ); - - const randomCountryCode = countries[Math.floor(Math.random() * countries.length)]; - await page.selectOption(selectors.address.countryByName, { value: randomCountryCode }); - - // Verify that postcode error is resolved after country change - await expect(page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); - - // Submit the form and ensure no errors are shown for international address - await commands.selectMarketingPrefs(page); - - await Promise.all([ - page.waitForNavigation(), - page.click(selectors.formFields.submitButton), - ]); - - await expect(page.locator(selectors.success.heading)).toContainText('Thank you, test!'); - - await page.close(); - }); -}); diff --git a/playwright-staging/tests/features/submit/marketingPreferencesData.feature b/playwright-staging/tests/features/submit/marketingPreferencesData.feature new file mode 100644 index 00000000..ed108732 --- /dev/null +++ b/playwright-staging/tests/features/submit/marketingPreferencesData.feature @@ -0,0 +1,11 @@ +@sanity @nightly-sanity @marketing-preferences-data @contact-store +Feature: Giftaid marketing preferences contact-store verification + + Scenario: Verify giftaid marketing preferences data in contact-store + Given I am on the Giftaid page + And I select Giftaid + When I populate the Giftaid form with generated supporter details + And I select generated marketing preferences + And I submit the Giftaid form + Then I should see the generated supporter thank you message + And the marketing preferences data should be stored in contact-store diff --git a/playwright-staging/tests/features/submit/marketingPreferencesData.spec.js b/playwright-staging/tests/features/submit/marketingPreferencesData.spec.js deleted file mode 100644 index 324be16b..00000000 --- a/playwright-staging/tests/features/submit/marketingPreferencesData.spec.js +++ /dev/null @@ -1,64 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { Commands } = require('../../utils/commands'); -const { MarketingPrefsVerify } = require('../../utils/marketingPrefsVerify'); -const { selectors } = require('../../utils/locators'); - -const Chance = require('chance'); -const chance = new Chance(); - -test('Verify giftaid marketing preferences data in contact-store @sanity @nightly-sanity', async ({ page }) => { - const firstName = chance.first(); - const lastName = chance.last(); - const phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, '') // UK phone number - const mobile = chance.phone({ country: "uk", mobile: true }).replace(/\s/g, '') // UK mobile number - const address1 = chance.street(); - const address2 = chance.street(); - const address3 = chance.city(); - const postcode = 'SE1 7TP'; - const town = chance.county(); - const email = `giftaid-staging-${Date.now().toString()}@email.sls.comicrelief.com`; - - const commands = new Commands(page); - - // Navigate to the giftaid page - await page.goto(process.env.BASE_URL, { timeout: 30000 }); - await page.waitForLoadState('load'); - await page.locator(selectors.giftaid.option).click(); - - // Populate all input fields using Commands class - await commands.populateFormFields(page, { - mobile, firstName, lastName, address1, address2, address3, town, postcode, email - }); - - // Select marketing preferences using Commands class - await commands.selectMarketingPrefs(page, { email, phone }); - - // Submit the form - await page.locator(selectors.formFields.submitButton).click(); - - // Verify success message - await expect(page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); - - // Retrieve and verify marketing preferences data - const mpData = await MarketingPrefsVerify.get(email); - - expect(mpData.campaign).toEqual('RND26'); - expect(mpData.firstname).toEqual(firstName); - expect(mpData.lastname).toEqual(lastName); - expect(mpData.email).toEqual(email); - expect(mpData.address1).toEqual(address1); - expect(mpData.town).toEqual(town); - expect(mpData.country).toEqual('GB'); - expect(mpData.transsourceurl).toContain(process.env.BASE_URL); - expect(mpData.transsource).toEqual('RND26_GiftAid'); - expect(mpData.transtype).toEqual('prefs'); - expect(mpData.permissionemail).toEqual('1'); - expect(mpData.permissionsms).toEqual('1'); - expect(mpData.permissionphone).toEqual('1'); - expect(mpData.phone).toEqual(phone); - expect(mpData.mobile).toEqual(mobile.replace(/^[07]{1}/, '+44')); - - await page.close(); -}); diff --git a/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature b/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature new file mode 100644 index 00000000..76a08b21 --- /dev/null +++ b/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature @@ -0,0 +1,35 @@ +@sanity @nightly-sanity @marketing-preferences +Feature: Marketing preferences validation + + Background: + Given I am on the Giftaid page + And I select Giftaid + And I complete the Giftaid form with valid details + + Scenario: Clicking marketing preference options should submit the Giftaid form + When I select all marketing preference options + And I enter valid marketing preference contact details + And I submit the Giftaid form + Then I should see the Giftaid thank you message + + Scenario: Email marketing preference field validation + When I select email marketing preference + And I enter valid marketing preference email + And I clear marketing preference email + Then I should see marketing preference email error "Please fill in your email address" + When I enter invalid marketing preference email "example@£$^&email.com" + Then I should see marketing preference email error "Please fill in a valid email address" + When I enter valid marketing preference email + And I submit the Giftaid form + Then I should see the Giftaid thank you message + + Scenario: Phone marketing preference field validation + When I select phone marketing preference + And I enter valid marketing preference phone + And I clear marketing preference phone + Then I should see marketing preference phone error "Please fill in your phone number" + When I enter invalid marketing preference phone "0208569424" + Then I should see marketing preference phone error "Please fill in a valid UK phone number, with no spaces" + When I enter valid marketing preference phone + And I submit the Giftaid form + Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/submit/marketingPreferencesValidation.spec.js b/playwright-staging/tests/features/submit/marketingPreferencesValidation.spec.js deleted file mode 100644 index ad9b341a..00000000 --- a/playwright-staging/tests/features/submit/marketingPreferencesValidation.spec.js +++ /dev/null @@ -1,82 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { Commands } = require('../../utils/commands'); -const { selectors } = require('../../utils/locators'); - -const Chance = require('chance'); -const chance = new Chance(); - -const email = `giftaid-update-staging-${chance.email()}`; -const phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, ''); - -test.describe('Marketing preferences validation @sanity @nightly-sanity', () => { - - test.beforeEach(async ({ page }) => { - const commands = new Commands(page); - await page.goto(process.env.BASE_URL, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - await page.click(selectors.giftaid.option); - await commands.populateFormFields(page); - }); - - test('clicking and unclicking marketing prefs options should submit the giftaid form', async ({ page }) => { - // Interact with marketing preferences - const marketingOptions = [ - selectors.marketingPreferences.options.email, - selectors.marketingPreferences.options.phone, - selectors.marketingPreferences.options.text, - ]; - - for (const option of marketingOptions) { - await page.click(option); - expect(await page.locator(option).isChecked()).toBeTruthy(); - } - - // Enter email and phone to validate the form can still submit - await expect(page.locator(selectors.marketingPreferences.fields.email)).toBeVisible(); - await page.fill(selectors.marketingPreferences.fields.email, email); - await expect(page.locator(selectors.marketingPreferences.fields.phone)).toBeVisible(); - await page.fill(selectors.marketingPreferences.fields.phone, phone); - - // Submit the form - await page.click(selectors.formFields.submitButton); - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); - }); - - test('Validate email marketing preference field', async ({ page }) => { - await page.click(selectors.marketingPreferences.options.email); - await page.fill(selectors.marketingPreferences.fields.email, email); - - // Clear and check for error - await page.fill(selectors.marketingPreferences.fields.email, ''); - await expect(page.locator(selectors.errorMessages.email)).toHaveText('Please fill in your email address'); - - // Input invalid email and check for error - await page.fill(selectors.marketingPreferences.fields.email, 'example@£$^&email.com'); - await expect(page.locator(selectors.errorMessages.email)).toHaveText('Please fill in a valid email address'); - - // Re-enter valid email and submit - await page.fill(selectors.marketingPreferences.fields.email, email); - await page.click(selectors.formFields.submitButton); - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); - }); - - test('Validate phone marketing preference field', async ({ page }) => { - await page.click(selectors.marketingPreferences.options.phone); - await page.fill(selectors.marketingPreferences.fields.phone, phone); - - // Clear and check for error - await page.fill(selectors.marketingPreferences.fields.phone, ''); - await expect(page.locator(selectors.errorMessages.phone)).toHaveText('Please fill in your phone number'); - - // Input invalid phone number and check for error - await page.fill(selectors.marketingPreferences.fields.phone, '0208569424'); - await expect(page.locator(selectors.errorMessages.phone)).toHaveText('Please fill in a valid UK phone number, with no spaces'); - - // Re-enter valid phone number and submit - await page.fill(selectors.marketingPreferences.fields.phone, phone); - await page.click(selectors.formFields.submitButton); - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); - }); -}); diff --git a/playwright-staging/tests/features/submit/postcodeLookup.feature b/playwright-staging/tests/features/submit/postcodeLookup.feature new file mode 100644 index 00000000..fee3d6bf --- /dev/null +++ b/playwright-staging/tests/features/submit/postcodeLookup.feature @@ -0,0 +1,23 @@ +@sanity @nightly-sanity @postcode +Feature: Postcode validation + + Background: + Given I am on the Giftaid page + And I select Giftaid + And I enter supporter details + + Scenario Outline: Invalid postcode formatting should show error message + When I enter postcode "" + Then I should see postcode error message "" + + Examples: + | postcode | message | + | S E 1 7 T P | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | SE$%TP | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + + Scenario: Valid UK postcode using postcode lookup should submit the form + When I enter postcode "SE1 7TP" + And I search for the postcode + And I select address from lookup or enter address manually + And I submit the Giftaid form + Then I should see the Giftaid thank you message with line break diff --git a/playwright-staging/tests/features/submit/postcodeLookup.spec.js b/playwright-staging/tests/features/submit/postcodeLookup.spec.js deleted file mode 100644 index 1268a83d..00000000 --- a/playwright-staging/tests/features/submit/postcodeLookup.spec.js +++ /dev/null @@ -1,52 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { selectors } = require('../../utils/locators'); - -test.describe('Postcode validation @sanity @nightly-sanity', () => { - - test.beforeEach(async ({ page }) => { - await page.goto(process.env.BASE_URL, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - await page.click(selectors.giftaid.option); - await page.fill(selectors.formFields.mobile, '07123456789'); - await page.fill(selectors.formFields.firstName, 'test'); - await page.fill(selectors.formFields.lastName, 'user'); - }); - - test('Postcode formatting errors', async ({ page }) => { - const postcodes = [ - { code: 'S E 1 7 T P', message: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, - { code: 'SE$%TP', message: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' } - ]; - - for (const { code, message } of postcodes) { - await page.fill(selectors.formFields.postcode, code); - await expect(page.locator(selectors.errorMessages.postcode)).toBeVisible(); - await expect(page.locator(selectors.errorMessages.postcode)).toContainText(message); - } - - await page.close(); - }); - - test('enter valid UK postcode using postcode lookup should be able to submit the form', async ({ page }) => { - await page.fill(selectors.formFields.postcode, 'SE1 7TP'); - await page.click(selectors.formFields.postcodeLookup); - - if (await page.isVisible(selectors.address.addressSelect)) { - await page.selectOption(selectors.address.addressSelect, { label: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }); - await expect(page.locator(selectors.formFields.postcode)).toHaveValue('SE1 7TP'); - } else { - await page.click(selectors.address.manualAddressLink); - await page.fill(selectors.address.address1, 'COMIC RELIEF'); - await page.fill(selectors.address.address2, 'CAMELFORD HOUSE 87-90'); - await page.fill(selectors.address.address3, 'ALBERT EMBANKMENT'); - await page.fill(selectors.address.town, 'LONDON'); - } - - await page.click(selectors.formFields.submitButton); - await expect(page.locator(selectors.success.heading)).toContainText('Thank you,\n' + 'test!'); - - await page.close(); - }); -}); diff --git a/playwright-staging/tests/features/submit/sorry.feature b/playwright-staging/tests/features/submit/sorry.feature new file mode 100644 index 00000000..5586aff9 --- /dev/null +++ b/playwright-staging/tests/features/submit/sorry.feature @@ -0,0 +1,7 @@ +@sanity @nightly-sanity @sorry +Feature: Giftaid sorry page + +Scenario: Accessing giftaid sorry page should show the sorry message +Given I navigate to the Giftaid sorry page +Then I should see the sorry heading +And I should see the sorry message paragraph diff --git a/playwright-staging/tests/features/submit/sorry.spec.js b/playwright-staging/tests/features/submit/sorry.spec.js deleted file mode 100644 index ffc54748..00000000 --- a/playwright-staging/tests/features/submit/sorry.spec.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { selectors } = require('../../utils/locators'); - -test('Accessing giftaid sorry page should show the sorry message @sanity @nightly-sanity', async ({ page }) => { - // Go directly to the "sorry" page appended to the base URL - await page.goto(`${process.env.BASE_URL}sorry`, { timeout: 30000 }); - - // Wait for the main header to be loaded and visible on the page - const header = page.locator(selectors.sorry.heading); - await expect(header).toBeVisible(); - await expect(header).toContainText('Sorry!'); - - // Verify that the first paragraph under the div > div is visible - const firstParagraph = page.locator(selectors.sorry.firstParagraph); - await expect(firstParagraph).toBeVisible(); - - await page.close(); -}); diff --git a/playwright-staging/tests/features/submit/successRedirect.feature b/playwright-staging/tests/features/submit/successRedirect.feature new file mode 100644 index 00000000..07c87692 --- /dev/null +++ b/playwright-staging/tests/features/submit/successRedirect.feature @@ -0,0 +1,10 @@ +@sanity @nightly-sanity @successRedirect +Feature: Giftaid success page redirect + + Scenario: Accessing success page should redirect to giftaid homepage + Given I navigate to the Giftaid success page + Then I should be redirected to the Giftaid homepage + And I should see the Giftaid heading + And I should see the Giftaid option + And I should see the mobile input field + diff --git a/playwright-staging/tests/features/submit/successRedirect.spec.js b/playwright-staging/tests/features/submit/successRedirect.spec.js deleted file mode 100644 index 0dac4165..00000000 --- a/playwright-staging/tests/features/submit/successRedirect.spec.js +++ /dev/null @@ -1,21 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { selectors } = require('../../utils/locators'); - -test('Accessing success page should redirect to giftaid homepage @sanity @nightly-sanity', async ({ page }) => { - // Navigate directly to the success page and expect a redirect - await page.goto(`${process.env.BASE_URL}success`, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Check if the expected header title is present, which indicates a successful redirect - const headerTitle = page.locator(selectors.homepage.heading); - await expect(headerTitle).toBeVisible(); - await expect(headerTitle).toContainText('Giftaid it'); - - // Verify the presence of key elements on the redirected homepage - await expect(page.locator(selectors.giftaid.option)).toBeVisible(); - await expect(page.locator(selectors.formFields.mobile)).toBeVisible(); - - await page.close(); -}); diff --git a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js new file mode 100644 index 00000000..cdfb00e7 --- /dev/null +++ b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js @@ -0,0 +1,15 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +When('I submit the Giftaid form', async function () { + await this.page.click(selectors.formFields.submitButton); +}); + +When('I select marketing preferences', async function () { + await this.commands.selectMarketingPrefs(this.page); +}); + +When('I complete the Giftaid form with valid details', async function () { + await this.commands.populateFormFields(this.page); +}); diff --git a/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js b/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js new file mode 100644 index 00000000..e9c1031d --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js @@ -0,0 +1,48 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +When('I clear the postcode field', async function () { + await this.page.locator(selectors.formFields.postcode).fill(''); +}); + +Then('I should see the address dropdown', async function () { + await expect(this.page.locator(selectors.address.addressSelect)).toBeVisible(); +}); + +Then('I should see address select error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.addressSelect)).toHaveText(message); +}); + +Then('I should see the manual address link', async function () { + await expect(this.page.locator(selectors.address.manualAddressLink)).toBeVisible(); +}); + +When('I click the manual address link', async function () { + await this.page.locator(selectors.address.manualAddressLink).click(); +}); + +Then('I should see the manual address fields', async function () { + await expect(this.page.locator(selectors.address.address1)).toBeVisible(); + await expect(this.page.locator(selectors.address.address2)).toBeVisible(); + await expect(this.page.locator(selectors.address.address3)).toBeVisible(); + await expect(this.page.locator(selectors.address.town)).toBeVisible(); + await expect(this.page.locator(selectors.address.country)).toBeVisible(); +}); + +When('I enter invalid address line 1', async function () { + // Should see error message for address1 when input with special characters is entered + await this.page.locator(selectors.address.address1).fill('@£%3dComic Relief'); +}); + +Then('I should see address line 1 error message', async function () { + await expect(this.page.locator(selectors.errorMessages.address1)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); +}); + +When('I enter invalid town', async function () { + await this.page.locator(selectors.address.town).fill(' Comic Relief'); +}); + +Then('I should see town error message', async function () { + await expect(this.page.locator(selectors.errorMessages.town)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); +}); diff --git a/playwright-staging/tests/step-definitions/submit/formValidation.steps.js b/playwright-staging/tests/step-definitions/submit/formValidation.steps.js new file mode 100644 index 00000000..7c664134 --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/formValidation.steps.js @@ -0,0 +1,48 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +When('I enter mobile number {string}', async function (mobile) { + await this.page.locator(selectors.formFields.mobile).fill(''); + await this.page.locator(selectors.formFields.mobile).type(mobile, { delay: 100 }); +}); + +Then('I should see mobile error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.mobile)).toHaveText(message); +}); + +When('I complete the Giftaid form with mobile number {string}', async function (mobile) { + await this.page.locator(selectors.formFields.mobile).fill(''); + await this.commands.populateFormFields(this.page, { mobile }); +}); + +When('I enter first name {string}', async function (firstName) { + const value = firstName === 'SPACE' ? ' ' : firstName; + await this.page.locator(selectors.formFields.firstName).fill(value); +}); + +Then('I should see first name error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText(message); +}); + +When('I complete the Giftaid form with first name {string}', async function (firstName) { + await this.page.locator(selectors.formFields.firstName).fill(''); + await this.commands.populateFormFields(this.page, { firstName }); +}); + +Then('I should see thank you message for {string}', async function (firstName) { + await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); +}); + +When('I enter last name {string}', async function (lastName) { + const value = lastName === 'SPACE' ? ' ' : lastName; + await this.page.locator(selectors.formFields.lastName).fill(value); +}); + +Then('I should see last name error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.lastName)).toHaveText(message); +}); + +Then('I should not see last name error message', async function () { + expect(await this.page.locator(selectors.errorMessages.lastName).count()).toEqual(0); +}); diff --git a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js index 06e5d74c..28d56aad 100644 --- a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js +++ b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js @@ -11,21 +11,6 @@ When('I select Giftaid', async function () { await this.page.click(selectors.giftaid.option); }); -When('I complete the Giftaid form with valid details', async function () { - await this.commands.populateFormFields(this.page); -}); - -When('I select marketing preferences', async function () { - await this.commands.selectMarketingPrefs(this.page); -}); - -When('I submit the Giftaid form', async function () { - await Promise.all([ - this.page.waitForNavigation(), - this.page.click(selectors.formFields.submitButton), - ]); -}); - Then('I should see the Giftaid thank you message', async function () { await expect(this.page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); }); diff --git a/playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js b/playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js new file mode 100644 index 00000000..decf1e89 --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js @@ -0,0 +1,35 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +When('I enter a non UK postcode', async function () { + await this.page.fill(selectors.formFields.postcode, '30916-395'); +}); + +Then('I should see postcode validation error for UK format', async function () { + await expect(this.page.locator(selectors.errorMessages.postcode)).toContainText( + 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' + ); +}); + +When('I enter international address details manually', async function () { + await this.page.click(selectors.address.manualAddressLink); + await this.page.fill(selectors.address.address1, '219 Beacon St'); + await this.page.fill(selectors.address.address2, 'Winder'); + await this.page.fill(selectors.address.town, 'GA'); +}); + +When('I select a non UK country', async function () { + const countries = await this.page.$$eval(selectors.address.countryOptions, options => + options + .map(option => option.value) + .filter(value => value && value !== 'GB') + ); + + const randomCountryCode = countries[Math.floor(Math.random() * countries.length)]; + await this.page.selectOption(selectors.address.countryByName, { value: randomCountryCode }); +}); + +Then('postcode error should disappear', async function () { + await expect(this.page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); +}); diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js new file mode 100644 index 00000000..274befd1 --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js @@ -0,0 +1,69 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const Chance = require('chance'); +const { MarketingPrefsVerify } = require('../../utils/marketingPrefsVerify'); +const { selectors } = require('../../utils/locators'); + +const chance = new Chance(); + +When('I populate the Giftaid form with generated supporter details', async function () { + this.supporter = { + firstName: chance.first(), + lastName: chance.last(), + phone: chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, ''), // UK phone number + mobile: chance.phone({ country: 'uk', mobile: true }).replace(/\s/g, ''), // UK mobile number + address1: chance.street(), + address2: chance.street(), + address3: chance.city(), + postcode: 'SE1 7TP', + town: chance.county(), + email: `giftaid-staging-${Date.now().toString()}@email.sls.comicrelief.com`, + }; + + // Populate all input fields using Commands class + await this.commands.populateFormFields(this.page, { + mobile: this.supporter.mobile, + firstName: this.supporter.firstName, + lastName: this.supporter.lastName, + address1: this.supporter.address1, + address2: this.supporter.address2, + address3: this.supporter.address3, + town: this.supporter.town, + postcode: this.supporter.postcode, + email: this.supporter.email, + }); +}); + +When('I select generated marketing preferences', async function () { + // Select marketing preferences using Commands class + await this.commands.selectMarketingPrefs(this.page, { + email: this.supporter.email, + phone: this.supporter.phone, + }); +}); + +Then('I should see the generated supporter thank you message', async function () { + // Verify success message + await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${this.supporter.firstName}!`); +}); + +Then('the marketing preferences data should be stored in contact-store', async function () { + // Retrieve and verify marketing preferences data + const mpData = await MarketingPrefsVerify.get(this.supporter.email); + + expect(mpData.campaign).toEqual('RND26'); + expect(mpData.firstname).toEqual(this.supporter.firstName); + expect(mpData.lastname).toEqual(this.supporter.lastName); + expect(mpData.email).toEqual(this.supporter.email); + expect(mpData.address1).toEqual(this.supporter.address1); + expect(mpData.town).toEqual(this.supporter.town); + expect(mpData.country).toEqual('GB'); + expect(mpData.transsourceurl).toContain(process.env.BASE_URL); + expect(mpData.transsource).toEqual('RND26_GiftAid'); + expect(mpData.transtype).toEqual('prefs'); + expect(mpData.permissionemail).toEqual('1'); + expect(mpData.permissionsms).toEqual('1'); + expect(mpData.permissionphone).toEqual('1'); + expect(mpData.phone).toEqual(this.supporter.phone); + expect(mpData.mobile).toEqual(this.supporter.mobile.replace(/^[07]{1}/, '+44')); +}); diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js new file mode 100644 index 00000000..1d744dae --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js @@ -0,0 +1,70 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const Chance = require('chance'); +const { selectors } = require('../../utils/locators'); + +const chance = new Chance(); + +const email = `giftaid-update-staging-${chance.email()}`; +const phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, ''); + +When('I select all marketing preference options', async function () { + const marketingOptions = [ + selectors.marketingPreferences.options.email, + selectors.marketingPreferences.options.phone, + selectors.marketingPreferences.options.text, + ]; + + for (const option of marketingOptions) { + await this.page.click(option); + expect(await this.page.locator(option).isChecked()).toBeTruthy(); + } +}); + +When('I enter valid marketing preference contact details', async function () { + await expect(this.page.locator(selectors.marketingPreferences.fields.email)).toBeVisible(); + await this.page.fill(selectors.marketingPreferences.fields.email, email); + + await expect(this.page.locator(selectors.marketingPreferences.fields.phone)).toBeVisible(); + await this.page.fill(selectors.marketingPreferences.fields.phone, phone); +}); + +When('I select email marketing preference', async function () { + await this.page.click(selectors.marketingPreferences.options.email); +}); + +When('I enter valid marketing preference email', async function () { + await this.page.fill(selectors.marketingPreferences.fields.email, email); +}); + +When('I clear marketing preference email', async function () { + await this.page.fill(selectors.marketingPreferences.fields.email, ''); +}); + +When('I enter invalid marketing preference email {string}', async function (invalidEmail) { + await this.page.fill(selectors.marketingPreferences.fields.email, invalidEmail); +}); + +Then('I should see marketing preference email error {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.email)).toHaveText(message); +}); + +When('I select phone marketing preference', async function () { + await this.page.click(selectors.marketingPreferences.options.phone); +}); + +When('I enter valid marketing preference phone', async function () { + await this.page.fill(selectors.marketingPreferences.fields.phone, phone); +}); + +When('I clear marketing preference phone', async function () { + await this.page.fill(selectors.marketingPreferences.fields.phone, ''); +}); + +When('I enter invalid marketing preference phone {string}', async function (invalidPhone) { + await this.page.fill(selectors.marketingPreferences.fields.phone, invalidPhone); +}); + +Then('I should see marketing preference phone error {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.phone)).toHaveText(message); +}); diff --git a/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js b/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js new file mode 100644 index 00000000..34fd548f --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js @@ -0,0 +1,39 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I enter supporter details', async function () { + await this.page.fill(selectors.formFields.mobile, '07123456789'); + await this.page.fill(selectors.formFields.firstName, 'test'); + await this.page.fill(selectors.formFields.lastName, 'user'); +}); + +When('I enter postcode {string}', async function (postcode) { + await this.page.fill(selectors.formFields.postcode, postcode); +}); + +Then('I should see postcode error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.postcode)).toBeVisible(); + await expect(this.page.locator(selectors.errorMessages.postcode)).toContainText(message); +}); + +When('I search for the postcode', async function () { + await this.page.click(selectors.formFields.postcodeLookup); +}); + +When('I select address from lookup or enter address manually', async function () { + if (await this.page.isVisible(selectors.address.addressSelect)) { + await this.page.selectOption(selectors.address.addressSelect, { label: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }); + await expect(this.page.locator(selectors.formFields.postcode)).toHaveValue('SE1 7TP'); + } else { + await this.page.click(selectors.address.manualAddressLink); + await this.page.fill(selectors.address.address1, 'COMIC RELIEF'); + await this.page.fill(selectors.address.address2, 'CAMELFORD HOUSE 87-90'); + await this.page.fill(selectors.address.address3, 'ALBERT EMBANKMENT'); + await this.page.fill(selectors.address.town, 'LONDON'); + } +}); + +Then('I should see the Giftaid thank you message with line break', async function () { + await expect(this.page.locator(selectors.success.heading)).toContainText('Thank you,\n' + 'test!'); +}); diff --git a/playwright-staging/tests/step-definitions/submit/sorryPage.steps.js b/playwright-staging/tests/step-definitions/submit/sorryPage.steps.js new file mode 100644 index 00000000..be723d9c --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/sorryPage.steps.js @@ -0,0 +1,18 @@ +const { Given, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I navigate to the Giftaid sorry page', async function () { + await this.page.goto(`${process.env.BASE_URL}sorry`, { timeout: 30000 }); +}); + +Then('I should see the sorry heading', async function () { + const header = this.page.locator(selectors.sorry.heading); + await expect(header).toBeVisible(); + await expect(header).toContainText('Sorry!'); +}); + +Then('I should see the sorry message paragraph', async function () { + const firstParagraph = this.page.locator(selectors.sorry.firstParagraph); + await expect(firstParagraph).toBeVisible(); +}); diff --git a/playwright-staging/tests/step-definitions/submit/successRedirect.steps.js b/playwright-staging/tests/step-definitions/submit/successRedirect.steps.js new file mode 100644 index 00000000..731de6d5 --- /dev/null +++ b/playwright-staging/tests/step-definitions/submit/successRedirect.steps.js @@ -0,0 +1,26 @@ +const { Given, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I navigate to the Giftaid success page', async function () { + await this.page.goto(`${process.env.BASE_URL}success`, { timeout: 30000 }); + await this.page.waitForLoadState('domcontentloaded'); +}); + +Then('I should be redirected to the Giftaid homepage', async function () { + const header = this.page.locator(selectors.homepage.heading); + await expect(header).toBeVisible(); + await expect(header).toContainText('Giftaid it'); +}); + +Then('I should see the Giftaid heading', async function () { + await expect(this.page.locator(selectors.homepage.heading)).toBeVisible(); +}); + +Then('I should see the Giftaid option', async function () { + await expect(this.page.locator(selectors.giftaid.option)).toBeVisible(); +}); + +Then('I should see the mobile input field', async function () { + await expect(this.page.locator(selectors.formFields.mobile)).toBeVisible(); +}); From 4004a8ade6ea45c54e84b59399573f91f817b1ac Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 5 May 2026 22:32:36 +0100 Subject: [PATCH 05/35] test: convert /update tests into Gherkin and add step-definitions --- .../internationalAddressesValidation.feature | 24 +-- .../tests/features/submit/sorry.feature | 8 +- .../features/update/formValidation.feature | 87 +++++++++ .../features/update/formValidation.spec.js | 182 ------------------ .../update/giftaidDeclarationOptions.feature | 17 ++ .../update/giftaidDeclarationOptions.spec.js | 30 --- .../internationalAddressesValidation.feature | 14 ++ .../internationalAddressesValidation.spec.js | 54 ------ .../tests/features/update/sorry.spec.js | 20 -- .../tests/features/update/updateSorry.feature | 7 + .../update/updateSuccessRedirect.feature | 7 + .../update/updateSuccessRedirect.spec.js | 18 -- .../update/validFormSubmission.feature | 11 ++ .../update/validFormSubmission.spec.js | 25 --- .../update/giftaidDeclaration.steps.js | 22 +++ .../update/giftaidUpdateCommon.steps.js | 46 +++++ .../internationalAddressValidation.steps.js | 38 ++++ .../update/sorryPage.steps.js | 18 ++ .../update/successRedirect.steps.js | 14 ++ .../update/updateFormValidation.steps.js | 132 +++++++++++++ 20 files changed, 429 insertions(+), 345 deletions(-) create mode 100644 playwright-staging/tests/features/update/formValidation.feature delete mode 100644 playwright-staging/tests/features/update/formValidation.spec.js create mode 100644 playwright-staging/tests/features/update/giftaidDeclarationOptions.feature delete mode 100644 playwright-staging/tests/features/update/giftaidDeclarationOptions.spec.js create mode 100644 playwright-staging/tests/features/update/internationalAddressesValidation.feature delete mode 100644 playwright-staging/tests/features/update/internationalAddressesValidation.spec.js delete mode 100644 playwright-staging/tests/features/update/sorry.spec.js create mode 100644 playwright-staging/tests/features/update/updateSorry.feature create mode 100644 playwright-staging/tests/features/update/updateSuccessRedirect.feature delete mode 100644 playwright-staging/tests/features/update/updateSuccessRedirect.spec.js create mode 100644 playwright-staging/tests/features/update/validFormSubmission.feature delete mode 100644 playwright-staging/tests/features/update/validFormSubmission.spec.js create mode 100644 playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js create mode 100644 playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js create mode 100644 playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js create mode 100644 playwright-staging/tests/step-definitions/update/sorryPage.steps.js create mode 100644 playwright-staging/tests/step-definitions/update/successRedirect.steps.js create mode 100644 playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js diff --git a/playwright-staging/tests/features/submit/internationalAddressesValidation.feature b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature index 4e3f57c0..a54ab7b4 100644 --- a/playwright-staging/tests/features/submit/internationalAddressesValidation.feature +++ b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature @@ -1,15 +1,15 @@ @sanity @nightly-sanity @international Feature: International address validation -Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the form -Given I am on the Giftaid page -And I select Giftaid -And I enter supporter details -When I enter a non UK postcode -Then I should see postcode validation error for UK format -When I enter international address details manually -And I select a non UK country -Then postcode error should disappear -When I select marketing preferences -And I submit the Giftaid form -Then I should see the Giftaid thank you message + Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the form + Given I am on the Giftaid page + And I select Giftaid + And I enter supporter details + When I enter a non UK postcode + Then I should see postcode validation error for UK format + When I enter international address details manually + And I select a non UK country + Then postcode error should disappear + When I select marketing preferences + And I submit the Giftaid form + Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/submit/sorry.feature b/playwright-staging/tests/features/submit/sorry.feature index 5586aff9..c3c04fe1 100644 --- a/playwright-staging/tests/features/submit/sorry.feature +++ b/playwright-staging/tests/features/submit/sorry.feature @@ -1,7 +1,7 @@ @sanity @nightly-sanity @sorry Feature: Giftaid sorry page -Scenario: Accessing giftaid sorry page should show the sorry message -Given I navigate to the Giftaid sorry page -Then I should see the sorry heading -And I should see the sorry message paragraph + Scenario: Accessing giftaid sorry page should show the sorry message + Given I navigate to the Giftaid sorry page + Then I should see the sorry heading + And I should see the sorry message paragraph diff --git a/playwright-staging/tests/features/update/formValidation.feature b/playwright-staging/tests/features/update/formValidation.feature new file mode 100644 index 00000000..ef9dbc55 --- /dev/null +++ b/playwright-staging/tests/features/update/formValidation.feature @@ -0,0 +1,87 @@ +@sanity @nightly-sanity @update-form-validation +Feature: Giftaid update form validation + + Background: + Given I am on the Giftaid update page + + Scenario: Empty input fields should show error messages + When I submit the Giftaid update form + Then I should see required update form error messages + + Scenario Outline: Invalid first name values should show error message on update form + When I enter update first name "" + Then I should see update first name error message "" + + Examples: + | firstName | message | + | Test^$%£ | This field only accepts alphabetic characters and ' - | + | SPACE | This field only accepts alphabetic characters and ' - | + | 123Test | This field only accepts alphabetic characters and ' - | + + Scenario: Valid first name should submit update form + When I complete the Giftaid update form with first name "John" + And I select yes for GiftAid declaration + And I submit the Giftaid update form + Then I should see update thank you message for "John" + + Scenario Outline: Invalid email values should show error message on update form + When I enter update email "" + Then I should see update email error message "" + + Examples: + | email | message | + | test@comic$relief.com | Please fill in a valid email address | + | test@c{(micrelief.com | Please fill in a valid email address | + | test@comic%relief.com | Please fill in a valid email address | + | Test0-9!#$%&'*+/=?^_{\|}~-@comicrelief_9-8.com.uk | Please fill in a valid email address | + + Scenario: Valid email should submit update form with no declaration + When I complete the Giftaid update form with generated email + And I select no for GiftAid declaration + And I submit the Giftaid update form + Then I should see update no declaration message + + Scenario Outline: Invalid mobile numbers should show error message on update form + When I enter update mobile number "" + Then I should see update mobile error message "" + + Examples: + | mobile | message | + | 0722345678 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0722345678900 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0722 345 6789 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0780ab5694245 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + + Scenario Outline: Valid mobile numbers should not show error message on update form + When I enter update mobile number "" + Then I should not see update mobile error message + + Examples: + | mobile | + | 07123456789 | + | 07340707252 | + + Scenario: Valid mobile number should submit update form + When I complete the Giftaid update form with generated mobile and last name "test" + And I select yes for GiftAid declaration + And I submit the Giftaid update form + Then I should see update thank you message for " test" + + Scenario Outline: Invalid postcode values should show error message on update form + When I enter update postcode "" + Then I should see update postcode error message "" + + Examples: + | postcode | message | + | S E 1 7 T P | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | SE$%TP | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | cro 7tp | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + + Scenario: Valid postcode should submit update form + When I enter update postcode "SE1 7TP" + And I search for the update postcode + And I select update address from lookup or enter address manually + And I complete remaining update form fields + And I select yes for GiftAid declaration + And I submit the Giftaid update form + Then I should see update thank you message for " test" diff --git a/playwright-staging/tests/features/update/formValidation.spec.js b/playwright-staging/tests/features/update/formValidation.spec.js deleted file mode 100644 index e6194fae..00000000 --- a/playwright-staging/tests/features/update/formValidation.spec.js +++ /dev/null @@ -1,182 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { Commands } = require('../../utils/commands'); -const { v4: uuidv4 } = require('uuid'); -const Chance = require('chance'); -const chance = new Chance(); -const { selectors } = require('../../utils/locators'); - -test.describe('Giftaid Update form validation @sanity @nightly-sanity', () => { - let commands; - - test.beforeEach(async ({ page }) => { - commands = new Commands(page); - // Navigate to the Giftaid Update form - await page.goto(`${process.env.BASE_URL}update`, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - }); - - test('empty input fields should show error messages', async ({ page }) => { - // Submit the form without filling out any fields - await page.click(selectors.formFields.submitButton); - - // Check for the error messages associated with each field - await expect(page.locator(selectors.errorMessages.firstName)).toHaveText('Please fill in your first name'); - await expect(page.locator(selectors.errorMessages.lastName)).toHaveText('Please fill in your last name'); - await expect(page.locator(selectors.errorMessages.email)).toHaveText('Please fill in your email address'); - await expect(page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter your postcode'); - await expect(page.locator(selectors.errorMessages.addressDetails)).toHaveText('Please fill in your address'); - await expect(page.locator(selectors.errorMessages.giftAidClaimChoice)).toHaveText('This field is required'); - await page.close(); - }); - - test('Validate first name field on Giftaid update form', async ({ page }) => { - const commands = new Commands(page); - - // Set up different first name test cases - const firstNameTestCases = [ - { input: 'Test^$%£', error: "This field only accepts alphabetic characters and ' -" }, // Test for invalid characters - { input: ' ', error: "This field only accepts alphabetic characters and ' -" }, // Test for space as input - { input: '123Test', error: "This field only accepts alphabetic characters and ' -" } // Test for alphanumeric input - ]; - - for (let testCase of firstNameTestCases) { - await page.fill(selectors.formFields.firstName, testCase.input); - if (testCase.input) { - await page.keyboard.press('Enter'); // Trigger validation by clicking submit button - } - await expect(page.locator(selectors.errorMessages.firstName)).toHaveText(testCase.error); - } - - // Test for a valid first name - await page.fill(selectors.formFields.firstName, ''); // clear firstname field - await commands.populateUpdateFormFields(page, { firstName: 'John' }); - await page.click(selectors.giftAidClaimChoice.yes); // Select yes for declaration - await page.click(selectors.formFields.submitButton); // Submit the form - - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, John!'); - await page.close(); - }); - - test('Validate email field on giftaid update form', async ({ page }) => { - const commands = new Commands(page); - - // Set up different email test cases - const emailTestCases = [ - { input: 'test@comic$relief.com', error: 'Please fill in a valid email address', visible: true }, - { input: 'test@c{(micrelief.com', error: 'Please fill in a valid email address', visible: true }, - { input: 'test@comic%relief.com', error: 'Please fill in a valid email address', visible: true }, - { input: 'te$%^st@comicrelief.com', error: '', visible: false }, - { input: 'Test0-9!#$%&\'*+/=?^_{|}~-@comicrelief_9-8.com.uk', error: 'Please fill in a valid email address', visible: true } - ]; - - for (let testCase of emailTestCases) { - await page.fill(selectors.marketingPreferences.fields.email, ''); // clear the email field before entering the test cases input - await page.fill(selectors.marketingPreferences.fields.email, testCase.input); - await page.keyboard.press('Enter'); // Trigger validation by clicking the submit button - if (testCase.visible) { - await expect(page.locator(selectors.errorMessages.email)).toBeVisible(); - await expect(page.locator(selectors.errorMessages.email)).toHaveText(testCase.error); - } else { - await expect(page.locator(selectors.errorMessages.email)).not.toBeVisible(); - } - } - - // Test for a valid email - const validEmail = `giftaid-update-staging-${chance.email()}`; - await page.fill(selectors.marketingPreferences.fields.email, ''); // clear email field - await commands.populateUpdateFormFields(page, { email: validEmail }); - await page.click(selectors.giftAidClaimChoice.no); // Select no for declaration - await page.click(selectors.formFields.submitButton); // Submit the form - - await expect(page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); - await page.close(); - }); - - test('Validate mobile number field on giftaid update form', async ({ page }) => { - const commands = new Commands(page); - // List of allowed prefixes for UK mobile numbers - const prefixes = ['071', '073', '074', '075', '077', '078', '079']; - // Randomly select one prefix from the list - const prefix = chance.pickone(prefixes); - // Generate the remaining 8 digits randomly - const mobile = `${prefix}${chance.string({ pool: '0123456789', length: 8 })}`; - console.log('mobile number generated', mobile); - - // Test cases for various mobile number validations - const mobileTestCases = [ - { input: '0722345678', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0722345678900', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0722 345 6789', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0780ab5694245', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '07123456789', valid: true }, - { input: '07340707252', valid: true }, - ]; - - for (let testCase of mobileTestCases) { - await page.locator(selectors.formFields.mobile).fill(''); // Clear the field before each test - await page.locator(selectors.formFields.mobile).type(testCase.input, { delay: 100 }); - if (testCase.valid) { - await expect(page.locator(selectors.errorMessages.mobile)).not.toBeVisible(); - } else { - await expect(page.locator(selectors.errorMessages.mobile)).toHaveText(testCase.error); - } - } - - // Validate correct mobile number - await page.locator(selectors.formFields.mobile).fill(''); // Ensure the field is cleared and filled with valid data - await commands.populateUpdateFormFields(page, { lastName: 'test', mobile: mobile }); - await page.click(selectors.giftAidClaimChoice.yes); // Select yes for declaration - await page.click(selectors.formFields.submitButton); // Submit the form - - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); - }); - - test('Postcode validation and form submission', async ({ page }) => { - // Define postcodes and expected error messages - const postcodes = [ - { input: 'S E 1 7 T P', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, - { input: 'SE$%TP', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, - { input: 'cro 7tp', error: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' } - ]; - - // Test for each invalid postcode - for (const postcode of postcodes) { - await page.fill(selectors.formFields.postcode, ''); - await page.type(selectors.formFields.postcode, postcode.input); - await expect(page.locator(selectors.errorMessages.postcode)).toBeVisible(); - await expect(page.locator(selectors.errorMessages.postcode)).toHaveText(postcode.error); - } - - // Test for a valid postcode and subsequent form submission - await page.fill(selectors.formFields.postcode, 'SE1 7TP'); - await page.click(selectors.formFields.postcodeLookup); - - // Checking whether address selection is available or if manual entry is needed - if (await page.locator(selectors.address.addressSelect).isVisible()) { - // Select the first address if available - const options = await page.$$eval(selectors.address.addressSelectOptions, options => options.map(option => option.value)); - await page.selectOption(selectors.address.addressSelect, options[1]); - await page.click(selectors.formFields.submitButton); - } else { - // Fallback to manual address input if no selection is available - await page.click(selectors.address.manualAddressLink); - await page.fill(selectors.address.address1, 'COMIC RELIEF'); - await page.fill(selectors.address.address2, 'CAMELFORD HOUSE 87-90'); - await page.fill(selectors.address.address3, 'ALBERT EMBANKMENT'); - await page.fill(selectors.address.town, 'LONDON'); - await page.click(selectors.formFields.submitButton); - } - - await page.locator(selectors.formFields.firstName).fill('test'); - await page.locator(selectors.formFields.lastName).fill(chance.last()); - await page.locator(selectors.marketingPreferences.fields.email).fill(`giftaid-update-staging-${chance.email()}`); - await page.fill(selectors.formFields.postcode, 'SE1 7TP'); - await page.click(selectors.giftAidClaimChoice.yes); // Select yes for declaration - await page.click(selectors.formFields.submitButton); // Submit the form - - await expect(page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); - await page.close(); - }); -}); diff --git a/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature b/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature new file mode 100644 index 00000000..ceed1d61 --- /dev/null +++ b/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature @@ -0,0 +1,17 @@ +@sanity @nightly-sanity @update-declaration +Feature: Giftaid declaration claim selection + + Scenario: Validate Giftaid declaration claim selections + Given I am on the Giftaid update page + When I complete the Giftaid update form with valid details + And I submit the Giftaid update form + Then I should see the Giftaid declaration section + + When I select yes for GiftAid declaration + Then yes option should be selected and no option should not be selected + + When I select no for GiftAid declaration + Then no option should be selected and yes option should not be selected + + When I submit the Giftaid update form + Then I should see update no declaration message diff --git a/playwright-staging/tests/features/update/giftaidDeclarationOptions.spec.js b/playwright-staging/tests/features/update/giftaidDeclarationOptions.spec.js deleted file mode 100644 index ee684b48..00000000 --- a/playwright-staging/tests/features/update/giftaidDeclarationOptions.spec.js +++ /dev/null @@ -1,30 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { Commands } = require('../../utils/commands'); -const { selectors } = require('../../utils/locators'); - -test('Validate Giftaid declaration claim selections @sanity @nightly-sanity', async ({ page }) => { - const commands = new Commands(page); - await page.goto(process.env.BASE_URL + 'update', { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Populate fields and submit the form to get to the Giftaid declaration part - await commands.populateUpdateFormFields(page); - await page.locator(selectors.formFields.submitButton).click(); - - // Select 'Yes' for Giftaid declaration and verify it is selected - await page.locator(selectors.giftAidClaimChoice.yes).click(); - expect(await page.locator(selectors.giftAidClaimChoice.yesInput).isChecked()).toBeTruthy(); - expect(await page.locator(selectors.giftAidClaimChoice.noInput).isChecked()).toBeFalsy(); - - // Select 'No' for Giftaid declaration and verify it is selected - await page.locator(selectors.giftAidClaimChoice.no).click(); - expect(await page.locator(selectors.giftAidClaimChoice.noInput).isChecked()).toBeTruthy(); - expect(await page.locator(selectors.giftAidClaimChoice.yesInput).isChecked()).toBeFalsy(); - - await page.locator(selectors.formFields.submitButton).click(); - await expect(page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); - - await page.close(); -}); diff --git a/playwright-staging/tests/features/update/internationalAddressesValidation.feature b/playwright-staging/tests/features/update/internationalAddressesValidation.feature new file mode 100644 index 00000000..399cace1 --- /dev/null +++ b/playwright-staging/tests/features/update/internationalAddressesValidation.feature @@ -0,0 +1,14 @@ +@sanity @nightly-sanity @update-international-address +Feature: International address validation on update form + + Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the update form + Given I am on the Giftaid update page + And I enter basic update supporter details + When I enter update postcode "30916-395" + Then I should see update postcode error message "Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below." + When I enter update international address details manually + And I select a non UK country on the update form + Then update postcode error should disappear + When I select yes for GiftAid declaration + And I submit the Giftaid update form + Then I should see update thank you message for "test" diff --git a/playwright-staging/tests/features/update/internationalAddressesValidation.spec.js b/playwright-staging/tests/features/update/internationalAddressesValidation.spec.js deleted file mode 100644 index 91ea0860..00000000 --- a/playwright-staging/tests/features/update/internationalAddressesValidation.spec.js +++ /dev/null @@ -1,54 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { v4: uuidv4 } = require('uuid'); -const { selectors } = require('../../utils/locators'); - -test.describe('International addresses validation on update form @sanity @nightly-sanity', () => { - test('selecting a non-UK country and entering a non-UK postcode should submit the update form', async ({ page }) => { - - await page.goto(process.env.BASE_URL + 'update', { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // fill in all input fields - // await page.locator('input#field-input--transactionId').fill(transactionId); - await page.locator(selectors.formFields.firstName).fill('test'); - await page.locator(selectors.formFields.lastName).fill('test lastname'); - await page.locator(selectors.marketingPreferences.fields.email).fill('giftaid-staging-@email.sls.comicrelief.com'); - - // enter a non-UK postcode and attempt to validate it - await page.locator(selectors.formFields.postcode).fill('30916-395'); - await expect(page.locator(selectors.errorMessages.postcode)).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - // manually enter international address details - await page.locator(selectors.address.manualAddressLink).click(); - await page.locator(selectors.address.address1).fill('219 Beacon St'); - await page.locator(selectors.address.address2).fill('Winder'); - await page.locator(selectors.address.address3).fill('Park Ridge'); - await page.locator(selectors.address.town).fill('GA'); - - // Select a random country from the dropdown (excluding UK to simulate international address) - const countryOptions = await page.$$eval(selectors.address.countryOptions, options => - options.map(option => option.value).filter(value => value && value !== 'GB') - ); - const randomCountryCode = countryOptions[Math.floor(Math.random() * countryOptions.length)]; - await page.locator(selectors.address.countryByName).selectOption({ value: randomCountryCode }); - - // Wait for the form to adjust to the selected country - await page.waitForTimeout(2000); - - // When an international country is selected, the postcode error for UK format should not show anymore - await expect(page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); - - // Select yes for giftaid declaration to complete the form - await page.locator(selectors.giftAidClaimChoice.yes).click(); - - // Submitting the form with valid international details - await page.locator(selectors.formFields.submitButton).click(); - - // Thank you message on success page - await expect(page.locator(selectors.success.heading)).toContainText('Thank you, test!'); - - await page.close(); - }); -}); diff --git a/playwright-staging/tests/features/update/sorry.spec.js b/playwright-staging/tests/features/update/sorry.spec.js deleted file mode 100644 index 6a08bc83..00000000 --- a/playwright-staging/tests/features/update/sorry.spec.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { selectors } = require('../../utils/locators'); - -test('Accessing giftaid update sorry page should show the sorry message @sanity @nightly-sanity', async ({ page }) => { - // Navigate to the 'Sorry' page of giftaid update form - await page.goto(`${process.env.BASE_URL}update/sorry`, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Check for the 'Sorry' message header - const headerText = await page.locator(selectors.sorry.heading).textContent(); - expect(headerText).toContain('Sorry!'); - - // Verify the sorry message - const sorryMessage = await page.locator(selectors.sorry.firstParagraph).isVisible(); - expect(sorryMessage).toBeTruthy(); - - await page.close(); -}); diff --git a/playwright-staging/tests/features/update/updateSorry.feature b/playwright-staging/tests/features/update/updateSorry.feature new file mode 100644 index 00000000..dc438481 --- /dev/null +++ b/playwright-staging/tests/features/update/updateSorry.feature @@ -0,0 +1,7 @@ +@sanity @nightly-sanity @update-sorry +Feature: Giftaid update sorry page + + Scenario: Accessing giftaid update sorry page should show the sorry message + Given I navigate to the Giftaid update sorry page + Then I should see the update sorry heading + And I should see the update sorry message diff --git a/playwright-staging/tests/features/update/updateSuccessRedirect.feature b/playwright-staging/tests/features/update/updateSuccessRedirect.feature new file mode 100644 index 00000000..a65427c6 --- /dev/null +++ b/playwright-staging/tests/features/update/updateSuccessRedirect.feature @@ -0,0 +1,7 @@ +@sanity @nightly-sanity @update-success-redirect +Feature: Giftaid update success page redirect + + Scenario: Accessing success page should redirect to giftaid update homepage + Given I navigate to the Giftaid update success page + Then I should be redirected to the Giftaid homepage + diff --git a/playwright-staging/tests/features/update/updateSuccessRedirect.spec.js b/playwright-staging/tests/features/update/updateSuccessRedirect.spec.js deleted file mode 100644 index c0108805..00000000 --- a/playwright-staging/tests/features/update/updateSuccessRedirect.spec.js +++ /dev/null @@ -1,18 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { selectors } = require('../../utils/locators'); - -test.describe('Success page redirect @sanity @nightly-sanity', () => { - test('Accessing success page should redirect to giftaid update homepage', async ({ page }) => { - // Navigate to the success page of the Giftaid update directly - await page.goto(`${process.env.BASE_URL}update/success`, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Confirm the page has the expected Giftaid title after redirection - const pageTitle = await page.locator(selectors.homepage.heading).textContent(); - expect(pageTitle).toContain('Giftaid it'); - - await page.close(); - }); -}); diff --git a/playwright-staging/tests/features/update/validFormSubmission.feature b/playwright-staging/tests/features/update/validFormSubmission.feature new file mode 100644 index 00000000..2eae5ce1 --- /dev/null +++ b/playwright-staging/tests/features/update/validFormSubmission.feature @@ -0,0 +1,11 @@ +@sanity @nightly-sanity @update-valid-submission +Feature: Valid Giftaid update submission + + # Step definitions for this feature are implemented in: + # tests/step-definitions/update/giftaidUpdateCommon.steps.js + Scenario: Valid giftaid update submission + Given I am on the Giftaid update page + When I complete the Giftaid update form with valid details + And I select yes for GiftAid declaration + And I submit the Giftaid update form + Then I should see update thank you message diff --git a/playwright-staging/tests/features/update/validFormSubmission.spec.js b/playwright-staging/tests/features/update/validFormSubmission.spec.js deleted file mode 100644 index eaa3ee94..00000000 --- a/playwright-staging/tests/features/update/validFormSubmission.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -// @ts-check -const { expect } = require('@playwright/test'); -const { test } = require('../../../browserstack'); -const { Commands } = require('../../utils/commands'); -const { selectors } = require('../../utils/locators'); - -test.only('Valid giftaid update submission @sanity @nightly-sanity', async ({ page }) => { - const commands = new Commands(page); - - // Navigate to the Giftaid update page - await page.goto(`${process.env.BASE_URL}update`, { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Populate all input fields with valid data - await commands.populateUpdateFormFields(page); - - // Select 'Yes' for GiftAid declaration - await page.locator(selectors.giftAidClaimChoice.yes).click(); - - // Submit the form and validate the thank you message - await page.locator(selectors.formFields.submitButton).click(); - await expect(page.locator(selectors.success.heading)).toContainText('Thank you, test!'); - - await page.close(); -}); diff --git a/playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js b/playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js new file mode 100644 index 00000000..bbb4e7e4 --- /dev/null +++ b/playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js @@ -0,0 +1,22 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +When('I complete the Giftaid update form with valid details', async function () { + await this.commands.populateUpdateFormFields(this.page); +}); + +Then('I should see the Giftaid declaration section', async function () { + await expect(this.page.locator(selectors.giftAidClaimChoice.yes)).toBeVisible(); + await expect(this.page.locator(selectors.giftAidClaimChoice.no)).toBeVisible(); +}); + +Then('yes option should be selected and no option should not be selected', async function () { + await expect(this.page.locator(selectors.giftAidClaimChoice.yesInput)).toBeChecked(); + await expect(this.page.locator(selectors.giftAidClaimChoice.noInput)).not.toBeChecked(); +}); + +Then('no option should be selected and yes option should not be selected', async function () { + await expect(this.page.locator(selectors.giftAidClaimChoice.noInput)).toBeChecked(); + await expect(this.page.locator(selectors.giftAidClaimChoice.yesInput)).not.toBeChecked(); +}); diff --git a/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js b/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js new file mode 100644 index 00000000..82e102fe --- /dev/null +++ b/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js @@ -0,0 +1,46 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I am on the Giftaid update page', async function () { + await this.page.goto(`${process.env.BASE_URL}update`, { timeout: 30000 }); + await this.page.waitForLoadState('domcontentloaded'); +}); + +When('I complete the Giftaid update form with valid details', async function () { + await this.commands.populateUpdateFormFields(this.page); +}); + +When('I submit the Giftaid update form', async function () { + await this.page.click(selectors.formFields.submitButton); +}); + +When('I select yes for GiftAid declaration', async function () { + await this.page.click(selectors.giftAidClaimChoice.yes); +}); + +When('I select no for GiftAid declaration', async function () { + await this.page.click(selectors.giftAidClaimChoice.no); +}); + +When('I enter update postcode {string}', async function (postcode) { + await this.page.fill(selectors.formFields.postcode, ''); + await this.page.type(selectors.formFields.postcode, postcode); +}); + +Then('I should see update postcode error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.postcode)).toBeVisible(); + await expect(this.page.locator(selectors.errorMessages.postcode)).toHaveText(message); +}); + +Then('I should see update thank you message for {string}', async function (firstName) { + await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); +}); + +Then('I should see update no declaration message', async function () { + await expect(this.page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); +}); + +Then('I should see update thank you message', async function () { + await expect(this.page.locator(selectors.success.heading)).toContainText('Thank you, test!'); +}); diff --git a/playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js b/playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js new file mode 100644 index 00000000..84c3bbe4 --- /dev/null +++ b/playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js @@ -0,0 +1,38 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I enter basic update supporter details', async function () { + // fill in all input fields + // await page.locator('input#field-input--transactionId').fill(transactionId); + await this.page.locator(selectors.formFields.firstName).fill('test'); + await this.page.locator(selectors.formFields.lastName).fill('test lastname'); + await this.page.locator(selectors.marketingPreferences.fields.email).fill('giftaid-staging-@email.sls.comicrelief.com'); +}); + +When('I enter update international address details manually', async function () { + // manually enter international address details + await this.page.locator(selectors.address.manualAddressLink).click(); + await this.page.locator(selectors.address.address1).fill('219 Beacon St'); + await this.page.locator(selectors.address.address2).fill('Winder'); + await this.page.locator(selectors.address.address3).fill('Park Ridge'); + await this.page.locator(selectors.address.town).fill('GA'); +}); + +When('I select a non UK country on the update form', async function () { + // Select a random country from the dropdown (excluding UK to simulate international address) + const countryOptions = await this.page.$$eval(selectors.address.countryOptions, options => + options.map(option => option.value).filter(value => value && value !== 'GB') + ); + + const randomCountryCode = countryOptions[Math.floor(Math.random() * countryOptions.length)]; + await this.page.locator(selectors.address.countryByName).selectOption({ value: randomCountryCode }); + + // Wait for the form to adjust to the selected country + await this.page.waitForTimeout(2000); +}); + +Then('update postcode error should disappear', async function () { + // When an international country is selected, the postcode error for UK format should not show anymore + await expect(this.page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); +}); diff --git a/playwright-staging/tests/step-definitions/update/sorryPage.steps.js b/playwright-staging/tests/step-definitions/update/sorryPage.steps.js new file mode 100644 index 00000000..0c5691f1 --- /dev/null +++ b/playwright-staging/tests/step-definitions/update/sorryPage.steps.js @@ -0,0 +1,18 @@ +const { Given, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I navigate to the Giftaid update sorry page', async function () { + // Navigate to the 'Sorry' page of giftaid update form + await this.page.goto(`${process.env.BASE_URL}update/sorry`, { timeout: 30000 }); + await this.page.waitForLoadState('domcontentloaded'); +}); + +Then('I should see the update sorry heading', async function () { + await expect(this.page.locator(selectors.sorry.heading)).toContainText('Sorry!'); +}); + +Then('I should see the update sorry message', async function () { + const sorryMessage = await this.page.locator(selectors.sorry.firstParagraph).isVisible(); + expect(sorryMessage).toBeTruthy(); +}); diff --git a/playwright-staging/tests/step-definitions/update/successRedirect.steps.js b/playwright-staging/tests/step-definitions/update/successRedirect.steps.js new file mode 100644 index 00000000..eb717947 --- /dev/null +++ b/playwright-staging/tests/step-definitions/update/successRedirect.steps.js @@ -0,0 +1,14 @@ +const { Given, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const { selectors } = require('../../utils/locators'); + +Given('I navigate to the Giftaid update success page', async function () { + // Navigate to the success page of the Giftaid update directly + await this.page.goto(`${process.env.BASE_URL}update/success`, { timeout: 30000 }); + await this.page.waitForLoadState('domcontentloaded'); +}); + +Then('I should be redirected to the Giftaid homepage', async function () { + // Confirm the page has the expected Giftaid title after redirection + await expect(this.page.locator(selectors.homepage.heading)).toContainText('Giftaid it'); +}); diff --git a/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js new file mode 100644 index 00000000..00a07d5e --- /dev/null +++ b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js @@ -0,0 +1,132 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); +const Chance = require('chance'); +const { selectors } = require('../../utils/locators'); + +const chance = new Chance(); + +Given('I am on the Giftaid update page', async function () { + await this.page.goto(`${process.env.BASE_URL}update`, { timeout: 30000 }); + await this.page.waitForLoadState('domcontentloaded'); +}); + +When('I submit the Giftaid update form', async function () { + await this.page.click(selectors.formFields.submitButton); +}); + +Then('I should see required update form error messages', async function () { + await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText('Please fill in your first name'); + await expect(this.page.locator(selectors.errorMessages.lastName)).toHaveText('Please fill in your last name'); + await expect(this.page.locator(selectors.errorMessages.email)).toHaveText('Please fill in your email address'); + await expect(this.page.locator(selectors.errorMessages.postcode)).toHaveText('Please enter your postcode'); + await expect(this.page.locator(selectors.errorMessages.addressDetails)).toHaveText('Please fill in your address'); + await expect(this.page.locator(selectors.errorMessages.giftAidClaimChoice)).toHaveText('This field is required'); +}); + +When('I enter update first name {string}', async function (firstName) { + const value = firstName === 'SPACE' ? ' ' : firstName; + await this.page.fill(selectors.formFields.firstName, value); + await this.page.keyboard.press('Enter'); +}); + +Then('I should see update first name error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText(message); +}); + +When('I complete the Giftaid update form with first name {string}', async function (firstName) { + await this.page.fill(selectors.formFields.firstName, ''); + await this.commands.populateUpdateFormFields(this.page, { firstName }); +}); + +When('I select yes for GiftAid declaration', async function () { + await this.page.click(selectors.giftAidClaimChoice.yes); +}); + +When('I select no for GiftAid declaration', async function () { + await this.page.click(selectors.giftAidClaimChoice.no); +}); + +Then('I should see update thank you message for {string}', async function (firstName) { + await expect( + this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); +}); + +When('I enter update email {string}', async function (email) { + await this.page.fill(selectors.marketingPreferences.fields.email, ''); + await this.page.fill(selectors.marketingPreferences.fields.email, email); + await this.page.keyboard.press('Enter'); +}); + +Then('I should see update email error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.email)).toBeVisible(); + await expect(this.page.locator(selectors.errorMessages.email)).toHaveText(message); +}); + +When('I complete the Giftaid update form with generated email', async function () { + const validEmail = `giftaid-update-staging-${chance.email()}`; + await this.page.fill(selectors.marketingPreferences.fields.email, ''); + await this.commands.populateUpdateFormFields(this.page, { email: validEmail }); +}); + +Then('I should see update no declaration message', async function () { + await expect( + this.page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); +}); + +When('I enter update mobile number {string}', async function (mobile) { + await this.page.locator(selectors.formFields.mobile).fill(''); + await this.page.locator(selectors.formFields.mobile).type(mobile, { delay: 100 }); +}); + +Then('I should see update mobile error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.mobile)).toHaveText(message); +}); + +Then('I should not see update mobile error message', async function () { + await expect(this.page.locator(selectors.errorMessages.mobile)).not.toBeVisible(); +}); + +When('I complete the Giftaid update form with generated mobile and last name {string}', async function (lastName) { + const prefixes = ['071', '073', '074', '075', '077', '078', '079']; + const prefix = chance.pickone(prefixes); + const mobile = `${prefix}${chance.string({ pool: '0123456789', length: 8 })}`; + + await this.page.locator(selectors.formFields.mobile).fill(''); + await this.commands.populateUpdateFormFields(this.page, { lastName, mobile }); +}); + +When('I enter update postcode {string}', async function (postcode) { + await this.page.fill(selectors.formFields.postcode, ''); + await this.page.type(selectors.formFields.postcode, postcode); +}); + +Then('I should see update postcode error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.postcode)).toBeVisible(); + await expect(this.page.locator(selectors.errorMessages.postcode)).toHaveText(message); +}); + +When('I search for the update postcode', async function () { + await this.page.click(selectors.formFields.postcodeLookup); +}); + +When('I select update address from lookup or enter address manually', async function () { + if (await this.page.locator(selectors.address.addressSelect).isVisible()) { + const options = await this.page.$$eval(selectors.address.addressSelectOptions, options => options.map(option => option.value)); + await this.page.selectOption(selectors.address.addressSelect, options[1]); + await this.page.click(selectors.formFields.submitButton); + } else { + await this.page.click(selectors.address.manualAddressLink); + await this.page.fill(selectors.address.address1, 'COMIC RELIEF'); + await this.page.fill(selectors.address.address2, 'CAMELFORD HOUSE 87-90'); + await this.page.fill(selectors.address.address3, 'ALBERT EMBANKMENT'); + await this.page.fill(selectors.address.town, 'LONDON'); + await this.page.click(selectors.formFields.submitButton); + } +}); + +When('I complete remaining update form fields', async function () { + await this.page.locator(selectors.formFields.firstName).fill('test'); + await this.page.locator(selectors.formFields.lastName).fill(chance.last()); + await this.page.locator(selectors.marketingPreferences.fields.email).fill(`giftaid-update-staging-${chance.email()}`); + await this.page.fill(selectors.formFields.postcode, 'SE1 7TP'); +}); From d2b564d77627d5974991a5434278d19a7054f387 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 5 May 2026 23:00:49 +0100 Subject: [PATCH 06/35] test: Add comments in cucumber config --- playwright-staging/config/cucumber.js | 2 +- playwright-staging/tests/support/hooks.js | 23 +++++++++++++++-------- playwright-staging/tests/support/world.js | 2 ++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/playwright-staging/config/cucumber.js b/playwright-staging/config/cucumber.js index b9cbbc51..beee3736 100644 --- a/playwright-staging/config/cucumber.js +++ b/playwright-staging/config/cucumber.js @@ -8,6 +8,6 @@ module.exports = { format: ['progress', 'summary'], // Use 'pretty' locally for readable step-by-step output. // On CI keep the output minimal to avoid noisy logs. - publishQuiet: true, + publishQuiet: true, // Hide the default Cucumber report publishing link (we check CI instead) }, }; diff --git a/playwright-staging/tests/support/hooks.js b/playwright-staging/tests/support/hooks.js index 9ead586d..fdba1c67 100644 --- a/playwright-staging/tests/support/hooks.js +++ b/playwright-staging/tests/support/hooks.js @@ -4,13 +4,15 @@ const { Before, After, Status, setDefaultTimeout } = require('@cucumber/cucumber const { chromium } = require('@playwright/test'); const { Commands } = require('../utils/commands'); -setDefaultTimeout(300 * 1000); +setDefaultTimeout(300 * 1000); // 5 mins +// Get Playwright version to match BrowserStack runtime const clientPlaywrightVersion = require('@playwright/test/package.json').version; +// BrowserStack capabilities const caps = { project: 'giftaid-react', - name: 'cucumber e2e tests', + name: 'e2e tests', browser: 'chrome', browser_version: 'latest', resolution: '1920x1080', @@ -18,6 +20,7 @@ const caps = { os_version: '11', 'browserstack.username': process.env.BROWSERSTACK_USERNAME, 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, + // Ensure BrowserStack Playwright version matches local version 'client.playwrightVersion': clientPlaywrightVersion, 'browserstack.playwrightVersion': clientPlaywrightVersion, @@ -28,22 +31,24 @@ const caps = { 'browserstack.idleTimeout': 300, }; +// Runs before each scenario Before(async function (scenario) { + // Set BrowserStack session name to scenario name (helps to see in BS dashboard) caps.name = scenario.pickle.name; + // Connect to BrowserStack via Playwright CDP this.browser = await chromium.connect({ - wsEndpoint: - `wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify(caps))}`, + wsEndpoint: `wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify(caps))}`, }); this.context = await this.browser.newContext({ - viewport: null, - serviceWorkers: 'block', + viewport: null, // Use full screen instead of fixed viewport + serviceWorkers: 'block', // Avoids caching issues }); this.page = await this.context.newPage(); - // maximise window + // Maximise browser window const session = await this.context.newCDPSession(this.page); const { windowId } = await session.send('Browser.getWindowForTarget'); await session.send('Browser.setWindowBounds', { @@ -54,6 +59,7 @@ Before(async function (scenario) { this.commands = new Commands(this.page); }); +// After each scenario completes, report the test result (pass/fail) to BrowserStack After(async function (scenario) { const testResult = { action: 'setSessionStatus', @@ -63,11 +69,12 @@ After(async function (scenario) { }, }; + // Close page if (this.page) { await this.page.evaluate(() => {}, `browserstack_executor: ${JSON.stringify(testResult)}`); await this.page.close(); } - + // Close context and browser if (this.context) { await this.context.close(); } diff --git a/playwright-staging/tests/support/world.js b/playwright-staging/tests/support/world.js index ab3a2bc3..bc162f1f 100644 --- a/playwright-staging/tests/support/world.js +++ b/playwright-staging/tests/support/world.js @@ -1,3 +1,5 @@ +// This defines shared context for each scenario +// Values stored here (browser, page, commands) are accessible across all step definitions via "this" const { setWorldConstructor } = require('@cucumber/cucumber'); class CustomWorld { From 6c97779ddc8752603cd9d0b3a300c34543ffd53a Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 7 May 2026 11:52:11 +0100 Subject: [PATCH 07/35] test: disable local playwright reports and test-results that generates every test run --- playwright-local/playwright-local.config.js | 13 ++++++------- playwright-staging/playwright.config.js | 10 ++++++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/playwright-local/playwright-local.config.js b/playwright-local/playwright-local.config.js index ad93f15e..18e9e717 100644 --- a/playwright-local/playwright-local.config.js +++ b/playwright-local/playwright-local.config.js @@ -20,14 +20,13 @@ module.exports = defineConfig({ expect: { timeout: 60 * 1000, }, - reporter: [ - ['list'], - ['html', { open: 'never' }] - ], + reporter: process.env.CI ? [['list'], ['html', { open: 'never' }]] : [['list']], use: { - actionTimeout: 0, - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + // Disable local Playwright traces/videos/screenshots to avoid generating + // test-results folders locally. In CI, keep artifacts for debugging failures. + trace: process.env.CI ? 'on-first-retry' : 'off', + screenshot: process.env.CI ? 'only-on-failure' : 'off', + video: process.env.CI ? 'retain-on-failure' : 'off', }, /* Configure projects for major browsers */ diff --git a/playwright-staging/playwright.config.js b/playwright-staging/playwright.config.js index 818d0dd5..7e498bc1 100644 --- a/playwright-staging/playwright.config.js +++ b/playwright-staging/playwright.config.js @@ -18,10 +18,16 @@ const config = { workers: 3, use:{ viewport: null, + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ actionTimeout: 0, - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'retain-on-failure', + + // Disable local Playwright traces/videos/screenshots to avoid generating + // test-results folders locally. We rely on BrowserStack videos and CI logs + // for debugging test failures instead. + trace: process.env.CI ? 'retain-on-failure' : 'off', + screenshot: process.env.CI ? 'only-on-failure' : 'off', + video: process.env.CI ? 'retain-on-failure' : 'off', navigationTimeout: 45000, scriptTimeout: 60000, // this is needed for long running scripts serviceWorkers: 'block', // optional but reduces flakiness From fd17063139266789ec8481b1cab62de58b7381ff Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Fri, 8 May 2026 16:41:27 +0100 Subject: [PATCH 08/35] test: move shard redirect step into comon step-definitions --- .../tests/step-definitions/common/giftaidCommon.steps.js | 4 ++++ .../tests/step-definitions/submit/successRedirect.steps.js | 6 ------ ...cessRedirect.steps.js => updateSuccessRedirect.steps.js} | 5 ----- 3 files changed, 4 insertions(+), 11 deletions(-) rename playwright-staging/tests/step-definitions/update/{successRedirect.steps.js => updateSuccessRedirect.steps.js} (64%) diff --git a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js index cdfb00e7..9f1b6bfc 100644 --- a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js +++ b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js @@ -13,3 +13,7 @@ When('I select marketing preferences', async function () { When('I complete the Giftaid form with valid details', async function () { await this.commands.populateFormFields(this.page); }); + +Then('I should be redirected to the Giftaid homepage', async function () { + await expect(this.page.locator(selectors.homepage.heading)).toContainText('Giftaid it'); +}); diff --git a/playwright-staging/tests/step-definitions/submit/successRedirect.steps.js b/playwright-staging/tests/step-definitions/submit/successRedirect.steps.js index 731de6d5..c297bfbf 100644 --- a/playwright-staging/tests/step-definitions/submit/successRedirect.steps.js +++ b/playwright-staging/tests/step-definitions/submit/successRedirect.steps.js @@ -7,12 +7,6 @@ Given('I navigate to the Giftaid success page', async function () { await this.page.waitForLoadState('domcontentloaded'); }); -Then('I should be redirected to the Giftaid homepage', async function () { - const header = this.page.locator(selectors.homepage.heading); - await expect(header).toBeVisible(); - await expect(header).toContainText('Giftaid it'); -}); - Then('I should see the Giftaid heading', async function () { await expect(this.page.locator(selectors.homepage.heading)).toBeVisible(); }); diff --git a/playwright-staging/tests/step-definitions/update/successRedirect.steps.js b/playwright-staging/tests/step-definitions/update/updateSuccessRedirect.steps.js similarity index 64% rename from playwright-staging/tests/step-definitions/update/successRedirect.steps.js rename to playwright-staging/tests/step-definitions/update/updateSuccessRedirect.steps.js index eb717947..e118322b 100644 --- a/playwright-staging/tests/step-definitions/update/successRedirect.steps.js +++ b/playwright-staging/tests/step-definitions/update/updateSuccessRedirect.steps.js @@ -7,8 +7,3 @@ Given('I navigate to the Giftaid update success page', async function () { await this.page.goto(`${process.env.BASE_URL}update/success`, { timeout: 30000 }); await this.page.waitForLoadState('domcontentloaded'); }); - -Then('I should be redirected to the Giftaid homepage', async function () { - // Confirm the page has the expected Giftaid title after redirection - await expect(this.page.locator(selectors.homepage.heading)).toContainText('Giftaid it'); -}); From f1951116724b93b8586b02564f7fbefc80437e87 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 12 May 2026 12:55:01 +0100 Subject: [PATCH 09/35] test: setup and convert playwright-local tests into cucumber --- package.json | 5 + playwright-local/config/cucumber.js | 13 + playwright-local/playwright-local.config.js | 2 +- .../features/submit/addressValidation.feature | 43 ++ .../features/submit/formValidation.feature | 55 +++ .../internationalAddressesValidation.feature | 18 + .../marketingPreferencesValidation.feature | 36 ++ .../features/submit/postcodeLookup.feature | 23 + .../submit/validGiftaidSubmission.feature | 12 + .../update/updateFormValidation.feature | 104 ++++ ...teInternationalAddressesValidation.feature | 17 + .../update/updateValidFormSubmission.feature | 11 + .../common/giftaidCommon.steps.js | 60 +++ .../submit/addressValidation.steps.js | 47 ++ .../submit/formValidation.steps.js | 37 ++ .../internationalAddressesValidation.steps.js | 20 + .../marketingPreferencesValidation.steps.js | 63 +++ .../submit/postcodeLookup.steps.js | 18 + .../submit/validGiftaidSubmission.steps.js | 7 + .../update/giftaidUpdateCommon.steps.js | 22 + .../update/updateFormValidation.steps.js | 64 +++ ...eInternationalAddressesValidation.steps.js | 24 + .../tests/submit/addressValidation.spec.js | 66 --- .../tests/submit/formValidation.spec.js | 82 ---- .../internationalAddressesValidation.spec.js | 49 -- .../marketingPreferencesValidation.spec.js | 78 --- .../tests/submit/postcodeLookup.spec.js | 50 -- .../tests/submit/validFormSubmission.spec.js | 32 -- playwright-local/tests/support/hooks.js | 40 ++ playwright-local/tests/support/world.js | 14 + .../tests/update/formValidation.spec.js | 313 ------------ .../internationalAddressesValidation.spec.js | 52 -- .../tests/update/validFormSubmission.spec.js | 25 - .../features/submit/addressValidation.feature | 34 +- .../features/submit/formValidation.feature | 54 +-- .../internationalAddressesValidation.feature | 12 +- .../submit/marketingPreferencesData.feature | 10 +- .../marketingPreferencesValidation.feature | 34 +- .../features/submit/postcodeLookup.feature | 12 +- .../submit/validFormSubmission.feature | 4 +- .../features/update/formValidation.feature | 26 +- .../internationalAddressesValidation.feature | 12 +- .../update/validFormSubmission.feature | 2 +- .../common/giftaidCommon.steps.js | 2 +- .../submit/addressValidation.steps.js | 10 +- .../submit/formValidation.steps.js | 20 +- .../submit/giftaidSubmission.steps.js | 2 +- .../internationalAddressValidation.steps.js | 6 +- .../marketingPreferencesContactStore.steps.js | 8 +- .../marketingPreferencesValidation.steps.js | 24 +- .../submit/postcodeValidation.steps.js | 8 +- .../update/giftaidUpdateCommon.steps.js | 10 +- .../internationalAddressValidation.steps.js | 6 +- .../update/updateFormValidation.steps.js | 36 +- yarn.lock | 448 +++++++++++++++++- 55 files changed, 1355 insertions(+), 927 deletions(-) create mode 100644 playwright-local/config/cucumber.js create mode 100644 playwright-local/tests/features/submit/addressValidation.feature create mode 100644 playwright-local/tests/features/submit/formValidation.feature create mode 100644 playwright-local/tests/features/submit/internationalAddressesValidation.feature create mode 100644 playwright-local/tests/features/submit/marketingPreferencesValidation.feature create mode 100644 playwright-local/tests/features/submit/postcodeLookup.feature create mode 100644 playwright-local/tests/features/submit/validGiftaidSubmission.feature create mode 100644 playwright-local/tests/features/update/updateFormValidation.feature create mode 100644 playwright-local/tests/features/update/updateInternationalAddressesValidation.feature create mode 100644 playwright-local/tests/features/update/updateValidFormSubmission.feature create mode 100644 playwright-local/tests/step-definitions/common/giftaidCommon.steps.js create mode 100644 playwright-local/tests/step-definitions/submit/addressValidation.steps.js create mode 100644 playwright-local/tests/step-definitions/submit/formValidation.steps.js create mode 100644 playwright-local/tests/step-definitions/submit/internationalAddressesValidation.steps.js create mode 100644 playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js create mode 100644 playwright-local/tests/step-definitions/submit/postcodeLookup.steps.js create mode 100644 playwright-local/tests/step-definitions/submit/validGiftaidSubmission.steps.js create mode 100644 playwright-local/tests/step-definitions/update/giftaidUpdateCommon.steps.js create mode 100644 playwright-local/tests/step-definitions/update/updateFormValidation.steps.js create mode 100644 playwright-local/tests/step-definitions/update/updateInternationalAddressesValidation.steps.js delete mode 100644 playwright-local/tests/submit/addressValidation.spec.js delete mode 100644 playwright-local/tests/submit/formValidation.spec.js delete mode 100644 playwright-local/tests/submit/internationalAddressesValidation.spec.js delete mode 100644 playwright-local/tests/submit/marketingPreferencesValidation.spec.js delete mode 100644 playwright-local/tests/submit/postcodeLookup.spec.js delete mode 100644 playwright-local/tests/submit/validFormSubmission.spec.js create mode 100644 playwright-local/tests/support/hooks.js create mode 100644 playwright-local/tests/support/world.js delete mode 100644 playwright-local/tests/update/formValidation.spec.js delete mode 100644 playwright-local/tests/update/internationalAddressesValidation.spec.js delete mode 100644 playwright-local/tests/update/validFormSubmission.spec.js diff --git a/package.json b/package.json index ce0981d7..c840b077 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,10 @@ "test:playwright-local:ci:chromium": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local:local:chromium", "test:playwright-local:ci:mobile": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local:local:mobile", "test:playwright-local:local:chrome:mobile": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local:local", + "test:cucumber:local": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", + "test:cucumber:local:sanity": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:ci": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local", + "test:cucumber:ci:sanity": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:sanity", "snyk-protect": "snyk-protect", "prepublish": "yarn snyk-protect" }, @@ -59,6 +63,7 @@ "@babel/runtime": "^7.11.2", "@comicrelief/data-models": "^1.15.4", "@comicrelief/test-utils": "^1.5.13", + "@cucumber/cucumber": "8.9.1", "@playwright/test": "1.38.1", "babel-eslint": "^10.1.0", "babel-loader": "^8.1.0", diff --git a/playwright-local/config/cucumber.js b/playwright-local/config/cucumber.js new file mode 100644 index 00000000..b9cbbc51 --- /dev/null +++ b/playwright-local/config/cucumber.js @@ -0,0 +1,13 @@ +module.exports = { + default: { + paths: ['tests/features/**/*.feature'], + require: [ + 'tests/support/**/*.js', + 'tests/step-definitions/**/*.js', + ], + format: ['progress', 'summary'], + // Use 'pretty' locally for readable step-by-step output. + // On CI keep the output minimal to avoid noisy logs. + publishQuiet: true, + }, +}; diff --git a/playwright-local/playwright-local.config.js b/playwright-local/playwright-local.config.js index 18e9e717..ee6a71a0 100644 --- a/playwright-local/playwright-local.config.js +++ b/playwright-local/playwright-local.config.js @@ -49,7 +49,7 @@ module.exports = defineConfig({ } ], - /* Run your local dev server before starting the tests */ + /* Run 'yarn start' before starting the tests */ webServer: { command: 'yarn start', port: 3000, diff --git a/playwright-local/tests/features/submit/addressValidation.feature b/playwright-local/tests/features/submit/addressValidation.feature new file mode 100644 index 00000000..de9608f8 --- /dev/null +++ b/playwright-local/tests/features/submit/addressValidation.feature @@ -0,0 +1,43 @@ +@sanity @address-validation +Feature: Address validation + + Background: + Given I am on the local Giftaid page + And I select the local Giftaid option + And I enter the local supporter details + + Scenario: Empty postcode should show an error message + When I clear the local postcode field + And I submit the local Giftaid form + Then I should see the local postcode error message "Please enter your postcode" + + Scenario Outline: Invalid postcodes should show error messages + When I enter the local postcode "" + Then I should see the local postcode error message "" + + Examples: + | postcode | message | + | 12SE17TP | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | comic relief | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | cro 7tp | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + + Scenario: Entering a postcode without selecting an address should show an error message + When I enter the local postcode "SE1 7TP" + And I search for the local postcode + Then I should see the local address dropdown + When I submit the local Giftaid form + Then I should see the local address select error message "Please select your address" + + Scenario: Clicking the manual address link should show the address fields + When I enter the local postcode "SE1 7TP" + Then I should see the local manual address link + When I click the local manual address link + Then I should see the local manual address fields + + Scenario: Invalid address fields should show error messages + When I enter the local postcode "SE1 7TP" + And I click the local manual address link + And I enter the local invalid address line 1 + Then I should see the local address line 1 error message + When I enter the local invalid town + Then I should see the local town error message diff --git a/playwright-local/tests/features/submit/formValidation.feature b/playwright-local/tests/features/submit/formValidation.feature new file mode 100644 index 00000000..e23f25d7 --- /dev/null +++ b/playwright-local/tests/features/submit/formValidation.feature @@ -0,0 +1,55 @@ +@sanity @form-validation +Feature: Form validation + + Background: + Given I am on the local Giftaid page + And I select the local Giftaid option + + Scenario Outline: Invalid mobile numbers should show an error message + When I enter the local mobile number "" + Then I should see the local mobile error message "Please enter a valid mobile phone number - it must be the same number associated with your donation." + + Examples: + | mobile | + | 0712345678 | + | 0712345678900 | + | 0712 345 6789 | + | 0780ab5694245 | + + Scenario: Valid mobile number should submit the form + When I complete the local Giftaid form with valid details + And I submit the local Giftaid form + Then I should see the local thank you message "Thank you, test!" + + Scenario Outline: Invalid first names should show an error message + When I enter the local first name "" + Then I should see the local first name error message "This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters" + + Examples: + | firstName | + | Test^$%£ | + | SPACE | + | 123Test | + + Scenario: Valid first name should submit the form + When I complete the local Giftaid form with the first name "testFirstname" + And I submit the local Giftaid form + Then I should see the local thank you message "Thank you, testFirstname!" + + Scenario Outline: Invalid last names should show an error message + When I enter the local last name "" + Then I should see the local last name error message "This field only accepts 25 alphanumeric characters and , . ( ) / & ' - starting with alphanumeric characters" + + Examples: + | lastName | + | Test^$%£ | + | SPACE | + + Scenario: Alphanumeric last name should not show an error message + When I enter the local last name "123Test" + Then I should not see the local last name error message + + Scenario: Valid last name should submit the form + When I complete the local Giftaid form with valid details + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/features/submit/internationalAddressesValidation.feature b/playwright-local/tests/features/submit/internationalAddressesValidation.feature new file mode 100644 index 00000000..1c17266d --- /dev/null +++ b/playwright-local/tests/features/submit/internationalAddressesValidation.feature @@ -0,0 +1,18 @@ +@sanity @international-address-validation +Feature: International address validation + + Background: + Given I am on the local Giftaid page + And I select the local Giftaid option + And I enter the local supporter details + + Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the form + When I enter the local postcode "30916-395" + Then I should see the local postcode error message "Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below." + When I click the local manual address link + And I enter the local international address details + And I select a random local non-UK country + Then I should not see the local postcode error message + When I select the local marketing preferences + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/features/submit/marketingPreferencesValidation.feature b/playwright-local/tests/features/submit/marketingPreferencesValidation.feature new file mode 100644 index 00000000..a1ab4e1a --- /dev/null +++ b/playwright-local/tests/features/submit/marketingPreferencesValidation.feature @@ -0,0 +1,36 @@ +@sanity @marketing-preferences-validation +Feature: Marketing preferences validation + + Background: + Given I am on the local Giftaid page + And I select the local Giftaid option + And I complete the local Giftaid form with valid details + + Scenario: Clicking marketing preference options should submit the Giftaid form + When I select all the local marketing preference options + And I enter the local marketing email + And I enter the local marketing phone + And I submit the local Giftaid form + Then I should see the local thank you message "Thank you, test!" + + Scenario: The email marketing preference field should show validation errors + When I select the local email marketing preference + And I enter the local marketing email + And I clear the local marketing email + Then I should see the local marketing email error message "Please fill in your email address" + When I enter an invalid local marketing email "example@£$^&email.com" + Then I should see the local marketing email error message "Please fill in a valid email address" + When I enter the local marketing email + And I submit the local Giftaid form + Then I should see the local thank you message "Thank you, test!" + + Scenario: The phone marketing preference field should show validation errors + When I select the local phone marketing preference + And I enter the local marketing phone + And I clear the local marketing phone + Then I should see the local marketing phone error message "Please fill in your phone number" + When I enter an invalid local marketing phone "0208569424" + Then I should see the local marketing phone error message "Please fill in a valid UK phone number, with no spaces" + When I enter the local marketing phone + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/features/submit/postcodeLookup.feature b/playwright-local/tests/features/submit/postcodeLookup.feature new file mode 100644 index 00000000..12668ad8 --- /dev/null +++ b/playwright-local/tests/features/submit/postcodeLookup.feature @@ -0,0 +1,23 @@ +@sanity @postcode-lookup +Feature: Postcode lookup validation + + Background: + Given I am on the local Giftaid page + And I select the local Giftaid option + And I enter the local supporter details + + Scenario Outline: Postcode formatting errors should show validation message + When I enter the local postcode "" + Then I should see the local postcode error message "" + + Examples: + | postcode | message | + | S E 1 7 T P | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + | SE$%TP | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | + + Scenario: Enter valid UK postcode using postcode lookup should submit the form + When I enter the local postcode "SE1 7TP" + And I search for the local postcode + And I select the local lookup address or enter the address manually + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/features/submit/validGiftaidSubmission.feature b/playwright-local/tests/features/submit/validGiftaidSubmission.feature new file mode 100644 index 00000000..93ed4f36 --- /dev/null +++ b/playwright-local/tests/features/submit/validGiftaidSubmission.feature @@ -0,0 +1,12 @@ +@sanity @valid-giftaid-submission +Feature: Valid Giftaid submission + + Background: + Given I am on the local Giftaid page + And I select the local Giftaid option + + Scenario: Valid Giftaid submission + When I complete the local Giftaid form with valid details + And I select the local marketing preferences + And I submit the local Giftaid form and wait for the navigation + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/features/update/updateFormValidation.feature b/playwright-local/tests/features/update/updateFormValidation.feature new file mode 100644 index 00000000..84f9c2bb --- /dev/null +++ b/playwright-local/tests/features/update/updateFormValidation.feature @@ -0,0 +1,104 @@ +@sanity @update-form-validation +Feature: Giftaid update form validation + + Background: + Given I am on the local Giftaid update page + + Scenario: Empty input fields should show error messages + When I submit the local Giftaid form + Then I should see the local update required field error messages + When I click the local manual address link + Then I should see the local update manual address required error messages + And I should see the local update GiftAid declaration error message + + Scenario Outline: Invalid update first names should show an error message + When I enter the local first name "" + Then I should see the local update first name error message "This field only accepts alphabetic characters and ' -" + + Examples: + | firstName | + | Test^$%£ | + | 123Test | + | SPACE | + + Scenario: A valid update first name should submit the form + When I complete the local Giftaid update form with valid details + And I select yes for the local update GiftAid declaration + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," + + Scenario Outline: Invalid update last names should show an error message + When I enter the local last name "" + Then I should see the local update last name error message "This field only accepts alphanumeric characters and , . ( ) / & ' -" + + Examples: + | lastName | + | Test^$%£ | + | SPACE | + + Scenario: An alphanumeric update last name should not show an error message + When I enter the local last name "123Test" + Then I should not see the local last name error message + + Scenario Outline: Invalid update emails should show an error message + When I enter the local email "" + Then I should see the local update email error message "Please fill in a valid email address" + + Examples: + | email | + | test@comic$relief.com | + | test@c{(micrelief.com | + | test@comic%relief.com | + | Test0-9!#$%&'*+/=?^_{\|}~-@comicrelief_9-8.com.uk | + + Scenario: A valid special character email should not show an error message + When I enter the local email "te$%^st@comicrelief.com" + Then I should not see the local update email error message + + Scenario Outline: Update mobile number validation + When I enter the local mobile number "" + Then I should see the local mobile error message "" + + Examples: + | mobile | message | + | 0722345678 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0722345678900 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0722 345 6789 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + | 0780ab5694245 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | + + Scenario Outline: Valid update mobile numbers should not show an error message + When I enter the local mobile number "" + Then I should not see the local mobile error message + + Examples: + | mobile | + | 07123456789 | + | 07340707252 | + + Scenario Outline: Invalid update postcodes should show an error message + When I enter the local postcode "" + Then I should see the local postcode error message "Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below." + + Examples: + | postcode | + | S E 1 7 T P | + | SE$%TP | + | cro 7tp | + + Scenario Outline: Compact UK postcodes should not show a format error + When I enter the local postcode "" + Then I should not see the local postcode error message + + Examples: + | postcode | + | se17tp | + | SE17TP | + + Scenario: Entering a valid UK postcode on the update form using postcode lookup should submit the form + When I complete the local update supporter details + And I enter the local postcode "SE1 7TP" + And I search for the local postcode + And I select the local update lookup address or enter the address manually + And I select yes for the local update GiftAid declaration + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/features/update/updateInternationalAddressesValidation.feature b/playwright-local/tests/features/update/updateInternationalAddressesValidation.feature new file mode 100644 index 00000000..634d4ae9 --- /dev/null +++ b/playwright-local/tests/features/update/updateInternationalAddressesValidation.feature @@ -0,0 +1,17 @@ +@sanity @update-international-address-validation +Feature: International address validation on the update form + + Background: + Given I am on the local Giftaid update page + + Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the update form + When I complete the local update supporter details + And I enter the local postcode "30916-395" + Then I should see the local postcode error message "Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below." + When I click the local manual address link + And I enter the local update international address details + And I select a random local update non-UK country + Then I should not see the local postcode error message + When I select yes for the local update GiftAid declaration + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/features/update/updateValidFormSubmission.feature b/playwright-local/tests/features/update/updateValidFormSubmission.feature new file mode 100644 index 00000000..8f490608 --- /dev/null +++ b/playwright-local/tests/features/update/updateValidFormSubmission.feature @@ -0,0 +1,11 @@ +@sanity @update-valid-form-submission +Feature: Valid Giftaid update submission + + Background: + Given I am on the local Giftaid update page + + Scenario: Valid Giftaid update submission + When I complete the local Giftaid update form with valid details + And I select yes for the local update GiftAid declaration + And I submit the local Giftaid form + Then I should see the local thank you message containing "Thank you," diff --git a/playwright-local/tests/step-definitions/common/giftaidCommon.steps.js b/playwright-local/tests/step-definitions/common/giftaidCommon.steps.js new file mode 100644 index 00000000..44fbf2d2 --- /dev/null +++ b/playwright-local/tests/step-definitions/common/giftaidCommon.steps.js @@ -0,0 +1,60 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +Given('I am on the local Giftaid page', async function () { + await this.page.goto(process.env.BASE_URL, { + waitUntil: 'networkidle', + timeout: 60000, + }); +}); + +Given('I select the local Giftaid option', async function () { + await this.page.locator('#field-label--giftaid').click(); +}); + +Given('I enter the local supporter details', async function () { + await this.page.locator('#field-input--mobile').fill('07123456789'); + await this.page.locator('input#field-input--firstname').fill('test'); + await this.page.locator('input#field-input--lastname').fill('user'); +}); + +When('I submit the local Giftaid form', async function () { + await this.page.locator('button[type=submit]').click(); +}); + +When('I enter the local postcode {string}', async function (postcode) { + await this.page.locator('input#field-input--postcode').fill(postcode); +}); + +When('I search for the local postcode', async function () { + await this.page.locator('#postcode_button').click(); +}); + +When('I click the local manual address link', async function () { + await this.page.locator('a[aria-describedby=field-error--addressDetails]').click(); +}); + +Then('I should see the local postcode error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--postcode > span')).toBeVisible(); + await expect(this.page.locator('div#field-error--postcode > span')).toContainText(message); +}); + +Then('I should not see the local postcode error message', async function () { + await expect(this.page.locator('div#field-error--postcode > span')).not.toBeVisible(); +}); + +Then('I should see the local thank you message {string}', async function (message) { + await expect(this.page.locator('div > h1')).toHaveText(message, { timeout: 15000 }); +}); + +Then('I should see the local thank you message containing {string}', async function (message) { + await expect(this.page.locator('div > h1')).toContainText(message, { timeout: 15000 }); +}); + +When('I complete the local Giftaid form with valid details', async function () { + await this.commands.populateFormFields(this.page, { mobile: '07123456789' }); +}); + +When('I select the local marketing preferences', async function () { + await this.commands.selectMarketingPrefs(this.page); +}); diff --git a/playwright-local/tests/step-definitions/submit/addressValidation.steps.js b/playwright-local/tests/step-definitions/submit/addressValidation.steps.js new file mode 100644 index 00000000..59a2272e --- /dev/null +++ b/playwright-local/tests/step-definitions/submit/addressValidation.steps.js @@ -0,0 +1,47 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +When('I clear the local postcode field', async function () { + await this.page.locator('input#field-input--postcode').fill(''); +}); + +Then('I should see the local address dropdown', async function () { + await expect(this.page.locator('#field-select--addressSelect')).toBeVisible(); +}); + +Then('I should see the local address select error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--addressSelect > span')).toHaveText(message); +}); + +Then('I should see the local manual address link', async function () { + await expect(this.page.locator('a[aria-describedby=field-error--addressDetails]')).toBeVisible(); +}); + +Then('I should see the local manual address fields', async function () { + await expect(this.page.locator('#field-input--address1')).toBeVisible(); + await expect(this.page.locator('#field-input--address2')).toBeVisible(); + await expect(this.page.locator('#field-input--address3')).toBeVisible(); + await expect(this.page.locator('#field-input--town')).toBeVisible(); + await expect(this.page.locator('select#field-select--country')).toBeVisible(); +}); + +When('I enter the local invalid address line 1', async function () { + // Should see error message for address1 when input with special characters is entered + await this.page.locator('#field-input--address1').fill('@£%3dComic Relief'); +}); + +Then('I should see the local address line 1 error message', async function () { + await expect(this.page.locator('#field-error--address1 > span')).toHaveText( + "This field only accepts alphanumeric characters and ' . - & _ /" + ); +}); + +When('I enter the local invalid town', async function () { + await this.page.locator('#field-input--town').fill(' Comic Relief'); +}); + +Then('I should see the local town error message', async function () { + await expect(this.page.locator('#field-error--town > span')).toHaveText( + "This field only accepts alphanumeric characters and ' . - & _ /" + ); +}); diff --git a/playwright-local/tests/step-definitions/submit/formValidation.steps.js b/playwright-local/tests/step-definitions/submit/formValidation.steps.js new file mode 100644 index 00000000..437a965f --- /dev/null +++ b/playwright-local/tests/step-definitions/submit/formValidation.steps.js @@ -0,0 +1,37 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +When('I enter the local mobile number {string}', async function (mobile) { + await this.page.locator('#field-input--mobile').fill(''); + await this.page.locator('#field-input--mobile').type(mobile, { delay: 100 }); +}); + +Then('I should see the local mobile error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--mobile > span')).toHaveText(message); +}); + +When('I complete the local Giftaid form with the first name {string}', async function (firstName) { + await this.commands.populateFormFields(this.page, { firstName }); +}); + +When('I enter the local first name {string}', async function (firstName) { + const value = firstName === 'SPACE' ? ' ' : firstName; + await this.page.locator('#field-input--firstname').fill(value); +}); + +Then('I should see the local first name error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--firstname')).toHaveText(message); +}); + +When('I enter the local last name {string}', async function (lastName) { + const value = lastName === 'SPACE' ? ' ' : lastName; + await this.page.locator('#field-input--lastname').fill(value); +}); + +Then('I should see the local last name error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--lastname > span')).toHaveText(message); +}); + +Then('I should not see the local last name error message', async function () { + await expect(this.page.locator('div#field-error--lastname > span')).toHaveCount(0); +}); diff --git a/playwright-local/tests/step-definitions/submit/internationalAddressesValidation.steps.js b/playwright-local/tests/step-definitions/submit/internationalAddressesValidation.steps.js new file mode 100644 index 00000000..918f5ab0 --- /dev/null +++ b/playwright-local/tests/step-definitions/submit/internationalAddressesValidation.steps.js @@ -0,0 +1,20 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +When('I enter the local international address details', async function () { + await this.page.locator('#field-input--address1').fill('219 Beacon St'); + await this.page.locator('#field-input--address2').fill('Winder'); + await this.page.locator('input#field-input--town').fill('GA'); +}); + +When('I select a random local non-UK country', async function () { + const countries = await this.page.$$eval('select#field-select--country > option', options => + options + .map(option => option.value) + .filter(value => value && value !== 'GB') + ); + + const randomCountryCode = countries[Math.floor(Math.random() * countries.length)]; + + await this.page.selectOption('select[name="country"]', { value: randomCountryCode }); +}); diff --git a/playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js b/playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js new file mode 100644 index 00000000..8ffc8d10 --- /dev/null +++ b/playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js @@ -0,0 +1,63 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +const Chance = require('chance'); +const chance = new Chance(); + +const email = `giftaid-staging-${Date.now().toString()}@email.sls.comicrelief.com`; +const phone = chance.phone({ country: 'uk', mobile: true }).replace(/\s/g, ''); + +const marketingOptions = [ + '[aria-label="field-label--Email--Email"]', + '[aria-label="field-label--Phone--Phone"]', + '[aria-label="field-label--Text--SMS"]', +]; + +When('I select all the local marketing preference options', async function () { + for (const option of marketingOptions) { + await this.page.locator(option).click(); + await expect(this.page.locator(option)).toBeChecked(); + } +}); + +When('I select the local email marketing preference', async function () { + await this.page.locator('[aria-label="field-label--Email--Email"]').click(); +}); + +When('I select the local phone marketing preference', async function () { + await this.page.locator('[aria-label="field-label--Phone--Phone"]').click(); +}); + +When('I enter the local marketing email', async function () { + await expect(this.page.locator('input#field-input--email')).toBeVisible(); + await this.page.locator('input#field-input--email').fill(email); +}); + +When('I clear the local marketing email', async function () { + await this.page.locator('input#field-input--email').fill(''); +}); + +When('I enter an invalid local marketing email {string}', async function (invalidEmail) { + await this.page.locator('input#field-input--email').fill(invalidEmail); +}); + +Then('I should see the local marketing email error message {string}', async function (message) { + await expect(this.page.locator('#field-error--email')).toHaveText(message); +}); + +When('I enter the local marketing phone', async function () { + await expect(this.page.locator('input#field-input--phone')).toBeVisible(); + await this.page.locator('input#field-input--phone').fill(phone); +}); + +When('I clear the local marketing phone', async function () { + await this.page.locator('input#field-input--phone').fill(''); +}); + +When('I enter an invalid local marketing phone {string}', async function (invalidPhone) { + await this.page.locator('input#field-input--phone').fill(invalidPhone); +}); + +Then('I should see the local marketing phone error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--phone > span')).toHaveText(message); +}); diff --git a/playwright-local/tests/step-definitions/submit/postcodeLookup.steps.js b/playwright-local/tests/step-definitions/submit/postcodeLookup.steps.js new file mode 100644 index 00000000..97571800 --- /dev/null +++ b/playwright-local/tests/step-definitions/submit/postcodeLookup.steps.js @@ -0,0 +1,18 @@ +const { When } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +When('I select the local lookup address or enter the address manually', async function () { + if (await this.page.locator('#field-select--addressSelect').isVisible()) { + await this.page.locator('select#field-select--addressSelect').selectOption({ + label: 'COMIC RELIEF, CAMELFORD HOUSE 87-90', + }); + + await expect(this.page.locator('input#field-input--postcode')).toHaveValue('SE1 7TP'); + } else { + await this.page.locator('a[aria-describedby=field-error--addressDetails]').click(); + await this.page.locator('#field-input--address1').fill('COMIC RELIEF'); + await this.page.locator('#field-input--address2').fill('CAMELFORD HOUSE 87-90'); + await this.page.locator('#field-input--address3').fill('ALBERT EMBANKMENT'); + await this.page.locator('#field-input--town').fill('LONDON'); + } +}); diff --git a/playwright-local/tests/step-definitions/submit/validGiftaidSubmission.steps.js b/playwright-local/tests/step-definitions/submit/validGiftaidSubmission.steps.js new file mode 100644 index 00000000..8acb0dd8 --- /dev/null +++ b/playwright-local/tests/step-definitions/submit/validGiftaidSubmission.steps.js @@ -0,0 +1,7 @@ +const { When } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +When('I submit the local Giftaid form and wait for the navigation', async function () { + await this.page.locator('button[type=submit]').click(); + await expect(this.page.locator('div > h1')).toContainText(/Thank you,|Sorry!/); +}); diff --git a/playwright-local/tests/step-definitions/update/giftaidUpdateCommon.steps.js b/playwright-local/tests/step-definitions/update/giftaidUpdateCommon.steps.js new file mode 100644 index 00000000..097624c6 --- /dev/null +++ b/playwright-local/tests/step-definitions/update/giftaidUpdateCommon.steps.js @@ -0,0 +1,22 @@ +const { Given, When } = require('@cucumber/cucumber'); + +Given('I am on the local Giftaid update page', async function () { + await this.page.goto(`${process.env.BASE_URL}/update`, { + waitUntil: 'networkidle', + timeout: 60000, + }); +}); + +When('I complete the local Giftaid update form with valid details', async function () { + await this.commands.populateUpdateFormFields(this.page); +}); + +When('I complete the local update supporter details', async function () { + await this.page.locator('#field-input--firstname').fill('test'); + await this.page.locator('#field-input--lastname').fill('test lastname'); + await this.page.locator('input#field-input--email').fill('giftaid-staging-@email.sls.comicrelief.com'); +}); + +When('I select yes for the local update GiftAid declaration', async function () { + await this.page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); +}); diff --git a/playwright-local/tests/step-definitions/update/updateFormValidation.steps.js b/playwright-local/tests/step-definitions/update/updateFormValidation.steps.js new file mode 100644 index 00000000..16fb6ae6 --- /dev/null +++ b/playwright-local/tests/step-definitions/update/updateFormValidation.steps.js @@ -0,0 +1,64 @@ +const { Given, When, Then } = require('@cucumber/cucumber'); +const { expect } = require('@playwright/test'); + +Then('I should see the local update required field error messages', async function () { + await expect(this.page.locator('div#field-error--firstname > span')).toContainText('Please fill in your first name'); + await expect(this.page.locator('div#field-error--lastname > span')).toContainText('Please fill in your last name'); + await expect(this.page.locator('div#field-error--postcode > span')).toContainText('Please enter your postcode'); + await expect(this.page.locator('div#field-error--addressDetails > span')).toContainText('Please fill in your address'); +}); + +Then('I should see the local update manual address required error messages', async function () { + await expect(this.page.locator('div#field-error--address1 > span')).toContainText('Please fill in your address line 1'); + await expect(this.page.locator('div#field-error--town > span')).toContainText('Please fill in your town/city'); +}); + +Then('I should see the local update GiftAid declaration error message', async function () { + await expect(this.page.locator('div#field-error--giftAidClaimChoice > span')).toContainText('This field is required'); +}); + +Then('I should see the local update first name error message {string}', async function (message) { + await expect(this.page.locator('#field-error--firstname')).toContainText(message); +}); + +Then('I should see the local update last name error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--lastname > span')).toContainText(message); +}); + +When('I enter the local email {string}', async function (email) { + await this.page.locator('input#field-input--email').fill(email); +}); + +Then('I should see the local update email error message {string}', async function (message) { + await expect(this.page.locator('div#field-error--email > span')).toContainText(message); +}); + +Then('I should not see the local update email error message', async function () { + await expect(this.page.locator('div#field-error--email > span')).not.toBeVisible(); +}); + +Then('I should not see the local mobile error message', async function () { + await expect(this.page.locator('div#field-error--mobile > span')).not.toBeVisible(); +}); + +When('I select the local update lookup address or enter the address manually', async function () { + if (await this.page.locator('#field-select--addressSelect').isVisible()) { + await expect(this.page.locator('#field-select--addressSelect')).toBeVisible(); + + const optionToSelect = await this.page + .locator('option', { hasText: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }) + .textContent(); + + await this.page.locator('select#field-select--addressSelect').selectOption({ + label: optionToSelect, + }); + + await expect(this.page.locator('input#field-input--postcode')).toHaveValue('SE1 7TP'); + } else { + await this.page.locator('a[aria-describedby=field-error--addressDetails]').click(); + await this.page.locator('#field-input--address1').fill('COMIC RELIEF'); + await this.page.locator('#field-input--address2').fill('CAMELFORD HOUSE 87-90'); + await this.page.locator('#field-input--address3').fill('ALBERT EMBANKMENT'); + await this.page.locator('#field-input--town').fill('LONDON'); + } +}); diff --git a/playwright-local/tests/step-definitions/update/updateInternationalAddressesValidation.steps.js b/playwright-local/tests/step-definitions/update/updateInternationalAddressesValidation.steps.js new file mode 100644 index 00000000..92c8f98d --- /dev/null +++ b/playwright-local/tests/step-definitions/update/updateInternationalAddressesValidation.steps.js @@ -0,0 +1,24 @@ +const { When } = require('@cucumber/cucumber'); + +When('I enter the local update international address details', async function () { + await this.page.locator('#field-input--address1').fill('219 Beacon St'); + await this.page.locator('#field-input--address2').fill('Winder'); + await this.page.locator('#field-input--address3').fill('Park Ridge'); + await this.page.locator('#field-input--town').fill('GA'); +}); + +When('I select a random local update non-UK country', async function () { + const countryOptions = await this.page.$$eval('select#field-select--country>option', options => + options + .map(option => option.value) + .filter(value => value && value !== 'GB') + ); + + const randomCountryCode = countryOptions[Math.floor(Math.random() * countryOptions.length)]; + + await this.page.locator('select[name="country"]').selectOption({ + value: randomCountryCode, + }); + + await this.page.waitForTimeout(2000); +}); diff --git a/playwright-local/tests/submit/addressValidation.spec.js b/playwright-local/tests/submit/addressValidation.spec.js deleted file mode 100644 index 9779e779..00000000 --- a/playwright-local/tests/submit/addressValidation.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); - -test.describe('Address validation', () => { - - test.beforeEach(async ({ page }) => { - await page.goto('/', { timeout: 30000 }); - - await page.waitForLoadState('domcontentloaded'); - await page.locator('#field-label--giftaid').click(); - await page.locator('#field-input--mobile').fill('07123456789'); - await page.locator('input#field-input--firstname').fill('test'); - await page.locator('input#field-input--lastname').fill('user'); - }); - - test('empty postcode should show error message', async ({ page }) => { - await page.locator('input#field-input--postcode').fill(''); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter your postcode'); - await page.close(); - }); - - test('invalid postcodes should show error messages', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('12SE17TP'); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - await page.locator('input#field-input--postcode').fill('comic relief'); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - await page.locator('input#field-input--postcode').fill('cro 7tp'); - await expect(page.locator('div#field-error--postcode > span')).toHaveText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - await page.close(); - }); - - test('enter postcode but submit without selecting address should show error message', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('SE1 7TP'); - await page.locator('#postcode_button').click(); - await expect(page.locator('#field-select--addressSelect')).toBeVisible(); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div#field-error--addressSelect > span')).toHaveText('Please select your address'); - await page.close(); - }); - - test('clicking on manual address link should show address fields', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('SE1 7TP'); - await expect(page.locator('a[aria-describedby=field-error--addressDetails]')).toBeVisible(); - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await expect(page.locator('#field-input--address1')).toBeVisible(); - await expect(page.locator('#field-input--address2')).toBeVisible(); - await expect(page.locator('#field-input--address3')).toBeVisible(); - await expect(page.locator('#field-input--town')).toBeVisible(); - await expect(page.locator('select#field-select--country')).toBeVisible(); - await page.close(); - }); - - test('validate address fields', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('SE1 7TP'); - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - - // Should see error message for address1 when inout with special characters is entered - await page.locator('#field-input--address1').fill('@£%3dComic Relief'); - await expect(page.locator('#field-error--address1 > span')).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); - await page.locator('#field-input--town').fill(' Comic Relief'); - await expect(page.locator('#field-error--town > span')).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); - - await page.close(); - }); -}); diff --git a/playwright-local/tests/submit/formValidation.spec.js b/playwright-local/tests/submit/formValidation.spec.js deleted file mode 100644 index b2e03ab5..00000000 --- a/playwright-local/tests/submit/formValidation.spec.js +++ /dev/null @@ -1,82 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); -const { Commands } = require('../utils/commands'); - -test.describe('Address validation', () => { - - test.beforeEach(async ({ page }) => { - await page.goto('/', { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - await page.locator('#field-label--giftaid').click(); - }); - - test('Validate mobile number field', async ({ page }) => { - const commands = new Commands(page); - - // Test cases for various mobile number validations - const mobileTestCases = [ - { input: '0712345678', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0712345678900', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0712 345 6789', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0780ab5694245', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - ]; - - for (let testCase of mobileTestCases) { - await page.locator('#field-input--mobile').fill(''); // Clear the field before each test - await page.locator('#field-input--mobile').type(testCase.input, { delay: 100 }); - await expect(page.locator('div#field-error--mobile > span')).toHaveText(testCase.error); - } - - // Validate correct mobile number - await page.locator('#field-input--mobile').fill(''); // Ensure the field is cleared and filled with valid data - await commands.populateFormFields(page, { mobile: '07123456789' }); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div > h1')).toHaveText('Thank you, test!'); - }); - - test('validate first name field', async ({ page }) => { - const commands = new Commands(page); - - // First name with invalid characters - await page.locator('#field-input--firstname').fill('Test^$%£'); - await expect(page.locator('div#field-error--firstname')).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); - - // First name with just a space - await page.locator('#field-input--firstname').fill(' '); - await expect(page.locator('div#field-error--firstname')).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); - - // First name with alphanumeric characters - await page.locator('#field-input--firstname').fill('123Test'); - await expect(page.locator('div#field-error--firstname')).toHaveText('This field only accepts 25 alphabetic characters and \' - starting with alphabetic characters'); - - // Validate correct first name - await page.locator('#field-input--firstname').fill(''); - await commands.populateFormFields(page, { firstName: 'testFirstname' }); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div > h1')).toHaveText('Thank you, testFirstname!'); - }); - - test('validate last name field', async ({ page }) => { - const commands = new Commands(page); - - // Last name with invalid characters - await page.locator('#field-input--lastname').fill('Test^$%£'); - await expect(page.locator('div#field-error--lastname > span')).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); - - // Last name with just a space - await page.locator('#field-input--lastname').fill(' '); - await expect(page.locator('div#field-error--lastname > span')).toHaveText('This field only accepts 25 alphanumeric characters and , . ( ) / & \' - starting with alphanumeric characters'); - - // Last name with alphanumeric characters (valid case) - await page.locator('#field-input--lastname').fill('123Test'); - expect(await page.locator('div#field-error--lastname > span').count()).toEqual(0); - - // Validate correct last name - await page.locator('#field-input--lastname').fill(''); - await commands.populateFormFields(page); - await page.locator('button[type=submit]').click(); - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - await page.close(); - }); -}); diff --git a/playwright-local/tests/submit/internationalAddressesValidation.spec.js b/playwright-local/tests/submit/internationalAddressesValidation.spec.js deleted file mode 100644 index ea20a39f..00000000 --- a/playwright-local/tests/submit/internationalAddressesValidation.spec.js +++ /dev/null @@ -1,49 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); -const { Commands } = require('../utils/commands'); - -test.describe('International addresses validation', () => { - test('selecting a non-UK country and entering a non-UK postcode should submit the form', async ({ page }) => { - - const commands = new Commands(page); - - await page.goto('/', { timeout: 30000 }); - - await page.waitForLoadState('domcontentloaded'); - - await page.waitForLoadState('domcontentloaded'); - - // Click to activate the form and fill in default values - await page.click('#field-label--giftaid'); - await page.fill('#field-input--mobile', '07123456789'); - await page.fill('input#field-input--firstname', 'test'); - await page.fill('input#field-input--lastname', 'user'); - await page.fill('input#field-input--postcode', '30916-395'); // Non-UK postcode - - // Verify error message for UK postcode requirement - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - // Fill in address details - await page.click('a[aria-describedby=field-error--addressDetails]'); - await page.fill('#field-input--address1', '219 Beacon St'); - await page.fill('#field-input--address2', 'Winder'); - await page.fill('input#field-input--town', 'GA'); - - // Select a random non-UK country - const countries = await page.$$eval('select#field-select--country > option', options => options.map(option => option.value)); - const randomCountryCode = countries[Math.floor(Math.random() * countries.length)]; - await page.selectOption('select[name="country"]', { value: randomCountryCode }); - - // Verify that postcode error is resolved after country change - await expect(page.locator('div#field-error--postcode > span')).not.toBeVisible(); - - // Submit the form and ensure no errors are shown for international address - await commands.selectMarketingPrefs(page); // Assuming this handles checkbox interactions - await page.click('button[type=submit]'); - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - await page.close(); - - await page.close(); - }); -}); diff --git a/playwright-local/tests/submit/marketingPreferencesValidation.spec.js b/playwright-local/tests/submit/marketingPreferencesValidation.spec.js deleted file mode 100644 index 4240b3da..00000000 --- a/playwright-local/tests/submit/marketingPreferencesValidation.spec.js +++ /dev/null @@ -1,78 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); -const { Commands } = require('../utils/commands'); - -const Chance = require('chance'); -const chance = new Chance(); - -const email = `giftaid-staging-${Date.now().toString()}@email.sls.comicrelief.com`; -const phone = chance.phone({ country: 'uk', mobile: true }).replace(/\s/g, ''); - -test.describe('Marketing preferences validation', () => { - - test.beforeEach(async ({ page }) => { - - const commands = new Commands(page); - await page.goto('/', { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - await page.click('#field-label--giftaid'); - await commands.populateFormFields(page); - }); - - test('clicking and unclicking marketing prefs options should submit the giftaid form', async ({ page }) => { - // Interact with marketing preferences - const marketingOptions = ['[aria-label="field-label--Email--Email"]', '[aria-label="field-label--Phone--Phone"]', '[aria-label="field-label--Text--SMS"]']; - for (const option of marketingOptions) { - await page.click(option); - expect(await page.locator(option).isChecked()).toBeTruthy(); - } - - // Enter email and phone to validate the form can still submit - await expect(page.locator('input#field-input--email')).toBeVisible(); - await page.fill('input#field-input--email', email); - await expect(page.locator('input#field-input--phone')).toBeVisible(); - await page.fill('input#field-input--phone', phone); - - // Submit the form - await page.click('button[type=submit]'); - await expect(page.locator('div > h1')).toHaveText('Thank you, test!'); - }); - - test('Validate email marketing preference field', async ({ page }) => { - await page.click('[aria-label="field-label--Email--Email"]'); - await page.fill('input#field-input--email', email); - - // Clear and check for error - await page.fill('input#field-input--email', ''); - await expect(page.locator('#field-error--email')).toHaveText('Please fill in your email address'); - - // Input invalid email and check for error - await page.fill('input#field-input--email', 'example@£$^&email.com'); - await expect(page.locator('#field-error--email')).toHaveText('Please fill in a valid email address'); - - // Re-enter valid email and submit - await page.fill('input#field-input--email', email); - await page.click('button[type=submit]'); - await expect(page.locator('div > h1')).toHaveText('Thank you, test!'); - }); - - test('Validate phone marketing preference field', async ({ page }) => { - await page.click('[aria-label="field-label--Phone--Phone"]'); - await page.fill('input#field-input--phone', phone); - - // Clear and check for error - await page.fill('input#field-input--phone', ''); - await expect(page.locator('div#field-error--phone > span')).toHaveText('Please fill in your phone number'); - - // Input invalid phone number and check for error - await page.fill('input#field-input--phone', '0208569424'); - await expect(page.locator('div#field-error--phone > span')).toHaveText('Please fill in a valid UK phone number, with no spaces'); - - // Re-enter valid phone number and submit - await page.fill('input#field-input--phone', phone); - await page.click('button[type=submit]'); - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - await page.close(); - }); -}); diff --git a/playwright-local/tests/submit/postcodeLookup.spec.js b/playwright-local/tests/submit/postcodeLookup.spec.js deleted file mode 100644 index 63959b33..00000000 --- a/playwright-local/tests/submit/postcodeLookup.spec.js +++ /dev/null @@ -1,50 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); - -test.describe('Postcode validation', () => { - - test.beforeEach(async ({ page }) => { - await page.goto('/', { timeout: 30000 }); - - await page.waitForLoadState('domcontentloaded'); - await page.click('#field-label--giftaid'); - await page.fill('#field-input--mobile', '07123456789'); - await page.fill('input#field-input--firstname', 'test'); - await page.fill('input#field-input--lastname', 'user'); - }); - - test('Postcode formatting errors', async ({ page }) => { - const postcodes = [ - { code: 'S E 1 7 T P', message: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' }, - { code: 'SE$%TP', message: 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' } - ]; - - for (const { code, message } of postcodes) { - await page.fill('input#field-input--postcode', code); - await expect(page.locator('div#field-error--postcode > span')).toBeVisible(); - await expect(page.locator('div#field-error--postcode > span')).toContainText(message); - } - await page.close(); - }); - - test('enter valid UK postcode using postcode lookup should be able to submit the form', async ({ page }) => { - await page.fill('input#field-input--postcode', 'SE1 7TP'); - await page.click('#postcode_button'); - - if (await page.isVisible('#field-select--addressSelect')) { - await page.selectOption('select#field-select--addressSelect', { label: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }); - await expect(page.locator('input#field-input--postcode')).toHaveValue('SE1 7TP'); - } else { - await page.click('a[aria-describedby=field-error--addressDetails]'); - await page.fill('#field-input--address1', 'COMIC RELIEF'); - await page.fill('#field-input--address2', 'CAMELFORD HOUSE 87-90'); - await page.fill('#field-input--address3', 'ALBERT EMBANKMENT'); - await page.fill('#field-input--town', 'LONDON'); - } - - await page.click('button[type=submit]'); - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + 'test!'); - - await page.close(); - }); -}); diff --git a/playwright-local/tests/submit/validFormSubmission.spec.js b/playwright-local/tests/submit/validFormSubmission.spec.js deleted file mode 100644 index 59c675dc..00000000 --- a/playwright-local/tests/submit/validFormSubmission.spec.js +++ /dev/null @@ -1,32 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); -const { Commands } = require('../utils/commands'); - -test('Valid giftaid submission', async ({ page }) => { - - const commands = new Commands(page); - - await page.goto('/', { timeout: 30000 }); - await page.waitForLoadState('domcontentloaded'); - - // Click the Giftaid checkbox - await page.click('#field-label--giftaid'); - - // Populate all the form fields with valid inputs - await commands.populateFormFields(page); - - // Select marketing preferences as required - await commands.selectMarketingPrefs(page); - - // Submit the form and wait for the navigation to ensure the submission goes through - await Promise.all([ - page.waitForNavigation(), // This ensures that the navigation happens before the check - page.click('button[type=submit]') - ]); - - // Check for the thank you message to confirm successful submission - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - - await page.close(); -}); diff --git a/playwright-local/tests/support/hooks.js b/playwright-local/tests/support/hooks.js new file mode 100644 index 00000000..2668dabb --- /dev/null +++ b/playwright-local/tests/support/hooks.js @@ -0,0 +1,40 @@ +require('dotenv').config(); + +const { Before, After, setDefaultTimeout } = require('@cucumber/cucumber'); +const { chromium } = require('@playwright/test'); +const { Commands } = require('../utils/commands'); + +setDefaultTimeout(300 * 1000); + +// Runs before each scenario +Before(async function () { + this.browser = await chromium.launch({ + channel: 'chrome', + headless: process.env.HEADED !== 'true', + }); + + this.context = await this.browser.newContext({ + viewport: { + width: 1300, + height: 1000, + }, + serviceWorkers: 'block', // Avoids caching issues + }); + + this.page = await this.context.newPage(); + this.commands = new Commands(this.page); +}); + +After(async function () { + if (this.page) { + await this.page.close(); + } + // Close context and browser + if (this.context) { + await this.context.close(); + } + + if (this.browser) { + await this.browser.close(); + } +}); diff --git a/playwright-local/tests/support/world.js b/playwright-local/tests/support/world.js new file mode 100644 index 00000000..bc162f1f --- /dev/null +++ b/playwright-local/tests/support/world.js @@ -0,0 +1,14 @@ +// This defines shared context for each scenario +// Values stored here (browser, page, commands) are accessible across all step definitions via "this" +const { setWorldConstructor } = require('@cucumber/cucumber'); + +class CustomWorld { + constructor() { + this.browser = null; + this.context = null; + this.page = null; + this.commands = null; + } +} + +setWorldConstructor(CustomWorld); diff --git a/playwright-local/tests/update/formValidation.spec.js b/playwright-local/tests/update/formValidation.spec.js deleted file mode 100644 index 7fee95a5..00000000 --- a/playwright-local/tests/update/formValidation.spec.js +++ /dev/null @@ -1,313 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); -const { Commands } = require('../utils/commands'); -const Chance = require('chance'); -const chance = new Chance(); - -const email = `giftaid-staging-${Date.now().toString()}@email.sls.comicrelief.com`; - -test.describe('Giftaid update form validation', () => { - - test.beforeEach(async ({ page }) => { - await page.goto('/update', { timeout: 30000 }); - - await page.waitForLoadState('domcontentloaded'); - }); - - test('empty input fields should show error messages', async ({ page }) => { - - // submit the form - await page.locator('button[type=submit]').click(); - - await expect(page.locator('div#field-error--firstname > span')).toContainText('Please fill in your first name'); - await expect(page.locator('div#field-error--lastname > span')).toContainText('Please fill in your last name'); - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter your postcode'); - await expect(page.locator('div#field-error--addressDetails > span')).toContainText('Please fill in your address'); - - // click on manual address link to show address fields error messages - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await expect(page.locator('div#field-error--address1 > span')).toContainText('Please fill in your address line 1'); - await expect(page.locator('div#field-error--town > span')).toContainText('Please fill in your town/city'); - - // giftaid declaration error message - await expect(page.locator('div#field-error--giftAidClaimChoice > span')).toContainText('This field is required'); - - await page.close(); - }); - - - test('validate first name field on giftaid update form', async ({ page }) => { - - const commands = new Commands(page); - - await page.locator('#field-input--firstname').fill('test'); - await page.locator('#field-input--firstname').fill(''); - await expect(page.locator('#field-error--firstname')).toContainText('Please fill in your first name'); - - // enter firstname field with special chars should show error message - await page.locator('#field-input--firstname').type('Test^$%£'); - await expect(page.locator('#field-error--firstname')).toContainText('This field only accepts alphabetic characters and \' -\n'); - - // firstname with just a space should show error message - await page.keyboard.press('Backspace'); - await page.locator('#field-input--firstname').type(' '); - await expect(page.locator('#field-error--firstname')).toContainText('This field only accepts alphabetic characters and \' -\n'); - - // firstname with a mixture of alphanumeric chars should show error message - await page.locator('#field-input--firstname').fill(''); // clear the first-name field - await page.locator('#field-input--firstname').type('123Test'); - await expect(page.locator('#field-error--firstname')).toContainText('This field only accepts alphabetic characters and \' -\n'); - - // clear the first name field - await page.locator('#field-input--firstname').fill(''); - - // entering valid input fields should be able to submit the form - await commands.populateUpdateFormFields(page); - - // select giftaid declaration - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - // submit the form - await page.locator('button[type=submit]').click(); - - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - - await page.close(); - }); - - test('validate last name field on giftaid update form', async ({ page }) => { - - const commands = new Commands(page); - - await page.locator('#field-input--lastname').fill('test lastname'); - await page.locator('#field-input--lastname').fill(''); - await expect(page.locator('div#field-error--lastname > span')).toContainText('Please fill in your last name'); - - // enter lastname field with special chars should show error message - await page.locator('#field-input--lastname').type('Test^$%£'); - await expect(page.locator('div#field-error--lastname > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' -'); - - // lastname with just a space should show error message - await page.keyboard.press('Backspace'); - await page.locator('#field-input--lastname').type(' '); - await expect(page.locator('div#field-error--lastname > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' -'); - - // lastname with a mixture of alphanumeric chars should not show error message - await page.locator('#field-input--lastname').fill(''); // clear the last-name field - await page.locator('#field-input--lastname').type('123Test'); - // should not show error message - expect(await page.locator('div#field-error--lastname > span').count()).toEqual(0); - - // clear the last name field - await page.locator('#field-input--lastname').fill(''); - - // entering valid input fields should be able to submit the form - await commands.populateUpdateFormFields(page); - - // select giftaid declaration - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - // submit the form - await page.locator('button[type=submit]').click(); - - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - - await page.close(); - - }); - - test('validate email field on giftaid update form', async ({ page }) => { - - const commands = new Commands(page); - - // email validation - // email that has $ after the domian name should show error message - await page.locator('input#field-input--email').fill('test@comic$relief.com'); - await expect(page.locator('div#field-error--email > span')).toContainText('Please fill in a valid email address'); - - // email that has @ after the domian name should show error message - await page.locator('input#field-input--email').fill(''); // clear the email field - await page.locator('input#field-input--email').type('test@c{(micrelief.com'); - await expect(page.locator('div#field-error--email > span')).toContainText('Please fill in a valid email address'); - - // email that has % after the domian name should show error message - await page.locator('input#field-input--email').fill(''); - await page.locator('input#field-input--email').type('test@comic%relief.com'); - await expect(page.locator('div#field-error--email > span')).toContainText('Please fill in a valid email address'); - - // email that has special chars $%^ before domain name should not show error message - await page.locator('input#field-input--email').fill(''); - await page.locator('input#field-input--email').type('te$%^st@comicrelief.com'); - await expect(page.locator('div#field-error--email > span')).not.toBeVisible(); - - // email that has mix of special chars that's valid and not valid should show error message - await page.locator('input#field-input--email').fill(''); - await page.locator('input#field-input--email').type('Test0-9!#$%&\'*+/=?^_{|}~-@comicrelief_9-8.com.uk'); - await expect(page.locator('div#field-error--email > span')).toContainText('Please fill in a valid email address'); - - // clear the email field - await page.locator('input#field-input--email').fill(''); - - // entering valid input fields should be able to submit the form - await commands.populateUpdateFormFields(page); - - // select giftaid declaration - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - // submit the form - await page.locator('button[type=submit]').click(); - - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - - await page.close(); - }); - - test('Validate mobile number field', async ({ page }) => { - const commands = new Commands(page); - // List of allowed prefixes for UK mobile numbers - const prefixes = ['071', '073', '074', '075', '077', '078', '079']; - // Randomly select one prefix from the list - const prefix = chance.pickone(prefixes); - // Generate the remaining 8 digits randomly - const mobile = `${prefix}${chance.string({ pool: '0123456789', length: 8 })}`; - console.log('mobile number generated', mobile); - - // Test cases for various mobile number validations - const mobileTestCases = [ - { input: '0722345678', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0722345678900', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0722 345 6789', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '0780ab5694245', error: 'Please enter a valid mobile phone number - it must be the same number associated with your donation.' }, - { input: '07123456789', valid: true }, - { input: '07340707252', valid: true }, - ]; - - for (let testCase of mobileTestCases) { - await page.locator('#field-input--mobile').fill(''); // Clear the field before each test - await page.locator('#field-input--mobile').type(testCase.input, { delay: 100 }); - if (testCase.valid) { - await expect(page.locator('div#field-error--mobile > span')).not.toBeVisible(); - } else { - await expect(page.locator('div#field-error--mobile > span')).toHaveText(testCase.error); - } - } - - // Validate correct mobile number - await page.locator('#field-input--mobile').fill(''); // Ensure the field is cleared before filling with valid data - - await commands.populateUpdateFormFields(page, { mobile: mobile }); - - // Select yes for giftaid declaration to complete the form - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - await page.locator('button[type=submit]').click(); - await expect(page.locator('div > h1')).toHaveText('Thank you, test!'); - }); - - test('postcode entered with extra spaces should show error message', async ({ page }) => { - - await page.locator('input#field-input--postcode').type('S E 1 7 T P'); - await expect(page.locator('div#field-error--postcode > span')).toBeVisible(); - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - await page.close(); - }); - - test('compact lowercase and no-space UK postcodes do not show format error (aligned with data-models / postcode)', async ({ page }) => { - await page.locator('input#field-input--postcode').fill('se17tp'); - await expect(page.locator('div#field-error--postcode > span')).not.toBeVisible(); - await page.locator('input#field-input--postcode').fill('SE17TP'); - await expect(page.locator('div#field-error--postcode > span')).not.toBeVisible(); - await page.close(); - }); - - test('postcode entered with special characters should show error message', async ({ page }) => { - - await page.locator('input#field-input--postcode').type('SE$%TP'); - await expect(page.locator('div#field-error--postcode > span')).toBeVisible(); - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - await page.close(); - }); - - test('postcode with incorrect format like "cro 7tp" should show error message', async ({ page }) => { - - await page.locator('input#field-input--postcode').type('cro 7tp'); - await expect(page.locator('div#field-error--postcode > span')).toBeVisible(); - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - await page.close(); - }); - - test('enter valid UK postcode on giftaid update form using postcode lookup should be able to submit the form', async ({ page }) => { - - // fill in all input fields - await page.locator('#field-input--firstname').fill('test'); - await page.locator('#field-input--lastname').fill('test lastname'); - await page.locator('input#field-input--email').fill('giftaid-staging-@email.sls.comicrelief.com'); - - // enter postcode - await page.locator('input#field-input--postcode').fill('SE1 7TP'); - // click on postcode lookup button - await page.locator('#postcode_button').click(); - - if (await page.locator('#field-select--addressSelect').isVisible()) { - console.log('postcode lookup address dropdown present select the address'); - - await expect(page.locator('#field-select--addressSelect')).toBeVisible(); - - await page.waitForSelector('select#field-select--addressSelect'); - - const optionToSelect = await page.locator('option', { hasText: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }).textContent(); - console.log('selected option: ', optionToSelect); - - // Use option text to select - await page.locator('select#field-select--addressSelect').selectOption({ label: optionToSelect }); - - // expect pre-enetered se17tp postcode to change to SE1 7TP when address is selected by removing the extra spaces - await expect(page.locator('input#field-input--postcode')).toHaveValue('SE1 7TP'); - - const addressLine1 = await page.evaluate(() => document.querySelector('#field-input--address1').getAttribute('value')); - console.log('Address line 1 field value is : ', addressLine1); - - const addressLine2 = await page.evaluate(() => document.querySelector('#field-input--address2').getAttribute('value')); - console.log('Address line 1 field value is : ', addressLine2); - - const addressLine3 = await page.evaluate(() => document.querySelector('#field-input--address3').getAttribute('value')); - console.log('Address line 1 field value is : ', addressLine3); - - const town = await page.evaluate(() => document.querySelector('input#field-input--town').getAttribute('value')); - console.log('Address line 1 field value is : ', town); - - // select giftaid declaration - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - // clicking on submit button should show error on address lookup - await page.locator('button[type=submit]').click(); - - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - } else { - - // click on manual address link - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await page.locator('#field-input--address1').type('COMIC RELIEF'); - await page.locator('#field-input--address2').type('CAMELFORD HOUSE 87-90'); - await page.locator('#field-input--address3').type('ALBERT EMBANKMENT'); - await page.locator('#field-input--town').type('LONDON'); - - // select giftaid declaration - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - // clicking on submit button should show error on address lookup - await page.locator('button[type=submit]').click(); - - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - } - await page.close(); - }); -}); diff --git a/playwright-local/tests/update/internationalAddressesValidation.spec.js b/playwright-local/tests/update/internationalAddressesValidation.spec.js deleted file mode 100644 index 1d4dd934..00000000 --- a/playwright-local/tests/update/internationalAddressesValidation.spec.js +++ /dev/null @@ -1,52 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); -const { v4: uuidv4 } = require('uuid'); - -test.describe('International addresses validation on update form', () => { - test('selecting a non-UK country and entering a non-UK postcode should submit the update form', async ({ page }) => { - - await page.goto('/update', { timeout: 30000 }); - - await page.waitForLoadState('domcontentloaded'); - - /// fill in all input fields - await page.locator('#field-input--firstname').fill('test'); - await page.locator('#field-input--lastname').fill('test lastname'); - await page.locator('input#field-input--email').fill('giftaid-staging-@email.sls.comicrelief.com'); - - // enter a non-UK postcode and attempt to validate it - await page.locator('input#field-input--postcode').fill('30916-395'); - await expect(page.locator('div#field-error--postcode > span')).toContainText('Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.'); - - // manually enter international address details - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await page.locator('#field-input--address1').fill('219 Beacon St'); - await page.locator('#field-input--address2').fill('Winder'); - await page.locator('#field-input--address3').fill('Park Ridge'); - await page.locator('#field-input--town').fill('GA'); - - // Select a random country from the dropdown (excluding UK to simulate international address) - const countryOptions = await page.$$eval('select#field-select--country>option', options => - options.map(option => option.value).filter(value => value !== 'GB') - ); - const randomCountryCode = countryOptions[Math.floor(Math.random() * countryOptions.length)]; - await page.locator('select[name="country"]').selectOption({ value: randomCountryCode }); - - // Wait for the form to adjust to the selected country - await page.waitForTimeout(2000); - - // When an international country is selected, the postcode error for UK format should not show anymore - await expect(page.locator('div#field-error--postcode > span')).not.toBeVisible(); - - // Select yes for giftaid declaration to complete the form - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - // Submitting the form with valid international details - await page.locator('button[type=submit]').click(); - - // Thank you message on success page - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - await page.close(); - }); -}); diff --git a/playwright-local/tests/update/validFormSubmission.spec.js b/playwright-local/tests/update/validFormSubmission.spec.js deleted file mode 100644 index ad4b59cd..00000000 --- a/playwright-local/tests/update/validFormSubmission.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); -const { Commands } = require('../utils/commands'); - -test('Valid Giftaid Update submission', async ({ page }) => { - - const commands = new Commands(page); - - await page.goto('/update', { timeout: 30000 }); - - await page.waitForLoadState('domcontentloaded'); - - // Populate all input fields with valid data - await commands.populateUpdateFormFields(page); - - // Select 'Yes' for GiftAid declaration - await page.locator('#giftAidClaimChoice>div:nth-child(2)>label').click(); - - // Submit the form and validate the thank you message - await page.locator('button[type=submit]').click(); - await expect(page.locator('div > h1')).toContainText('Thank you,\n' + - 'test!'); - - await page.close(); -}); diff --git a/playwright-staging/tests/features/submit/addressValidation.feature b/playwright-staging/tests/features/submit/addressValidation.feature index cacd5a43..d4c10755 100644 --- a/playwright-staging/tests/features/submit/addressValidation.feature +++ b/playwright-staging/tests/features/submit/addressValidation.feature @@ -3,41 +3,41 @@ Feature: Address validation Background: Given I am on the Giftaid page - And I select Giftaid - And I enter supporter details + And I select the Giftaid option + And I enter the supporter details - Scenario: Empty postcode should show error message + Scenario: Empty postcode should show an error message When I clear the postcode field And I submit the Giftaid form - Then I should see postcode error message "Please enter your postcode" + Then I should see the postcode error message "Please enter your postcode" Scenario Outline: Invalid postcodes should show error messages - When I enter postcode "" - Then I should see postcode error message "" + When I enter the postcode "" + Then I should see the postcode error message "" Examples: - | postcode | message | + | postcode | message | | 12SE17TP | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | | comic relief | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | | cro 7tp | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | - Scenario: Enter postcode but submit without selecting address should show error message - When I enter postcode "SE1 7TP" + Scenario: Entering a postcode without selecting an address should show an error message + When I enter the postcode "SE1 7TP" And I search for the postcode Then I should see the address dropdown When I submit the Giftaid form - Then I should see address select error message "Please select your address" + Then I should see the address select error message "Please select your address" - Scenario: Clicking on manual address link should show address fields - When I enter postcode "SE1 7TP" + Scenario: Clicking the manual address link should show the address fields + When I enter the postcode "SE1 7TP" Then I should see the manual address link When I click the manual address link Then I should see the manual address fields Scenario: Invalid address fields should show error messages - When I enter postcode "SE1 7TP" + When I enter the postcode "SE1 7TP" And I click the manual address link - And I enter invalid address line 1 - Then I should see address line 1 error message - When I enter invalid town - Then I should see town error message + And I enter an invalid address line 1 + Then I should see the address line 1 error message + When I enter an invalid town + Then I should see the town error message diff --git a/playwright-staging/tests/features/submit/formValidation.feature b/playwright-staging/tests/features/submit/formValidation.feature index f55c37ba..f8e48dc5 100644 --- a/playwright-staging/tests/features/submit/formValidation.feature +++ b/playwright-staging/tests/features/submit/formValidation.feature @@ -3,53 +3,53 @@ Feature: Giftaid form validation Background: Given I am on the Giftaid page - And I select Giftaid + And I select the Giftaid option - Scenario Outline: Invalid mobile numbers should show error message - When I enter mobile number "" - Then I should see mobile error message "" + Scenario Outline: Invalid mobile numbers should show an error message + When I enter the mobile number "" + Then I should see the mobile error message "" Examples: - | mobile | message | + | mobile | message | | 0712345678 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | | 0712345678900 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | | 0712 345 6789 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | | 0780ab5694245 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | - Scenario: Valid mobile number should submit the form - When I complete the Giftaid form with mobile number "07123456789" + Scenario: A valid mobile number should submit the form + When I complete the Giftaid form with the mobile number "07123456789" And I submit the Giftaid form Then I should see the Giftaid thank you message - Scenario Outline: Invalid first name values should show error message - When I enter first name "" - Then I should see first name error message "" + Scenario Outline: Invalid first name values should show an error message + When I enter the first name "" + Then I should see the first name error message "" Examples: - | firstName | message | - | Test^$%£ | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | - | SPACE | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | - | 123Test | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | + | firstName | message | + | Test^$%£ | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | + | SPACE | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | + | 123Test | This field only accepts 25 alphabetic characters and ' - starting with alphabetic characters | - Scenario: Valid first name should submit the form - When I complete the Giftaid form with first name "testFirstname" + Scenario: A valid first name should submit the form + When I complete the Giftaid form with the first name "testFirstname" And I submit the Giftaid form - Then I should see thank you message for "testFirstname" + Then I should see the thank you message for "testFirstname" - Scenario Outline: Invalid last name values should show error message - When I enter last name "" - Then I should see last name error message "" + Scenario Outline: Invalid last name values should show an error message + When I enter the last name "" + Then I should see the last name error message "" Examples: - | lastName | message | - | Test^$%£ | This field only accepts 25 alphanumeric characters and , . ( ) / & ' - starting with alphanumeric characters | - | SPACE | This field only accepts 25 alphanumeric characters and , . ( ) / & ' - starting with alphanumeric characters | + | lastName | message | + | Test^$%£ | This field only accepts 25 alphanumeric characters and , . ( ) / & ' - starting with alphanumeric characters | + | SPACE | This field only accepts 25 alphanumeric characters and , . ( ) / & ' - starting with alphanumeric characters | - Scenario: Alphanumeric last name should not show error message - When I enter last name "123Test" - Then I should not see last name error message + Scenario: An alphanumeric last name should not show an error message + When I enter the last name "123Test" + Then I should not see the last name error message - Scenario: Valid last name should submit the form + Scenario: A valid last name should submit the form When I complete the Giftaid form with valid details And I submit the Giftaid form Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/submit/internationalAddressesValidation.feature b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature index a54ab7b4..cf620bb3 100644 --- a/playwright-staging/tests/features/submit/internationalAddressesValidation.feature +++ b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature @@ -3,13 +3,13 @@ Feature: International address validation Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the form Given I am on the Giftaid page - And I select Giftaid - And I enter supporter details + And I select the Giftaid option + And I enter the supporter details When I enter a non UK postcode - Then I should see postcode validation error for UK format - When I enter international address details manually + Then I should see the postcode validation error for UK format + When I enter the international address details manually And I select a non UK country - Then postcode error should disappear - When I select marketing preferences + Then the postcode error should disappear + When I select the marketing preferences And I submit the Giftaid form Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/submit/marketingPreferencesData.feature b/playwright-staging/tests/features/submit/marketingPreferencesData.feature index ed108732..2f74c40a 100644 --- a/playwright-staging/tests/features/submit/marketingPreferencesData.feature +++ b/playwright-staging/tests/features/submit/marketingPreferencesData.feature @@ -3,9 +3,9 @@ Feature: Giftaid marketing preferences contact-store verification Scenario: Verify giftaid marketing preferences data in contact-store Given I am on the Giftaid page - And I select Giftaid - When I populate the Giftaid form with generated supporter details - And I select generated marketing preferences + And I select the Giftaid option + When I populate the Giftaid form with the generated supporter details + And I select the marketing preferences And I submit the Giftaid form - Then I should see the generated supporter thank you message - And the marketing preferences data should be stored in contact-store + Then I should see the supporter thank you message + And the marketing preferences data should be stored in the contact-store diff --git a/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature b/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature index 76a08b21..f98da6d4 100644 --- a/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature +++ b/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature @@ -3,33 +3,33 @@ Feature: Marketing preferences validation Background: Given I am on the Giftaid page - And I select Giftaid + And I select the Giftaid option And I complete the Giftaid form with valid details Scenario: Clicking marketing preference options should submit the Giftaid form - When I select all marketing preference options - And I enter valid marketing preference contact details + When I select all the marketing preference options + And I enter the valid marketing preference contact details And I submit the Giftaid form Then I should see the Giftaid thank you message Scenario: Email marketing preference field validation - When I select email marketing preference - And I enter valid marketing preference email - And I clear marketing preference email - Then I should see marketing preference email error "Please fill in your email address" - When I enter invalid marketing preference email "example@£$^&email.com" - Then I should see marketing preference email error "Please fill in a valid email address" - When I enter valid marketing preference email + When I select the email marketing preference + And I enter a valid marketing preference email + And I clear the marketing preference email + Then I should see the marketing preference email error "Please fill in your email address" + When I enter an invalid marketing preference email "example@£$^&email.com" + Then I should see the marketing preference email error "Please fill in a valid email address" + When I enter a valid marketing preference email And I submit the Giftaid form Then I should see the Giftaid thank you message Scenario: Phone marketing preference field validation - When I select phone marketing preference - And I enter valid marketing preference phone - And I clear marketing preference phone - Then I should see marketing preference phone error "Please fill in your phone number" - When I enter invalid marketing preference phone "0208569424" - Then I should see marketing preference phone error "Please fill in a valid UK phone number, with no spaces" - When I enter valid marketing preference phone + When I select the phone marketing preference + And I enter a valid marketing preference phone + And I clear the marketing preference phone + Then I should see the marketing preference phone error "Please fill in your phone number" + When I enter an invalid marketing preference phone "0208569424" + Then I should see the marketing preference phone error "Please fill in a valid UK phone number, with no spaces" + When I enter a valid marketing preference phone And I submit the Giftaid form Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/submit/postcodeLookup.feature b/playwright-staging/tests/features/submit/postcodeLookup.feature index fee3d6bf..ffb7b8d9 100644 --- a/playwright-staging/tests/features/submit/postcodeLookup.feature +++ b/playwright-staging/tests/features/submit/postcodeLookup.feature @@ -3,12 +3,12 @@ Feature: Postcode validation Background: Given I am on the Giftaid page - And I select Giftaid - And I enter supporter details + And I select the Giftaid option + And I enter the supporter details Scenario Outline: Invalid postcode formatting should show error message - When I enter postcode "" - Then I should see postcode error message "" + When I enter the postcode "" + Then I should see the postcode error message "" Examples: | postcode | message | @@ -16,8 +16,8 @@ Feature: Postcode validation | SE$%TP | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | Scenario: Valid UK postcode using postcode lookup should submit the form - When I enter postcode "SE1 7TP" + When I enter the postcode "SE1 7TP" And I search for the postcode - And I select address from lookup or enter address manually + And I select the address from lookup or enter address manually And I submit the Giftaid form Then I should see the Giftaid thank you message with line break diff --git a/playwright-staging/tests/features/submit/validFormSubmission.feature b/playwright-staging/tests/features/submit/validFormSubmission.feature index 75d2a36a..413c0906 100644 --- a/playwright-staging/tests/features/submit/validFormSubmission.feature +++ b/playwright-staging/tests/features/submit/validFormSubmission.feature @@ -3,9 +3,9 @@ Feature: Giftaid submission Scenario: Submit Giftaid form with valid details Given I am on the Giftaid page - When I select Giftaid + When I select the Giftaid option And I complete the Giftaid form with valid details - And I select marketing preferences + And I select the marketing preferences And I submit the Giftaid form Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/update/formValidation.feature b/playwright-staging/tests/features/update/formValidation.feature index ef9dbc55..8e67fbbd 100644 --- a/playwright-staging/tests/features/update/formValidation.feature +++ b/playwright-staging/tests/features/update/formValidation.feature @@ -6,11 +6,11 @@ Feature: Giftaid update form validation Scenario: Empty input fields should show error messages When I submit the Giftaid update form - Then I should see required update form error messages + Then I should see the required update form error messages Scenario Outline: Invalid first name values should show error message on update form - When I enter update first name "" - Then I should see update first name error message "" + When I enter the update first name "" + Then I should see the update first name error message "" Examples: | firstName | message | @@ -25,8 +25,8 @@ Feature: Giftaid update form validation Then I should see update thank you message for "John" Scenario Outline: Invalid email values should show error message on update form - When I enter update email "" - Then I should see update email error message "" + When I enter the update email "" + Then I should see the update email error message "" Examples: | email | message | @@ -36,14 +36,14 @@ Feature: Giftaid update form validation | Test0-9!#$%&'*+/=?^_{\|}~-@comicrelief_9-8.com.uk | Please fill in a valid email address | Scenario: Valid email should submit update form with no declaration - When I complete the Giftaid update form with generated email + When I complete the Giftaid update form with the email And I select no for GiftAid declaration And I submit the Giftaid update form Then I should see update no declaration message Scenario Outline: Invalid mobile numbers should show error message on update form - When I enter update mobile number "" - Then I should see update mobile error message "" + When I enter the update mobile number "" + Then I should see the update mobile error message "" Examples: | mobile | message | @@ -53,8 +53,8 @@ Feature: Giftaid update form validation | 0780ab5694245 | Please enter a valid mobile phone number - it must be the same number associated with your donation. | Scenario Outline: Valid mobile numbers should not show error message on update form - When I enter update mobile number "" - Then I should not see update mobile error message + When I enter the update mobile number "" + Then I should not see the update mobile error message Examples: | mobile | @@ -62,7 +62,7 @@ Feature: Giftaid update form validation | 07340707252 | Scenario: Valid mobile number should submit update form - When I complete the Giftaid update form with generated mobile and last name "test" + When I complete the Giftaid update form with the mobile and last name "test" And I select yes for GiftAid declaration And I submit the Giftaid update form Then I should see update thank you message for " test" @@ -80,8 +80,8 @@ Feature: Giftaid update form validation Scenario: Valid postcode should submit update form When I enter update postcode "SE1 7TP" And I search for the update postcode - And I select update address from lookup or enter address manually - And I complete remaining update form fields + And I select the update address from lookup or enter address manually + And I complete the remaining update form fields And I select yes for GiftAid declaration And I submit the Giftaid update form Then I should see update thank you message for " test" diff --git a/playwright-staging/tests/features/update/internationalAddressesValidation.feature b/playwright-staging/tests/features/update/internationalAddressesValidation.feature index 399cace1..3dc60eb4 100644 --- a/playwright-staging/tests/features/update/internationalAddressesValidation.feature +++ b/playwright-staging/tests/features/update/internationalAddressesValidation.feature @@ -3,12 +3,12 @@ Feature: International address validation on update form Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the update form Given I am on the Giftaid update page - And I enter basic update supporter details - When I enter update postcode "30916-395" - Then I should see update postcode error message "Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below." - When I enter update international address details manually + And I enter the update supporter details + When I enter the update postcode "30916-395" + Then I should see the update postcode error message "Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below." + When I enter the update international address details manually And I select a non UK country on the update form - Then update postcode error should disappear + Then the update postcode error should disappear When I select yes for GiftAid declaration And I submit the Giftaid update form - Then I should see update thank you message for "test" + Then I should see the update thank you message for "test" diff --git a/playwright-staging/tests/features/update/validFormSubmission.feature b/playwright-staging/tests/features/update/validFormSubmission.feature index 2eae5ce1..2637302b 100644 --- a/playwright-staging/tests/features/update/validFormSubmission.feature +++ b/playwright-staging/tests/features/update/validFormSubmission.feature @@ -8,4 +8,4 @@ Feature: Valid Giftaid update submission When I complete the Giftaid update form with valid details And I select yes for GiftAid declaration And I submit the Giftaid update form - Then I should see update thank you message + Then I should see the update thank you message diff --git a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js index 9f1b6bfc..e5fc067f 100644 --- a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js +++ b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js @@ -6,7 +6,7 @@ When('I submit the Giftaid form', async function () { await this.page.click(selectors.formFields.submitButton); }); -When('I select marketing preferences', async function () { +When('I select the marketing preferences', async function () { await this.commands.selectMarketingPrefs(this.page); }); diff --git a/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js b/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js index e9c1031d..b76bbbde 100644 --- a/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js @@ -10,7 +10,7 @@ Then('I should see the address dropdown', async function () { await expect(this.page.locator(selectors.address.addressSelect)).toBeVisible(); }); -Then('I should see address select error message {string}', async function (message) { +Then('I should see the address select error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.addressSelect)).toHaveText(message); }); @@ -30,19 +30,19 @@ Then('I should see the manual address fields', async function () { await expect(this.page.locator(selectors.address.country)).toBeVisible(); }); -When('I enter invalid address line 1', async function () { +When('I enter an invalid address line 1', async function () { // Should see error message for address1 when input with special characters is entered await this.page.locator(selectors.address.address1).fill('@£%3dComic Relief'); }); -Then('I should see address line 1 error message', async function () { +Then('I should see the address line 1 error message', async function () { await expect(this.page.locator(selectors.errorMessages.address1)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); }); -When('I enter invalid town', async function () { +When('I enter an invalid town', async function () { await this.page.locator(selectors.address.town).fill(' Comic Relief'); }); -Then('I should see town error message', async function () { +Then('I should see the town error message', async function () { await expect(this.page.locator(selectors.errorMessages.town)).toHaveText("This field only accepts alphanumeric characters and ' . - & _ /"); }); diff --git a/playwright-staging/tests/step-definitions/submit/formValidation.steps.js b/playwright-staging/tests/step-definitions/submit/formValidation.steps.js index 7c664134..f722ddf6 100644 --- a/playwright-staging/tests/step-definitions/submit/formValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/formValidation.steps.js @@ -2,47 +2,47 @@ const { When, Then } = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); const { selectors } = require('../../utils/locators'); -When('I enter mobile number {string}', async function (mobile) { +When('I enter the mobile number {string}', async function (mobile) { await this.page.locator(selectors.formFields.mobile).fill(''); await this.page.locator(selectors.formFields.mobile).type(mobile, { delay: 100 }); }); -Then('I should see mobile error message {string}', async function (message) { +Then('I should see the mobile error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.mobile)).toHaveText(message); }); -When('I complete the Giftaid form with mobile number {string}', async function (mobile) { +When('I complete the Giftaid form with the mobile number {string}', async function (mobile) { await this.page.locator(selectors.formFields.mobile).fill(''); await this.commands.populateFormFields(this.page, { mobile }); }); -When('I enter first name {string}', async function (firstName) { +When('I enter the first name {string}', async function (firstName) { const value = firstName === 'SPACE' ? ' ' : firstName; await this.page.locator(selectors.formFields.firstName).fill(value); }); -Then('I should see first name error message {string}', async function (message) { +Then('I should see the first name error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText(message); }); -When('I complete the Giftaid form with first name {string}', async function (firstName) { +When('I complete the Giftaid form with the first name {string}', async function (firstName) { await this.page.locator(selectors.formFields.firstName).fill(''); await this.commands.populateFormFields(this.page, { firstName }); }); -Then('I should see thank you message for {string}', async function (firstName) { +Then('I should see the thank you message for {string}', async function (firstName) { await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); }); -When('I enter last name {string}', async function (lastName) { +When('I enter the last name {string}', async function (lastName) { const value = lastName === 'SPACE' ? ' ' : lastName; await this.page.locator(selectors.formFields.lastName).fill(value); }); -Then('I should see last name error message {string}', async function (message) { +Then('I should see the last name error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.lastName)).toHaveText(message); }); -Then('I should not see last name error message', async function () { +Then('I should not see the last name error message', async function () { expect(await this.page.locator(selectors.errorMessages.lastName).count()).toEqual(0); }); diff --git a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js index 28d56aad..723fb1ea 100644 --- a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js +++ b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js @@ -7,7 +7,7 @@ Given('I am on the Giftaid page', async function () { await this.page.waitForLoadState('domcontentloaded'); }); -When('I select Giftaid', async function () { +When('I select the Giftaid option', async function () { await this.page.click(selectors.giftaid.option); }); diff --git a/playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js b/playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js index decf1e89..83f790a9 100644 --- a/playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/internationalAddressValidation.steps.js @@ -6,13 +6,13 @@ When('I enter a non UK postcode', async function () { await this.page.fill(selectors.formFields.postcode, '30916-395'); }); -Then('I should see postcode validation error for UK format', async function () { +Then('I should see the postcode validation error for UK format', async function () { await expect(this.page.locator(selectors.errorMessages.postcode)).toContainText( 'Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below.' ); }); -When('I enter international address details manually', async function () { +When('I enter the international address details manually', async function () { await this.page.click(selectors.address.manualAddressLink); await this.page.fill(selectors.address.address1, '219 Beacon St'); await this.page.fill(selectors.address.address2, 'Winder'); @@ -30,6 +30,6 @@ When('I select a non UK country', async function () { await this.page.selectOption(selectors.address.countryByName, { value: randomCountryCode }); }); -Then('postcode error should disappear', async function () { +Then('the postcode error should disappear', async function () { await expect(this.page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); }); diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js index 274befd1..a7989f97 100644 --- a/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js @@ -6,7 +6,7 @@ const { selectors } = require('../../utils/locators'); const chance = new Chance(); -When('I populate the Giftaid form with generated supporter details', async function () { +When('I populate the Giftaid form with the generated supporter details', async function () { this.supporter = { firstName: chance.first(), lastName: chance.last(), @@ -34,7 +34,7 @@ When('I populate the Giftaid form with generated supporter details', async funct }); }); -When('I select generated marketing preferences', async function () { +When('I select the marketing preferences', async function () { // Select marketing preferences using Commands class await this.commands.selectMarketingPrefs(this.page, { email: this.supporter.email, @@ -42,12 +42,12 @@ When('I select generated marketing preferences', async function () { }); }); -Then('I should see the generated supporter thank you message', async function () { +Then('I should see the supporter thank you message', async function () { // Verify success message await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${this.supporter.firstName}!`); }); -Then('the marketing preferences data should be stored in contact-store', async function () { +Then('the marketing preferences data should be stored in the contact-store', async function () { // Retrieve and verify marketing preferences data const mpData = await MarketingPrefsVerify.get(this.supporter.email); diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js index 1d744dae..61cf9645 100644 --- a/playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesValidation.steps.js @@ -8,7 +8,7 @@ const chance = new Chance(); const email = `giftaid-update-staging-${chance.email()}`; const phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, ''); -When('I select all marketing preference options', async function () { +When('I select all the marketing preference options', async function () { const marketingOptions = [ selectors.marketingPreferences.options.email, selectors.marketingPreferences.options.phone, @@ -21,7 +21,7 @@ When('I select all marketing preference options', async function () { } }); -When('I enter valid marketing preference contact details', async function () { +When('I enter the valid marketing preference contact details', async function () { await expect(this.page.locator(selectors.marketingPreferences.fields.email)).toBeVisible(); await this.page.fill(selectors.marketingPreferences.fields.email, email); @@ -29,42 +29,42 @@ When('I enter valid marketing preference contact details', async function () { await this.page.fill(selectors.marketingPreferences.fields.phone, phone); }); -When('I select email marketing preference', async function () { +When('I select the email marketing preference', async function () { await this.page.click(selectors.marketingPreferences.options.email); }); -When('I enter valid marketing preference email', async function () { +When('I enter a valid marketing preference email', async function () { await this.page.fill(selectors.marketingPreferences.fields.email, email); }); -When('I clear marketing preference email', async function () { +When('I clear the marketing preference email', async function () { await this.page.fill(selectors.marketingPreferences.fields.email, ''); }); -When('I enter invalid marketing preference email {string}', async function (invalidEmail) { +When('I enter an invalid marketing preference email {string}', async function (invalidEmail) { await this.page.fill(selectors.marketingPreferences.fields.email, invalidEmail); }); -Then('I should see marketing preference email error {string}', async function (message) { +Then('I should see the marketing preference email error {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.email)).toHaveText(message); }); -When('I select phone marketing preference', async function () { +When('I select the phone marketing preference', async function () { await this.page.click(selectors.marketingPreferences.options.phone); }); -When('I enter valid marketing preference phone', async function () { +When('I enter a valid marketing preference phone', async function () { await this.page.fill(selectors.marketingPreferences.fields.phone, phone); }); -When('I clear marketing preference phone', async function () { +When('I clear the marketing preference phone', async function () { await this.page.fill(selectors.marketingPreferences.fields.phone, ''); }); -When('I enter invalid marketing preference phone {string}', async function (invalidPhone) { +When('I enter an invalid marketing preference phone {string}', async function (invalidPhone) { await this.page.fill(selectors.marketingPreferences.fields.phone, invalidPhone); }); -Then('I should see marketing preference phone error {string}', async function (message) { +Then('I should see the marketing preference phone error {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.phone)).toHaveText(message); }); diff --git a/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js b/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js index 34fd548f..971351e3 100644 --- a/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js @@ -2,17 +2,17 @@ const { Given, When, Then } = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); const { selectors } = require('../../utils/locators'); -Given('I enter supporter details', async function () { +Given('I enter the supporter details', async function () { await this.page.fill(selectors.formFields.mobile, '07123456789'); await this.page.fill(selectors.formFields.firstName, 'test'); await this.page.fill(selectors.formFields.lastName, 'user'); }); -When('I enter postcode {string}', async function (postcode) { +When('I enter the postcode {string}', async function (postcode) { await this.page.fill(selectors.formFields.postcode, postcode); }); -Then('I should see postcode error message {string}', async function (message) { +Then('I should see the postcode error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.postcode)).toBeVisible(); await expect(this.page.locator(selectors.errorMessages.postcode)).toContainText(message); }); @@ -21,7 +21,7 @@ When('I search for the postcode', async function () { await this.page.click(selectors.formFields.postcodeLookup); }); -When('I select address from lookup or enter address manually', async function () { +When('I select the address from lookup or enter address manually', async function () { if (await this.page.isVisible(selectors.address.addressSelect)) { await this.page.selectOption(selectors.address.addressSelect, { label: 'COMIC RELIEF, CAMELFORD HOUSE 87-90' }); await expect(this.page.locator(selectors.formFields.postcode)).toHaveValue('SE1 7TP'); diff --git a/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js b/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js index 82e102fe..b621d445 100644 --- a/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js +++ b/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js @@ -23,24 +23,24 @@ When('I select no for GiftAid declaration', async function () { await this.page.click(selectors.giftAidClaimChoice.no); }); -When('I enter update postcode {string}', async function (postcode) { +When('I enter the update postcode {string}', async function (postcode) { await this.page.fill(selectors.formFields.postcode, ''); await this.page.type(selectors.formFields.postcode, postcode); }); -Then('I should see update postcode error message {string}', async function (message) { +Then('I should see the update postcode error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.postcode)).toBeVisible(); await expect(this.page.locator(selectors.errorMessages.postcode)).toHaveText(message); }); -Then('I should see update thank you message for {string}', async function (firstName) { +Then('I should see the update thank you message for {string}', async function (firstName) { await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); }); -Then('I should see update no declaration message', async function () { +Then('I should see the update no declaration message', async function () { await expect(this.page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); }); -Then('I should see update thank you message', async function () { +Then('I should see the update thank you message', async function () { await expect(this.page.locator(selectors.success.heading)).toContainText('Thank you, test!'); }); diff --git a/playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js b/playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js index 84c3bbe4..1efc89d7 100644 --- a/playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js +++ b/playwright-staging/tests/step-definitions/update/internationalAddressValidation.steps.js @@ -2,7 +2,7 @@ const { Given, When, Then } = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); const { selectors } = require('../../utils/locators'); -Given('I enter basic update supporter details', async function () { +Given('I enter the update supporter details', async function () { // fill in all input fields // await page.locator('input#field-input--transactionId').fill(transactionId); await this.page.locator(selectors.formFields.firstName).fill('test'); @@ -10,7 +10,7 @@ Given('I enter basic update supporter details', async function () { await this.page.locator(selectors.marketingPreferences.fields.email).fill('giftaid-staging-@email.sls.comicrelief.com'); }); -When('I enter update international address details manually', async function () { +When('I enter the update international address details manually', async function () { // manually enter international address details await this.page.locator(selectors.address.manualAddressLink).click(); await this.page.locator(selectors.address.address1).fill('219 Beacon St'); @@ -32,7 +32,7 @@ When('I select a non UK country on the update form', async function () { await this.page.waitForTimeout(2000); }); -Then('update postcode error should disappear', async function () { +Then('the update postcode error should disappear', async function () { // When an international country is selected, the postcode error for UK format should not show anymore await expect(this.page.locator(selectors.errorMessages.postcode)).not.toBeVisible(); }); diff --git a/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js index 00a07d5e..42405dcd 100644 --- a/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js +++ b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js @@ -14,7 +14,7 @@ When('I submit the Giftaid update form', async function () { await this.page.click(selectors.formFields.submitButton); }); -Then('I should see required update form error messages', async function () { +Then('I should see the required update form error messages', async function () { await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText('Please fill in your first name'); await expect(this.page.locator(selectors.errorMessages.lastName)).toHaveText('Please fill in your last name'); await expect(this.page.locator(selectors.errorMessages.email)).toHaveText('Please fill in your email address'); @@ -23,13 +23,13 @@ Then('I should see required update form error messages', async function () { await expect(this.page.locator(selectors.errorMessages.giftAidClaimChoice)).toHaveText('This field is required'); }); -When('I enter update first name {string}', async function (firstName) { +When('I enter the update first name {string}', async function (firstName) { const value = firstName === 'SPACE' ? ' ' : firstName; await this.page.fill(selectors.formFields.firstName, value); await this.page.keyboard.press('Enter'); }); -Then('I should see update first name error message {string}', async function (message) { +Then('I should see the update first name error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText(message); }); @@ -38,55 +38,55 @@ When('I complete the Giftaid update form with first name {string}', async functi await this.commands.populateUpdateFormFields(this.page, { firstName }); }); -When('I select yes for GiftAid declaration', async function () { +When('I select yes for the GiftAid declaration', async function () { await this.page.click(selectors.giftAidClaimChoice.yes); }); -When('I select no for GiftAid declaration', async function () { +When('I select no for the GiftAid declaration', async function () { await this.page.click(selectors.giftAidClaimChoice.no); }); -Then('I should see update thank you message for {string}', async function (firstName) { +Then('I should see the update thank you message for {string}', async function (firstName) { await expect( this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); }); -When('I enter update email {string}', async function (email) { +When('I enter the update email {string}', async function (email) { await this.page.fill(selectors.marketingPreferences.fields.email, ''); await this.page.fill(selectors.marketingPreferences.fields.email, email); await this.page.keyboard.press('Enter'); }); -Then('I should see update email error message {string}', async function (message) { +Then('I should see the update email error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.email)).toBeVisible(); await expect(this.page.locator(selectors.errorMessages.email)).toHaveText(message); }); -When('I complete the Giftaid update form with generated email', async function () { +When('I complete the Giftaid update form with the email', async function () { const validEmail = `giftaid-update-staging-${chance.email()}`; await this.page.fill(selectors.marketingPreferences.fields.email, ''); await this.commands.populateUpdateFormFields(this.page, { email: validEmail }); }); -Then('I should see update no declaration message', async function () { +Then('I should see the update no declaration message', async function () { await expect( this.page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); }); -When('I enter update mobile number {string}', async function (mobile) { +When('I enter the update mobile number {string}', async function (mobile) { await this.page.locator(selectors.formFields.mobile).fill(''); await this.page.locator(selectors.formFields.mobile).type(mobile, { delay: 100 }); }); -Then('I should see update mobile error message {string}', async function (message) { +Then('I should see the update mobile error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.mobile)).toHaveText(message); }); -Then('I should not see update mobile error message', async function () { +Then('I should not see the update mobile error message', async function () { await expect(this.page.locator(selectors.errorMessages.mobile)).not.toBeVisible(); }); -When('I complete the Giftaid update form with generated mobile and last name {string}', async function (lastName) { +When('I complete the Giftaid update form with the mobile and last name {string}', async function (lastName) { const prefixes = ['071', '073', '074', '075', '077', '078', '079']; const prefix = chance.pickone(prefixes); const mobile = `${prefix}${chance.string({ pool: '0123456789', length: 8 })}`; @@ -95,12 +95,12 @@ When('I complete the Giftaid update form with generated mobile and last name {st await this.commands.populateUpdateFormFields(this.page, { lastName, mobile }); }); -When('I enter update postcode {string}', async function (postcode) { +When('I enter the update postcode {string}', async function (postcode) { await this.page.fill(selectors.formFields.postcode, ''); await this.page.type(selectors.formFields.postcode, postcode); }); -Then('I should see update postcode error message {string}', async function (message) { +Then('I should see the update postcode error message {string}', async function (message) { await expect(this.page.locator(selectors.errorMessages.postcode)).toBeVisible(); await expect(this.page.locator(selectors.errorMessages.postcode)).toHaveText(message); }); @@ -109,7 +109,7 @@ When('I search for the update postcode', async function () { await this.page.click(selectors.formFields.postcodeLookup); }); -When('I select update address from lookup or enter address manually', async function () { +When('I select the update address from lookup or enter address manually', async function () { if (await this.page.locator(selectors.address.addressSelect).isVisible()) { const options = await this.page.$$eval(selectors.address.addressSelectOptions, options => options.map(option => option.value)); await this.page.selectOption(selectors.address.addressSelect, options[1]); @@ -124,7 +124,7 @@ When('I select update address from lookup or enter address manually', async func } }); -When('I complete remaining update form fields', async function () { +When('I complete the remaining update form fields', async function () { await this.page.locator(selectors.formFields.firstName).fill('test'); await this.page.locator(selectors.formFields.lastName).fill(chance.last()); await this.page.locator(selectors.marketingPreferences.fields.email).fill(`giftaid-update-staging-${chance.email()}`); diff --git a/yarn.lock b/yarn.lock index 02df1c88..9bfbc160 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1388,6 +1388,11 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + "@comicrelief/data-models@^1.15.4": version "1.71.1" resolved "https://registry.yarnpkg.com/@comicrelief/data-models/-/data-models-1.71.1.tgz#3861e94c8fe9180c3ee0e5c86605073ce5df4778" @@ -1439,6 +1444,124 @@ resolved "https://registry.yarnpkg.com/@comicrelief/test-utils/-/test-utils-1.5.15.tgz#48ee30ccfa44d220dabce8dd7e9bb43c8e043814" integrity sha512-XsShlQcGzHDv6FVlJLvWGDPdY4mgqFNWdw+dXlGFXCCiC2WCpVQzVdzdInOTfvCZZXLAHDTT+RaF+RZlj3VVRQ== +"@cucumber/ci-environment@9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/ci-environment/-/ci-environment-9.1.0.tgz#6d868141c7cfd616931f14723e122a1069401998" + integrity sha512-jdnF6APXP3GawMue8kdMxhu6TBhyRUO4KDRxTowf06NtclLjIw2Ybpo9IcIOMvE8kHukvJyM00uxWX+CfS7JgQ== + +"@cucumber/cucumber-expressions@16.1.0": + version "16.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber-expressions/-/cucumber-expressions-16.1.0.tgz#2a2538b775e83b84a275ea10f618242717937968" + integrity sha512-Q/tKDNje9RrcOXF2TO2NwTW92rzk+RwKkhYYKLxQT26Co8Qbjom0Cz02HsCMA2wjJ8dw6/d2IbWgiOay9RQA+w== + dependencies: + regexp-match-indices "1.0.2" + +"@cucumber/cucumber@8.9.1": + version "8.9.1" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber/-/cucumber-8.9.1.tgz#6b3bb74e5811d69aee85eaac0298218cb38ab6c7" + integrity sha512-Ir0yloCGu25mnllHunOAaOVXIKrRSE0ICF1FleoJzeupgYWK/x8o6hjOGRJf1Ui17GoRs1CfkP44/K29lmpMtA== + dependencies: + "@cucumber/ci-environment" "9.1.0" + "@cucumber/cucumber-expressions" "16.1.0" + "@cucumber/gherkin" "25.0.2" + "@cucumber/gherkin-streams" "5.0.1" + "@cucumber/gherkin-utils" "8.0.2" + "@cucumber/html-formatter" "20.2.0" + "@cucumber/message-streams" "4.0.1" + "@cucumber/messages" "20.0.0" + "@cucumber/tag-expressions" "4.1.0" + assertion-error-formatter "^3.0.0" + capital-case "^1.0.4" + chalk "^4.1.2" + cli-table3 "0.6.3" + commander "^9.0.0" + debug "^4.3.4" + duration "^0.2.2" + durations "^3.4.2" + error-stack-parser "^2.1.4" + figures "^3.2.0" + glob "^7.1.6" + has-ansi "^4.0.1" + indent-string "^4.0.0" + is-installed-globally "^0.4.0" + is-stream "^2.0.0" + knuth-shuffle-seeded "^1.0.6" + lodash.merge "^4.6.2" + lodash.mergewith "^4.6.2" + mz "^2.7.0" + progress "^2.0.3" + resolve-pkg "^2.0.0" + semver "7.3.8" + string-argv "^0.3.1" + strip-ansi "6.0.1" + supports-color "^8.1.1" + tmp "^0.2.1" + util-arity "^1.1.0" + verror "^1.10.0" + xmlbuilder "^15.1.1" + yup "^0.32.11" + +"@cucumber/gherkin-streams@5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin-streams/-/gherkin-streams-5.0.1.tgz#8c2142d295cd05644456be7282b4bd756c95c4cd" + integrity sha512-/7VkIE/ASxIP/jd4Crlp4JHXqdNFxPGQokqWqsaCCiqBiu5qHoKMxcWNlp9njVL/n9yN4S08OmY3ZR8uC5x74Q== + dependencies: + commander "9.1.0" + source-map-support "0.5.21" + +"@cucumber/gherkin-utils@8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin-utils/-/gherkin-utils-8.0.2.tgz#deae231f84e91f120501d22187c66d36e6c6b59f" + integrity sha512-aQlziN3r3cTwprEDbLEcFoMRQajb9DTOu2OZZp5xkuNz6bjSTowSY90lHUD2pWT7jhEEckZRIREnk7MAwC2d1A== + dependencies: + "@cucumber/gherkin" "^25.0.0" + "@cucumber/messages" "^19.1.4" + "@teppeis/multimaps" "2.0.0" + commander "9.4.1" + source-map-support "^0.5.21" + +"@cucumber/gherkin@25.0.2", "@cucumber/gherkin@^25.0.0": + version "25.0.2" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin/-/gherkin-25.0.2.tgz#e430879f01978d1f9e7a7aa0563031a3a36022e7" + integrity sha512-EdsrR33Y5GjuOoe2Kq5Y9DYwgNRtUD32H4y2hCrT6+AWo7ibUQu7H+oiWTgfVhwbkHsZmksxHSxXz/AwqqyCRQ== + dependencies: + "@cucumber/messages" "^19.1.4" + +"@cucumber/html-formatter@20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@cucumber/html-formatter/-/html-formatter-20.2.0.tgz#20857efec721fbc5d64cc31b0107575db1e58651" + integrity sha512-apcxS5Imeh3Wk4VMkuB3C4UQ+0/PVlNTkcWx9/5wwd+p3EnEbtvbZUhYIHgVBm+0FKEc22yrXBEc0N85fT/r4A== + +"@cucumber/message-streams@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/message-streams/-/message-streams-4.0.1.tgz#a5339d3504594bb2edb5732aaae94dddb24d0970" + integrity sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA== + +"@cucumber/messages@20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-20.0.0.tgz#494d30bd2880b04dcb3a958f8c0ec5638b7b3596" + integrity sha512-JFrFwuhxsbig0afaViNhuzoQyC+GQzlI7m+rX+lSiDGV13K3sJzMmHjkbCiNOgoRlKAMwIGR9TRMH0xj9/My0w== + dependencies: + "@types/uuid" "8.3.4" + class-transformer "0.5.1" + reflect-metadata "0.1.13" + uuid "9.0.0" + +"@cucumber/messages@^19.1.4": + version "19.1.4" + resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-19.1.4.tgz#5cefc47cac3004c0bc38d42933042ec248bb747c" + integrity sha512-Pksl0pnDz2l1+L5Ug85NlG6LWrrklN9qkMxN5Mv+1XZ3T6u580dnE6mVaxjJRdcOq4tR17Pc0RqIDZMyVY1FlA== + dependencies: + "@types/uuid" "8.3.4" + class-transformer "0.5.1" + reflect-metadata "0.1.13" + uuid "9.0.0" + +"@cucumber/tag-expressions@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/tag-expressions/-/tag-expressions-4.1.0.tgz#9a91b0e0dd2f2ba703e3038c52b49b9ac06c2c6f" + integrity sha512-chTnjxV3vryL75N90wJIMdMafXmZoO2JgNJLYpsfcALL2/IQrRiny3vM9DgD5RDCSt1LNloMtb7rGey9YWxCsA== + "@emotion/cache@^10.0.27": version "10.0.29" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" @@ -2253,6 +2376,11 @@ "@svgr/plugin-svgo" "^4.3.1" loader-utils "^1.2.3" +"@teppeis/multimaps@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@teppeis/multimaps/-/multimaps-2.0.0.tgz#2114ee964b702f9777d0e07899087ad9cd89a0de" + integrity sha512-TL1adzq1HdxUf9WYduLcQ/DNGYiz71U31QRgbnr0Ef1cPyOUOsBojxHVWpFeOSUucB6Lrs0LxFRA14ntgtkc9w== + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -2451,6 +2579,11 @@ dependencies: source-map "^0.6.1" +"@types/uuid@8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + "@types/webpack-env@^1.15.0": version "1.18.1" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.18.1.tgz#49699bb508961e14a3bfb68c78cd87b296889d1d" @@ -3265,6 +3398,15 @@ assert@^1.1.1: object-assign "^4.1.1" util "0.10.3" +assertion-error-formatter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz#be9c8825dee6a8a6c72183d915912d9b57d5d265" + integrity sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ== + dependencies: + diff "^4.0.1" + pad-right "^0.2.2" + repeat-string "^1.6.1" + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -4832,6 +4974,15 @@ caniuse-lite@^1.0.30001629: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001632.tgz#964207b7cba5851701afb4c8afaf1448db3884b6" integrity sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg== +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + capture-stack-trace@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.2.tgz#1c43f6b059d4249e7f3f8724f15f048b927d3a8a" @@ -5046,6 +5197,11 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" +class-transformer@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -5107,6 +5263,15 @@ cli-table3@0.5.1: optionalDependencies: colors "^1.1.2" +cli-table3@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" + integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + cli-width@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" @@ -5288,6 +5453,16 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== +commander@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.1.0.tgz#a6b263b2327f2e188c6402c42623327909f2dbec" + integrity sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w== + +commander@9.4.1: + version "9.4.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" + integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw== + commander@^2.15.1, commander@^2.19.0, commander@^2.20.0, commander@^2.8.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -5303,6 +5478,11 @@ commander@^7.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +commander@^9.0.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -6036,6 +6216,14 @@ d3-voronoi@^1.1.4: resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg== +d@1, d@^1.0.1, d@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== + dependencies: + es5-ext "^0.10.64" + type "^2.7.2" + damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -6078,6 +6266,13 @@ debug@^3.0.0, debug@^3.1.0, debug@^3.2.5, debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.3.4: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + decamelize-keys@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" @@ -6330,6 +6525,11 @@ detect-port@^1.3.0: address "^1.0.1" debug "4" +diff@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.4.tgz#7a6dbfda325f25f07517e9b518f897c08332e07d" + integrity sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -6618,6 +6818,19 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" +duration@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/duration/-/duration-0.2.2.tgz#ddf149bc3bc6901150fe9017111d016b3357f529" + integrity sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg== + dependencies: + d "1" + es5-ext "~0.10.46" + +durations@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/durations/-/durations-3.4.2.tgz#1de230454373cccfecab927de0bebae2295301db" + integrity sha512-V/lf7y33dGaypZZetVI1eu7BmvkbC4dItq12OElLRpKuaU5JxQstV2zHwLv8P7cNbQ+KL1WD80zMCTx5dNC4dg== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -6772,6 +6985,13 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error-stack-parser@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== + dependencies: + stackframe "^1.3.4" + es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2: version "1.22.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" @@ -6862,6 +7082,16 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14, es5-ext@~0.10.46: + version "0.10.64" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + esniff "^2.0.1" + next-tick "^1.1.0" + es5-shim@^4.5.13: version "4.6.7" resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.6.7.tgz#bc67ae0fc3dd520636e0a1601cc73b450ad3e955" @@ -6872,6 +7102,15 @@ es6-error@^4.1.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + es6-promise@^4.0.5: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -6882,6 +7121,14 @@ es6-shim@^0.35.5: resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.8.tgz#89216f6fbf8bacba3f897c8c0e814d2a41c05fb7" integrity sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg== +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c" + integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== + dependencies: + d "^1.0.2" + ext "^1.7.0" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -7120,6 +7367,16 @@ eslint@^7.8.1: text-table "^0.2.0" v8-compile-cache "^2.0.3" +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== + dependencies: + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" + espree@^7.3.0, espree@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" @@ -7182,6 +7439,14 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + event-stream@=3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -7365,6 +7630,13 @@ ext-name@^5.0.0: ext-list "^2.0.0" sort-keys-length "^1.0.0" +ext@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -7554,7 +7826,7 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" -figures@^3.0.0: +figures@^3.0.0, figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== @@ -8291,6 +8563,13 @@ global-dirs@^0.1.0: dependencies: ini "^1.3.4" +global-dirs@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" + integrity sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA== + dependencies: + ini "2.0.0" + global-modules@2.0.0, global-modules@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -8566,6 +8845,13 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" +has-ansi@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-4.0.1.tgz#f216a8c8d7b129e490dc15f4a62cc1cdb9603ce8" + integrity sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A== + dependencies: + ansi-regex "^4.1.0" + has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -9215,6 +9501,11 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" @@ -9607,6 +9898,14 @@ is-installed-globally@^0.1.0: global-dirs "^0.1.0" is-path-inside "^1.0.0" +is-installed-globally@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + is-jpg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-jpg/-/is-jpg-2.0.0.tgz#2e1997fa6e9166eaac0242daae443403e4ef1d97" @@ -9704,6 +10003,11 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -10221,6 +10525,13 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +knuth-shuffle-seeded@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz#01f1b65733aa7540ee08d8b0174164d22081e4e1" + integrity sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg== + dependencies: + seed-random "~2.2.0" + language-subtag-registry@~0.3.2: version "0.3.22" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" @@ -10427,6 +10738,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + lodash.tail@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" @@ -11160,7 +11476,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -11188,7 +11504,7 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mz@^2.6.0: +mz@^2.6.0, mz@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== @@ -11249,6 +11565,11 @@ nested-object-assign@^1.0.1: resolved "https://registry.yarnpkg.com/nested-object-assign/-/nested-object-assign-1.0.4.tgz#c9db56078eb6043960fdb6ba918a5122a06ccac4" integrity sha512-FlZ7oN9ICt+fbcJ4ag2IsALIcalfE/E16ttdSA8peBiHJI+oEKdOcafqDnUbeUe5NwWGn/m9zZGO9qrAGzfesg== +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -11945,6 +12266,13 @@ package-json@^4.0.0: registry-url "^3.0.3" semver "^5.1.0" +pad-right@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/pad-right/-/pad-right-0.2.2.tgz#6fbc924045d244f2a2a244503060d3bfc6009774" + integrity sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g== + dependencies: + repeat-string "^1.5.2" + pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -12781,7 +13109,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -progress@^2.0.0: +progress@^2.0.0, progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -13691,6 +14019,11 @@ reduce-function-call@^1.0.1: dependencies: balanced-match "^1.0.0" +reflect-metadata@0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + refractor@^2.4.1: version "2.10.1" resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e" @@ -13756,6 +14089,18 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexp-match-indices@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz#cf20054a6f7d5b3e116a701a7b00f82889d10da6" + integrity sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ== + dependencies: + regexp-tree "^0.1.11" + +regexp-tree@^0.1.11: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" @@ -13872,7 +14217,7 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== -repeat-string@^1.5.4, repeat-string@^1.6.1: +repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== @@ -13977,6 +14322,13 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== +resolve-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-2.0.0.tgz#ac06991418a7623edc119084edc98b0e6bf05a41" + integrity sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ== + dependencies: + resolve-from "^5.0.0" + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -14249,6 +14601,11 @@ scss-tokenizer@^0.2.3: js-base64 "^2.1.8" source-map "^0.4.2" +seed-random@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/seed-random/-/seed-random-2.2.0.tgz#2a9b19e250a817099231a5b99a4daf80b7fbed54" + integrity sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ== + seek-bzip@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" @@ -14297,6 +14654,13 @@ semver-truncate@^1.1.2: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== +semver@7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" @@ -14695,7 +15059,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@~0.5.12: +source-map-support@0.5.21, source-map-support@^0.5.21, source-map-support@~0.5.12: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -14866,6 +15230,11 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== + start-server-and-test@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-2.0.0.tgz#0644809d63036a8a001efb70582f3e37ebfdd33d" @@ -14966,6 +15335,11 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== +string-argv@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + string-natural-compare@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" @@ -15086,6 +15460,13 @@ strip-ansi@5.2.0, strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -15100,13 +15481,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -15221,6 +15595,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -15575,6 +15956,11 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmp@^0.2.1: + version "0.2.5" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" + integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow== + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -15803,6 +16189,11 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +type@^2.7.2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.3.tgz#436981652129285cc3ba94f392886c2637ea0486" + integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ== + typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -16118,6 +16509,13 @@ update-notifier@^2.3.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -16213,6 +16611,11 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== +util-arity@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/util-arity/-/util-arity-1.1.0.tgz#59d01af1fdb3fede0ac4e632b0ab5f6ce97c9330" + integrity sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA== + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -16273,6 +16676,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + uuid@^3.0.1, uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -16334,6 +16742,15 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +verror@^1.10.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.1.tgz#4bf09eeccf4563b109ed4b3d458380c972b0cdeb" + integrity sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + vfile-location@^2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" @@ -16779,6 +17196,11 @@ xml-name-validator@^4.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== +xmlbuilder@^15.1.1: + version "15.1.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" + integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== + xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" From ae0d8a7ba86f683cc83b6a65c479b1dd1705fca5 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 12 May 2026 13:03:42 +0100 Subject: [PATCH 10/35] ci: Add retry and parallel options in the config --- playwright-local/config/cucumber.js | 4 +++- playwright-staging/config/cucumber.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/playwright-local/config/cucumber.js b/playwright-local/config/cucumber.js index b9cbbc51..deb7b02f 100644 --- a/playwright-local/config/cucumber.js +++ b/playwright-local/config/cucumber.js @@ -5,9 +5,11 @@ module.exports = { 'tests/support/**/*.js', 'tests/step-definitions/**/*.js', ], - format: ['progress', 'summary'], // Use 'pretty' locally for readable step-by-step output. // On CI keep the output minimal to avoid noisy logs. + format: ['progress', 'summary'], + retry: 2, // Retry failed scenarios twice + parallel: 3, // Run scenarios in parallel workers publishQuiet: true, }, }; diff --git a/playwright-staging/config/cucumber.js b/playwright-staging/config/cucumber.js index beee3736..da890dbd 100644 --- a/playwright-staging/config/cucumber.js +++ b/playwright-staging/config/cucumber.js @@ -8,6 +8,8 @@ module.exports = { format: ['progress', 'summary'], // Use 'pretty' locally for readable step-by-step output. // On CI keep the output minimal to avoid noisy logs. + retry: process.env.CI ? 2 : 0, // no retries when running locally + parallel: 3, publishQuiet: true, // Hide the default Cucumber report publishing link (we check CI instead) }, }; From 69e5750cfac347315269cb26e7e20fdc27f03e55 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 12 May 2026 13:08:50 +0100 Subject: [PATCH 11/35] ci: update playwright run with cucumber script --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 631457a3..c6c7d093 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,8 +34,8 @@ jobs: - name: Install playwright browsers run: yarn playwright install chromium - - name: Run Playwright Chrome Tests - run: yarn test:playwright-local:ci:chromium + - name: Run Cucumber Giftaid Sanity Tests + run: yarn test:cucumber:ci:sanity continue-on-error: false env: NODE_ENV: development @@ -85,8 +85,8 @@ jobs: - name: Install playwright browsers (WebKit) run: yarn playwright install webkit - - name: Run Mobile WebKit Tests - run: yarn test:playwright-local:ci:mobile + - name: Run Mobile Cucumber Tests + run: yarn test:cucumber:ci:sanity continue-on-error: false env: NODE_ENV: development From 65a24df47fdb092baaba53daed71180b76df5e70 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 12 May 2026 13:49:06 +0100 Subject: [PATCH 12/35] test: Add mobile safari config and parallel scripts --- .github/workflows/main.yml | 4 +-- package.json | 10 +++++++ playwright-local/tests/support/hooks.js | 39 +++++++++++++++++-------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c6c7d093..07573ce8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: run: yarn playwright install chromium - name: Run Cucumber Giftaid Sanity Tests - run: yarn test:cucumber:ci:sanity + run: yarn test:cucumber:ci:chromium:sanity continue-on-error: false env: NODE_ENV: development @@ -86,7 +86,7 @@ jobs: run: yarn playwright install webkit - name: Run Mobile Cucumber Tests - run: yarn test:cucumber:ci:sanity + run: yarn test:cucumber:ci:mobile:sanity continue-on-error: false env: NODE_ENV: development diff --git a/package.json b/package.json index c840b077..e85c68f2 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,18 @@ "test:playwright-local:local:chrome:mobile": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local:local", "test:cucumber:local": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", "test:cucumber:local:sanity": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:chromium": "cd playwright-local && BROWSER=chromium BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", + "test:cucumber:local:chromium:sanity": "cd playwright-local && BROWSER=chromium BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:chromium:headed": "cd playwright-local && BROWSER=chromium HEADED=true BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:mobile": "cd playwright-local && BROWSER=mobile-safari BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", + "test:cucumber:local:mobile:sanity": "cd playwright-local && BROWSER=mobile-safari BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:mobile:headed": "cd playwright-local && BROWSER=mobile-safari HEADED=true BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", "test:cucumber:ci": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local", "test:cucumber:ci:sanity": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:sanity", + "test:cucumber:ci:chromium": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:chromium", + "test:cucumber:ci:chromium:sanity": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:chromium:sanity", + "test:cucumber:ci:mobile": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:mobile", + "test:cucumber:ci:mobile:sanity": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:mobile:sanity", "snyk-protect": "snyk-protect", "prepublish": "yarn snyk-protect" }, diff --git a/playwright-local/tests/support/hooks.js b/playwright-local/tests/support/hooks.js index 2668dabb..132e13eb 100644 --- a/playwright-local/tests/support/hooks.js +++ b/playwright-local/tests/support/hooks.js @@ -1,30 +1,45 @@ require('dotenv').config(); const { Before, After, setDefaultTimeout } = require('@cucumber/cucumber'); -const { chromium } = require('@playwright/test'); +const { chromium, webkit, devices } = require('@playwright/test'); const { Commands } = require('../utils/commands'); setDefaultTimeout(300 * 1000); // Runs before each scenario Before(async function () { - this.browser = await chromium.launch({ - channel: 'chrome', - headless: process.env.HEADED !== 'true', - }); + const browserName = process.env.BROWSER || 'chromium'; + const isMobileSafari = browserName === 'mobile-safari'; - this.context = await this.browser.newContext({ - viewport: { - width: 1300, - height: 1000, - }, - serviceWorkers: 'block', // Avoids caching issues - }); + this.browser = isMobileSafari + ? await webkit.launch({ + headless: process.env.HEADED !== 'true', + }) + : await chromium.launch({ + channel: 'chrome', + headless: process.env.HEADED !== 'true', + }); + + this.context = await this.browser.newContext( + isMobileSafari + ? { + ...devices['iPhone 12'], + serviceWorkers: 'block', + } + : { + viewport: { + width: 1300, + height: 1000, + }, + serviceWorkers: 'block', + } + ); this.page = await this.context.newPage(); this.commands = new Commands(this.page); }); +// Runs after each scenario After(async function () { if (this.page) { await this.page.close(); From 9c220955afd79c86c8add7cb00ce6dfb27f5dc2c Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 12 May 2026 14:15:09 +0100 Subject: [PATCH 13/35] test: fix marketing prefs step by adding scrollingintoview --- .../marketingPreferencesValidation.steps.js | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js b/playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js index 8ffc8d10..4fb5adf9 100644 --- a/playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js +++ b/playwright-local/tests/step-definitions/submit/marketingPreferencesValidation.steps.js @@ -7,16 +7,20 @@ const chance = new Chance(); const email = `giftaid-staging-${Date.now().toString()}@email.sls.comicrelief.com`; const phone = chance.phone({ country: 'uk', mobile: true }).replace(/\s/g, ''); -const marketingOptions = [ - '[aria-label="field-label--Email--Email"]', - '[aria-label="field-label--Phone--Phone"]', - '[aria-label="field-label--Text--SMS"]', -]; - When('I select all the local marketing preference options', async function () { + const marketingOptions = [ + '[aria-label="field-label--Email--Email"]', + '[aria-label="field-label--Phone--Phone"]', + '[aria-label="field-label--Text--SMS"]', + ]; + for (const option of marketingOptions) { - await this.page.locator(option).click(); - await expect(this.page.locator(option)).toBeChecked(); + const checkbox = this.page.locator(option); + + await checkbox.scrollIntoViewIfNeeded(); + await checkbox.check({ force: true }); + + await expect(checkbox).toBeChecked(); } }); From 3edd445a3cb32b08eaf2794302846a111bed9e32 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 12 May 2026 17:22:14 +0100 Subject: [PATCH 14/35] test: few tweaks --- .../features/submit/validFormSubmission.feature | 6 +++--- .../tests/features/update/formValidation.feature | 14 +++++++------- .../update/giftaidDeclarationOptions.feature | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/playwright-staging/tests/features/submit/validFormSubmission.feature b/playwright-staging/tests/features/submit/validFormSubmission.feature index 413c0906..df180bf0 100644 --- a/playwright-staging/tests/features/submit/validFormSubmission.feature +++ b/playwright-staging/tests/features/submit/validFormSubmission.feature @@ -1,11 +1,11 @@ @sanity @nightly-sanity Feature: Giftaid submission - Scenario: Submit Giftaid form with valid details + Scenario: Valid Giftaid submission Given I am on the Giftaid page - When I select the Giftaid option + And I select the Giftaid option And I complete the Giftaid form with valid details And I select the marketing preferences - And I submit the Giftaid form + When I submit the Giftaid form Then I should see the Giftaid thank you message diff --git a/playwright-staging/tests/features/update/formValidation.feature b/playwright-staging/tests/features/update/formValidation.feature index 8e67fbbd..fba73bf5 100644 --- a/playwright-staging/tests/features/update/formValidation.feature +++ b/playwright-staging/tests/features/update/formValidation.feature @@ -22,7 +22,7 @@ Feature: Giftaid update form validation When I complete the Giftaid update form with first name "John" And I select yes for GiftAid declaration And I submit the Giftaid update form - Then I should see update thank you message for "John" + Then I should see the update thank you message for "John" Scenario Outline: Invalid email values should show error message on update form When I enter the update email "" @@ -39,7 +39,7 @@ Feature: Giftaid update form validation When I complete the Giftaid update form with the email And I select no for GiftAid declaration And I submit the Giftaid update form - Then I should see update no declaration message + Then I should see the update no declaration message Scenario Outline: Invalid mobile numbers should show error message on update form When I enter the update mobile number "" @@ -65,11 +65,11 @@ Feature: Giftaid update form validation When I complete the Giftaid update form with the mobile and last name "test" And I select yes for GiftAid declaration And I submit the Giftaid update form - Then I should see update thank you message for " test" + Then I should see the update thank you message for " test" Scenario Outline: Invalid postcode values should show error message on update form - When I enter update postcode "" - Then I should see update postcode error message "" + When I enter the update postcode "" + Then I should see the update postcode error message "" Examples: | postcode | message | @@ -78,10 +78,10 @@ Feature: Giftaid update form validation | cro 7tp | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | Scenario: Valid postcode should submit update form - When I enter update postcode "SE1 7TP" + When I enter the update postcode "SE1 7TP" And I search for the update postcode And I select the update address from lookup or enter address manually And I complete the remaining update form fields And I select yes for GiftAid declaration And I submit the Giftaid update form - Then I should see update thank you message for " test" + Then I should see the update thank you message for " test" diff --git a/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature b/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature index ceed1d61..6d804b53 100644 --- a/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature +++ b/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature @@ -14,4 +14,4 @@ Feature: Giftaid declaration claim selection Then no option should be selected and yes option should not be selected When I submit the Giftaid update form - Then I should see update no declaration message + Then I should see the update no declaration message From dd18155a00298019f6194a64d7cba68b9cce4a7c Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 13 May 2026 15:40:39 +0100 Subject: [PATCH 15/35] test: fix failing staging tests locally --- .../features/submit/marketingPreferencesData.feature | 2 +- ...mission.feature => validGifaidSubmission.feature} | 2 +- .../step-definitions/common/giftaidCommon.steps.js | 8 ++++++-- .../submit/giftaidSubmission.steps.js | 4 +++- ...re.steps.js => marketingPreferencesData.steps.js} | 10 +--------- playwright-staging/tests/utils/commands.js | 12 +++++++----- playwright-staging/tests/utils/locators.js | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) rename playwright-staging/tests/features/submit/{validFormSubmission.feature => validGifaidSubmission.feature} (90%) rename playwright-staging/tests/step-definitions/submit/{marketingPreferencesContactStore.steps.js => marketingPreferencesData.steps.js} (87%) diff --git a/playwright-staging/tests/features/submit/marketingPreferencesData.feature b/playwright-staging/tests/features/submit/marketingPreferencesData.feature index 2f74c40a..dfe31a39 100644 --- a/playwright-staging/tests/features/submit/marketingPreferencesData.feature +++ b/playwright-staging/tests/features/submit/marketingPreferencesData.feature @@ -4,7 +4,7 @@ Feature: Giftaid marketing preferences contact-store verification Scenario: Verify giftaid marketing preferences data in contact-store Given I am on the Giftaid page And I select the Giftaid option - When I populate the Giftaid form with the generated supporter details + When I populate the Giftaid form with the supporter details And I select the marketing preferences And I submit the Giftaid form Then I should see the supporter thank you message diff --git a/playwright-staging/tests/features/submit/validFormSubmission.feature b/playwright-staging/tests/features/submit/validGifaidSubmission.feature similarity index 90% rename from playwright-staging/tests/features/submit/validFormSubmission.feature rename to playwright-staging/tests/features/submit/validGifaidSubmission.feature index df180bf0..4d5ad7bd 100644 --- a/playwright-staging/tests/features/submit/validFormSubmission.feature +++ b/playwright-staging/tests/features/submit/validGifaidSubmission.feature @@ -1,5 +1,5 @@ @sanity @nightly-sanity -Feature: Giftaid submission +Feature: Valid Giftaid submission Scenario: Valid Giftaid submission Given I am on the Giftaid page diff --git a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js index e5fc067f..a82756d4 100644 --- a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js +++ b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js @@ -3,11 +3,15 @@ const { expect } = require('@playwright/test'); const { selectors } = require('../../utils/locators'); When('I submit the Giftaid form', async function () { - await this.page.click(selectors.formFields.submitButton); + await this.page.locator(selectors.formFields.submitButton).click(); + await this.page.waitForLoadState('networkidle'); }); When('I select the marketing preferences', async function () { - await this.commands.selectMarketingPrefs(this.page); + await this.commands.selectMarketingPrefs(this.page, { + email: this.supporter.email, + phone: this.supporter.phone, + }); }); When('I complete the Giftaid form with valid details', async function () { diff --git a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js index 723fb1ea..2cdb7640 100644 --- a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js +++ b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js @@ -12,5 +12,7 @@ When('I select the Giftaid option', async function () { }); Then('I should see the Giftaid thank you message', async function () { - await expect(this.page.locator(selectors.success.heading)).toHaveText('Thank you, test!'); + await expect(this.page.locator(selectors.success.heading)).toContainText('Thank you, test!', { + timeout: 30000, + }); }); diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js similarity index 87% rename from playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js rename to playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js index a7989f97..52ba41a5 100644 --- a/playwright-staging/tests/step-definitions/submit/marketingPreferencesContactStore.steps.js +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js @@ -6,7 +6,7 @@ const { selectors } = require('../../utils/locators'); const chance = new Chance(); -When('I populate the Giftaid form with the generated supporter details', async function () { +When('I populate the Giftaid form with the supporter details', async function () { this.supporter = { firstName: chance.first(), lastName: chance.last(), @@ -34,14 +34,6 @@ When('I populate the Giftaid form with the generated supporter details', async f }); }); -When('I select the marketing preferences', async function () { - // Select marketing preferences using Commands class - await this.commands.selectMarketingPrefs(this.page, { - email: this.supporter.email, - phone: this.supporter.phone, - }); -}); - Then('I should see the supporter thank you message', async function () { // Verify success message await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${this.supporter.firstName}!`); diff --git a/playwright-staging/tests/utils/commands.js b/playwright-staging/tests/utils/commands.js index 92a7cf78..4d651a42 100644 --- a/playwright-staging/tests/utils/commands.js +++ b/playwright-staging/tests/utils/commands.js @@ -46,14 +46,16 @@ class Commands { * @param options - Optional marketing preferences. */ async selectMarketingPrefs(page, { - email = `giftaid-staging-${chance.email()}`, - phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, '') // UK phone number + email = `giftaid-staging-${Date.now()}@email.sls.comicrelief.com`, + phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, '') } = {}) { await page.locator('#field-wrapper--Email > div').click(); - await page.locator('input#field-input--email').type(email); + await page.locator('input#field-input--email').fill(email); + await page.locator('#field-wrapper--Phone > div').click(); - await page.locator('input#field-input--phone').type(phone, { delay: 200 }); - await page.locator('input#field-label--Text--SMS').click(); + await page.locator('input#field-input--phone').fill(phone); + + await page.locator('input#field-label--Text--SMS').check({ force: true }); } /** diff --git a/playwright-staging/tests/utils/locators.js b/playwright-staging/tests/utils/locators.js index 547c9297..31b72c68 100644 --- a/playwright-staging/tests/utils/locators.js +++ b/playwright-staging/tests/utils/locators.js @@ -63,7 +63,7 @@ const selectors = { }, success: { - heading: 'div.success-wrapper--inner h1', + heading: 'h1', }, sorry: { heading: 'div > h1', From a7e3b1bcaff789467b88e47dcdd9d1ef22bc7c1d Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 14 May 2026 15:59:41 +0100 Subject: [PATCH 16/35] test: resolve ambiguous steps --- .../features/submit/addressValidation.feature | 9 +-- .../submit/marketingPreferencesData.feature | 2 +- .../submit/validGifaidSubmission.feature | 2 +- .../common/giftaidCommon.steps.js | 25 ++++++-- .../submit/addressValidation.steps.js | 4 +- .../submit/formValidation.steps.js | 4 +- .../submit/giftaidSubmission.steps.js | 8 ++- .../submit/marketingPreferencesData.steps.js | 9 +-- .../submit/postcodeValidation.steps.js | 7 ++- .../update/giftaidDeclaration.steps.js | 6 +- .../update/giftaidUpdateCommon.steps.js | 2 +- .../update/updateFormValidation.steps.js | 39 +----------- .../update/updateSuccessRedirect.steps.js | 4 +- playwright-staging/tests/support/hooks.js | 3 +- playwright-staging/tests/utils/commands.js | 63 +++++++++---------- 15 files changed, 85 insertions(+), 102 deletions(-) diff --git a/playwright-staging/tests/features/submit/addressValidation.feature b/playwright-staging/tests/features/submit/addressValidation.feature index d4c10755..458972e2 100644 --- a/playwright-staging/tests/features/submit/addressValidation.feature +++ b/playwright-staging/tests/features/submit/addressValidation.feature @@ -7,7 +7,8 @@ Feature: Address validation And I enter the supporter details Scenario: Empty postcode should show an error message - When I clear the postcode field + When I enter the postcode "E1 8QS" + And I clear the postcode field And I submit the Giftaid form Then I should see the postcode error message "Please enter your postcode" @@ -22,20 +23,20 @@ Feature: Address validation | cro 7tp | Please enter a valid UK postcode, using a space. For non-UK addresses, please use manual entry below. | Scenario: Entering a postcode without selecting an address should show an error message - When I enter the postcode "SE1 7TP" + When I enter the postcode "E1 8QS" And I search for the postcode Then I should see the address dropdown When I submit the Giftaid form Then I should see the address select error message "Please select your address" Scenario: Clicking the manual address link should show the address fields - When I enter the postcode "SE1 7TP" + When I enter the postcode "E1 8QS" Then I should see the manual address link When I click the manual address link Then I should see the manual address fields Scenario: Invalid address fields should show error messages - When I enter the postcode "SE1 7TP" + When I enter the postcode "E1 8QS" And I click the manual address link And I enter an invalid address line 1 Then I should see the address line 1 error message diff --git a/playwright-staging/tests/features/submit/marketingPreferencesData.feature b/playwright-staging/tests/features/submit/marketingPreferencesData.feature index dfe31a39..5e836549 100644 --- a/playwright-staging/tests/features/submit/marketingPreferencesData.feature +++ b/playwright-staging/tests/features/submit/marketingPreferencesData.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @marketing-preferences-data @contact-store +@sanity @nightly-sanity @marketing-preferences-data Feature: Giftaid marketing preferences contact-store verification Scenario: Verify giftaid marketing preferences data in contact-store diff --git a/playwright-staging/tests/features/submit/validGifaidSubmission.feature b/playwright-staging/tests/features/submit/validGifaidSubmission.feature index 4d5ad7bd..1b7c15cd 100644 --- a/playwright-staging/tests/features/submit/validGifaidSubmission.feature +++ b/playwright-staging/tests/features/submit/validGifaidSubmission.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity +@sanity @nightly-sanity @validSubmission Feature: Valid Giftaid submission Scenario: Valid Giftaid submission diff --git a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js index a82756d4..e011f3ac 100644 --- a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js +++ b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js @@ -1,21 +1,34 @@ -const { Given, When, Then } = require('@cucumber/cucumber'); +const { When, Then } = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); +const Chance = require('chance'); const { selectors } = require('../../utils/locators'); +const chance = new Chance(); + When('I submit the Giftaid form', async function () { await this.page.locator(selectors.formFields.submitButton).click(); - await this.page.waitForLoadState('networkidle'); }); When('I select the marketing preferences', async function () { - await this.commands.selectMarketingPrefs(this.page, { - email: this.supporter.email, - phone: this.supporter.phone, + await this.commands.selectMarketingPrefs({ + email: this.supporter?.email, + phone: this.supporter?.phone, }); }); When('I complete the Giftaid form with valid details', async function () { - await this.commands.populateFormFields(this.page); + this.supporter = { + firstName: chance.first(), + lastName: chance.last(), + mobile: chance.phone({ country: 'uk', mobile: true }).replace(/\s/g, ''), + postcode: chance.postcode(), + address1: chance.address(), + address2: chance.street(), + address3: 'test address 3', + town: chance.city(), + }; + + await this.commands.populateFormFields(this.supporter); }); Then('I should be redirected to the Giftaid homepage', async function () { diff --git a/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js b/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js index b76bbbde..dd70daf8 100644 --- a/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/addressValidation.steps.js @@ -3,7 +3,9 @@ const { expect } = require('@playwright/test'); const { selectors } = require('../../utils/locators'); When('I clear the postcode field', async function () { - await this.page.locator(selectors.formFields.postcode).fill(''); + const postcodeField = this.page.locator(selectors.formFields.postcode); + await postcodeField.fill(''); + await expect(postcodeField).toHaveValue(''); }); Then('I should see the address dropdown', async function () { diff --git a/playwright-staging/tests/step-definitions/submit/formValidation.steps.js b/playwright-staging/tests/step-definitions/submit/formValidation.steps.js index f722ddf6..06aa2fc8 100644 --- a/playwright-staging/tests/step-definitions/submit/formValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/formValidation.steps.js @@ -13,7 +13,7 @@ Then('I should see the mobile error message {string}', async function (message) When('I complete the Giftaid form with the mobile number {string}', async function (mobile) { await this.page.locator(selectors.formFields.mobile).fill(''); - await this.commands.populateFormFields(this.page, { mobile }); + await this.commands.populateFormFields({ mobile }); }); When('I enter the first name {string}', async function (firstName) { @@ -27,7 +27,7 @@ Then('I should see the first name error message {string}', async function (messa When('I complete the Giftaid form with the first name {string}', async function (firstName) { await this.page.locator(selectors.formFields.firstName).fill(''); - await this.commands.populateFormFields(this.page, { firstName }); + await this.commands.populateFormFields({ firstName }); }); Then('I should see the thank you message for {string}', async function (firstName) { diff --git a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js index 2cdb7640..ebe6df57 100644 --- a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js +++ b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js @@ -12,7 +12,9 @@ When('I select the Giftaid option', async function () { }); Then('I should see the Giftaid thank you message', async function () { - await expect(this.page.locator(selectors.success.heading)).toContainText('Thank you, test!', { - timeout: 30000, - }); + const expectedFirstName = this.supporter?.firstName || 'test'; + await expect(this.page.locator('h1')).toContainText( + `Thank you, ${expectedFirstName}!`, + { timeout: 30000 } + ); }); diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js index 52ba41a5..0adae59a 100644 --- a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js @@ -21,7 +21,7 @@ When('I populate the Giftaid form with the supporter details', async function () }; // Populate all input fields using Commands class - await this.commands.populateFormFields(this.page, { + await this.commands.populateFormFields({ mobile: this.supporter.mobile, firstName: this.supporter.firstName, lastName: this.supporter.lastName, @@ -30,13 +30,14 @@ When('I populate the Giftaid form with the supporter details', async function () address3: this.supporter.address3, town: this.supporter.town, postcode: this.supporter.postcode, - email: this.supporter.email, }); }); Then('I should see the supporter thank you message', async function () { - // Verify success message - await expect(this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${this.supporter.firstName}!`); + await expect(this.page.locator('h1')).toHaveText( + `Thank you, ${this.supporter.firstName}!`, + { timeout: 15000 } + ); }); Then('the marketing preferences data should be stored in the contact-store', async function () { diff --git a/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js b/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js index 971351e3..8c03b79c 100644 --- a/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js +++ b/playwright-staging/tests/step-definitions/submit/postcodeValidation.steps.js @@ -9,7 +9,12 @@ Given('I enter the supporter details', async function () { }); When('I enter the postcode {string}', async function (postcode) { - await this.page.fill(selectors.formFields.postcode, postcode); + const postcodeField = this.page.locator(selectors.formFields.postcode); + + await postcodeField.fill(''); + await postcodeField.fill(postcode); + + await expect(postcodeField).toHaveValue(postcode); }); Then('I should see the postcode error message {string}', async function (message) { diff --git a/playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js b/playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js index bbb4e7e4..a55e8b98 100644 --- a/playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js +++ b/playwright-staging/tests/step-definitions/update/giftaidDeclaration.steps.js @@ -1,11 +1,7 @@ -const { When, Then } = require('@cucumber/cucumber'); +const { Then } = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); const { selectors } = require('../../utils/locators'); -When('I complete the Giftaid update form with valid details', async function () { - await this.commands.populateUpdateFormFields(this.page); -}); - Then('I should see the Giftaid declaration section', async function () { await expect(this.page.locator(selectors.giftAidClaimChoice.yes)).toBeVisible(); await expect(this.page.locator(selectors.giftAidClaimChoice.no)).toBeVisible(); diff --git a/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js b/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js index b621d445..4707f923 100644 --- a/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js +++ b/playwright-staging/tests/step-definitions/update/giftaidUpdateCommon.steps.js @@ -8,7 +8,7 @@ Given('I am on the Giftaid update page', async function () { }); When('I complete the Giftaid update form with valid details', async function () { - await this.commands.populateUpdateFormFields(this.page); + await this.commands.populateUpdateFormFields(); }); When('I submit the Giftaid update form', async function () { diff --git a/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js index 42405dcd..a32fc896 100644 --- a/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js +++ b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js @@ -1,19 +1,10 @@ -const { Given, When, Then } = require('@cucumber/cucumber'); +const { When, Then } = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); const Chance = require('chance'); const { selectors } = require('../../utils/locators'); const chance = new Chance(); -Given('I am on the Giftaid update page', async function () { - await this.page.goto(`${process.env.BASE_URL}update`, { timeout: 30000 }); - await this.page.waitForLoadState('domcontentloaded'); -}); - -When('I submit the Giftaid update form', async function () { - await this.page.click(selectors.formFields.submitButton); -}); - Then('I should see the required update form error messages', async function () { await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText('Please fill in your first name'); await expect(this.page.locator(selectors.errorMessages.lastName)).toHaveText('Please fill in your last name'); @@ -29,10 +20,6 @@ When('I enter the update first name {string}', async function (firstName) { await this.page.keyboard.press('Enter'); }); -Then('I should see the update first name error message {string}', async function (message) { - await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText(message); -}); - When('I complete the Giftaid update form with first name {string}', async function (firstName) { await this.page.fill(selectors.formFields.firstName, ''); await this.commands.populateUpdateFormFields(this.page, { firstName }); @@ -46,11 +33,6 @@ When('I select no for the GiftAid declaration', async function () { await this.page.click(selectors.giftAidClaimChoice.no); }); -Then('I should see the update thank you message for {string}', async function (firstName) { - await expect( - this.page.locator(selectors.success.heading)).toHaveText(`Thank you, ${firstName}!`); -}); - When('I enter the update email {string}', async function (email) { await this.page.fill(selectors.marketingPreferences.fields.email, ''); await this.page.fill(selectors.marketingPreferences.fields.email, email); @@ -65,12 +47,7 @@ Then('I should see the update email error message {string}', async function (mes When('I complete the Giftaid update form with the email', async function () { const validEmail = `giftaid-update-staging-${chance.email()}`; await this.page.fill(selectors.marketingPreferences.fields.email, ''); - await this.commands.populateUpdateFormFields(this.page, { email: validEmail }); -}); - -Then('I should see the update no declaration message', async function () { - await expect( - this.page.locator(selectors.success.heading)).toHaveText('Thanks for letting us know'); + await this.commands.populateUpdateFormFields({ email: validEmail }); }); When('I enter the update mobile number {string}', async function (mobile) { @@ -92,17 +69,7 @@ When('I complete the Giftaid update form with the mobile and last name {string}' const mobile = `${prefix}${chance.string({ pool: '0123456789', length: 8 })}`; await this.page.locator(selectors.formFields.mobile).fill(''); - await this.commands.populateUpdateFormFields(this.page, { lastName, mobile }); -}); - -When('I enter the update postcode {string}', async function (postcode) { - await this.page.fill(selectors.formFields.postcode, ''); - await this.page.type(selectors.formFields.postcode, postcode); -}); - -Then('I should see the update postcode error message {string}', async function (message) { - await expect(this.page.locator(selectors.errorMessages.postcode)).toBeVisible(); - await expect(this.page.locator(selectors.errorMessages.postcode)).toHaveText(message); + await this.commands.populateUpdateFormFields({ lastName, mobile }); }); When('I search for the update postcode', async function () { diff --git a/playwright-staging/tests/step-definitions/update/updateSuccessRedirect.steps.js b/playwright-staging/tests/step-definitions/update/updateSuccessRedirect.steps.js index e118322b..a40ec447 100644 --- a/playwright-staging/tests/step-definitions/update/updateSuccessRedirect.steps.js +++ b/playwright-staging/tests/step-definitions/update/updateSuccessRedirect.steps.js @@ -1,6 +1,4 @@ -const { Given, Then } = require('@cucumber/cucumber'); -const { expect } = require('@playwright/test'); -const { selectors } = require('../../utils/locators'); +const { Given } = require('@cucumber/cucumber'); Given('I navigate to the Giftaid update success page', async function () { // Navigate to the success page of the Giftaid update directly diff --git a/playwright-staging/tests/support/hooks.js b/playwright-staging/tests/support/hooks.js index fdba1c67..561cccce 100644 --- a/playwright-staging/tests/support/hooks.js +++ b/playwright-staging/tests/support/hooks.js @@ -2,7 +2,7 @@ require('dotenv').config(); const { Before, After, Status, setDefaultTimeout } = require('@cucumber/cucumber'); const { chromium } = require('@playwright/test'); -const { Commands } = require('../utils/commands'); +const Commands = require('../utils/commands'); setDefaultTimeout(300 * 1000); // 5 mins @@ -56,6 +56,7 @@ Before(async function (scenario) { bounds: { windowState: 'maximized' }, }); + /** @type {Commands} */ this.commands = new Commands(this.page); }); diff --git a/playwright-staging/tests/utils/commands.js b/playwright-staging/tests/utils/commands.js index 4d651a42..d1f5a53b 100644 --- a/playwright-staging/tests/utils/commands.js +++ b/playwright-staging/tests/utils/commands.js @@ -15,11 +15,10 @@ class Commands { } /** - * Populate giftaid from fields - * @param page - Playwright page object. + * Populate giftaid form fields * @param userData - Optional user data for form filling. */ - async populateFormFields(page, { + async populateFormFields({ mobile = chance.phone({ country: 'uk', mobile: true }).replace(/\s/g, ''), // Remove spaces from the phone number firstName = 'test', lastName = chance.last(), @@ -29,41 +28,39 @@ class Commands { address3 = 'test address 3', town = chance.city(), } = {}) { - await page.locator('#field-input--mobile').type(mobile); - await page.locator('input#field-input--firstname').type(firstName); - await page.locator('input#field-input--lastname').type(lastName); - await page.locator('input#field-input--postcode').type(postcode); - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await page.locator('input#field-input--address1').type(address1); - await page.locator('input#field-input--address2').type(address2); - await page.locator('input#field-input--address3').type(address3); - await page.locator('input#field-input--town').type(town); + await this.page.locator('#field-input--mobile').fill(mobile); + await this.page.locator('input#field-input--firstname').fill(firstName); + await this.page.locator('input#field-input--lastname').fill(lastName); + await this.page.locator('input#field-input--postcode').fill(postcode); + await this.page.locator('a[aria-describedby=field-error--addressDetails]').click(); + await this.page.locator('input#field-input--address1').fill(address1); + await this.page.locator('input#field-input--address2').fill(address2); + await this.page.locator('input#field-input--address3').fill(address3); + await this.page.locator('input#field-input--town').fill(town); } /** * Select marketing preferences opt ins - * @param page - Playwright page object. * @param options - Optional marketing preferences. */ - async selectMarketingPrefs(page, { + async selectMarketingPrefs({ email = `giftaid-staging-${Date.now()}@email.sls.comicrelief.com`, phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, '') } = {}) { - await page.locator('#field-wrapper--Email > div').click(); - await page.locator('input#field-input--email').fill(email); + await this.page.locator('#field-wrapper--Email > div').click(); + await this.page.locator('input#field-input--email').fill(email); - await page.locator('#field-wrapper--Phone > div').click(); - await page.locator('input#field-input--phone').fill(phone); + await this.page.locator('#field-wrapper--Phone > div').click(); + await this.page.locator('input#field-input--phone').fill(phone); - await page.locator('input#field-label--Text--SMS').check({ force: true }); + await this.page.locator('input#field-label--Text--SMS').check({ force: true }); } /** - * Populate giftaid update from fields - * @param page - Playwright page object. + * Populate giftaid update form fields * @param userData - Optional user data for form filling. */ - async populateUpdateFormFields(page, { + async populateUpdateFormFields({ firstName = 'test', lastName = chance.last(), email = `giftaid-update-staging-${chance.email()}`, @@ -74,17 +71,17 @@ class Commands { address3 = 'test address 3', town = chance.city(), } = {}) { - await page.locator('input#field-input--firstname').fill(firstName); - await page.locator('input#field-input--lastname').fill(lastName); - await page.locator('input#field-input--postcode').fill(postcode); - await page.locator('input#field-input--email').fill(email); - await page.locator('#field-input--mobile').fill(mobile); - await page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await page.locator('input#field-input--address1').fill(address1); - await page.locator('input#field-input--address2').fill(address2); - await page.locator('input#field-input--address3').fill(address3); - await page.locator('input#field-input--town').fill(town); + await this.page.locator('input#field-input--firstname').fill(firstName); + await this.page.locator('input#field-input--lastname').fill(lastName); + await this.page.locator('input#field-input--postcode').fill(postcode); + await this.page.locator('input#field-input--email').fill(email); + await this.page.locator('#field-input--mobile').fill(mobile); + await this.page.locator('a[aria-describedby=field-error--addressDetails]').click(); + await this.page.locator('input#field-input--address1').fill(address1); + await this.page.locator('input#field-input--address2').fill(address2); + await this.page.locator('input#field-input--address3').fill(address3); + await this.page.locator('input#field-input--town').fill(town); } } -module.exports = { Commands }; +module.exports = Commands; From f0a2b5c0336e3766acfee29638314be307ee7a4e Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 14 May 2026 16:00:41 +0100 Subject: [PATCH 17/35] test: fix campaign code from RND26 to SR26 --- .../step-definitions/submit/marketingPreferencesData.steps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js index 0adae59a..2d0b44c3 100644 --- a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js @@ -44,7 +44,7 @@ Then('the marketing preferences data should be stored in the contact-store', asy // Retrieve and verify marketing preferences data const mpData = await MarketingPrefsVerify.get(this.supporter.email); - expect(mpData.campaign).toEqual('RND26'); + expect(mpData.campaign).toEqual('SR26'); expect(mpData.firstname).toEqual(this.supporter.firstName); expect(mpData.lastname).toEqual(this.supporter.lastName); expect(mpData.email).toEqual(this.supporter.email); From 4769a96ec17129c9c1ac4735653712b82ec1a408 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 14 May 2026 16:13:54 +0100 Subject: [PATCH 18/35] test: remove nightly-sanity tag --- playwright-staging/browserstack.js | 92 ------------------- .../features/submit/addressValidation.feature | 2 +- .../features/submit/formValidation.feature | 2 +- .../internationalAddressesValidation.feature | 2 +- .../submit/marketingPreferencesData.feature | 2 +- .../marketingPreferencesValidation.feature | 2 +- .../features/submit/postcodeLookup.feature | 2 +- .../tests/features/submit/sorry.feature | 2 +- .../features/submit/successRedirect.feature | 2 +- .../submit/validGifaidSubmission.feature | 2 +- .../features/update/formValidation.feature | 2 +- .../update/giftaidDeclarationOptions.feature | 2 +- .../internationalAddressesValidation.feature | 2 +- .../tests/features/update/updateSorry.feature | 2 +- .../update/updateSuccessRedirect.feature | 2 +- .../update/validFormSubmission.feature | 2 +- 16 files changed, 15 insertions(+), 107 deletions(-) delete mode 100644 playwright-staging/browserstack.js diff --git a/playwright-staging/browserstack.js b/playwright-staging/browserstack.js deleted file mode 100644 index 04725a9e..00000000 --- a/playwright-staging/browserstack.js +++ /dev/null @@ -1,92 +0,0 @@ -require('dotenv').config(); - -const base = require('@playwright/test'); -const clientPlaywrightVersion = require('@playwright/test/package.json').version; // "1.56.1" - -// BrowserStack Specific Capabilities. -const caps = { - project: 'giftaid-react', - name: 'e2e tests', - browser: 'chrome', - browser_version: 'latest', - resolution: '1920x1080', - os: 'Windows', - os_version: '11', - 'browserstack.username': process.env.BROWSERSTACK_USERNAME, - 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, - 'client.playwrightVersion': clientPlaywrightVersion, - 'browserstack.playwrightVersion': clientPlaywrightVersion, - - // logs - 'browserstack.networkLogs': true, - 'browserstack.console': 'info', - 'browserstack.debug': true, - 'browserstack.idleTimeout': 300, -}; - -// Patching the capabilities dynamically according to the project name. -const patchCaps = (name, title) => { - const combination = name.split(/@browserstack/)[0]; - const [browserCaps, rawOsCaps] = combination.split(':'); - let [browser, browser_version] = (browserCaps || '').split('@'); - - browser = (browser || 'chrome').toLowerCase(); - if (browser === 'chromium') browser = 'chrome'; - - const osCaps = (rawOsCaps || '').trim(); - const osTokens = osCaps ? osCaps.split(/\s+/) : []; - const os = osTokens.shift() || 'Windows'; - const os_version = osTokens.join(' ') || '11'; - - caps.browser = browser; - caps.browser_version = browser_version || 'latest'; - caps.os = os; - caps.os_version = os_version; - caps.name = title; -}; - -const isHash = (entity) => Boolean(entity && typeof(entity) === "object" && !Array.isArray(entity)); -const nestedKeyValue = (hash, keys) => keys.reduce((hash, key) => (isHash(hash) ? hash[key] : undefined), hash); -const isUndefined = val => (val === undefined || val === null || val === ''); -const evaluateSessionStatus = (status) => { - if (!isUndefined(status)) { - status = status.toLowerCase(); - } - if (status === "passed") { - return "passed"; - } else if (status === "failed" || status === "timedout") { - return "failed"; - } else { - return ""; - } -} - -exports.test = base.test.extend({ - page: async ({ page, playwright }, use, testInfo) => { - // Use BrowserStack Launched Browser according to capabilities for cross-browser testing. - if (testInfo.project.name.match(/browserstack/)) { - patchCaps(testInfo.project.name,`${testInfo.title}`); - const vBrowser = await playwright.chromium.connect({ - wsEndpoint: - `wss://cdp.browserstack.com/playwright?caps=` + - `${encodeURIComponent(JSON.stringify(caps))}`, - }); - const vContext = await vBrowser.newContext(testInfo.project.use); - const vPage = await vContext.newPage(); - await use(vPage); - const testResult = { - action: 'setSessionStatus', - arguments: { - status: evaluateSessionStatus(testInfo.status), - reason: nestedKeyValue(testInfo, ['error', 'message']) - }, - }; - await vPage.evaluate(() => {}, - `browserstack_executor: ${JSON.stringify(testResult)}`); - await vPage.close(); - await vBrowser.close(); - } else { - use(page); - } - }, -}); diff --git a/playwright-staging/tests/features/submit/addressValidation.feature b/playwright-staging/tests/features/submit/addressValidation.feature index 458972e2..1a0f4233 100644 --- a/playwright-staging/tests/features/submit/addressValidation.feature +++ b/playwright-staging/tests/features/submit/addressValidation.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @address-validation +@sanity @address-validation Feature: Address validation Background: diff --git a/playwright-staging/tests/features/submit/formValidation.feature b/playwright-staging/tests/features/submit/formValidation.feature index f8e48dc5..860671d3 100644 --- a/playwright-staging/tests/features/submit/formValidation.feature +++ b/playwright-staging/tests/features/submit/formValidation.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @form-validation +@sanity @form-validation Feature: Giftaid form validation Background: diff --git a/playwright-staging/tests/features/submit/internationalAddressesValidation.feature b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature index cf620bb3..ab352e38 100644 --- a/playwright-staging/tests/features/submit/internationalAddressesValidation.feature +++ b/playwright-staging/tests/features/submit/internationalAddressesValidation.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @international +@sanity @international Feature: International address validation Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the form diff --git a/playwright-staging/tests/features/submit/marketingPreferencesData.feature b/playwright-staging/tests/features/submit/marketingPreferencesData.feature index 5e836549..84134e89 100644 --- a/playwright-staging/tests/features/submit/marketingPreferencesData.feature +++ b/playwright-staging/tests/features/submit/marketingPreferencesData.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @marketing-preferences-data +@sanity @marketing-preferences-data Feature: Giftaid marketing preferences contact-store verification Scenario: Verify giftaid marketing preferences data in contact-store diff --git a/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature b/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature index f98da6d4..4fd6c5e5 100644 --- a/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature +++ b/playwright-staging/tests/features/submit/marketingPreferencesValidation.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @marketing-preferences +@sanity @marketing-preferences Feature: Marketing preferences validation Background: diff --git a/playwright-staging/tests/features/submit/postcodeLookup.feature b/playwright-staging/tests/features/submit/postcodeLookup.feature index ffb7b8d9..949c9afc 100644 --- a/playwright-staging/tests/features/submit/postcodeLookup.feature +++ b/playwright-staging/tests/features/submit/postcodeLookup.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @postcode +@sanity @postcode Feature: Postcode validation Background: diff --git a/playwright-staging/tests/features/submit/sorry.feature b/playwright-staging/tests/features/submit/sorry.feature index c3c04fe1..7dac52a6 100644 --- a/playwright-staging/tests/features/submit/sorry.feature +++ b/playwright-staging/tests/features/submit/sorry.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @sorry +@sanity @sorry Feature: Giftaid sorry page Scenario: Accessing giftaid sorry page should show the sorry message diff --git a/playwright-staging/tests/features/submit/successRedirect.feature b/playwright-staging/tests/features/submit/successRedirect.feature index 07c87692..d8a6ced0 100644 --- a/playwright-staging/tests/features/submit/successRedirect.feature +++ b/playwright-staging/tests/features/submit/successRedirect.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @successRedirect +@sanity @successRedirect Feature: Giftaid success page redirect Scenario: Accessing success page should redirect to giftaid homepage diff --git a/playwright-staging/tests/features/submit/validGifaidSubmission.feature b/playwright-staging/tests/features/submit/validGifaidSubmission.feature index 1b7c15cd..f5ac6c4e 100644 --- a/playwright-staging/tests/features/submit/validGifaidSubmission.feature +++ b/playwright-staging/tests/features/submit/validGifaidSubmission.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @validSubmission +@sanity @validSubmission Feature: Valid Giftaid submission Scenario: Valid Giftaid submission diff --git a/playwright-staging/tests/features/update/formValidation.feature b/playwright-staging/tests/features/update/formValidation.feature index fba73bf5..d13d43c3 100644 --- a/playwright-staging/tests/features/update/formValidation.feature +++ b/playwright-staging/tests/features/update/formValidation.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @update-form-validation +@sanity @update-form-validation Feature: Giftaid update form validation Background: diff --git a/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature b/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature index 6d804b53..30012122 100644 --- a/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature +++ b/playwright-staging/tests/features/update/giftaidDeclarationOptions.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @update-declaration +@sanity @update-declaration Feature: Giftaid declaration claim selection Scenario: Validate Giftaid declaration claim selections diff --git a/playwright-staging/tests/features/update/internationalAddressesValidation.feature b/playwright-staging/tests/features/update/internationalAddressesValidation.feature index 3dc60eb4..de710a6b 100644 --- a/playwright-staging/tests/features/update/internationalAddressesValidation.feature +++ b/playwright-staging/tests/features/update/internationalAddressesValidation.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @update-international-address +@sanity @update-international-address Feature: International address validation on update form Scenario: Selecting a non-UK country and entering a non-UK postcode should submit the update form diff --git a/playwright-staging/tests/features/update/updateSorry.feature b/playwright-staging/tests/features/update/updateSorry.feature index dc438481..23864263 100644 --- a/playwright-staging/tests/features/update/updateSorry.feature +++ b/playwright-staging/tests/features/update/updateSorry.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @update-sorry +@sanity @update-sorry Feature: Giftaid update sorry page Scenario: Accessing giftaid update sorry page should show the sorry message diff --git a/playwright-staging/tests/features/update/updateSuccessRedirect.feature b/playwright-staging/tests/features/update/updateSuccessRedirect.feature index a65427c6..0b04b0ce 100644 --- a/playwright-staging/tests/features/update/updateSuccessRedirect.feature +++ b/playwright-staging/tests/features/update/updateSuccessRedirect.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @update-success-redirect +@sanity @update-success-redirect Feature: Giftaid update success page redirect Scenario: Accessing success page should redirect to giftaid update homepage diff --git a/playwright-staging/tests/features/update/validFormSubmission.feature b/playwright-staging/tests/features/update/validFormSubmission.feature index 2637302b..c0210323 100644 --- a/playwright-staging/tests/features/update/validFormSubmission.feature +++ b/playwright-staging/tests/features/update/validFormSubmission.feature @@ -1,4 +1,4 @@ -@sanity @nightly-sanity @update-valid-submission +@sanity @update-valid-submission Feature: Valid Giftaid update submission # Step definitions for this feature are implemented in: From bbb00de7b74f4983055524be48d70b5791f62ba3 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 14 May 2026 16:38:36 +0100 Subject: [PATCH 19/35] use consistent kebab casing --- .../tests/features/submit/successRedirect.feature | 2 +- .../tests/features/submit/validGifaidSubmission.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/playwright-staging/tests/features/submit/successRedirect.feature b/playwright-staging/tests/features/submit/successRedirect.feature index d8a6ced0..a0a1398d 100644 --- a/playwright-staging/tests/features/submit/successRedirect.feature +++ b/playwright-staging/tests/features/submit/successRedirect.feature @@ -1,4 +1,4 @@ -@sanity @successRedirect +@sanity @success-redirect Feature: Giftaid success page redirect Scenario: Accessing success page should redirect to giftaid homepage diff --git a/playwright-staging/tests/features/submit/validGifaidSubmission.feature b/playwright-staging/tests/features/submit/validGifaidSubmission.feature index f5ac6c4e..7963e66c 100644 --- a/playwright-staging/tests/features/submit/validGifaidSubmission.feature +++ b/playwright-staging/tests/features/submit/validGifaidSubmission.feature @@ -1,4 +1,4 @@ -@sanity @validSubmission +@sanity @valid-submission Feature: Valid Giftaid submission Scenario: Valid Giftaid submission From 06a398acd4c8b34d33aa4f3f67f91d0f191f1086 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 14 May 2026 16:52:08 +0100 Subject: [PATCH 20/35] config: add playwright equivalent timeouts in cucumber config --- playwright-staging/tests/support/hooks.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/playwright-staging/tests/support/hooks.js b/playwright-staging/tests/support/hooks.js index 561cccce..d2d7fbba 100644 --- a/playwright-staging/tests/support/hooks.js +++ b/playwright-staging/tests/support/hooks.js @@ -48,6 +48,12 @@ Before(async function (scenario) { this.page = await this.context.newPage(); + // Keep default Playwright action/assertion timeout consistent across Cucumber tests + this.page.setDefaultTimeout(30000); + + // Increase navigation timeout for slower redirects/page loads on BrowserStack + this.page.setDefaultNavigationTimeout(45000); + // Maximise browser window const session = await this.context.newCDPSession(this.page); const { windowId } = await session.send('Browser.getWindowForTarget'); From 051336b1b50e25a36e12ba1c9cf7a47d04a67c38 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 14 May 2026 16:57:37 +0100 Subject: [PATCH 21/35] move browserstack capabilities into cucumber config --- playwright-staging/config/browserstack.js | 26 ++++++++++++++++++++++ playwright-staging/tests/support/hooks.js | 27 +---------------------- 2 files changed, 27 insertions(+), 26 deletions(-) create mode 100644 playwright-staging/config/browserstack.js diff --git a/playwright-staging/config/browserstack.js b/playwright-staging/config/browserstack.js new file mode 100644 index 00000000..8f629823 --- /dev/null +++ b/playwright-staging/config/browserstack.js @@ -0,0 +1,26 @@ +// Get Playwright version to match BrowserStack runtime +const clientPlaywrightVersion = require('@playwright/test/package.json').version; + +const caps = { + project: 'giftaid-react', + name: 'e2e tests', + browser: 'chrome', + browser_version: 'latest', + resolution: '1920x1080', + os: 'Windows', + os_version: '11', + 'browserstack.username': process.env.BROWSERSTACK_USERNAME, + 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, + + // Match BrowserStack Playwright version with local version + 'client.playwrightVersion': clientPlaywrightVersion, + 'browserstack.playwrightVersion': clientPlaywrightVersion, + + // BrowserStack logs/debugging + 'browserstack.networkLogs': true, + 'browserstack.console': 'info', + 'browserstack.debug': true, + 'browserstack.idleTimeout': 300, +}; + +module.exports = caps; diff --git a/playwright-staging/tests/support/hooks.js b/playwright-staging/tests/support/hooks.js index d2d7fbba..72796d4e 100644 --- a/playwright-staging/tests/support/hooks.js +++ b/playwright-staging/tests/support/hooks.js @@ -1,36 +1,11 @@ require('dotenv').config(); - +const caps = require('../../config/browserstack'); const { Before, After, Status, setDefaultTimeout } = require('@cucumber/cucumber'); const { chromium } = require('@playwright/test'); const Commands = require('../utils/commands'); setDefaultTimeout(300 * 1000); // 5 mins -// Get Playwright version to match BrowserStack runtime -const clientPlaywrightVersion = require('@playwright/test/package.json').version; - -// BrowserStack capabilities -const caps = { - project: 'giftaid-react', - name: 'e2e tests', - browser: 'chrome', - browser_version: 'latest', - resolution: '1920x1080', - os: 'Windows', - os_version: '11', - 'browserstack.username': process.env.BROWSERSTACK_USERNAME, - 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, - // Ensure BrowserStack Playwright version matches local version - 'client.playwrightVersion': clientPlaywrightVersion, - 'browserstack.playwrightVersion': clientPlaywrightVersion, - - // logs - 'browserstack.networkLogs': true, - 'browserstack.console': 'info', - 'browserstack.debug': true, - 'browserstack.idleTimeout': 300, -}; - // Runs before each scenario Before(async function (scenario) { // Set BrowserStack session name to scenario name (helps to see in BS dashboard) From b3125f6b74eff7ade0a04a0d5d672724824de695 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Thu, 14 May 2026 17:14:43 +0100 Subject: [PATCH 22/35] keep the test script as before --- playwright-staging/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/playwright-staging/package.json b/playwright-staging/package.json index ac585018..b5f75c57 100644 --- a/playwright-staging/package.json +++ b/playwright-staging/package.json @@ -17,8 +17,6 @@ "uuid": "8.3.2" }, "scripts": { - "test:sanity": "FORCE_COLOR=1 playwright test --grep '@sanity'", - "test:cucumber": "FORCE_COLOR=1 cucumber-js --config config/cucumber.js", - "test:cucumber:sanity": "FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'" + "test:sanity": "FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'" } } From 1968a49de3ff36642d390de75c9b92c3b518f338 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 19 May 2026 12:28:54 +0100 Subject: [PATCH 23/35] test: add default navigation timeout --- playwright-local/tests/support/hooks.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/playwright-local/tests/support/hooks.js b/playwright-local/tests/support/hooks.js index 132e13eb..80ffe41f 100644 --- a/playwright-local/tests/support/hooks.js +++ b/playwright-local/tests/support/hooks.js @@ -36,6 +36,10 @@ Before(async function () { ); this.page = await this.context.newPage(); + + // Increase navigation timeout for slower redirects/page loads + this.page.setDefaultNavigationTimeout(45000); + this.commands = new Commands(this.page); }); From 7637a840cb8a51b656ae58223fb63032fef93fe0 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 19 May 2026 12:51:55 +0100 Subject: [PATCH 24/35] downgrade cucumber version to 8.9.1 to support node 16 --- playwright-staging/package.json | 2 +- playwright-staging/yarn.lock | 707 ++++++++++++++++---------------- 2 files changed, 349 insertions(+), 360 deletions(-) diff --git a/playwright-staging/package.json b/playwright-staging/package.json index b5f75c57..7573fff9 100644 --- a/playwright-staging/package.json +++ b/playwright-staging/package.json @@ -8,7 +8,7 @@ "devDependencies": { "@comicrelief/data-models": "^1.29.6", "@comicrelief/test-utils": "^1.5.15", - "@cucumber/cucumber": "^12.8.2", + "@cucumber/cucumber": "8.9.1", "@playwright/test": "1.56.1", "axios": "^0.21.1", "chance": "^1.1.7", diff --git a/playwright-staging/yarn.lock b/playwright-staging/yarn.lock index 1aae373d..c9132af3 100644 --- a/playwright-staging/yarn.lock +++ b/playwright-staging/yarn.lock @@ -2,20 +2,6 @@ # yarn lockfile v1 -"@babel/code-frame@^7.26.2": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" - integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== - dependencies: - "@babel/helper-validator-identifier" "^7.28.5" - js-tokens "^4.0.0" - picocolors "^1.1.1" - -"@babel/helper-validator-identifier@^7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" - integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== - "@babel/runtime@^7.10.5": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" @@ -23,6 +9,11 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.15.4": + version "7.29.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.2.tgz#9a6e2d05f4b6692e1801cd4fb176ad823930ed5e" + integrity sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g== + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -43,43 +34,43 @@ resolved "https://registry.yarnpkg.com/@comicrelief/test-utils/-/test-utils-1.5.15.tgz#48ee30ccfa44d220dabce8dd7e9bb43c8e043814" integrity sha512-XsShlQcGzHDv6FVlJLvWGDPdY4mgqFNWdw+dXlGFXCCiC2WCpVQzVdzdInOTfvCZZXLAHDTT+RaF+RZlj3VVRQ== -"@cucumber/ci-environment@13.0.0": - version "13.0.0" - resolved "https://registry.yarnpkg.com/@cucumber/ci-environment/-/ci-environment-13.0.0.tgz#0a9c4e279814af864cd1591c4c16f284e14af39b" - integrity sha512-cs+3NzfNkGbcmHPddjEv4TKFiBpZRQ6WJEEufB9mw+ExS22V/4R/zpDSEG+fsJ/iSNCd6A2sATdY8PFOyY3YnA== +"@cucumber/ci-environment@9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/ci-environment/-/ci-environment-9.1.0.tgz#6d868141c7cfd616931f14723e122a1069401998" + integrity sha512-jdnF6APXP3GawMue8kdMxhu6TBhyRUO4KDRxTowf06NtclLjIw2Ybpo9IcIOMvE8kHukvJyM00uxWX+CfS7JgQ== -"@cucumber/cucumber-expressions@19.0.0": - version "19.0.0" - resolved "https://registry.yarnpkg.com/@cucumber/cucumber-expressions/-/cucumber-expressions-19.0.0.tgz#562c932b1e6808485e4a45bf9cbcc93cdc3b1d45" - integrity sha512-4FKoOQh2Uf6F6/Ln+1OxuK8LkTg6PyAqekhf2Ix8zqV2M54sH+m7XNJNLhOFOAW/t9nxzRbw2CcvXbCLjcvHZg== +"@cucumber/cucumber-expressions@16.1.0": + version "16.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber-expressions/-/cucumber-expressions-16.1.0.tgz#2a2538b775e83b84a275ea10f618242717937968" + integrity sha512-Q/tKDNje9RrcOXF2TO2NwTW92rzk+RwKkhYYKLxQT26Co8Qbjom0Cz02HsCMA2wjJ8dw6/d2IbWgiOay9RQA+w== dependencies: regexp-match-indices "1.0.2" -"@cucumber/cucumber@^12.8.2": - version "12.8.2" - resolved "https://registry.yarnpkg.com/@cucumber/cucumber/-/cucumber-12.8.2.tgz#6f8ffbfdd5b135ce6625b8047c461721dc0cb4ec" - integrity sha512-IvprstODr0JYTtVG7CQbphN6AGRpzzAQ1EjG7TSumuS15uvVt0inWm8/9uzX8oJwEv5ReU7JruDFim4938omog== - dependencies: - "@cucumber/ci-environment" "13.0.0" - "@cucumber/cucumber-expressions" "19.0.0" - "@cucumber/gherkin" "38.0.0" - "@cucumber/gherkin-streams" "6.0.0" - "@cucumber/gherkin-utils" "11.0.0" - "@cucumber/html-formatter" "23.1.0" - "@cucumber/junit-xml-formatter" "0.13.3" - "@cucumber/message-streams" "4.1.1" - "@cucumber/messages" "32.3.1" - "@cucumber/pretty-formatter" "1.0.1" - "@cucumber/tag-expressions" "9.1.0" +"@cucumber/cucumber@8.9.1": + version "8.9.1" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber/-/cucumber-8.9.1.tgz#6b3bb74e5811d69aee85eaac0298218cb38ab6c7" + integrity sha512-Ir0yloCGu25mnllHunOAaOVXIKrRSE0ICF1FleoJzeupgYWK/x8o6hjOGRJf1Ui17GoRs1CfkP44/K29lmpMtA== + dependencies: + "@cucumber/ci-environment" "9.1.0" + "@cucumber/cucumber-expressions" "16.1.0" + "@cucumber/gherkin" "25.0.2" + "@cucumber/gherkin-streams" "5.0.1" + "@cucumber/gherkin-utils" "8.0.2" + "@cucumber/html-formatter" "20.2.0" + "@cucumber/message-streams" "4.0.1" + "@cucumber/messages" "20.0.0" + "@cucumber/tag-expressions" "4.1.0" assertion-error-formatter "^3.0.0" capital-case "^1.0.4" chalk "^4.1.2" - cli-table3 "0.6.5" - commander "^14.0.0" + cli-table3 "0.6.3" + commander "^9.0.0" debug "^4.3.4" + duration "^0.2.2" + durations "^3.4.2" error-stack-parser "^2.1.4" figures "^3.2.0" - glob "^13.0.0" + glob "^7.1.6" has-ansi "^4.0.1" indent-string "^4.0.0" is-installed-globally "^0.4.0" @@ -87,97 +78,79 @@ knuth-shuffle-seeded "^1.0.6" lodash.merge "^4.6.2" lodash.mergewith "^4.6.2" - luxon "3.7.2" - mkdirp "^3.0.0" mz "^2.7.0" progress "^2.0.3" - read-package-up "^12.0.0" - semver "7.7.4" - string-argv "0.3.1" + resolve-pkg "^2.0.0" + semver "7.3.8" + string-argv "^0.3.1" + strip-ansi "6.0.1" supports-color "^8.1.1" - type-fest "^4.41.0" + tmp "^0.2.1" util-arity "^1.1.0" - yaml "^2.2.2" - yup "1.7.1" + verror "^1.10.0" + xmlbuilder "^15.1.1" + yup "^0.32.11" -"@cucumber/gherkin-streams@6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@cucumber/gherkin-streams/-/gherkin-streams-6.0.0.tgz#51e78a333439c6ed3d9e731d69ad3729a749028a" - integrity sha512-HLSHMmdDH0vCr7vsVEURcDA4WwnRLdjkhqr6a4HQ3i4RFK1wiDGPjBGVdGJLyuXuRdJpJbFc6QxHvT8pU4t6jw== +"@cucumber/gherkin-streams@5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin-streams/-/gherkin-streams-5.0.1.tgz#8c2142d295cd05644456be7282b4bd756c95c4cd" + integrity sha512-/7VkIE/ASxIP/jd4Crlp4JHXqdNFxPGQokqWqsaCCiqBiu5qHoKMxcWNlp9njVL/n9yN4S08OmY3ZR8uC5x74Q== dependencies: - commander "14.0.0" + commander "9.1.0" source-map-support "0.5.21" -"@cucumber/gherkin-utils@11.0.0": - version "11.0.0" - resolved "https://registry.yarnpkg.com/@cucumber/gherkin-utils/-/gherkin-utils-11.0.0.tgz#167afa559978cf6fbe2b583d3d5f9e7c4741c28a" - integrity sha512-LJ+s4+TepHTgdKWDR4zbPyT7rQjmYIcukTwNbwNwgqr6i8Gjcmzf6NmtbYDA19m1ZFg6kWbFsmHnj37ZuX+kZA== +"@cucumber/gherkin-utils@8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin-utils/-/gherkin-utils-8.0.2.tgz#deae231f84e91f120501d22187c66d36e6c6b59f" + integrity sha512-aQlziN3r3cTwprEDbLEcFoMRQajb9DTOu2OZZp5xkuNz6bjSTowSY90lHUD2pWT7jhEEckZRIREnk7MAwC2d1A== dependencies: - "@cucumber/gherkin" "^38.0.0" - "@cucumber/messages" "^32.0.0" - "@teppeis/multimaps" "3.0.0" - commander "14.0.2" + "@cucumber/gherkin" "^25.0.0" + "@cucumber/messages" "^19.1.4" + "@teppeis/multimaps" "2.0.0" + commander "9.4.1" source-map-support "^0.5.21" -"@cucumber/gherkin@38.0.0", "@cucumber/gherkin@^38.0.0": - version "38.0.0" - resolved "https://registry.yarnpkg.com/@cucumber/gherkin/-/gherkin-38.0.0.tgz#6c74388f95694e4c92762aeddf3d5638dbedf540" - integrity sha512-duEXK+KDfQUzu3vsSzXjkxQ2tirF5PRsc1Xrts6THKHJO6mjw4RjM8RV+vliuDasmhhrmdLcOcM7d9nurNTJKw== +"@cucumber/gherkin@25.0.2", "@cucumber/gherkin@^25.0.0": + version "25.0.2" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin/-/gherkin-25.0.2.tgz#e430879f01978d1f9e7a7aa0563031a3a36022e7" + integrity sha512-EdsrR33Y5GjuOoe2Kq5Y9DYwgNRtUD32H4y2hCrT6+AWo7ibUQu7H+oiWTgfVhwbkHsZmksxHSxXz/AwqqyCRQ== dependencies: - "@cucumber/messages" ">=31.0.0 <33" + "@cucumber/messages" "^19.1.4" -"@cucumber/html-formatter@23.1.0": - version "23.1.0" - resolved "https://registry.yarnpkg.com/@cucumber/html-formatter/-/html-formatter-23.1.0.tgz#6b9f759f9d50355b0cb28edde3ad3580d91f7081" - integrity sha512-DcCSFoGs6jbwzXPgX1CwgJKEE+ZMcIEzq/0Memg0o24maNn9NJizBFHmoFWG4iv/OxHza+mvc+56cTHetfHndw== +"@cucumber/html-formatter@20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@cucumber/html-formatter/-/html-formatter-20.2.0.tgz#20857efec721fbc5d64cc31b0107575db1e58651" + integrity sha512-apcxS5Imeh3Wk4VMkuB3C4UQ+0/PVlNTkcWx9/5wwd+p3EnEbtvbZUhYIHgVBm+0FKEc22yrXBEc0N85fT/r4A== -"@cucumber/junit-xml-formatter@0.13.3": - version "0.13.3" - resolved "https://registry.yarnpkg.com/@cucumber/junit-xml-formatter/-/junit-xml-formatter-0.13.3.tgz#a6ee049caa4afe9160f1514b8c65f24a00e71f42" - integrity sha512-w9ujOxiuKDtU6fLzJz+wp4Sgp5Xu6ba7ls00LHJccVmQU0Ba7zs+AHnv3iIgPjKZAQe1w8x93dr8Gaubh7Vqkg== - dependencies: - "@cucumber/query" "^15.0.1" - "@teppeis/multimaps" "^3.0.0" - luxon "^3.5.0" - xmlbuilder "^15.1.1" - -"@cucumber/message-streams@4.1.1": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@cucumber/message-streams/-/message-streams-4.1.1.tgz#d3a271e6f6c90a52d731fb3554a56c4c6b456d17" - integrity sha512-QCAntLajesWMyX+mZKrj63YghVAts7yKFlZe46XprLbdJZN0ddB+f/Mr9OnyWKC2DHhJ18jzCfKIFCaqpAmUxg== - dependencies: - mime "^3.0.0" +"@cucumber/message-streams@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/message-streams/-/message-streams-4.0.1.tgz#a5339d3504594bb2edb5732aaae94dddb24d0970" + integrity sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA== -"@cucumber/messages@32.3.1", "@cucumber/messages@>=31.0.0 <33", "@cucumber/messages@^32.0.0": - version "32.3.1" - resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-32.3.1.tgz#8c6990554c35fb9bcff0b7f09fe52ddfd479dbce" - integrity sha512-yNQq1KoXRYaEKrWMFmpUQX7TdeQuU9jeGgJAZ3dArTsC/T4NpJ6DnqaJIIgwPnz/wtQIQTNX7/h0rOuF5xY4qQ== +"@cucumber/messages@20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-20.0.0.tgz#494d30bd2880b04dcb3a958f8c0ec5638b7b3596" + integrity sha512-JFrFwuhxsbig0afaViNhuzoQyC+GQzlI7m+rX+lSiDGV13K3sJzMmHjkbCiNOgoRlKAMwIGR9TRMH0xj9/My0w== dependencies: + "@types/uuid" "8.3.4" class-transformer "0.5.1" - reflect-metadata "0.2.2" - -"@cucumber/pretty-formatter@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@cucumber/pretty-formatter/-/pretty-formatter-1.0.1.tgz#65d6c1df436920036a7bd02d08cb44d20e7af0ab" - integrity sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ== - dependencies: - ansi-styles "^5.0.0" - cli-table3 "^0.6.0" - figures "^3.2.0" - ts-dedent "^2.0.0" + reflect-metadata "0.1.13" + uuid "9.0.0" -"@cucumber/query@^15.0.1": - version "15.0.1" - resolved "https://registry.yarnpkg.com/@cucumber/query/-/query-15.0.1.tgz#91b701121ba95caf7d0e6d9de95041ec3396d297" - integrity sha512-FMfT3orJblRsOxvU2doECBvQmauizYlj+5JsM8atAKKPbnQTj7v2/OrnuykvQpfZNBf19DYbRq1e832vllRP/g== +"@cucumber/messages@^19.1.4": + version "19.1.4" + resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-19.1.4.tgz#5cefc47cac3004c0bc38d42933042ec248bb747c" + integrity sha512-Pksl0pnDz2l1+L5Ug85NlG6LWrrklN9qkMxN5Mv+1XZ3T6u580dnE6mVaxjJRdcOq4tR17Pc0RqIDZMyVY1FlA== dependencies: - "@teppeis/multimaps" "3.0.0" - lodash.sortby "^4.7.0" + "@types/uuid" "8.3.4" + class-transformer "0.5.1" + reflect-metadata "0.1.13" + uuid "9.0.0" -"@cucumber/tag-expressions@9.1.0": - version "9.1.0" - resolved "https://registry.yarnpkg.com/@cucumber/tag-expressions/-/tag-expressions-9.1.0.tgz#5c63cf716b6d688f140d0e4c0cc858bfd5703618" - integrity sha512-bvHjcRFZ+J1TqIa9eFNO1wGHqwx4V9ZKV3hYgkuK/VahHx73uiP4rKV3JVrvWSMrwrFvJG6C8aEwnCWSvbyFdQ== +"@cucumber/tag-expressions@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/tag-expressions/-/tag-expressions-4.1.0.tgz#9a91b0e0dd2f2ba703e3038c52b49b9ac06c2c6f" + integrity sha512-chTnjxV3vryL75N90wJIMdMafXmZoO2JgNJLYpsfcALL2/IQrRiny3vM9DgD5RDCSt1LNloMtb7rGey9YWxCsA== "@jridgewell/gen-mapping@^0.3.0": version "0.3.2" @@ -226,15 +199,20 @@ dependencies: playwright "1.56.1" -"@teppeis/multimaps@3.0.0", "@teppeis/multimaps@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@teppeis/multimaps/-/multimaps-3.0.0.tgz#bb9c3f8d569f589e548586fa0bbf423010ddfdc5" - integrity sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q== +"@teppeis/multimaps@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@teppeis/multimaps/-/multimaps-2.0.0.tgz#2114ee964b702f9777d0e07899087ad9cd89a0de" + integrity sha512-TL1adzq1HdxUf9WYduLcQ/DNGYiz71U31QRgbnr0Ef1cPyOUOsBojxHVWpFeOSUucB6Lrs0LxFRA14ntgtkc9w== -"@types/normalize-package-data@^2.4.4": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" - integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== +"@types/lodash@^4.14.175": + version "4.17.24" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.24.tgz#4ae334fc62c0e915ca8ed8e35dcc6d4eeb29215f" + integrity sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ== + +"@types/uuid@8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== acorn@^8.5.0: version "8.8.2" @@ -265,11 +243,6 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -290,6 +263,11 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + assertion-error-formatter@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz#be9c8825dee6a8a6c72183d915912d9b57d5d265" @@ -311,17 +289,18 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" -balanced-match@^4.0.2: - version "4.0.4" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" - integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -brace-expansion@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" - integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== +brace-expansion@^1.1.7: + version "1.1.14" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.14.tgz#d9de602370d91347cd9ddad1224d4fd701eb348b" + integrity sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g== dependencies: - balanced-match "^4.0.2" + balanced-match "^1.0.0" + concat-map "0.0.1" buffer-from@^1.0.0: version "1.1.2" @@ -357,10 +336,10 @@ class-transformer@0.5.1: resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== -cli-table3@0.6.5, cli-table3@^0.6.0: - version "0.6.5" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" - integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== +cli-table3@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" + integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== dependencies: string-width "^4.2.0" optionalDependencies: @@ -402,31 +381,49 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -commander@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.0.tgz#f244fc74a92343514e56229f16ef5c5e22ced5e9" - integrity sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA== - -commander@14.0.2: - version "14.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.2.tgz#b71fd37fe4069e4c3c7c13925252ada4eba14e8e" - integrity sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ== +commander@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.1.0.tgz#a6b263b2327f2e188c6402c42623327909f2dbec" + integrity sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w== -commander@^14.0.0: - version "14.0.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.3.tgz#425d79b48f9af82fcd9e4fc1ea8af6c5ec07bbc2" - integrity sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw== +commander@9.4.1: + version "9.4.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" + integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw== commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +commander@^9.0.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +d@1, d@^1.0.1, d@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== + dependencies: + es5-ext "^0.10.64" + type "^2.7.2" + debug@^4.3.4: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" @@ -444,6 +441,19 @@ dotenv@^8.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== +duration@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/duration/-/duration-0.2.2.tgz#ddf149bc3bc6901150fe9017111d016b3357f529" + integrity sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg== + dependencies: + d "1" + es5-ext "~0.10.46" + +durations@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/durations/-/durations-3.4.2.tgz#1de230454373cccfecab927de0bebae2295301db" + integrity sha512-V/lf7y33dGaypZZetVI1eu7BmvkbC4dItq12OElLRpKuaU5JxQstV2zHwLv8P7cNbQ+KL1WD80zMCTx5dNC4dg== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -456,11 +466,63 @@ error-stack-parser@^2.1.4: dependencies: stackframe "^1.3.4" +es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14, es5-ext@~0.10.46: + version "0.10.64" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + esniff "^2.0.1" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c" + integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== + dependencies: + d "^1.0.2" + ext "^1.7.0" + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== + dependencies: + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" + +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + +ext@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" @@ -469,6 +531,11 @@ extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + faker@^5.5.3: version "5.5.3" resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" @@ -481,11 +548,6 @@ figures@^3.2.0: dependencies: escape-string-regexp "^1.0.5" -find-up-simple@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/find-up-simple/-/find-up-simple-1.0.1.tgz#18fb90ad49e45252c4d7fca56baade04fa3fca1e" - integrity sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ== - fn-name@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c" @@ -496,19 +558,27 @@ follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + fsevents@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -glob@^13.0.0: - version "13.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d" - integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw== +glob@^7.1.6: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: - minimatch "^10.2.2" - minipass "^7.1.3" - path-scurry "^2.0.2" + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" global-dirs@^3.0.0: version "3.0.1" @@ -540,24 +610,20 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -hosted-git-info@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-9.0.2.tgz#b38c8a802b274e275eeeccf9f4a1b1a0a8557ada" - integrity sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg== - dependencies: - lru-cache "^11.1.0" - indent-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -index-to-position@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/index-to-position/-/index-to-position-1.2.0.tgz#c800eb34dacf4dbf96b9b06c7eb78d5f704138b4" - integrity sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw== +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" -inherits@^2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -614,11 +680,6 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - knuth-shuffle-seeded@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz#01f1b65733aa7540ee08d8b0174164d22081e4e1" @@ -631,6 +692,11 @@ lodash-es@^4.17.11: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash-es@^4.17.21: + version "4.18.1" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.18.1.tgz#b962eeb80d9d983a900bf342961fb7418ca10b1d" + integrity sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -641,11 +707,6 @@ lodash.mergewith@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== - lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -658,37 +719,19 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" -lru-cache@^11.0.0, lru-cache@^11.1.0: - version "11.3.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.3.5.tgz#29047d348c0b2793e3112a01c739bb7c6d855637" - integrity sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw== - -luxon@3.7.2, luxon@^3.5.0: - version "3.7.2" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.7.2.tgz#d697e48f478553cca187a0f8436aff468e3ba0ba" - integrity sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew== - -mime@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" - integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== - -minimatch@^10.2.2: - version "10.2.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" - integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: - brace-expansion "^5.0.5" - -minipass@^7.1.2, minipass@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" - integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== + yallist "^4.0.0" -mkdirp@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" - integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== +minimatch@^3.1.1: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== + dependencies: + brace-expansion "^1.1.7" ms@^2.1.3: version "2.1.3" @@ -704,6 +747,16 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" +nanoclone@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" + integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA== + +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -712,15 +765,6 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -normalize-package-data@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-8.0.0.tgz#bdce7ff2d6ba891b853e179e45a5337766e304a7" - integrity sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ== - dependencies: - hosted-git-info "^9.0.0" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - o-stream@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/o-stream/-/o-stream-0.3.0.tgz#204d27bc3fb395164507d79b381e91752e8daedc" @@ -731,6 +775,13 @@ object-assign@^4.0.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + pad-right@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/pad-right/-/pad-right-0.2.2.tgz#6fbc924045d244f2a2a244503060d3bfc6009774" @@ -738,27 +789,10 @@ pad-right@^0.2.2: dependencies: repeat-string "^1.5.2" -parse-json@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-8.3.0.tgz#88a195a2157025139a2317a4f2f9252b61304ed5" - integrity sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ== - dependencies: - "@babel/code-frame" "^7.26.2" - index-to-position "^1.1.0" - type-fest "^4.39.1" - -path-scurry@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85" - integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg== - dependencies: - lru-cache "^11.0.0" - minipass "^7.1.2" - -picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== playwright-core@1.56.1: version "1.56.1" @@ -804,31 +838,11 @@ property-expr@^2.0.2: resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== -property-expr@^2.0.5: +property-expr@^2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== -read-package-up@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/read-package-up/-/read-package-up-12.0.0.tgz#7ae889586f397b7a291ca59ce08caf7e9f68a61c" - integrity sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw== - dependencies: - find-up-simple "^1.0.1" - read-pkg "^10.0.0" - type-fest "^5.2.0" - -read-pkg@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-10.1.0.tgz#eff31c7e505a4995a85c5af017b3dc413745431c" - integrity sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg== - dependencies: - "@types/normalize-package-data" "^2.4.4" - normalize-package-data "^8.0.0" - parse-json "^8.3.0" - type-fest "^5.4.4" - unicorn-magic "^0.4.0" - readable-stream@^2.3.5: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" @@ -842,10 +856,10 @@ readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" -reflect-metadata@0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" - integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== +reflect-metadata@0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== regenerator-runtime@^0.13.11: version "0.13.11" @@ -879,6 +893,18 @@ replace-ext@^1.0.0: resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-2.0.0.tgz#ac06991418a7623edc119084edc98b0e6bf05a41" + integrity sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ== + dependencies: + resolve-from "^5.0.0" + safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -889,10 +915,12 @@ seed-random@~2.2.0: resolved "https://registry.yarnpkg.com/seed-random/-/seed-random-2.2.0.tgz#2a9b19e250a817099231a5b99a4daf80b7fbed54" integrity sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ== -semver@7.7.4, semver@^7.3.5: - version "7.7.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" - integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== +semver@7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" source-map-support@0.5.21, source-map-support@^0.5.21, source-map-support@~0.5.20: version "0.5.21" @@ -912,41 +940,15 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" - integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.23" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz#b069e687b1291a32f126893ed76a27a745ee2133" - integrity sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw== - stackframe@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== -string-argv@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== +string-argv@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== string-width@^4.2.0: version "4.2.3" @@ -964,7 +966,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^6.0.1: +strip-ansi@6.0.1, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -990,11 +992,6 @@ synchronous-promise@^2.0.13: resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.17.tgz#38901319632f946c982152586f2caf8ddc25c032" integrity sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g== -tagged-tag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/tagged-tag/-/tagged-tag-1.0.0.tgz#a0b5917c2864cba54841495abfa3f6b13edcf4d6" - integrity sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng== - terser@^5.7.1: version "5.16.5" resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.5.tgz#1c285ca0655f467f92af1bbab46ab72d1cb08e5a" @@ -1019,47 +1016,25 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -tiny-case@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" - integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== +tmp@^0.2.1: + version "0.2.5" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" + integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow== toposort@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== -ts-dedent@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" - integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== - tslib@^2.0.3: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -type-fest@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" - integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== - -type-fest@^4.39.1, type-fest@^4.41.0: - version "4.41.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" - integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== - -type-fest@^5.2.0, type-fest@^5.4.4: - version "5.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-5.6.0.tgz#502f7a003b7309e96a7e17052cc2ab2c7e5c7a31" - integrity sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA== - dependencies: - tagged-tag "^1.0.0" - -unicorn-magic@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.4.0.tgz#78c6a090fd6d07abd2468b83b385603e00dfdb24" - integrity sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw== +type@^2.7.2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.3.tgz#436981652129285cc3ba94f392886c2637ea0486" + integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ== upper-case-first@^2.0.2: version "2.0.2" @@ -1083,13 +1058,19 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -validate-npm-package-license@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== +uuid@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + +verror@^1.10.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.1.tgz#4bf09eeccf4563b109ed4b3d458380c972b0cdeb" + integrity sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg== dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" vinyl-sourcemaps-apply@^0.2.1: version "0.2.1" @@ -1110,25 +1091,20 @@ vinyl@^2.2.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + xmlbuilder@^15.1.1: version "15.1.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== -yaml@^2.2.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.3.tgz#a0d6bd2efb3dd03c59370223701834e60409bd7d" - integrity sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg== - -yup@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/yup/-/yup-1.7.1.tgz#4c47c6bb367df08d4bc597f8c4c4f5fc4277f6ab" - integrity sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw== - dependencies: - property-expr "^2.0.5" - tiny-case "^1.0.3" - toposort "^2.0.2" - type-fest "^2.19.0" +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yup@^0.29.3: version "0.29.3" @@ -1142,3 +1118,16 @@ yup@^0.29.3: property-expr "^2.0.2" synchronous-promise "^2.0.13" toposort "^2.0.2" + +yup@^0.32.11: + version "0.32.11" + resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" + integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/lodash" "^4.14.175" + lodash "^4.17.21" + lodash-es "^4.17.21" + nanoclone "^0.2.1" + property-expr "^2.0.4" + toposort "^2.0.2" From 01353cca501a70feb38d3c91f2821b60bd3c676b Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 19 May 2026 12:52:31 +0100 Subject: [PATCH 25/35] test: move resuable steps into giftaid common --- .../common/giftaidCommon.steps.js | 19 +++++++++++++++++- .../submit/giftaidSubmission.steps.js | 20 ------------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js index e011f3ac..9262f05f 100644 --- a/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js +++ b/playwright-staging/tests/step-definitions/common/giftaidCommon.steps.js @@ -1,10 +1,27 @@ -const { When, Then } = require('@cucumber/cucumber'); +const { When, Then, Given} = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); const Chance = require('chance'); const { selectors } = require('../../utils/locators'); const chance = new Chance(); +Given('I am on the Giftaid page', async function () { + await this.page.goto(process.env.BASE_URL, { timeout: 30000 }); + await this.page.waitForLoadState('domcontentloaded'); +}); + +When('I select the Giftaid option', async function () { + await this.page.click(selectors.giftaid.option); +}); + +Then('I should see the Giftaid thank you message', async function () { + const expectedFirstName = this.supporter?.firstName || 'test'; + await expect(this.page.locator('h1')).toContainText( + `Thank you, ${expectedFirstName}!`, + { timeout: 30000 } + ); +}); + When('I submit the Giftaid form', async function () { await this.page.locator(selectors.formFields.submitButton).click(); }); diff --git a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js index ebe6df57..e69de29b 100644 --- a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js +++ b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js @@ -1,20 +0,0 @@ -const { Given, When, Then } = require('@cucumber/cucumber'); -const { expect } = require('@playwright/test'); -const { selectors } = require('../../utils/locators'); - -Given('I am on the Giftaid page', async function () { - await this.page.goto(process.env.BASE_URL, { timeout: 30000 }); - await this.page.waitForLoadState('domcontentloaded'); -}); - -When('I select the Giftaid option', async function () { - await this.page.click(selectors.giftaid.option); -}); - -Then('I should see the Giftaid thank you message', async function () { - const expectedFirstName = this.supporter?.firstName || 'test'; - await expect(this.page.locator('h1')).toContainText( - `Thank you, ${expectedFirstName}!`, - { timeout: 30000 } - ); -}); From db2969fffc3edc143872cdd75652de19286462ad Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 19 May 2026 12:53:07 +0100 Subject: [PATCH 26/35] test: delete giftaid submission steps file as it's moved to common --- .../tests/step-definitions/submit/giftaidSubmission.steps.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js diff --git a/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js b/playwright-staging/tests/step-definitions/submit/giftaidSubmission.steps.js deleted file mode 100644 index e69de29b..00000000 From b545fc736ef50501b792b2cf07918d9a486fca10 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 19 May 2026 12:59:23 +0100 Subject: [PATCH 27/35] test: update transsource value to SR26_GiftAid --- .../step-definitions/submit/marketingPreferencesData.steps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js index 2d0b44c3..12ffcb2d 100644 --- a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js @@ -52,7 +52,7 @@ Then('the marketing preferences data should be stored in the contact-store', asy expect(mpData.town).toEqual(this.supporter.town); expect(mpData.country).toEqual('GB'); expect(mpData.transsourceurl).toContain(process.env.BASE_URL); - expect(mpData.transsource).toEqual('RND26_GiftAid'); + expect(mpData.transsource).toEqual('SR26_GiftAid'); expect(mpData.transtype).toEqual('prefs'); expect(mpData.permissionemail).toEqual('1'); expect(mpData.permissionsms).toEqual('1'); From 65b48d48a9d2ce218a3575a6204eece2c534e0ef Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 19 May 2026 13:12:16 +0100 Subject: [PATCH 28/35] test: fix missing update validation step definition; populateUpdateFormFields method call --- .../step-definitions/update/updateFormValidation.steps.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js index a32fc896..df89b4b5 100644 --- a/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js +++ b/playwright-staging/tests/step-definitions/update/updateFormValidation.steps.js @@ -20,9 +20,13 @@ When('I enter the update first name {string}', async function (firstName) { await this.page.keyboard.press('Enter'); }); +Then('I should see the update first name error message {string}', async function (message) { + await expect(this.page.locator(selectors.errorMessages.firstName)).toHaveText(message); +}); + When('I complete the Giftaid update form with first name {string}', async function (firstName) { await this.page.fill(selectors.formFields.firstName, ''); - await this.commands.populateUpdateFormFields(this.page, { firstName }); + await this.commands.populateUpdateFormFields({ firstName }); }); When('I select yes for the GiftAid declaration', async function () { From 9dafdd1b84410b66bdc2fece04883e012005f591 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Tue, 19 May 2026 13:48:29 +0100 Subject: [PATCH 29/35] add comments in playwright-local config --- playwright-local/tests/support/hooks.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/playwright-local/tests/support/hooks.js b/playwright-local/tests/support/hooks.js index 80ffe41f..608602ae 100644 --- a/playwright-local/tests/support/hooks.js +++ b/playwright-local/tests/support/hooks.js @@ -1,30 +1,31 @@ require('dotenv').config(); const { Before, After, setDefaultTimeout } = require('@cucumber/cucumber'); -const { chromium, webkit, devices } = require('@playwright/test'); +const { chromium, webkit, devices } = require('@playwright/test'); // imports playwright browsers and devices const { Commands } = require('../utils/commands'); -setDefaultTimeout(300 * 1000); +setDefaultTimeout(300 * 1000); // 5 mins // Runs before each scenario Before(async function () { const browserName = process.env.BROWSER || 'chromium'; const isMobileSafari = browserName === 'mobile-safari'; - this.browser = isMobileSafari + this.browser = isMobileSafari // Launches WebKit for mobile Safari ? await webkit.launch({ - headless: process.env.HEADED !== 'true', + headless: process.env.HEADED !== 'true', // Checks whether to run mobile Safari mode }) : await chromium.launch({ channel: 'chrome', - headless: process.env.HEADED !== 'true', + headless: process.env.HEADED !== 'true', // Runs headless by default }); + // Creates a fresh isolated browser session for each scenario this.context = await this.browser.newContext( isMobileSafari ? { ...devices['iPhone 12'], - serviceWorkers: 'block', + serviceWorkers: 'block', // Blocks service workers to reduce caching/flaky behaviour } : { viewport: { @@ -40,7 +41,7 @@ Before(async function () { // Increase navigation timeout for slower redirects/page loads this.page.setDefaultNavigationTimeout(45000); - this.commands = new Commands(this.page); + this.commands = new Commands(this.page); // Creates a new browser tab }); // Runs after each scenario From 78bc781b7e519ce48d66d07c77e54a87ee6a398e Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 20 May 2026 12:55:42 +0100 Subject: [PATCH 30/35] test: move selectors to locators file --- .../submit/validGifaidSubmission.feature | 4 +- .../submit/marketingPreferencesData.steps.js | 1 - playwright-staging/tests/utils/commands.js | 49 ++++++++++--------- playwright-staging/tests/utils/locators.js | 1 + 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/playwright-staging/tests/features/submit/validGifaidSubmission.feature b/playwright-staging/tests/features/submit/validGifaidSubmission.feature index 7963e66c..bd19a197 100644 --- a/playwright-staging/tests/features/submit/validGifaidSubmission.feature +++ b/playwright-staging/tests/features/submit/validGifaidSubmission.feature @@ -1,7 +1,7 @@ @sanity @valid-submission -Feature: Valid Giftaid submission +Feature: Valid Giftaid Submission - Scenario: Valid Giftaid submission + Scenario: Valid Giftaid Submission Given I am on the Giftaid page And I select the Giftaid option And I complete the Giftaid form with valid details diff --git a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js index 12ffcb2d..c2b4496e 100644 --- a/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js +++ b/playwright-staging/tests/step-definitions/submit/marketingPreferencesData.steps.js @@ -2,7 +2,6 @@ const { When, Then } = require('@cucumber/cucumber'); const { expect } = require('@playwright/test'); const Chance = require('chance'); const { MarketingPrefsVerify } = require('../../utils/marketingPrefsVerify'); -const { selectors } = require('../../utils/locators'); const chance = new Chance(); diff --git a/playwright-staging/tests/utils/commands.js b/playwright-staging/tests/utils/commands.js index d1f5a53b..e18820e4 100644 --- a/playwright-staging/tests/utils/commands.js +++ b/playwright-staging/tests/utils/commands.js @@ -1,3 +1,4 @@ +const { selectors } = require('./locators'); const Chance = require('chance'); const chance = new Chance(); @@ -28,15 +29,15 @@ class Commands { address3 = 'test address 3', town = chance.city(), } = {}) { - await this.page.locator('#field-input--mobile').fill(mobile); - await this.page.locator('input#field-input--firstname').fill(firstName); - await this.page.locator('input#field-input--lastname').fill(lastName); - await this.page.locator('input#field-input--postcode').fill(postcode); - await this.page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await this.page.locator('input#field-input--address1').fill(address1); - await this.page.locator('input#field-input--address2').fill(address2); - await this.page.locator('input#field-input--address3').fill(address3); - await this.page.locator('input#field-input--town').fill(town); + await this.page.locator(selectors.formFields.mobile).fill(mobile); + await this.page.locator(selectors.formFields.firstName).fill(firstName); + await this.page.locator(selectors.formFields.lastName).fill(lastName); + await this.page.locator(selectors.formFields.postcode).fill(postcode); + await this.page.locator(selectors.address.manualAddressLink).click(); + await this.page.locator(selectors.address.address1).fill(address1); + await this.page.locator(selectors.address.address2).fill(address2); + await this.page.locator(selectors.address.address3).fill(address3); + await this.page.locator(selectors.address.town).fill(town); } /** @@ -47,13 +48,13 @@ class Commands { email = `giftaid-staging-${Date.now()}@email.sls.comicrelief.com`, phone = chance.phone({ country: 'uk', mobile: false }).replace(/\s/g, '') } = {}) { - await this.page.locator('#field-wrapper--Email > div').click(); - await this.page.locator('input#field-input--email').fill(email); + await this.page.locator(selectors.marketingPreferences.options.email).click(); + await this.page.locator(selectors.marketingPreferences.fields.email).fill(email); - await this.page.locator('#field-wrapper--Phone > div').click(); - await this.page.locator('input#field-input--phone').fill(phone); + await this.page.locator(selectors.marketingPreferences.options.phone).click(); + await this.page.locator(selectors.marketingPreferences.fields.phone).fill(phone); - await this.page.locator('input#field-label--Text--SMS').check({ force: true }); + await this.page.locator(selectors.marketingPreferences.options.text).check({ force: true }); } /** @@ -71,16 +72,16 @@ class Commands { address3 = 'test address 3', town = chance.city(), } = {}) { - await this.page.locator('input#field-input--firstname').fill(firstName); - await this.page.locator('input#field-input--lastname').fill(lastName); - await this.page.locator('input#field-input--postcode').fill(postcode); - await this.page.locator('input#field-input--email').fill(email); - await this.page.locator('#field-input--mobile').fill(mobile); - await this.page.locator('a[aria-describedby=field-error--addressDetails]').click(); - await this.page.locator('input#field-input--address1').fill(address1); - await this.page.locator('input#field-input--address2').fill(address2); - await this.page.locator('input#field-input--address3').fill(address3); - await this.page.locator('input#field-input--town').fill(town); + await this.page.locator(selectors.formFields.firstName).fill(firstName); + await this.page.locator(selectors.formFields.lastName).fill(lastName); + await this.page.locator(selectors.formFields.postcode).fill(postcode); + await this.page.locator(selectors.formFields.email).fill(email); + await this.page.locator(selectors.formFields.mobile).fill(mobile); + await this.page.locator(selectors.address.manualAddressLink).click(); + await this.page.locator(selectors.address.address1).fill(address1); + await this.page.locator(selectors.address.address2).fill(address2); + await this.page.locator(selectors.address.address3).fill(address3); + await this.page.locator(selectors.address.town).fill(town); } } diff --git a/playwright-staging/tests/utils/locators.js b/playwright-staging/tests/utils/locators.js index 31b72c68..2fb95d0c 100644 --- a/playwright-staging/tests/utils/locators.js +++ b/playwright-staging/tests/utils/locators.js @@ -18,6 +18,7 @@ const selectors = { mobile: '#field-input--mobile', firstName: 'input#field-input--firstname', lastName: 'input#field-input--lastname', + email: 'input#field-input--email', postcode: 'input#field-input--postcode', postcodeLookup: '#postcode_button', submitButton: 'button[type=submit]', From fbf2563c856d40c9a99a54936534d76e0b1c775e Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 20 May 2026 15:30:41 +0100 Subject: [PATCH 31/35] test: remove playwright.config files --- playwright-staging/playwright.config.js | 51 ------------------------- 1 file changed, 51 deletions(-) delete mode 100644 playwright-staging/playwright.config.js diff --git a/playwright-staging/playwright.config.js b/playwright-staging/playwright.config.js deleted file mode 100644 index 7e498bc1..00000000 --- a/playwright-staging/playwright.config.js +++ /dev/null @@ -1,51 +0,0 @@ -// @ts-check -const { devices } = require('@playwright/test'); - -const config = { - testDir: 'tests', - testMatch: '**/*.spec.js', - /* Maximum time one test can run for. */ - timeout: 300 * 1000, - expect: { - /** - * Maximum time expect() should wait for the condition to be met. - * For example in `await expect(locator).toHaveText();` - */ - timeout: 30 * 1000, - }, - reporter: 'list', - retries: 2, - workers: 3, - use:{ - viewport: null, - - /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ - actionTimeout: 0, - - // Disable local Playwright traces/videos/screenshots to avoid generating - // test-results folders locally. We rely on BrowserStack videos and CI logs - // for debugging test failures instead. - trace: process.env.CI ? 'retain-on-failure' : 'off', - screenshot: process.env.CI ? 'only-on-failure' : 'off', - video: process.env.CI ? 'retain-on-failure' : 'off', - navigationTimeout: 45000, - scriptTimeout: 60000, // this is needed for long running scripts - serviceWorkers: 'block', // optional but reduces flakiness - }, - grep: [new RegExp('@sanity')], - - /* Configure projects for major browsers */ - projects: [ - // -- BrowserStack Projects -- - // name should be of the format browser@browser_version:os os_version@browserstack - { - name: 'chrome@latest:Windows 11@browserstack', - use: { - browserName: 'chromium', - ...devices['Desktop Chrome'], - }, - }, - ], -}; - -module.exports = config; From a173f531ef366ac98bdfa43388d2c42c9a3eae3e Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 20 May 2026 15:44:46 +0100 Subject: [PATCH 32/35] remove local playwright.config file; fix casing --- playwright-local/playwright-local.config.js | 59 ------------------- .../submit/validGiftaidSubmission.feature | 4 +- 2 files changed, 2 insertions(+), 61 deletions(-) delete mode 100644 playwright-local/playwright-local.config.js diff --git a/playwright-local/playwright-local.config.js b/playwright-local/playwright-local.config.js deleted file mode 100644 index ee6a71a0..00000000 --- a/playwright-local/playwright-local.config.js +++ /dev/null @@ -1,59 +0,0 @@ -// @ts-check -const { defineConfig, devices } = require('@playwright/test'); - -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -require('dotenv').config(); - -/** - * @see https://playwright.dev/docs/test-configuration - */ -module.exports = defineConfig({ - testDir: '.', - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - retries: 1, - workers: 2, - timeout: 60 * 1000, - expect: { - timeout: 60 * 1000, - }, - reporter: process.env.CI ? [['list'], ['html', { open: 'never' }]] : [['list']], - use: { - // Disable local Playwright traces/videos/screenshots to avoid generating - // test-results folders locally. In CI, keep artifacts for debugging failures. - trace: process.env.CI ? 'on-first-retry' : 'off', - screenshot: process.env.CI ? 'only-on-failure' : 'off', - video: process.env.CI ? 'retain-on-failure' : 'off', - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { - ...devices['Desktop Chrome'], - viewport: { - width: 1300, - height: 1000 - } - } - }, - { - name: 'mobile-safari', - use: { ...devices['iPhone 12'] }, - timeout: 360_000, - expect: { timeout: 20_000 } - } - ], - - /* Run 'yarn start' before starting the tests */ - webServer: { - command: 'yarn start', - port: 3000, - timeout: 120000, - reuseExistingServer: true, - }, -}); diff --git a/playwright-local/tests/features/submit/validGiftaidSubmission.feature b/playwright-local/tests/features/submit/validGiftaidSubmission.feature index 93ed4f36..a9f30572 100644 --- a/playwright-local/tests/features/submit/validGiftaidSubmission.feature +++ b/playwright-local/tests/features/submit/validGiftaidSubmission.feature @@ -1,11 +1,11 @@ @sanity @valid-giftaid-submission -Feature: Valid Giftaid submission +Feature: Valid Giftaid Submission Background: Given I am on the local Giftaid page And I select the local Giftaid option - Scenario: Valid Giftaid submission + Scenario: Valid Giftaid Submission When I complete the local Giftaid form with valid details And I select the local marketing preferences And I submit the local Giftaid form and wait for the navigation From 6e86b813633f063adf1e873ece0488c13a30280b Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 20 May 2026 16:17:59 +0100 Subject: [PATCH 33/35] remove playwright scripts --- package.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/package.json b/package.json index e85c68f2..d1734239 100644 --- a/package.json +++ b/package.json @@ -37,15 +37,6 @@ "start": "node scripts/start.js", "build": "node scripts/build.js", "lint": "eslint --color src", - "test:playwright-local:local": "playwright test --config=./playwright-local/playwright-local.config.js", - "test:playwright-local:local:chromium": "playwright test --config=./playwright-local/playwright-local.config.js --project=chromium", - "test:playwright-local:local:chromium--h": "playwright test --config=./playwright-local/playwright-local.config.js --project=chromium --headed", - "test:playwright-local:local:mobile": "playwright test --config=./playwright-local/playwright-local.config.js --project=mobile-safari", - "test:playwright-local:local:mobile--h": "playwright test --config=./playwright-local/playwright-local.config.js --project=mobile-safari --headed", - "test:playwright-local:ci": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local", - "test:playwright-local:ci:chromium": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local:local:chromium", - "test:playwright-local:ci:mobile": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local:local:mobile", - "test:playwright-local:local:chrome:mobile": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:playwright-local:local", "test:cucumber:local": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", "test:cucumber:local:sanity": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", "test:cucumber:local:chromium": "cd playwright-local && BROWSER=chromium BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", From 24c2b212de3a5ac412643b4bea7d7069b4a14198 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 20 May 2026 16:26:39 +0100 Subject: [PATCH 34/35] remove FORCE_COLOR from the local cucumber scripts --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index d1734239..0288ea35 100644 --- a/package.json +++ b/package.json @@ -37,14 +37,14 @@ "start": "node scripts/start.js", "build": "node scripts/build.js", "lint": "eslint --color src", - "test:cucumber:local": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", - "test:cucumber:local:sanity": "cd playwright-local && BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", - "test:cucumber:local:chromium": "cd playwright-local && BROWSER=chromium BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", - "test:cucumber:local:chromium:sanity": "cd playwright-local && BROWSER=chromium BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", - "test:cucumber:local:chromium:headed": "cd playwright-local && BROWSER=chromium HEADED=true BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", - "test:cucumber:local:mobile": "cd playwright-local && BROWSER=mobile-safari BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js", - "test:cucumber:local:mobile:sanity": "cd playwright-local && BROWSER=mobile-safari BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", - "test:cucumber:local:mobile:headed": "cd playwright-local && BROWSER=mobile-safari HEADED=true BASE_URL=http://localhost:3000 FORCE_COLOR=1 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local": "cd playwright-local && BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js", + "test:cucumber:local:sanity": "cd playwright-local && BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:chromium": "cd playwright-local && BROWSER=chromium BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js", + "test:cucumber:local:chromium:sanity": "cd playwright-local && BROWSER=chromium BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:chromium:headed": "cd playwright-local && BROWSER=chromium HEADED=true BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:mobile": "cd playwright-local && BROWSER=mobile-safari BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js", + "test:cucumber:local:mobile:sanity": "cd playwright-local && BROWSER=mobile-safari BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js --tags '@sanity'", + "test:cucumber:local:mobile:headed": "cd playwright-local && BROWSER=mobile-safari HEADED=true BASE_URL=http://localhost:3000 cucumber-js --config config/cucumber.js --tags '@sanity'", "test:cucumber:ci": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local", "test:cucumber:ci:sanity": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:sanity", "test:cucumber:ci:chromium": "export NODE_ENV=development; start-server-and-test start http://localhost:3000 test:cucumber:local:chromium", From f5be6b8da5a0e332626b6e8c8fb4709833798b02 Mon Sep 17 00:00:00 2001 From: Krupa Pammi Date: Wed, 20 May 2026 16:29:33 +0100 Subject: [PATCH 35/35] use only 2 parallel workers in playwright-local tests --- playwright-local/config/cucumber.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright-local/config/cucumber.js b/playwright-local/config/cucumber.js index deb7b02f..680c684d 100644 --- a/playwright-local/config/cucumber.js +++ b/playwright-local/config/cucumber.js @@ -9,7 +9,7 @@ module.exports = { // On CI keep the output minimal to avoid noisy logs. format: ['progress', 'summary'], retry: 2, // Retry failed scenarios twice - parallel: 3, // Run scenarios in parallel workers + parallel: 2, // Run scenarios in parallel workers publishQuiet: true, }, };