0% found this document useful (0 votes)
21 views32 pages

Lab 1

The document outlines a comprehensive test plan for the AuthKit Authentication Library, detailing various test cases for user registration, including valid and invalid scenarios. It includes Playwright code for automated testing of these cases, alongside boundary value analysis for book prices and decision table testing for discounts based on user login status and cart value. Additionally, it describes state transition testing for login functionality, ensuring robust coverage of the authentication process.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views32 pages

Lab 1

The document outlines a comprehensive test plan for the AuthKit Authentication Library, detailing various test cases for user registration, including valid and invalid scenarios. It includes Playwright code for automated testing of these cases, alongside boundary value analysis for book prices and decision table testing for discounts based on user login status and cart value. Additionally, it describes state transition testing for login functionality, ensuring robust coverage of the authentication process.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

Addis Ababa Institute of Technology

School of Information Technology and


Engineering
AuthKit Authentication Authentication Library
Test Plan Document

NAME ID SECTION

Netsanet Tewodros UGR/3048/13​ ​ ​ ​ 2


Lab 1

Input Type or Test Case Input Value Expected Equivalence


test case Description Output Class

Valid Email and Both are Valid eve.holt@reqre HTTP 200 OK, valid
password s.in, pistol Token returned

Missing Email provided eve.holt@reqre HTTP invalid


password and password is s.in, null 400,”Missing
missing password” error

Missing email Password null, pistol HTTP 400, invalid


provided and "Missing email
email is missing or username"

Invalid Email Incorrect format invalid-email, HTTP 400, invalid


Format email pistol "Note: Only
defined users
succeed
registration
"

Both Missing Both the email null, null HTTP 400, invalid
and password is "Missing email
not provided or username"

Email is not netsi@reqres.in HTTP 400, invalid


available in data , pistol "Note: Only
base defined users
succeed
registration
"
Postman screenshot one
Postman screenshot two
Postman screenshot three
Postman screenshoot four
Postman screenshoot five
Postman screenshoot six
Playwright screenshoot

playwright code

import { test, expect, request } from '@playwright/test';

// Test case 1: Valid input


test('Register user with valid credentials and API key', async () => {
const apiContext = await request.newContext({
baseURL: 'https://reqres.in',
extraHTTPHeaders: {
'Content-Type': 'application/json',
'x-api-key': 'reqres-free-v1'
}
})

const response = await apiContext.post('/api/register', {


data: {
email: 'eve.holt@reqres.in',
password: 'pistol'
}
});

expect(response.status()).toBe(200);

const responseBody = await response.json();


console.log('Response:', responseBody);
expect(responseBody).toHaveProperty('id');
expect(responseBody).toHaveProperty('token');
});

// Test case 2: Missing password


test('Register user with missing password', async () => {
const apiContext = await request.newContext({
baseURL: 'https://reqres.in',
extraHTTPHeaders: {
'Content-Type': 'application/json',
'x-api-key': 'reqres-free-v1'
}
});

const response = await apiContext.post('/api/register', {


data: {
email: 'eve.holt@reqres.in',
password: ''
}
});

expect(response.status()).toBe(400);
const responseBody = await response.json();
console.log('Response:', responseBody);
expect(responseBody.error).toBe('Missing password');
});

// Test case 3: Missing email


test('Register user with missing email', async () => {
const apiContext = await request.newContext({
baseURL: 'https://reqres.in',
extraHTTPHeaders: {
'Content-Type': 'application/json',
'x-api-key': 'reqres-free-v1'
}
});

const response = await apiContext.post('/api/register', {


data: {
email: '',
password: 'pistol'
}
});
expect(response.status()).toBe(400);
const responseBody = await response.json();
console.log('Response:', responseBody);
expect(responseBody.error).toBe('Missing email or username');
});

// Test case 4: Invalid email format


