Skip to content
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
Binary file added ghibli-gif.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions playwright/helpers/recycle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { test, expect, Page } from '@playwright/test';
import {getAuthFileByProjectName,
getEmailAddressForProject,
restoreAuthState,
letCookiesExpire,
restoreExpiredCookies,
MailpitCodeFetcher} from "../utils/functions.ts"


export async function loginUser(page: Page, testInfo: any, password: string,){
const emailAddress = getEmailAddressForProject(testInfo);
await page.goto("https://audaf-testing.onrender.com")
await page.getByPlaceholder("Enter email").click();
await page.getByPlaceholder("Enter email").fill(emailAddress);
await page.getByPlaceholder("Password").click();
await page.getByPlaceholder("Password").fill(password);

// Handle reCAPTCHA
if (await page.$('iframe[src*="recaptcha"]')) {
await page.waitForFunction(() => {return document.querySelector('iframe[src*="recaptcha"]');});
const frames = page.frames();
const recaptchaFrame = frames.find(f => f.url().includes('recaptcha'));
if (recaptchaFrame) {await recaptchaFrame.getByRole('checkbox', { name: "I'm not a robot" }).click();}
}else{
await page.waitForSelector('iframe[src*="recaptcha"]', { timeout: 10000 });
const recaptchaFrame = page.frameLocator('iframe[src*="recaptcha"]');
await recaptchaFrame.getByRole('checkbox', { name: "I'm not a robot" }).click();
}

await page.getByRole('button', { name: 'Sign In' }).click();
}
30 changes: 29 additions & 1 deletion playwright/helper/functions.ts → playwright/utils/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export function getAuthFileByProjectName(projectName: string) {
}

export function getAuthFileTamperedByProjectName(projectName: string) {
if(projectName !== "chromium" || "firefox"){
projectName = "chromium"
}
return path.join(authDir, `userTampered-${projectName.toLowerCase()}.json`);
}

Expand Down Expand Up @@ -73,7 +76,7 @@ export const restoreAuthState = async function(page: any, filePath: string) {
}
}

export const setUserTamperedToSameAsUser = async function(page: any, projectName: string) {
export const setUserTamperedToSameAsUser = async function(projectName: string) {
const userFilePath = getAuthFileByProjectName(projectName);
const tamperedFilePath = getAuthFileTamperedByProjectName(projectName);
// Implementation for setting tampered user state to same as regular user
Expand All @@ -83,6 +86,31 @@ export const setUserTamperedToSameAsUser = async function(page: any, projectName
}
}

const tampering = function(projectName: string, cookieName: string){
const toBeTamperedFilePath = getAuthFileTamperedByProjectName(projectName);

if (existsSync(toBeTamperedFilePath)) {
const raw = readFileSync(toBeTamperedFilePath, 'utf8');
const data = JSON.parse(raw);

const tokenCookie = data.cookies.find((el: any) => el.name === cookieName);

if (tokenCookie) {
tokenCookie.value = "wrongtoken";
writeFileSync(toBeTamperedFilePath, JSON.stringify(data, null, 2), 'utf8');
}
} else {
console.log('File does not exist at path:', toBeTamperedFilePath);
}
}
export const tamperWithJWTToken = async function(projectName: string) {
tampering(projectName, "token");
};

export const tamperWithCSRFToken = async function(projectName: string) {
tampering(projectName,"csrf-token-prod")
};

export const letCookiesExpire = async function(page: any) {
const context = page.context();
const cookies = await context.cookies();
Expand Down
93 changes: 84 additions & 9 deletions tests/01-createAccount.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MailpitCodeFetcher,
readEmailData,
saveEmailAddressForProject,
getAuthFileByProjectName,
getAuthFileUnverified} from "../playwright/helper/functions.ts"
getAuthFileUnverified} from "../playwright/utils/functions.ts"



Expand Down Expand Up @@ -79,6 +79,89 @@ test.describe.serial('create accounts and testing account creation with already
await expect(page.getByText('Email already in use')).toBeVisible({ timeout: 15000 });
});

test("trying to create account with mismatched password and confirm password", async({page}, testInfo)=>{
const projectName = testInfo.project.name;
const emailAddress = `test-user-${projectName.toLowerCase()}-${Date.now()}@gamil.com`;

await page.goto('https://audaf-testing.onrender.com/signup');
await page.getByRole('textbox', { name: 'Password', exact: true }).click();
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('securepassword123');
await page.getByRole('textbox', { name: 'Confirm Password' }).click();
await page.getByRole('textbox', { name: 'Confirm Password' }).fill('mismatched1'); //<- mismatching
await page.getByRole('textbox', { name: 'Username' }).click();
await page.getByRole('textbox', { name: 'Username' }).fill('testusername2');
await page.getByRole('textbox', { name: 'Email Address' }).click();
await page.getByRole('textbox', { name: 'Email Address' }).fill(emailAddress);
await page.locator('input[type="file"]').setInputFiles('jellyfishWallpaper.jpg');
await page.getByRole('button', { name: '-- Select country --' }).click();
await page.getByRole('button', { name: 'Albania flag Albania' }).click();
await expect(page.getByRole('button', { name: 'Create Account' })).toBeDisabled();
});

