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
15 changes: 14 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
WEBSITE_URL=
WEBSITE_URL=

TEST_USER_NAME=
TEST_USER_EMAIL=
TEST_USER_PASSWORD=

TEST_ADMIN_EMAIL=
TEST_ADMIN_PASSWORD=

TEST_LAWYER_EMAIL=
TEST_LAWYER_PASSWORD=

TEST_CLIENT_EMAIL=
TEST_CLIENT_PASSWORD=
11 changes: 11 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ jobs:
runs-on: ubuntu-latest
env:
WEBSITE_URL: ${{ secrets.WEBSITE_URL }}
TEST_USER_NAME: ${{ secrets.TEST_USER_NAME }}
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
TEST_ADMIN_EMAIL: ${{ secrets.TEST_ADMIN_EMAIL }}
TEST_ADMIN_PASSWORD: ${{ secrets.TEST_ADMIN_PASSWORD }}
TEST_LAWYER_EMAIL: ${{ secrets.TEST_LAWYER_EMAIL }}
TEST_LAWYER_PASSWORD: ${{ secrets.TEST_LAWYER_PASSWORD }}
TEST_CLIENT_EMAIL: ${{ secrets.TEST_CLIENT_EMAIL }}
TEST_CLIENT_PASSWORD: ${{ secrets.TEST_CLIENT_PASSWORD }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand All @@ -19,6 +28,8 @@ jobs:
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run auth setup
run: npx playwright test tests/auth.setup.ts --project=setup
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"@types/node": "^24.3.0"
},
"dependencies": {
"dotenv": "^17.2.1"
"dotenv": "^17.2.3"
}
}
5 changes: 5 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ export default defineConfig({

/* Configure projects for major browsers */
projects: [
{
name: 'setup',
testMatch: /.*\.setup\.ts/,
},

{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
Expand Down
44 changes: 44 additions & 0 deletions tests/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { test as setup, expect } from '@playwright/test';

const TEST_ADMIN_EMAIL = process.env.TEST_ADMIN_EMAIL;
const TEST_ADMIN_PASSWORD = process.env.TEST_ADMIN_PASSWORD;
const TEST_LAWYER_EMAIL = process.env.TEST_LAWYER_EMAIL;
const TEST_LAWYER_PASSWORD = process.env.TEST_LAWYER_PASSWORD;
const TEST_CLIENT_EMAIL = process.env.TEST_CLIENT_EMAIL;
const TEST_CLIENT_PASSWORD = process.env.TEST_CLIENT_PASSWORD;

const adminFile = 'playwright/.auth/admin.json';

setup('authenticate as admin', async ({ page }) => {
await page.goto('/login.php');

await page.fill('input[name="email"]', TEST_ADMIN_EMAIL!);
await page.fill('input[name="password"]', TEST_ADMIN_PASSWORD!);
await page.getByRole('button', { name: 'Login Now' }).click();

await page.context().storageState({ path: adminFile });
});

const clientFile = 'playwright/.auth/client.json';

setup('authenticate as client', async ({ page }) => {
await page.goto('/login.php');

await page.fill('input[name="email"]', TEST_CLIENT_EMAIL!);
await page.fill('input[name="password"]', TEST_CLIENT_PASSWORD!);
await page.getByRole('button', { name: 'Login Now' }).click();

await page.context().storageState({ path: clientFile });
});

const lawyerFile = 'playwright/.auth/lawyer.json';

setup('authenticate as lawyer', async ({ page }) => {
await page.goto('/login.php');

await page.fill('input[name="email"]', TEST_LAWYER_EMAIL!);
await page.fill('input[name="password"]', TEST_LAWYER_PASSWORD!);
await page.getByRole('button', { name: 'Login Now' }).click();

await page.context().storageState({ path: lawyerFile });
});
159 changes: 159 additions & 0 deletions tests/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { test, expect } from '@playwright/test';
import crypto from 'crypto';

// Localize environment variables
const TEST_USER_NAME = process.env.TEST_USER_NAME;
const TEST_USER_EMAIL = process.env.TEST_USER_EMAIL;
const TEST_USER_PASSWORD = process.env.TEST_USER_PASSWORD;
const TEST_ADMIN_EMAIL = process.env.TEST_ADMIN_EMAIL;
const TEST_ADMIN_PASSWORD = process.env.TEST_ADMIN_PASSWORD;
const TEST_LAWYER_EMAIL = process.env.TEST_LAWYER_EMAIL;
const TEST_LAWYER_PASSWORD = process.env.TEST_LAWYER_PASSWORD;
const TEST_CLIENT_EMAIL = process.env.TEST_CLIENT_EMAIL;
const TEST_CLIENT_PASSWORD = process.env.TEST_CLIENT_PASSWORD;

// Check if required environment variables are set
if (!TEST_USER_NAME || !TEST_USER_EMAIL || !TEST_USER_PASSWORD) {
throw new Error('Missing required environment variables: TEST_USER_NAME, TEST_USER_EMAIL, TEST_USER_PASSWORD');
}

if (!TEST_ADMIN_EMAIL || !TEST_ADMIN_PASSWORD) {
throw new Error('Missing required environment variables: TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD');
}

if (!TEST_LAWYER_EMAIL || !TEST_LAWYER_PASSWORD) {
throw new Error('Missing required environment variables: TEST_LAWYER_EMAIL, TEST_LAWYER_PASSWORD');
}

if (!TEST_CLIENT_EMAIL || !TEST_CLIENT_PASSWORD) {
throw new Error('Missing required environment variables: TEST_CLIENT_EMAIL, TEST_CLIENT_PASSWORD');
}

// Setup test - ensure test user exists for duplicate tests
test.beforeAll('setup: create test user if not exists', async ({ browser }) => {
const context = await browser.newContext();
const page = await context.newPage();

try {
await page.goto('/register.php');

// Try to create the test user
await page.fill('input[name="first_name"]', TEST_USER_NAME);
await page.fill('input[name="last_name"]', TEST_USER_NAME);
await page.fill('input[name="email"]', TEST_USER_EMAIL);
await page.fill('input[name="password"]', TEST_USER_PASSWORD);

await page.getByRole('button', { name: 'Create Account' }).click();

// Don't fail if user already exists - that's what we want
console.log('Test user setup completed (may already exist)');
} catch (error) {
console.log('Test user setup: user might already exist');
} finally {
await context.close();
}
});

function generateUniqueUser() {
const uniqueId = `${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
return {
first_name: `${uniqueId}`,
last_name: `TestUser`,
email: `test+${uniqueId}@example.com`,
password: 'Password123!'
};
}

test.describe("User Registration", () => {

test('users can register with unique email', async ({ page }) => {
await page.goto('/register.php');

const user = generateUniqueUser();

// Fill in registration form with unique email
await page.fill('input[name="first_name"]', user.first_name);
await page.fill('input[name="last_name"]', user.last_name);
await page.fill('input[name="email"]', user.email);
await page.fill('input[name="password"]', user.password);
await page.fill('input[name="confirm_password"]', user.password);
await page.getByRole('button', { name: 'Create Account' }).click();

await expect(page).toHaveURL(/login/);
});

test('users cannot register with duplicate email', async ({ page }) => {
await page.goto('/register.php');

const user = generateUniqueUser();

await page.fill('input[name="first_name"]', user.first_name);
await page.fill('input[name="last_name"]', user.last_name);
await page.fill('input[name="email"]', TEST_USER_EMAIL);
await page.fill('input[name="password"]', user.password);
await page.fill('input[name="confirm_password"]', user.password);
await page.getByRole('button', { name: 'Create Account' }).click();

await expect(page.locator('.alert-danger')).toBeVisible();
});
})

test.describe("User Login", () => {

test('users can login with correct email and password', async ({ page }) => {
await page.goto('/login.php');

await page.fill('input[name="email"]', TEST_USER_EMAIL!);
await page.fill('input[name="password"]', TEST_USER_PASSWORD!);
await page.getByRole('button', { name: 'Login' }).click();

await expect(page).toHaveURL(/dashboard/);
});

test('users cannot login with incorrect email or password', async ({ page }) => {
await page.goto('/login.php');

await page.fill('input[name="email"]', TEST_USER_EMAIL!);
await page.fill('input[name="password"]', 'wrongpassword123');
await page.getByRole('button', { name: 'Login' }).click();

await expect(page.locator('.alert-danger')).toBeVisible();
await expect(page).toHaveURL(/login/);
});
})

test.describe("Role Based Access Control", () => {

test.describe("Admin Role", () => {
test.use({ storageState: 'playwright/.auth/admin.json' });

test('admin users can access admin features', async ({ page }) => {
await page.goto('/login.php');

await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('span.badge-role')).toHaveText(/Admin/i);
});
});

test.describe("Lawyer Role", () => {
test.use({ storageState: 'playwright/.auth/lawyer.json' });

test('lawyers can access lawyer features', async ({ page }) => {
await page.goto('/login.php');

await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('span.badge-role')).toHaveText(/Lawyer/i);
});
});

test.describe("Client Role", () => {
test.use({ storageState: 'playwright/.auth/client.json' });

test('clients can access client features', async ({ page }) => {
await page.goto('/login.php');

await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('span.badge-role')).toHaveText(/Client/i);
});
});
});
4 changes: 2 additions & 2 deletions tests/example.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ test('register page', async ({ page }) => {
await page.goto('/login.php');

// Click the get started link.
await page.getByRole('link', { name: 'Create an account' }).click();
await page.getByRole('link', { name: 'Create Account' }).click();

// Expects page to have a button with the name of Create Account.
await expect(page.getByRole('button', { name: 'Register' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Create Account' })).toBeVisible();
});