Skip to content

martin/qa-challenge #9

New issue

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

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

Already on GitHub? # to your account

Closed
Closed
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
37 changes: 37 additions & 0 deletions .github/workflows/cypress.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Cypress Tests

on:
pull_request:
branches:
- '**'
workflow_dispatch:
inputs:
spec:
description: 'Cypress spec pattern (e.g. cypress/e2e/#_user.cy.ts)'
required: false
default: ''

jobs:
cypress-run:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20

- name: Install dependencies
run: npm ci

- name: Run Cypress tests
run: |
if [ -n "${{ github.event.inputs.spec }}" ]; then
npx cypress run --spec "${{ github.event.inputs.spec }}"
else
npx cypress run
fi
# default the execution to all spec files, but if a specific spec is provided, run that instead
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
27 changes: 27 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { defineConfig } from 'cypress';

export default defineConfig({
e2e: {
baseUrl: 'https://www.automationexercise.com',
specPattern: 'cypress/e2e/**/*.cy.ts',
viewportWidth: 1280,
viewportHeight: 720,
defaultCommandTimeout: 2000,
pageLoadTimeout: 30000,
video: false,
screenshotOnRunFailure: false,
screenshotsFolder: 'cypress/screenshots',
videosFolder: 'cypress/videos',
setupNodeEvents(on, config) {
// implement node event listeners here
return config;
},
},
retries: {
runMode: 2,
openMode: 0,
},
env: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding environment-specific configs

env: {
  apiUrl: 'https://automationexercise.com/api',
  retryAttempts: 3,
  testTimeout: 10000,
}

// Environment variables can be added here
},
});
58 changes: 58 additions & 0 deletions cypress/data/TestDataGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { faker } from '@faker-js/faker';
import { User } from './user';

/**
* Utility class for generating test data
*/
export default class TestDataGenerator {
/**
* Generate random user data for registration
*/
static generateUserData(): User {
const firstName = faker.person.firstName();
const lastName = faker.person.lastName();
const email = faker.internet.email({ firstName, lastName, provider: 'NANLabs.com' });
const password = faker.internet.password({length: 8}) + 'A1!';

return {
name: `${firstName} ${lastName}`,
firstName,
lastName,
email,
password,
dateOfBirth: this.parseDateOfBirth(faker.date.birthdate({ min: 18, max: 65, mode: 'age' }).toString()),
company: faker.company.name(),
address1: faker.location.streetAddress(),
address2: faker.location.streetAddress(false),
country: 'United States',
state: faker.location.state(),
city: faker.location.city(),
zipcode: faker.location.zipCode('#####'),
mobileNumber: faker.phone.number(),
title: faker.helpers.arrayElement(["Mr", "Mrs"]),
newsletter: faker.helpers.arrayElement([true, false]),
specialOffers: faker.helpers.arrayElement([true, false]),
};
}

/**
* Format a date to "DD Month YYYY" (e.g., "10 July 1977")
*/
static parseDateOfBirth(dateString: string): {
day: string;
month: string;
year: string;
} {
const date = new Date(dateString);

const day = date.getUTCDate().toString().padStart(2, '');
const month = date.toLocaleString('en-GB', { month: 'long', timeZone: 'UTC' });
const year = date.getUTCFullYear().toString();

return {
day,
month,
year,
};
}
}
24 changes: 24 additions & 0 deletions cypress/data/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export type User = {
title: 'Mr' | 'Mrs';
firstName: string;
lastName: string;
name: string;
email: string;
password: string;
dateOfBirth: {
day: string;
month: string;
year: string;
};
company: string;
address1: string;
address2: string;
country: string;
state: string;
city: string;
zipcode: string;
mobileNumber: string;
newsletter?: boolean;
specialOffers?: boolean;
};

74 changes: 74 additions & 0 deletions cypress/e2e/#_user.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

import TestDataGenerator from '../data/TestDataGenerator';
import { User } from '../data/user';
import homePage from '../pages/HomePage';
import loginPage from '../pages/#Page';
import { createUser } from '../utils/Helper';

describe('Test Case 3: Login User with incorrect email and password', () => {

// Define test data inline
const invalidUser = {
email: "invalid@example.com",
password: "wrongpassword"
};

beforeEach(() => {
// Clear cookies and local storage to ensure a clean state
cy.clearCookies();
cy.clearLocalStorage();
});

it('should show error message with incorrect credentials', () => {

homePage.visit();
homePage.verifyHomePageIsVisible();

homePage.navbar.click#LoginButton();

loginPage.verifyLoginToYourAccountIsVisible();

// Enter incorrect email address and password
loginPage.login(invalidUser.email, invalidUser.password);

// erify error 'Your email or password is incorrect!' is visible
loginPage.verifyLoginErrorMessage();

});
});

