Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E2E tests for products #198

Merged
merged 2 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .env.local-example
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ SHOPIFY_MULTIPASS_SECRET=''
# Playwright URL for local runs
PLAYWRIGHT_TEST_BASE_URL='http://127.0.0.1:3000'
# Set a product name to use in your own tests
PLAYWRIGHT_PRODUCT_NAME='Mesh Gym Shorts'
PLAYWRIGHT_PRODUCT_NAME_INSTOCK='Mesh Gym Shorts'
PLAYWRIGHT_PRODUCT_SIZE_INSTOCK='L'
PLAYWRIGHT_PRODUCT_COLOR_INSTOCK='White'
PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK='An Exceptional Tee for Men'
PLAYWRIGHT_PRODUCT_SIZE_OUTOFSTOCK='XS'
PLAYWRIGHT_PRODUCT_COLOR_OUTOFSTOCK='Gray'
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ jobs:
run: npx playwright test
env:
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
PLAYWRIGHT_PRODUCT_NAME: ${{ vars.PLAYWRIGHT_PRODUCT_NAME }}
PLAYWRIGHT_PRODUCT_NAME_INSTOCK: ${{ vars.PLAYWRIGHT_PRODUCT_NAME_INSTOCK }}
PLAYWRIGHT_PRODUCT_SIZE_INSTOCK: ${{ vars.PLAYWRIGHT_PRODUCT_SIZE_INSTOCK }}
PLAYWRIGHT_PRODUCT_COLOR_INSTOCK: ${{ vars.PLAYWRIGHT_PRODUCT_COLOR_INSTOCK }}
PLAYWRIGHT_COLLECTION_NAME: ${{ vars.PLAYWRIGHT_COLLECTION_NAME }}
PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK: ${{ vars.PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK }}
PLAYWRIGHT_PRODUCT_SIZE_OUTOFSTOCK: ${{ vars.PLAYWRIGHT_PRODUCT_SIZE_OUTOFSTOCK }}
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,12 @@ You can run and develop your Playwright tests locally using the following proces
### CI
Make sure you have set these environment variables in your repository:
- `PLAYWRIGHT_TEST_BASE_URL` - this will be set automatically by the GitHub Actions workflow;
- `PLAYWRIGHT_PRODUCT_NAME` - a product name to find in a collection and use in tests;
- `PLAYWRIGHT_COLLECTION_NAME` - the name of the collection that your `PLAYWRIGHT_PRODUCT_NAME` relates to.
- `PLAYWRIGHT_PRODUCT_NAME_INSTOCK` - a product name to find in a collection and use in tests;
- `PLAYWRIGHT_PRODUCT_SIZE_INSTOCK` and `PLAYWRIGHT_PRODUCT_COLOR_INSTOCK` - should be the combination of size and color for your `PLAYWRIGHT_PRODUCT_NAME_INSTOCK` product;
- `PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK` - a product name to find in a collection and use in tests;
- `PLAYWRIGHT_PRODUCT_SIZE_OUTOFSTOCK` and `PLAYWRIGHT_PRODUCT_COLOR_OUTOFSTOCK` - should be the combination of size and color for your `PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK` product;
- `PLAYWRIGHT_COLLECTION_NAME` - the name of the collection that your `PLAYWRIGHT_PRODUCT_NAME_INSTOCK` and `PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK` relate to.
- `PLAYWRIGHT_BRAND_NAME` - any brand name in your store.

# Deploying to production

Expand Down
4 changes: 3 additions & 1 deletion e2e/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { faker } from '@faker-js/faker';

export const PRODUCT_NAME = process.env.PLAYWRIGHT_PRODUCT_NAME;
export const PRODUCT_NAME_INSTOCK = process.env.PLAYWRIGHT_PRODUCT_NAME_INSTOCK;
export const PRODUCT_COLOR_INSTOCK = process.env.PLAYWRIGHT_PRODUCT_COLOR_INSTOCK;
export const PRODUCT_SIZE_INSTOCK = process.env.PLAYWRIGHT_PRODUCT_SIZE_INSTOCK;
export const PRODUCT_OUTOFSTOCK = process.env.PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK;
export const PRODUCT_COLOR_OUTOFSTOCK = process.env.PLAYWRIGHT_PRODUCT_COLOR_OUTOFSTOCK;
export const PRODUCT_SIZE_OUTOFSTOCK = process.env.PLAYWRIGHT_PRODUCT_SIZE_OUTOFSTOCK;
Expand Down
6 changes: 6 additions & 0 deletions e2e/page-objects/collections-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Page } from '@playwright/test';
import { expect } from 'playwright/test';