test("trying to create account with invalid email format", async({page}, testInfo)=>{
const projectName = testInfo.project.name;
const emailAddress = `test-user-${projectName.toLowerCase()}-${Date.now()}gamil.com`; // <- invalid format

await page.goto('https://audaf-testing.onrender.com/signup');
await page.getByRole('textbox', { name: 'Password', exact: true }).click();
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('securepassword123');
await page.getByRole('textbox', { name: 'Confirm Password' }).click();
await page.getByRole('textbox', { name: 'Confirm Password' }).fill('securepassword123');
await page.getByRole('textbox', { name: 'Username' }).click();
await page.getByRole('textbox', { name: 'Username' }).fill('testusername2');
await page.getByRole('textbox', { name: 'Email Address' }).click();
await page.getByRole('textbox', { name: 'Email Address' }).fill(emailAddress);
await page.locator('input[type="file"]').setInputFiles('jellyfishWallpaper.jpg');
await page.getByRole('button', { name: '-- Select country --' }).click();
await page.getByRole('button', { name: 'Albania flag Albania' }).click();
await expect(page.getByRole('button', { name: 'Create Account' })).toBeDisabled();
});

test("trying to create account with weak password", async({page}, testInfo)=>{
const projectName = testInfo.project.name;
const emailAddress = `test-user-${projectName.toLowerCase()}-${Date.now()}@gamil.com`;

await page.goto('https://audaf-testing.onrender.com/signup');
await page.getByRole('textbox', { name: 'Password', exact: true }).click();
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('weak'); // <- weak password
await page.getByRole('textbox', { name: 'Confirm Password' }).click();
await page.getByRole('textbox', { name: 'Confirm Password' }).fill('weak');
await page.getByRole('textbox', { name: 'Username' }).click();
await page.getByRole('textbox', { name: 'Username' }).fill('testusername2');
await page.getByRole('textbox', { name: 'Email Address' }).click();
await page.getByRole('textbox', { name: 'Email Address' }).fill(emailAddress);
await page.locator('input[type="file"]').setInputFiles('jellyfishWallpaper.jpg');
await page.getByRole('button', { name: '-- Select country --' }).click();
await page.getByRole('button', { name: 'Albania flag Albania' }).click();
await expect(page.getByRole('button', { name: 'Create Account' })).toBeDisabled();
});

test("trying to create account with a profile picture in the wrong format", async({page}, testInfo)=>{
const projectName = testInfo.project.name;
const emailAddress = `test-user-${projectName.toLowerCase()}-${Date.now()}@gamil.com`;

await page.goto('https://audaf-testing.onrender.com/signup');
await page.getByRole('textbox', { name: 'Password', exact: true }).click();
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('securepassword123');
await page.getByRole('textbox', { name: 'Confirm Password' }).click();
await page.getByRole('textbox', { name: 'Confirm Password' }).fill('securepassword123');
await page.getByRole('textbox', { name: 'Username' }).click();
await page.getByRole('textbox', { name: 'Username' }).fill('testusername2');
await page.getByRole('textbox', { name: 'Email Address' }).click();
await page.getByRole('textbox', { name: 'Email Address' }).fill(emailAddress);
await page.locator('input[type="file"]').setInputFiles('ghibli-gif.gif');
await page.getByRole('button', { name: '-- Select country --' }).click();
await page.getByRole('button', { name: 'Albania flag Albania' }).click();
await page.getByRole('button', { name: 'Create Account' }).click();
await page.waitForURL("https://audaf-testing.onrender.com/verify-email", { timeout: 30000 });
const allMessages = await page.consoleMessages();
const uploadFailed = allMessages.some(msg =>
msg.text().includes("avatar upload failed")
);

expect(uploadFailed).toBe(true);
});

