Skip to content

Commit

Permalink
Merge branch 'main' into gitlab-91
Browse files Browse the repository at this point in the history
  • Loading branch information
dheesen authored Jan 22, 2025
2 parents 6fbe133 + 58fb7e8 commit 0d53844
Show file tree
Hide file tree
Showing 19 changed files with 96 additions and 124 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

jobs:
build-and-selftest:
runs-on: windows-latest
runs-on: ubuntu-latest

env:
BASE_URL: https://hyva-demo.elgentos.io/
Expand Down
1 change: 0 additions & 1 deletion bypass-captcha.config.example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* It will set the global cookie to bypass CAPTCHA for Magento 2.
* See: https://github.com/elgentos/magento2-bypass-captcha-cookie
*
* //TODO The extension is WIP. Currently being developed.
*/
import { FullConfig } from '@playwright/test';
import * as playwright from 'playwright';
Expand Down
2 changes: 0 additions & 2 deletions playwright.config.example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,10 @@ export default defineConfig({

/* Configure projects for major browsers */
projects: [
// TODO: uncomment the setup line once authentication works!
// Import our auth.setup.ts file
//{ name: 'setup', testMatch: /.*\.setup\.ts/ },

{
// TODO: uncomment dependency and storage state once authentication works!
name: 'chromium',
testMatch: testFiles,
use: {
Expand Down
47 changes: 32 additions & 15 deletions tests/base/account.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {test, expect} from '@playwright/test';
import {MainMenuPage} from './fixtures/mainmenu.page';
import {LoginPage} from './fixtures/login.page';
import {RegisterPage} from './fixtures/register.page';
import {AccountPage} from './fixtures/account.page';
import {NewsletterSubscriptionPage} from './fixtures/newsletter.page';

Expand All @@ -8,9 +10,6 @@ import inputvalues from './config/input-values/input-values.json';
import selectors from './config/selectors/selectors.json';
import verify from './config/expected/expected.json';

// no resetting storageState, mainmenu has more functionalities when logged in.
// TODO: remove this beforeEach() once authentication as project set-up/fixture works.

// Before each test, log in
test.beforeEach(async ({ page, browserName }) => {
const browserEngine = browserName?.toUpperCase() || "UNKNOWN";
Expand All @@ -32,8 +31,6 @@ test.describe('Account information actions', {annotation: {type: 'Account Dashbo
await page.waitForLoadState();
});

// TODO: add test to update e-mail address

/**
* @feature Magento 2 Change Password
* @scenario User changes their password
Expand All @@ -46,24 +43,47 @@ test.describe('Account information actions', {annotation: {type: 'Account Dashbo
* @then I should see a notification that my password has been updated
* @and I should be able to login with my new credentials.
*/
test('I can change my password',{ tag: '@account-credentials', }, async ({page, browserName}) => {

//TODO: Remove the skip when all issues are fixed.
test.skip('I can change my password',{ tag: '@account-credentials', }, async ({page}) => {
// Create instances and set variables
const mainMenu = new MainMenuPage(page);
const registerPage = new RegisterPage(page);
const accountPage = new AccountPage(page);
let changedPasswordValue = process.env.MAGENTO_EXISTING_ACCOUNT_CHANGED_PASSWORD;
const loginPage = new LoginPage(page);

const browserEngine = browserName?.toUpperCase() || "UNKNOWN";
let randomNumberforEmail = Math.floor(Math.random() * 101);
let emailPasswordUpdatevalue = `passwordupdate-${randomNumberforEmail}-${browserEngine}@example.com`;
let passwordInputValue = process.env.MAGENTO_EXISTING_ACCOUNT_PASSWORD;
let changedPasswordValue = process.env.MAGENTO_EXISTING_ACCOUNT_CHANGED_PASSWORD;

// Log out of current account
if(await page.getByRole('link', { name: selectors.mainMenu.myAccountLogoutItem }).isVisible()){
await mainMenu.logout();
}

// Create account
if(!changedPasswordValue || !passwordInputValue) {
throw new Error("Changed password or original password in your .env file is not defined or could not be read.");
}

// Navigate to Account Information, confirm by checking heading above sidebar
const sidebarAccountInfoLink = page.getByRole('link', { name: 'Account Information' });
sidebarAccountInfoLink.click();
await expect(page.getByRole('heading', { name: 'Account Information' }).locator('span')).toBeVisible();
await registerPage.createNewAccount(inputvalues.accountCreation.firstNameValue, inputvalues.accountCreation.lastNameValue, emailPasswordUpdatevalue, passwordInputValue);

// Update password
await page.goto(slugs.account.changePasswordSlug);
await page.waitForLoadState();
await accountPage.updatePassword(passwordInputValue, changedPasswordValue);

// If login with changePasswordValue is possible, then password change was succesful.
await loginPage.login(emailPasswordUpdatevalue, changedPasswordValue);

// Logout again, login with original account
await mainMenu.logout();
let emailInputValue = process.env[`MAGENTO_EXISTING_ACCOUNT_EMAIL_${browserEngine}`];
if(!emailInputValue) {
throw new Error("MAGENTO_EXISTING_ACCOUNT_EMAIL_${browserEngine} and/or MAGENTO_EXISTING_ACCOUNT_PASSWORD have not defined in the .env file, or the account hasn't been created yet.");
}
await loginPage.login(emailInputValue, passwordInputValue);
});
});

Expand Down Expand Up @@ -182,14 +202,11 @@ test.describe.serial('Account address book actions', { annotation: {type: 'Accou
});
});

// TODO: move this to new spec file.
test.describe('Newsletter actions', { annotation: {type: 'Account Dashboard', description: 'Newsletter tests'},}, () => {
test.beforeEach(async ({page}) => {
await page.goto(slugs.account.accountOverviewSlug);
});

// TODO: What if website offers multiple subscriptions?

/**
* @feature Magento 2 newsletter subscriptions
* @scenario User (un)subscribes from a newsletter
Expand Down
2 changes: 0 additions & 2 deletions tests/base/cart.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ test.describe('Cart functionalities (guest)', () => {
const mainMenu = new MainMenuPage(page);
const productPage = new ProductPage(page);

//TODO: Use a storagestate or API call to add product to the cart so shorten test time
await page.goto(slugs.productpage.simpleProductSlug);
await productPage.addSimpleProductToCart(selectors.productPage.simpleProductTitle, slugs.productpage.simpleProductSlug);
await mainMenu.openMiniCart();
Expand Down Expand Up @@ -127,7 +126,6 @@ test.describe('Cart functionalities (guest)', () => {
throw new Error(`MAGENTO_COUPON_CODE_${browserEngine} appears to not be set in .env file. Value reported: ${discountCode}`);
}

// TODO: create API call to quickly add discount code rather than run a test again.
await cart.applyDiscountCode(discountCode);
await cart.removeDiscountCode();
});
Expand Down
66 changes: 52 additions & 14 deletions tests/base/checkout.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import {test, expect} from '@playwright/test';
import {LoginPage} from './fixtures/login.page';
import {MainMenuPage} from './fixtures/mainmenu.page';
import {ProductPage} from './fixtures/product.page';
import {AccountPage} from './fixtures/account.page';
import { CheckoutPage } from './fixtures/checkout.page';

import slugs from './config/slugs.json';
import inputvalues from './config/input-values/input-values.json';
import selectors from './config/selectors/selectors.json';
import verify from './config/expected/expected.json';
import { CheckoutPage } from './fixtures/checkout.page';

// no resetting storageState, mainmenu has more functionalities when logged in.

/**
* @feature BeforeEach runs before each test in this group.
Expand All @@ -25,7 +23,6 @@ import { CheckoutPage } from './fixtures/checkout.page';
test.beforeEach(async ({ page }) => {
const productPage = new ProductPage(page);

//TODO: Use a storagestate or API call to add product to the cart so shorten test time
await page.goto(slugs.productpage.simpleProductSlug);
await productPage.addSimpleProductToCart(selectors.productPage.simpleProductTitle, slugs.productpage.simpleProductSlug);
await page.goto(slugs.checkoutSlug);
Expand All @@ -34,7 +31,6 @@ test.beforeEach(async ({ page }) => {

test.describe('Checkout (login required)', () => {
// Before each test, log in
// TODO: remove this beforeEach() once authentication as project set-up/fixture works.
test.beforeEach(async ({ page, browserName }) => {
const browserEngine = browserName?.toUpperCase() || "UNKNOWN";
let emailInputValue = process.env[`MAGENTO_EXISTING_ACCOUNT_EMAIL_${browserEngine}`];
Expand All @@ -47,21 +43,65 @@ test.describe('Checkout (login required)', () => {
const loginPage = new LoginPage(page);
await loginPage.login(emailInputValue, passwordInputValue);
});

/**
* @feature Automatically fill in certain data in checkout (if user is logged in)
* @scenario When the user navigates to the checkout (with a product), their name and address should be filled in.
* @given I am logged in
* @and I have a product in my cart
* @and I have navigated to the checkout page
* @then My name and address should already be filled in
*/
test('My address should be already filled in at the checkout',{ tag: '@checkout',}, async ({page}) => {
let signInLink = page.getByRole('link', { name: selectors.credentials.loginButtonLabel });
let addressField = page.getByLabel(selectors.newAddress.streetAddressLabel);
let addressAlreadyAdded = false;

//TODO: Add Gherkin feature description
if(await signInLink.isVisible()) {
throw new Error(`Sign in link found, user is not logged in. Please check the test setup.`);
}

// name field should NOT be on the page
await expect(page.getByLabel(selectors.personalInformation.firstNameLabel)).toBeHidden();

if(await addressField.isVisible()) {
if(!addressAlreadyAdded){
// Address field is visible and addressalreadyAdded is not true, so we need to add an address to the account.
const accountPage = new AccountPage(page);

let phoneNumberValue = inputvalues.firstAddress.firstPhoneNumberValue;
let addressValue = inputvalues.firstAddress.firstStreetAddressValue;
let zipCodeValue = inputvalues.firstAddress.firstZipCodeValue;
let cityNameValue = inputvalues.firstAddress.firstCityValue;
let stateValue = inputvalues.firstAddress.firstProvinceValue;

await accountPage.addNewAddress(phoneNumberValue, addressValue, zipCodeValue, cityNameValue, stateValue);
} else {
throw new Error(`Address field is visible even though an address has been added to the account.`);
}
}
});


/**
* @feature Place order for simple product
* @scenario User places an order for a simple product
* @given I have a product in my cart
* @and I am on any page
* @when I navigate to the checkout
* @and I fill in the required fields
* @and I click the button to place my order
* @then I should see a confirmation that my order has been placed
* @and a order number should be created and show to me
*/
test('Place order for simple product',{ tag: '@simple-product-order',}, async ({page}) => {
const checkoutPage = new CheckoutPage(page);
await checkoutPage.placeOrder();
});



});

test.describe('Checkout (guest)', () => {
// TODO: Write test to confirm order can be placed without an account
// TODO: Write test for logged-in user who hasn't added an address yet.

/**
* @feature Discount Code
* @scenario User adds a discount code to their cart
Expand All @@ -75,7 +115,6 @@ test.describe('Checkout (guest)', () => {
* @and a discount should be applied to the product
*/
test('Add coupon code in checkout',{ tag: ['@checkout', '@coupon-code']}, async ({page, browserName}) => {
//TODO: Write tests to ensure code also works if user is NOT logged in.
const checkout = new CheckoutPage(page);
const browserEngine = browserName?.toUpperCase() || "UNKNOWN";
let discountCode = process.env[`MAGENTO_COUPON_CODE_${browserEngine}`];
Expand Down Expand Up @@ -110,7 +149,6 @@ test.describe('Checkout (guest)', () => {
throw new Error(`MAGENTO_COUPON_CODE appears to not be set in .env file. Value reported: ${discountCode}`);
}

// TODO: create API call to quickly add discount code rather than run a test again.
await checkout.applyDiscountCodeCheckout(discountCode);
await checkout.removeDiscountCode();
});
Expand Down
5 changes: 4 additions & 1 deletion tests/base/config/selectors/selectors.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
"nameFieldLabel": "Name",
"emailFieldLabel": "Email",
"passwordFieldLabel": "Password",
"newPasswordFieldLabel": "New Password",
"passwordConfirmFieldLabel": "Confirm Password",
"loginButtonLabel": "Sign In"
"newPasswordConfirmFieldLabel": "Confirm New Password",
"loginButtonLabel": "Sign In",
"currentPasswordFieldLabel": "Current Password"
},
"personalInformation": {
"firstNameLabel": "First Name",
Expand Down
3 changes: 2 additions & 1 deletion tests/base/config/slugs.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"createAccountSlug": "/customer/account/create",
"addressBookSlug": "/customer/address",
"addressIndexSlug": "/customer/address/index",
"addressNewSlug": "customer/address/new"
"addressNewSlug": "customer/address/new",
"changePasswordSlug": "/customer/account/edit/changepass/1/"
},
"productpage": {
"simpleProductSlug": "/push-it-messenger-bag.html",
Expand Down
28 changes: 4 additions & 24 deletions tests/base/fixtures/account.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ export class AccountPage {
readonly accountCreationPasswordRepeatField: Locator;
readonly accountCreationConfirmButton: Locator;

// fields below are not required when adding an address.
/*
readonly companyField: Locator;
readonly streetAddressFieldTwo: Locator;
readonly streetAddressFieldThree: Locator;
*/

// TODO: Update these functionalities to be able to take in non-required fields.

constructor(page: Page){
this.page = page;
Expand All @@ -49,20 +41,15 @@ export class AccountPage {
this.streetAddressField = page.getByLabel(selectors.newAddress.streetAddressLabel, {exact:true});
this.zipCodeField = page.getByLabel(selectors.newAddress.zipCodeLabel);
this.cityField = page.getByLabel(selectors.newAddress.cityNameLabel);
//TODO: countrySelect is used to change the country so it's not US.
//TODO: provinceSelect should be provinceField if country is, for example, Netherlands.
this.countrySelectorField = page.getByLabel(selectors.newAddress.countryLabel);
this.stateSelectorField = page.getByLabel(selectors.newAddress.provinceSelectLabel).filter({hasText: selectors.newAddress.provinceSelectFilterLabel});
this.saveAddressButton = page.getByRole('button',{name: selectors.newAddress.saveAdressButton});
//unrequired fields
// this.companyField = page.getByLabel(selectors.newAddress.companyNameLabel);

// Account Information elements
this.changePasswordCheck = page.getByRole('checkbox', {name: selectors.personalInformation.changePasswordCheckLabel});
//TODO: Fix these once I can log in again
this.currentPasswordField = page.getByLabel('Current Password');
this.newPasswordField = page.getByLabel('New Password', {exact:true});
this.confirmNewPasswordField = page.getByLabel('Confirm New Password')
this.currentPasswordField = page.getByLabel(selectors.credentials.currentPasswordFieldLabel);
this.newPasswordField = page.getByLabel(selectors.credentials.newPasswordFieldLabel, {exact:true});
this.confirmNewPasswordField = page.getByLabel(selectors.credentials.newPasswordConfirmFieldLabel);
this.genericSaveButton = page.getByRole('button', { name: selectors.general.genericSaveButtonLabel });

// Account Creation elements
Expand All @@ -79,11 +66,9 @@ export class AccountPage {
this.editAddressButton = page.getByRole('link', {name: selectors.accountDashboard.editAddressIconButton}).first();
}

//TODO: Add ability to choose different country other than US
async addNewAddress(phonenumber: string,streetName: string, zipCode: string, cityName: string, state: string){
let addressAddedNotification = verify.address.newAddressAddedNotifcation;


// Name should be filled in automatically.
await expect(this.firstNameField).not.toBeEmpty();
await expect(this.lastNameField).not.toBeEmpty();
Expand All @@ -104,7 +89,6 @@ export class AccountPage {
// the notification for a modified address is the same as the notification for a new address.
let addressModifiedNotification = verify.address.newAddressAddedNotifcation;

// .click() replaced by .press("Enter") as a workaround for webkit issues
await this.editAddressButton.click();

// Name should be filled in automatically, but editable.
Expand All @@ -117,7 +101,7 @@ export class AccountPage {
await this.zipCodeField.fill(zipCode);
await this.cityField.fill(cityName);
await this.stateSelectorField.selectOption(state);
// .click() replaced by .press("Enter") as a workaround for webkit issues

await this.saveAddressButton.click();
await this.page.waitForLoadState();

Expand All @@ -126,8 +110,6 @@ export class AccountPage {
}


// TODO: Update function to remove random address from address book?
// deleteAddressButton is currently the first instance it finds.
async deleteFirstAddressFromAddressBook(){
let addressDeletedNotification = verify.address.addressDeletedNotification;
// Dialog function to click confirm
Expand All @@ -137,7 +119,6 @@ export class AccountPage {
}
});

// .click() replaced by .press("Enter") as a workaround for webkit issues
await this.deleteAddressButton.click();
await this.page.waitForLoadState();
await expect(this.page.getByText(addressDeletedNotification)).toBeVisible();
Expand All @@ -151,7 +132,6 @@ export class AccountPage {
await this.newPasswordField.fill(newPassword);
await this.confirmNewPasswordField.fill(newPassword);

// .click() replaced by .press("Enter") as a workaround for webkit issues
await this.genericSaveButton.click();
await this.page.waitForLoadState();

Expand Down
3 changes: 0 additions & 3 deletions tests/base/fixtures/checkout.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import slugs from '../config/slugs.json';

export class CheckoutPage {

//TODO: Expand with fields for when user is not logged in or has not provided an address
readonly page: Page;
readonly shippingMethodOptionFixed: Locator;
readonly paymentMethodOptionCheck: Locator;
Expand Down Expand Up @@ -53,8 +52,6 @@ export class CheckoutPage {
let orderNumber = await this.page.locator('p').filter({ hasText: 'Your order number is:' }).getByRole('link').innerText();
console.log(`Your ordernumer is: ${orderNumber}`);

// This await only exists to report order number to the HTML reporter.
// TODO: replace this with a proper way to write something to the HTML reporter.
await expect(this.continueShoppingButton, `Your order number is: ${orderNumber}`).toBeVisible();
return orderNumber;
}
Expand Down
Loading

0 comments on commit 0d53844

Please sign in to comment.