describe('Login User wrong password', () => {

let userData: User;

before(() => {
// Generate random user data for #
userData = TestDataGenerator.generateUserData();

// Create the user through API
createUser(userData);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error Handling & Recovery

// Consider adding error handling for API operations
try {
  createUser(userData);
} catch (error) {
  cy.log('User creation failed, attempting cleanup...');
  // Handle conflicts or retry logic
}


cy.clearCookies();
cy.clearLocalStorage();
});

it('should show error message with incorrect password', () => {


cy.clearCookies();
cy.clearLocalStorage();
homePage.visit();
homePage.verifyHomePageIsVisible();


homePage.navbar.click#LoginButton();

loginPage.verifyLoginToYourAccountIsVisible();

// Enter incorrect email address and password
loginPage.login(userData.email, 'Invalid Password');

// erify error 'Your email or password is incorrect!' is visible
loginPage.verifyLoginErrorMessage();
});
})
52 changes: 52 additions & 0 deletions cypress/e2e/logOut_user.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import homePage from '../pages/HomePage';
import loginPage from '../pages/#Page';
import #Page from '../pages/#Page';
import TestDataGenerator from '../data/TestDataGenerator';
import { User } from '../data/user';
import { createUser } from '../utils/Helper';

describe('Test Case 4: Logout User', () => {

// Store user data for login test
let userData: User;

before(() => {
// Generate random user data for #
userData = TestDataGenerator.generateUserData();

// Create the user through API
createUser(userData);

cy.clearCookies();
cy.clearLocalStorage();
});

beforeEach(() => {
// Clear cookies and local storage to ensure a clean state
cy.clearCookies();
cy.clearLocalStorage();
});

it('should logout successfully', () => {

homePage.visit();
homePage.verifyHomePageIsVisible();

// # Process
homePage.navbar.click#LoginButton();
loginPage.verifyLoginToYourAccountIsVisible();

loginPage.login(userData.email, userData.password);
homePage.navbar.verifyLoggedInAs(userData.name);
// Intercept the logout request to verify it
cy.intercept('GET', '/logout').as('logoutRequest');
homePage.navbar.clickLogoutButton();
// Verify the request
cy.wait('@logoutRequest').then((interception) => {
expect(interception.response?.statusCode).to.eq(302);
});

loginPage.verifyLoginPageIsCurrentPage();
loginPage.verifyNewUser#IsVisible();
});
});
83 changes: 83 additions & 0 deletions cypress/e2e/register_user.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import TestDataGenerator from '../data/TestDataGenerator';
import homePage from '../pages/HomePage';
import loginPage from '../pages/#Page';
import #Page from '../pages/#Page';
import deleteAccountPage from '../pages/DeleteAccountPage';
import { createUser, verifyUserDetailByEmail, verifyUserLoggedIn } from '../utils/Helper';
import { User } from '../data/user';

describe('Test Case 1: Register User', () => {


// Generate random user data for registration

beforeEach(() => {
// Clear cookies and local storage to ensure a clean state
cy.clearCookies();
cy.clearLocalStorage();
});

it('should register a new user successfully', () => {
const userData = TestDataGenerator.generateUserData();
// Visit Home Page
homePage.visit();
homePage.verifyHomePageIsVisible();
// Click on '# / Login' button
homePage.navbar.click#LoginButton();
loginPage.verifyLoginPageIsCurrentPage();
loginPage.verifyNewUser#IsVisible();

// Enter name, email address and click '#' button
loginPage.#(userData.name, userData.email);
loginPage.verifyEnterAccountMessageIsVisible();

//Fill details: Title, Name, Email, Password, Date of birth and newsletter and special offers checkboxes
#Page.fillAccountInfo(userData);
// Fill details of the account adrress section
#Page.fillAddressInfo(userData);
#Page.clickCreateAccountButton();
// We can intercept the request to verify the contents
// Verify that 'ACCOUNT CREATED!' is visible
#Page.verifyAccountCreated();
#Page.clickContinueButton();
//Get the user object from the API and match it with the userData generated for the test
verifyUserDetailByEmail(userData);
// Verify that 'Logged in as username' is visible
homePage.navbar.verifyLoggedInAs(userData.name);
verifyUserLoggedIn(userData.email, userData.password);
// Click 'Delete Account' button
homePage.navbar.clickDeleteAccountButton();
// Verify that 'ACCOUNT DELETED!' is visible and click 'Continue' button
deleteAccountPage.verifyAccountDeletedMessageIsVisible();
deleteAccountPage.clickContinueButton();
});
});

describe('Test Case 5: Register User with existing email', () => {


beforeEach(() => {
// Clear cookies and local storage to ensure a clean state
cy.clearCookies();
cy.clearLocalStorage();
cy.visit('/')
});

it('should show error when registering with existing email', () => {
const userData : User = TestDataGenerator.generateUserData();
// Create a random user with the API endpoint
createUser(userData);

homePage.visit();
homePage.verifyHomePageIsVisible();

// Start # process
homePage.navbar.click#LoginButton();
loginPage.verifyLoginToYourAccountIsVisible();
// Try to register with the generated and registered email
loginPage.#(userData.name, userData.email);

// Verify error 'Email Address already exist!' is visible
loginPage.verify#ErrorMessage('Email Address already exist!');
});
});
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
Loading