export class CollectionsPage {
readonly page: Page;
Expand All @@ -13,4 +14,9 @@ export class CollectionsPage {
collectionSection = () => this.page.getByTestId('collection-section');
brandsSection = () => this.collectionSection().filter({ hasText: 'Brands' }).getByRole('list');
getBrandByName = (brand: string) => this.brandsSection().getByText(brand, { exact: true });

async selectProduct(productName: string) {
await this.getProductByName(productName).click();
await expect(this.page.getByLabel('Breadcrumb')).toContainText(productName);
}
}
41 changes: 41 additions & 0 deletions e2e/tests/product-page.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { test } from '../fixtures';
import { expect } from 'playwright/test';
import { getCollectionEndpoint } from '../utils';
import { COLLECTION_NAME, PRODUCT_COLOR_INSTOCK, PRODUCT_NAME_INSTOCK, PRODUCT_SIZE_INSTOCK } from '../constants';

test.describe('Product page', () => {
test.beforeEach('Navigate to the product', async ({ page, productPage, collectionsPage }) => {
if (!COLLECTION_NAME) {
test.skip(!COLLECTION_NAME, 'PLAYWRIGHT_COLLECTION_NAME was not defined');
return;
}
if (!PRODUCT_NAME_INSTOCK) {
test.skip(!PRODUCT_NAME_INSTOCK, 'PLAYWRIGHT_PRODUCT_NAME_INSTOCK was not defined');
return;
}

await page.goto(getCollectionEndpoint());
await collectionsPage.selectProduct(PRODUCT_NAME_INSTOCK);
});

test('Select product color and size and verify they displayed properly in the shopping cart', async ({
productPage,
shoppingCart
}) => {
if (!PRODUCT_COLOR_INSTOCK) {
test.skip(!PRODUCT_COLOR_INSTOCK, 'PLAYWRIGHT_PRODUCT_COLOR_INSTOCK was not defined');
return;
}
if (!PRODUCT_SIZE_INSTOCK) {
test.skip(!PRODUCT_SIZE_INSTOCK, 'PLAYWRIGHT_PRODUCT_SIZE_INSTOCK was not defined');
return;
}

await productPage.colorPicker(PRODUCT_COLOR_INSTOCK).click();
await productPage.sizePickerEnabled().getByText(PRODUCT_SIZE_INSTOCK, { exact: true }).click();
await expect(productPage.addToCartBtn()).not.toBeDisabled();
await productPage.addToCartBtn().click();
await shoppingCart.cartDialog().waitFor();
await expect(shoppingCart.shoppingCartItems()).toContainText(`${PRODUCT_COLOR_INSTOCK} / ${PRODUCT_SIZE_INSTOCK}`);
});
});
36 changes: 16 additions & 20 deletions e2e/tests/shopping-cart.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { test } from '../fixtures';
import {
COLLECTION_NAME,
PRODUCT_COLOR_OUTOFSTOCK,
PRODUCT_NAME,
PRODUCT_NAME_INSTOCK,
PRODUCT_OUTOFSTOCK,
PRODUCT_SIZE_OUTOFSTOCK
} from '../constants';
Expand All @@ -19,33 +19,32 @@ test.describe('Shopping cart', () => {
});

test('User is able to add product to cart', async ({ page, collectionsPage, shoppingCart, productPage }) => {
if (!PRODUCT_NAME) {
test.skip(!PRODUCT_NAME, 'PLAYWRIGHT_PRODUCT_NAME was not defined');
if (!PRODUCT_NAME_INSTOCK) {
test.skip(!PRODUCT_NAME_INSTOCK, 'PLAYWRIGHT_PRODUCT_NAME_INSTOCK was not defined');
return;
}

await collectionsPage.getProductByName(PRODUCT_NAME).click();
await expect(page.getByLabel('Breadcrumb')).toContainText(PRODUCT_NAME);
await collectionsPage.selectProduct(PRODUCT_NAME_INSTOCK);

const productPrice = await productPage.productPrice().innerText();

await productPage.addToCartBtn().click();
await expect(page.getByText('Shopping cart')).toBeVisible();
await expect(shoppingCart.shoppingCartItems()).toHaveCount(1);
await expect(shoppingCart.shoppingCartItems()).toContainText(PRODUCT_NAME);
await expect(shoppingCart.shoppingCartItems()).toContainText(PRODUCT_NAME_INSTOCK);
await expect(shoppingCart.cartTotalPrice()).toContainText(productPrice);
});

test('Checkout phase', async ({ page, shoppingCart, collectionsPage, productPage }) => {
if (!PRODUCT_NAME) {
test.skip(!PRODUCT_NAME, 'PLAYWRIGHT_PRODUCT_NAME was not defined');
if (!PRODUCT_NAME_INSTOCK) {
test.skip(!PRODUCT_NAME_INSTOCK, 'PLAYWRIGHT_PRODUCT_NAME_INSTOCK was not defined');
return;
}

await collectionsPage.getProductByName(PRODUCT_NAME).click();
await collectionsPage.selectProduct(PRODUCT_NAME_INSTOCK);
await productPage.addToCartBtn().click();
await expect(page.getByText('Shopping cart')).toBeVisible();
await expect(shoppingCart.shoppingCartItems()).toContainText(PRODUCT_NAME);
await expect(shoppingCart.shoppingCartItems()).toContainText(PRODUCT_NAME_INSTOCK);

await page.goto('/?shopify_checkout_action=success');

Expand All @@ -61,13 +60,12 @@ test.describe('Shopping cart', () => {
});

test('Adjust the number of items', async ({ shoppingCart, page, collectionsPage, productPage }) => {
if (!PRODUCT_NAME) {
test.skip(!PRODUCT_NAME, 'PLAYWRIGHT_PRODUCT_NAME was not defined');
if (!PRODUCT_NAME_INSTOCK) {
test.skip(!PRODUCT_NAME_INSTOCK, 'PLAYWRIGHT_PRODUCT_NAME_INSTOCK was not defined');
return;
}

await collectionsPage.getProductByName(PRODUCT_NAME).click();
await page.getByLabel('Breadcrumb').waitFor();
await collectionsPage.selectProduct(PRODUCT_NAME_INSTOCK);

const productPrice = await productPage.productPrice().innerText();
const convertedPrice = parseFloat(productPrice.replace('$', ''));
Expand All @@ -86,13 +84,12 @@ test.describe('Shopping cart', () => {
});

test('Remove items from the cart', async ({ shoppingCart, page, collectionsPage, productPage }) => {
if (!PRODUCT_NAME) {
test.skip(!PRODUCT_NAME, 'PLAYWRIGHT_PRODUCT_NAME was not defined');
if (!PRODUCT_NAME_INSTOCK) {
test.skip(!PRODUCT_NAME_INSTOCK, 'PLAYWRIGHT_PRODUCT_NAME_INSTOCK was not defined');
return;
}

await collectionsPage.getProductByName(PRODUCT_NAME).click();
await page.getByLabel('Breadcrumb').waitFor();
await collectionsPage.selectProduct(PRODUCT_NAME_INSTOCK);

const productPrice = await productPage.productPrice().innerText();

Expand Down Expand Up @@ -120,8 +117,7 @@ test.describe('Shopping cart', () => {
return;
}

await collectionsPage.getProductByName(PRODUCT_OUTOFSTOCK).click();
await page.getByLabel('Breadcrumb').waitFor();
await collectionsPage.selectProduct(PRODUCT_OUTOFSTOCK);

await productPage.colorPicker(PRODUCT_COLOR_OUTOFSTOCK).click();
await productPage.sizePickerDisabled().getByText(PRODUCT_SIZE_OUTOFSTOCK, { exact: true }).click();
Expand Down
Loading