// creates new user without verifying email and saves session/ cookies in userUnverified.json file for further testing
test("create account and don't verify email", async({page}, testInfo)=>{
const projectName = testInfo.project.name;
Expand Down Expand Up @@ -108,14 +191,6 @@ test.describe.serial('create accounts and testing account creation with already

// NEED TO CREATE FOLLOWING TESTS:
/*
mismatched password and confirm password
invalid email format
missing fields
dublicate username
weak password rejection
size limit for pic uploads
deleting account but enter the wrong email + verify deletion by trying to log in with deleted account
invalid data when updating profile
testing with expired verification code 10 min
testing with exipred/missing reset token -> hitting /reset-password directlty without going through the forgot password flow
testing 15 min tempEmail expiration for signup flow
Expand Down
55 changes: 38 additions & 17 deletions tests/02-authAndSecurity.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
// @ts-check
import { test, expect } from '@playwright/test';
import { restoreAuthState, getAuthFileTamperedByProjectName, setUserTamperedToSameAsUser, removeCookiesFromFile} from "../playwright/helper/functions.ts"
import { restoreAuthState,
getAuthFileTamperedByProjectName,
setUserTamperedToSameAsUser,
removeCookiesFromFile,
tamperWithJWTToken,
tamperWithCSRFToken,
letCookiesExpire,
restoreExpiredCookies,
getAuthFileByProjectName} from "../playwright/utils/functions.ts"


test.describe('Authentication and Security Tests', () => {
Expand All @@ -15,29 +24,41 @@ test.describe('Authentication and Security Tests', () => {
await page.goto('https://audaf-testing.onrender.com/home');
await expect(page).toHaveURL('https://audaf-testing.onrender.com/');
await expect(page.getByText('Welcome Back!', { exact: true})).toBeVisible();
await setUserTamperedToSameAsUser(page, testInfo.project.name); // Reset the tampered state to match the regular user state for further tests
await setUserTamperedToSameAsUser(testInfo.project.name); // Reset the tampered state to match the regular user state for further tests
});

test("session with tampered JWT should be rejected", async({page}, testInfo)=>{
// logic for the test
await setUserTamperedToSameAsUser(page, testInfo.project.name);
test("session with tampered JWT-token should be rejected", async({page}, testInfo)=>{
await page.goto('https://audaf-testing.onrender.com/home');
await expect(page.getByText('Welcome Home, testusername!', { exact: true})).toBeVisible();
await tamperWithJWTToken(getAuthFileTamperedByProjectName(testInfo.project.name))
await page.goto('https://audaf-testing.onrender.com/home');
await expect(page.getByText('Welcome Home, testusername!', { exact: true})).not.toBeVisible();
await setUserTamperedToSameAsUser(testInfo.project.name);
})

test("session with expired JWT should be rejected", async({page}, testInfo)=>{
// logic for the test
await setUserTamperedToSameAsUser(page, testInfo.project.name);
})
test("session with expired cookies should be rejected when navigating home", async({page}, testInfo)=>{
await page.goto('https://audaf-testing.onrender.com/home');
await expect(page.getByText('Welcome Home, testusername!', { exact: true})).toBeVisible();
await letCookiesExpire(page);
await page.goto('https://audaf-testing.onrender.com/home');
await expect(page.getByText('Welcome Back!', { exact: true})).toBeVisible();
await restoreExpiredCookies(page, getAuthFileByProjectName(testInfo.project.name));
});

test("session with missing CSRF token should be rejected", async({page}, testInfo)=>{
// logic for the test
await setUserTamperedToSameAsUser(page, testInfo.project.name);
})

test("session with invalid CSRF token should be rejected", async({page}, testInfo)=>{
// logic for the test
await setUserTamperedToSameAsUser(page, testInfo.project.name);
await page.goto('https://audaf-testing.onrender.com/home');
await expect(page.getByText('Welcome Home, testusername!', { exact: true})).toBeVisible();
await tamperWithCSRFToken(getAuthFileTamperedByProjectName(testInfo.project.name))
await page.goto('https://audaf-testing.onrender.com/home');
await expect(page.getByText('Welcome Home, testusername!', { exact: true})).not.toBeVisible();
await setUserTamperedToSameAsUser(testInfo.project.name);
})

});

// NEED TO CREATE TEST FOR RATE-LIMITING AND BRUTE-FORCE ATTACKS, BUT IT'S NOT POSSIBLE TO TEST IT WITH PLAYWRIGHT. NEED TO TEST IT MANUALLY OR WITH A DIFFERENT TOOL.
// NEED TO CREATE TEST FOR RATE-LIMITING AND BRUTE-FORCE ATTACKS, BUT IT'S NOT POSSIBLE TO TEST IT WITH PLAYWRIGHT. NEED TO TEST IT MANUALLY OR WITH A DIFFERENT TOOL.
/*
testing with expired verification code 10 min
testing with exipred/missing reset token -> hitting /reset-password directlty without going through the forgot password flow
testing 15 min tempEmail expiration for signup flow
*/
Loading
Loading