Skip to content
Open
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
31 changes: 31 additions & 0 deletions .features-gen/features/login.feature.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Generated from: features\login.feature
import { test } from "playwright-bdd";

test.describe('Login Feature', () => {

test.beforeEach('Background', async ({ Given, page }, testInfo) => { if (testInfo.error) return;
await Given('I open the "https://www.saucedemo.com/" page', null, { page });
});

test('Validate the login page title', async ({ Then, page }) => {
await Then('I should see the title "Swag Labs"', null, { page });
});

test('Validate login error message', async ({ Then, page }) => {
await Then('I will login as \'locked_out_user\'', null, { page });
});

});

// == technical section ==

test.use({
$test: [({}, use) => use(test), { scope: 'test', box: true }],
$uri: [({}, use) => use('features\\login.feature'), { scope: 'test', box: true }],
$bddFileData: [({}, use) => use(bddFileData), { scope: "test", box: true }],
});

const bddFileData = [ // bdd-data-start
{"pwTestLine":10,"pickleLine":6,"tags":[],"steps":[{"pwStepLine":7,"gherkinStepLine":4,"keywordType":"Context","textWithKeyword":"Given I open the \"https://www.saucedemo.com/\" page","isBg":true,"stepMatchArguments":[{"group":{"start":11,"value":"\"https://www.saucedemo.com/\"","children":[{"start":12,"value":"https://www.saucedemo.com/","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]},{"pwStepLine":11,"gherkinStepLine":8,"keywordType":"Outcome","textWithKeyword":"Then I should see the title \"Swag Labs\"","stepMatchArguments":[{"group":{"start":23,"value":"\"Swag Labs\"","children":[{"start":24,"value":"Swag Labs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},
{"pwTestLine":14,"pickleLine":10,"tags":[],"steps":[{"pwStepLine":7,"gherkinStepLine":4,"keywordType":"Context","textWithKeyword":"Given I open the \"https://www.saucedemo.com/\" page","isBg":true,"stepMatchArguments":[{"group":{"start":11,"value":"\"https://www.saucedemo.com/\"","children":[{"start":12,"value":"https://www.saucedemo.com/","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]},{"pwStepLine":15,"gherkinStepLine":11,"keywordType":"Outcome","textWithKeyword":"Then I will login as 'locked_out_user'","stepMatchArguments":[{"group":{"start":16,"value":"'locked_out_user'","children":[{"children":[{"children":[]}]},{"start":17,"value":"locked_out_user","children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},
]; // bdd-data-end
27 changes: 27 additions & 0 deletions .features-gen/features/purchase.feature.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Generated from: features\purchase.feature
import { test } from "playwright-bdd";

test.describe('Purchase Feature', () => {

test.beforeEach('Background', async ({ Given, page }, testInfo) => { if (testInfo.error) return;
await Given('I open the "https://www.saucedemo.com/" page', null, { page });
});

test('Validate successful purchase text', async ({ Then, page }) => {
await Then('I will login as \'standard_user\'', null, { page });
await Then('I will add the backpack to the cart', null, { page });
});

});

// == technical section ==

test.use({
$test: [({}, use) => use(test), { scope: 'test', box: true }],
$uri: [({}, use) => use('features\\purchase.feature'), { scope: 'test', box: true }],
$bddFileData: [({}, use) => use(bddFileData), { scope: "test", box: true }],
});

const bddFileData = [ // bdd-data-start
{"pwTestLine":10,"pickleLine":6,"tags":[],"steps":[{"pwStepLine":7,"gherkinStepLine":4,"keywordType":"Context","textWithKeyword":"Given I open the \"https://www.saucedemo.com/\" page","isBg":true,"stepMatchArguments":[{"group":{"start":11,"value":"\"https://www.saucedemo.com/\"","children":[{"start":12,"value":"https://www.saucedemo.com/","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]},{"pwStepLine":11,"gherkinStepLine":7,"keywordType":"Outcome","textWithKeyword":"Then I will login as 'standard_user'","stepMatchArguments":[{"group":{"start":16,"value":"'standard_user'","children":[{"children":[{"children":[]}]},{"start":17,"value":"standard_user","children":[{"children":[]}]}]},"parameterTypeName":"string"}]},{"pwStepLine":12,"gherkinStepLine":8,"keywordType":"Outcome","textWithKeyword":"Then I will add the backpack to the cart","stepMatchArguments":[]}]},
]; // bdd-data-end
27 changes: 27 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
11 changes: 8 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
report.json
cucumber_report.html
/node_modules

# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Dispatch to Grader

on:
pull_request_target:
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number in this repo (e.g., 119)'
required: true

jobs:
notify-grader:
runs-on: ubuntu-latest
steps:
- name: Verify token can access private grader repo
run: |
code=$(curl -s -o /dev/null -w "%{http_code}\n" \
-H "Authorization: token ${{ secrets.GRADER_REPO_PAT }}" \
https://api.github.com/repos/automationExamples/Playwright-Cucumber-Exercise-Eval)
echo "HTTP $code"; test "$code" = "200"

- name: Send repository_dispatch to grader
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.GRADER_REPO_PAT }}
repository: automationExamples/Playwright-Cucumber-Exercise-Eval
event-type: grade-assessment
client-payload: >
{
"pr_number": "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.pr_number || github.event.pull_request.number }}",
"repo_full": "${{ github.repository }}"
}
3 changes: 3 additions & 0 deletions Playwright-Cucumber-Exercise-main/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
report.json
cucumber_report.html
/node_modules
58 changes: 58 additions & 0 deletions Playwright-Cucumber-Exercise-main/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Sample Playwright Automation Test

## System Requirements

node >= v18.5.x

npm >= v7


## Setup

// Install Visual Studio Code (or any editor)

https://code.visualstudio.com/download


// Install Node.js

https://nodejs.org/en/download


```bash
git clone https://github.com/automationExamples/Playwright-Cucumber-Exercise.git
npm install
npx playwright install
```

### Recommended vscode extensions

Cucumber v1.7.0

Cucumber (Gherkin) Support enhanced for Behat


## Instructions
To run the test
```bash
npm run test
```

After running, to generate the cucumber report (cucumber_report.html)
```bash
npm run report
```

It is not expected that you complete every task, however, please give your best effort

You will be scored based on your ability to complete the following tasks:

- [ ] Install and setup this repository on your personal computer
- [ ] Complete the automation tasks listed below

### Tasks
- [ ] Modify the scenario 'Validate the login page title' from [login.feature](features/login.feature#8) which runs but fails. Determine the cause of the failure and update the scenario to pass in the test
- [ ] Extend the scenario 'Validate login error message' from [login.feature](features/login.feature#10) which runs and passes but is missing a step. Extend the scenario to validate the error message received.
- [ ] Modify and extend the 'Validate successful purchase text' from [purchase.feature](features/purchase.feature#6) with steps for each comment listed. Consider writing a new steps.ts file along with an appropriate page.ts
- [ ] Modify and extend the 'Validate product sort by price sort' from [product.feature](features/product.feature#6) with steps for each comment listed. Utilize the Scenario Outline and Examples table to parameterize the test
- [ ] Extend the testing coverage with anything you believe would be beneficial
3 changes: 3 additions & 0 deletions Playwright-Cucumber-Exercise-main/cucumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
default: `--require-module ts-node/register --require './steps/**/*.ts' --require './hooks/**/*.ts --format @cucumber/pretty-formatter`
};
12 changes: 12 additions & 0 deletions Playwright-Cucumber-Exercise-main/features/login.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Feature: Login Feature

Background:
Given I open the "https://www.saucedemo.com/" page

Scenario: Validate the login page title
# TODO: Fix this failing scenario
Then I should see the title "Labs Swag"

Scenario: Validate login error message
Then I will login as 'locked_out_user'
# TODO: Add a step to validate the error message received
26 changes: 26 additions & 0 deletions Playwright-Cucumber-Exercise-main/features/login/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//import { Given, When, Then } from "cypress-cucumber-preprocessor/steps";
import { test, createBdd } from "playwright-bdd";

import { expect } from "@playwright/test"; // Import expect


const { Given, When, Then }= createBdd(test);

Given('I open the {string} page', async ({page}, url) => {
await page.goto(url);
});
Then('I should see the title {string}',async ({page},title) => {
(await page.title()).includes(title).toBeTruthy;});


Then('I will login as {string}', async ({page}, username) => {

await page.locator('#user-name').fill(username);
await page.locator('#password').fill('secret_sauce');
await page.locator('#login-button').click();

const errorMessage = await page.locator('.error-message-container').allInnerTexts();
expect(errorMessage.includes('Epic sadface')).toBeTruthy;
});


17 changes: 17 additions & 0 deletions Playwright-Cucumber-Exercise-main/features/product.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Feature: Product Feature

Background:
Given I open the "https://www.saucedemo.com/" page

# Create a datatable to validate the Price (high to low) and Price (low to high) sort options (top-right) using a Scenario Outline
Scenario Outline: Validate product sort by price <sort>
When I will login as 'standard_user'
Then I sort products by "<sort_option>"

Examples:
| sort_option |
| Price (low to high) |
| Price (high to low) |



53 changes: 53 additions & 0 deletions Playwright-Cucumber-Exercise-main/features/product/product.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { test,createBdd } from "playwright-bdd";
import { expect } from '@playwright/test';
const { Given, When, Then }= createBdd(test);

Given('I open the Product page', async({page},url) => {
await page.goto(url);
});

When('I will login as user', async ({page}, username) => {

await page.locator('#user-name').fill(username);
await page.locator('#password').fill('secret_sauce');
await page.locator('#login-button').click();
await page.locator('.inventory_list').isVisible();
await page.locator('.inventory_list').shouldBeVisible();
});

Then('I sort products by {string}', async ({page}, sort_option) => {

if(sort_option === 'Price (low to high)') {

await page.locator('.product_sort_container').click();
await page.locator('.product_sort_container').selectOption('lohi');

const firstProductText = await page.locator('.inventory_item').first().allInnerTexts();
console.log('First product:', firstProductText);
expect(firstProductText.some(text => text.includes('Sauce Labs Onesie'))).toBeTruthy();

const lastProductText = await page.locator('.inventory_item').last().allInnerTexts();

console.log('Last product:', lastProductText);
expect(lastProductText.some(text => text.includes('Sauce Labs Fleece Jacket'))).toBeTruthy();


}
else if(sort_option === 'Price (high to low)') {

await page.locator('.product_sort_container').click();
await page.locator('.product_sort_container').selectOption('hilo');

const firstProductText = await page.locator('.inventory_item').first().allInnerTexts();
console.log('First product:', firstProductText);
expect(firstProductText.some(text => text.includes('Sauce Labs Fleece Jacket'))).toBeTruthy();

const lastProductText = await page.locator('.inventory_item').last().allInnerTexts();

console.log('Last product:', lastProductText);
expect(lastProductText.some(text => text.includes('Sauce Labs Onesie'))).toBeTruthy();


}

});
14 changes: 14 additions & 0 deletions Playwright-Cucumber-Exercise-main/features/purchase.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Feature: Purchase Feature

Background:
Given I open the "https://www.saucedemo.com/" page

Scenario: Validate successful purchase text
Then I will login as 'standard_user'
Then I will add the backpack to the cart
# TODO: Select the cart (top-right)
# TODO: Select Checkout
# TODO: Fill in the First Name, Last Name, and Zip/Postal Code
# TODO: Select Continue
# TODO: Select Finish
# TODO: Validate the text 'Thank you for your order!'
32 changes: 32 additions & 0 deletions Playwright-Cucumber-Exercise-main/features/purchase/purchase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { test, createBdd } from "playwright-bdd";

const { Given, When, Then }= createBdd(test);

//import { Given, When, Then } from "cypress-cucumber-preprocessor/steps";

Given('I open the Purchase page', async({page},url) => {
await page.goto(url);
});

Then("Then I will login as {string}", async({page},username) => {
await page.locator('#user-name').fill(username);
await page.locator('#password').fill('secret_sauce');
await page.locator('#login-button').click();
});

Then('I will add the backpack to the cart', async({page},item) => {
await page.locator('#add-to-cart-sauce-labs-backpack').click();
//await page.locator('.shopping_cart_badge').includes('1').tobeTruthy;
await page.locator('.shopping_cart_link').click();

//await page.locator('.cart_item').includes('Sauce Labs Backpack').tobeTruthy;
await page.locator('#checkout').click();
await page.locator('#first-name').fill('Smrutiranjan');
await page.locator('#last-name').fill('Mohanty');
await page.locator('#postal-code').fill('123456');
await page.locator('#continue').click();

//await page.locator('.cart_item').includes('Sauce Labs Backpack').tobeTruthy;
await page.locator('#finish').click();
//await page.locator('.complete-header').includes('Thank you for your order!').tobeTruthy;
});
13 changes: 13 additions & 0 deletions Playwright-Cucumber-Exercise-main/generate-report.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const reporter = require('cucumber-html-reporter');

const options = {
theme: 'bootstrap',
jsonFile: 'report.json',
output: 'cucumber_report.html',
reportSuiteAsScenarios: true,
scenarioTimestamp: true,
launchReport: true,
metadata: {}
};

reporter.generate(options);
13 changes: 13 additions & 0 deletions Playwright-Cucumber-Exercise-main/hooks/globalHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { After, Before, setDefaultTimeout } from "@cucumber/cucumber";
import { closeBrowser, initializeBrowser, initializePage } from "../playwrightUtilities";

setDefaultTimeout(15000);

Before( async () => {
await initializeBrowser();
await initializePage();
})

After( async () => {
await closeBrowser();
})
Loading
Loading