test('Register user with invalid email format', async () => {
const apiContext = await request.newContext({
baseURL: 'https://reqres.in',
extraHTTPHeaders: {
'Content-Type': 'application/json',
'x-api-key': 'reqres-free-v1'
}
});

const response = await apiContext.post('/api/register', {


data: {
email: 'not-an-email',
password: 'pistol'
}
});

expect(response.status()).toBe(400);
const responseBody = await response.json();
console.log('Response:', responseBody);
expect(responseBody.error).toBe('Note: Only defined users succeed
registration');
});

// Test case 5: Both fields empty


test('Register user with both fields empty', async () => {
const apiContext = await request.newContext({
baseURL: 'https://reqres.in',
extraHTTPHeaders: {
'Content-Type': 'application/json',
'x-api-key': 'reqres-free-v1'
}
});

const response = await apiContext.post('/api/register', {


data: {
email: '',
password: ''
}
});

expect(response.status()).toBe(400);
const responseBody = await response.json();
console.log('Response:', responseBody);
expect(responseBody.error).toBe('Missing email or username');

// Test case 6: Email not in database

});
test('Register user with email not in database', async () => {
const apiContext = await request.newContext({
baseURL: 'https://reqres.in',
extraHTTPHeaders: {
'Content-Type': 'application/json',
'x-api-key': 'reqres-free-v1'
}
});

const response = await apiContext.post('/api/register', {


data: {
email: 'unknown.user@reqres.in',
password: 'pistol'
}
});

expect(response.status()).toBe(400);
const responseBody = await response.json();
console.log('Response:', responseBody);
expect(responseBody.error).toBe('Note: Only defined users succeed
registration');
});
Lab 2
book prices
Test Type Value description

Minium 0.00 At the lower limit

Low 0.01 above the lower limit

Nominal 50.00 Middle of the range

High 99.99 Below the upper boundary

Maximum 100.00 At the upper boundary

Invalid -0.01 Below minimum and not exit

Invalid 100.01 Above maximum and not


exist

Boundary value test matrix

Test Case ID Test Condition Expected Result Actual Result

TC01 Price = 0 (Minium) No book price


should be below 0

TC02 Price = 0.01 (Low) Book price should


be ≥ 0.01

TC03 Price = 50 (Nominal) Book prices should


be valid and shown

TC04 Price = 99.99 (High) Book prices should


be ≤ 99.99

TC05 Price = 100 Book prices should


(Maximum) not exceed 100

TC06 Price < 0 (Invalid) Should not exist or


cause errors

TC07 Price > 100 (Invalid) Should not exist or


cause errors
Manually

Book Title Price

A Light in the Attic £51.77

Tipping the Velvet £53.74

Soumission £50.10

Sharp Objects £47.82

Sapiens £54.23

The Requiem Red £22.65

The Dirty Little £33.34

The coming women £17.93


import { test, expect } from '@playwright/test';
test('Boundary Value Analysis - Book Prices', async ({ page }) => {
await page.goto('http://books.toscrape.com/');

let pageNumber = 1;
let hasNextPage = true;

while (hasNextPage) {
console.log(`Checking page ${pageNumber}`);

// Take a screenshot of the current page


await page.screenshot({ path: `page_${pageNumber}.png` });

// Extract prices from current page


const prices = await page.$$eval('.product_price .price_color',
elements =>
elements.map(el => parseFloat(el.textContent!.replace('£',
'').trim()))
);

// Boundary checks
for (const price of prices) {
console.log(`Found price: £${price}`);
expect(price).toBeGreaterThanOrEqual(0);
expect(price).toBeLessThanOrEqual(100);
}

// Try to navigate to next page


const nextButton = page.locator('.next > a');
if (await nextButton.count()) {


await Promise.all([
page.waitForURL(/page-\d+\.html/), // Wait for URL change
instead of load state
nextButton.click()
]);
pageNumber++;
} else {
hasNextPage = false;
}
}

console.log('All prices validated against boundary values.');


});
Lab 3
1. Decision Table

Test Cases Logged In Coupon applied Cart ≥ $100 Expected


Discount

TC1 Yes Yes Yes 20%

TC2 No Yes Yes 10%

TC3 Yes No Yes 5%

TC4 No No No 0%

TC5 Yes Yes No 0%

TC6 Yes No No 0%

TC7 No Yes No 0%

TC8 No No Yes 0%
3.2 Designing Test Cases from the Decision Table
TC1: Logged in, Coupon Applied, Cart ≥ $100

●​ Preconditions: User is logged in, has a valid coupon​

●​ Steps:​

1.​ Log in with valid credentials​

2.​ Add items to cart worth $100+​

3.​ Apply a valid coupon​

4.​ View the discount​

●​ Expected Result: 20% discount is applied

TC2: Not Logged in, Coupon Applied, Cart ≥ $100

●​ Preconditions: Guest user, has a valid coupon​

●​ Steps:​

1.​ Open the site without logging in​

2.​ Add items to cart worth $100+​

3.​ Apply a valid coupon​

4.​ View the discount​

●​ Expected Result: 10% discount is applied

TC3: Logged in, No Coupon, Cart ≥ $100

●​ Preconditions: Logged-in user, no coupon used​

●​ Steps:​

1.​ Log in​

2.​ Add items to cart worth $100+​

3.​ Do not apply any coupon​

4.​ View the discount​

●​ Expected Result: 5% discount is applied

TC4: Not Logged in, No Coupon, Cart < $100


●​ Preconditions: Guest user, no coupon, low cart value​

●​ Steps:​

1.​ Open the site without logging in​

2.​ Add items to cart worth less than $100 (e.g., $50)​

3.​ Do not apply a coupon​

4.​ View the discount​

●​ Expected Result: 0% discount

TC5: Logged in, Coupon Applied, Cart < $100

●​ Preconditions: Logged in, valid coupon, cart below threshold​

●​ Steps:​

1.​ Log in​

2.​ Add items to cart worth less than $100​

3.​ Apply coupon​

4.​ View the discount​

●​ Expected Result: 0% discount

TC6: Logged in, No Coupon, Cart < $100

●​ Preconditions: Logged in, no coupon, small cart​

●​ Steps:​

1.​ Log in​

2.​ Add items to cart worth less than $100​

3.​ Don’t apply coupon​

4.​ View the discount​

●​ Expected Result: 0% discount

TC7: Not Logged in, Coupon Applied, Cart < $100

●​ Preconditions: Guest user, coupon used, cart < $100​

●​ Steps:​

1.​ Open the site without logging in​


2.​ Add items to cart worth less than $100​

3.​ Apply coupon​

4.​ View the discount​

●​ Expected Result: 0% discount

TC8: Not Logged in, No Coupon, Cart ≥ $100

●​ Preconditions: Guest user, high cart value, no coupon​

●​ Steps:​

1.​ Open site as guest​

2.​ Add items worth $100 or more​

3.​ Don’t apply coupon​

4.​ View the discount​

●​ Expected Result: 0% discount

Playwright code
Code:

import { test, expect } from '@playwright/test';

const testCases = [

{ loggedIn: true, couponApplied: true, cartTotal: 150,


expectedDiscount: 20 },

{ loggedIn: false, couponApplied: true, cartTotal: 150,


expectedDiscount: 10 },

{ loggedIn: true, couponApplied: false, cartTotal: 150,


expectedDiscount: 5 },
{ loggedIn: false, couponApplied: false, cartTotal: 50,
expectedDiscount: 0 },

];

testCases.forEach(({ loggedIn, couponApplied, cartTotal,


expectedDiscount }) => {

test(`loggedIn=${loggedIn}, couponApplied=${couponApplied},
cartTotal=${cartTotal}`, async ({ page }) => {

// STEP 1: Optional login

if (loggedIn) {

await page.goto('https://demo.nopcommerce.com/login');

await page.fill('input#Email', 'netsanettewodros62@gmail.com');

await page.fill('input#Password', '123123123');

await page.click('button.login-button'); // Adjust if needed

await page.waitForLoadState('networkidle');

// STEP 2: Go to Cart Page

await page.goto('https://demo.nopcommerce.com/cart');

// STEP 3: Apply coupon (if needed)

if (couponApplied) {

await page.fill('input[name="discountcouponcode"]',
'DISCOUNT2025');

await page.click('button[name="applydiscountcouponcode"]');

await page.waitForLoadState('networkidle');
}

// STEP 4: Simulate cart total (You need to pre-add enough items


manually for now)

// STEP 5: Get discount info — check HTML class from browser!

const discountElement = await page.locator('.order-total


.discount-value'); // You must inspect & confirm this selector

const discountExists = await discountElement.count();

let actualDiscount = 0;

if (discountExists) {

const text = await discountElement.textContent();

if (text) {

const percentMatch = text.match(/(\d+)%/);

if (percentMatch) {

actualDiscount = parseFloat(percentMatch[1]);

// STEP 6: Check result

expect(actualDiscount).toBe(expectedDiscount);

});

});
Lab 4

Define States and Transitions

States:

A: Start​

B: Logged In​

C: Invalid Attempt​

D: Locked Out (after 3 failures, if supported)​

Transitions:

A → B: Valid credentials​

A → C: Invalid credentials​

C → C: Repeat invalid credentials (up to 2 more)​

C → D: Locked out after 3 failed attempts

Graph for lab:


Screen shoot

Code for the lab four


import { test, expect, Page } from "@playwright/test";

const validUser = {
email: `user${Math.floor(Math.random() * 10000)}@example.com`,
password: `Pass${Math.floor(Math.random() * 1000)}!`,
};

const invalidUser = {
email: "invalidUser",
password: "Pass123!",
};

test.describe("Lab 4 – State Transition Testing (Login)", () => {


test.beforeEach(async ({ page }) => {

await page.goto("https://demo.nopcommerce.com/register");
await page.check("#gender-male");
await page.fill("#FirstName", "Test");
await page.fill("#LastName", "User");
await page.fill("#Email", validUser.email);
await page.fill("#Password", validUser.password);
await page.fill("#ConfirmPassword", validUser.password);
await page.click('button:has-text("Register")');
await page.waitForSelector(".result");
});

test("S0 → S1: Valid Login should go to dashboard", async ({ page })


=> {
await gotoLoginPage(page);
await login(page, validUser);
await expect(page.locator(".header-links
.ico-logout")).toBeVisible();
console.log("Transition: S0 → S1 (Success)");
});

test("S0 → S2: Invalid Login should show error", async ({ page }) =>
{
await gotoLoginPage(page);
await login(page, invalidUser);
await expect(page.locator(".message-error")).toBeVisible();
console.log(" Transition: S0 → S2 (Failure)");
});
test("S2 → S1: Recovery with valid login after failure", async ({
page }) => {
await gotoLoginPage(page);
await login(page, invalidUser);
await expect(page.locator(".message-error")).toBeVisible();
await login(page, validUser);
await expect(page.locator(".header-links
.ico-logout")).toBeVisible();
console.log("Transition: S2 → S1 (Recovery)");
});

test("S2 → S3: Too many failures lead to lockout (if supported)",


async ({
page,
}) => {
await gotoLoginPage(page);
for (let i = 0; i < 5; i++) {
await login(page, invalidUser);
await page.waitForTimeout(500);
}
console.log(" Would test lockout if system supports it");
});
});

async function gotoLoginPage(page: Page) {


await page.goto("https://demo.nopcommerce.com/login");
await page.waitForLoadState("networkidle");
}

async function login(page: Page, user: { email: string; password:


string }) {
await page.fill("#Email", user.email);
await page.fill("#Password", user.password);
await page.click('button:has-text("Log in")');
await page.waitForTimeout(1000);
}
Lab 5

5.1 Identify the Use Case


Steps:

1.​ Go to the site​

2.​ Register as a new user​

3.​ Login​

4.​ Add product(s) to cart​

5.​ Apply a coupon (optional)​

6.​ Proceed to checkout​

7.​ Fill billing/shipping/payment details​

8.​ Confirm the order​

9.​ Verify order success message

5.2. Use Case Scenario Table​

Step Action Expected Result

1 Visit homepage Homepage loads

2 Register new user Account is created

3 Login with new credentials Logged in and redirected

4 Add product to cart Product appears in cart

5 Apply coupon (optional) Discount applied if valid

6 Proceed to checkout Checkout page loads

7 Fill required details No validation errors

8 Confirm order Order confirmation page


shown

9 View success message Your order has been


successfully processed!

Code for lab 5


import { test, expect, Page } from "@playwright/test";

test("Lab 5: End-to-End Order Flow (Guest Checkout)", async ({ page })


=> {

await page.goto("https://demo.nopcommerce.com/");
await page.waitForLoadState("networkidle");

await page.click('a[href="/books"]');
await page.waitForLoadState("networkidle");

const addToCartButton = page.locator(".product-item


button.product-box-add-to-cart-button").first();
await addToCartButton.waitFor();
await addToCartButton.click();
await page.waitForSelector(".bar-notification.success");
await page.waitForTimeout(1000);

await page.click('a[href="/cart"]');
await page.waitForLoadState("networkidle");

await page.check("#termsofservice");
await page.click("#checkout");
await page.waitForLoadState("networkidle");

const guestCheckoutButton = page.locator('button:has-text("Checkout


as Guest")');
if (await guestCheckoutButton.isVisible()) {
await guestCheckoutButton.click();
await page.waitForLoadState("networkidle");
}
await page.fill("#BillingNewAddress_FirstName", "Test");
await page.fill("#BillingNewAddress_LastName", "User");
await page.fill(
"#BillingNewAddress_Email",
user${Math.floor(Math.random() * 10000)}@mail.com
);
await page.selectOption("#BillingNewAddress_CountryId", {
label: "United States",
});
await page.fill("#BillingNewAddress_City", "New York");
await page.fill("#BillingNewAddress_Address1", "123 Broadway");
await page.fill("#BillingNewAddress_ZipPostalCode", "10001");
await page.fill("#BillingNewAddress_PhoneNumber", "1234567890");

await page.click('button[name="save"]');
await page.waitForLoadState("networkidle");

await page.waitForSelector('input[name="shippingoption"]');
await page.locator('input[name="shippingoption"]').first().check();
await page.click('button[name="save"]');
await page.waitForLoadState("networkidle");

await page.waitForSelector('input[name="paymentmethod"]');
await page.locator('input[name="paymentmethod"]').first().check();
await page.click('button[name="save"]');
await page.waitForLoadState("networkidle");

await page.waitForSelector('button[name="save"]');
await page.click('button[name="save"]');
await page.waitForLoadState("networkidle");

await page.waitForSelector("button.confirm-order-next-step-button");
await page.click("button.confirm-order-next-step-button");
await page.waitForLoadState("networkidle");

await expect(page.locator(".section.order-completed")).toContainText(
"Your order has been successfully processed!"
);
console.log(" Order completed successfully.");
});

Reflection
1.​ Which technique was most effective for each system?​
For the systems we tested, automation using Playwright was the most effective
technique, especially for repetitive test cases and regression testing. It was
particularly useful on the "Books to Scrape" website where boundary value analysis
(BVA) could be consistently applied to test input ranges. Manual testing was more
useful for exploratory testing or when the system’s UI needed human judgment for
visual or usability issues.​

2.​ What challenges did you face in automation vs manual execution?​


One challenge with automation was setting up the testing environment and learning
the Playwright framework itself—it took time to configure scripts and selectors
properly. Also, dynamic elements like pop-ups or time-based events were harder to
handle automatically. In contrast, manual testing was slower and more prone to
human error, especially when running the same test multiple times or across different
browsers. However, it allowed more flexibility in adapting to unexpected behaviors in
the UI.​

3.​ How would you integrate these techniques into a CI/CD testing pipeline?​
To integrate these techniques into a CI/CD pipeline, I would first ensure that all
automated test scripts are stored in the project’s version control (e.g., GitHub). Then,
I’d configure the CI/CD tool (like GitHub Actions, Jenkins, or GitLab CI) to run the test
suite every time there is a new commit or pull request. This ensures that new code
doesn’t break existing functionality. Manual tests could be logged separately and
scheduled at key points, like before a major release or UI update, but most functional
and boundary tests would be automated and triggered automatically during the
CI/CD process.

You might also like