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
58 changes: 31 additions & 27 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
name: Playwright Tests
env:
NEXTAUTH_URL: http://localhost:3000
DB_NAME: 'animal-tracking'
MONGO_DB: ${{ secrets.MONGO_DB }}
NEXTAUTH_URL: http://localhost:3000
DB_NAME: 'animal-tracking'
MONGO_DB: ${{ secrets.MONGO_DB }}
AUTH_SECRET: ${{ secrets.AUTH_SECRET }}
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
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
test:
environment: dev
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- name: Print Environment Variables
run: printenv
- 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
32 changes: 32 additions & 0 deletions e2e/animals.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import test, { expect } from '@playwright/test';

test('create a new animal', async ({ page }) => {
await page.goto('/');
// Expect a title "to contain" a substring.
await page.getByRole('link', { name: 'app logo Progress' }).click();
await page.getByRole('link', { name: 'Log In' }).click();
await page.getByRole('textbox', { name: 'Email' }).click();
await page
.getByRole('textbox', { name: 'Email' })
.fill('alice3@gatech.edu');
await page.getByRole('textbox', { name: 'Email' }).press('Tab');
await page.getByRole('textbox', { name: 'Password' }).fill('12345678');
await page.getByRole('button', { name: 'Log In' }).click();

await page.getByRole('link', { name: 'Animals icon Animals' }).click();
await page
.getByRole('link', { name: 'create new animal Create New' })
.click();
await page.getByRole('textbox', { name: 'Animal Name' }).click();
await page.getByRole('textbox', { name: 'Animal Name' }).fill('Rover');
await page.getByLabel('Breed').selectOption('German Shepherd');
await page
.getByRole('spinbutton', { name: 'Total hours trained' })
.fill('5');

await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByText('Animal created successfully!')).toBeVisible();

await page.getByRole('link', { name: 'Animals icon Animals' }).click();
await expect(page.getByText('Rover - German Shepherd')).toBeVisible();
});
53 changes: 53 additions & 0 deletions e2e/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { test, expect } from '@playwright/test';

test.beforeAll(async ({ request }) => {
const response = await request.post('/api/user/register', {
data: {
fullName: 'Admin User',
email: 'admin@gatech.edu',
password: '12345678',
confirmPassword: '12345678',
admin: true,
},
});
await expect(response).toBeOK();
});

test('create admin user', async ({ page }) => {
await page.goto('/signup');
// Expect a title "to contain" a substring.
await page.getByRole('textbox', { name: 'Full Name' }).click();
await page.getByRole('textbox', { name: 'Full Name' }).fill('Admin User 2');
await page.getByRole('textbox', { name: 'Full Name' }).press('Tab');
await page
.getByRole('textbox', { name: 'Email' })
.fill('admin2@gatech.edu');
await page.getByRole('textbox', { name: 'Password', exact: true }).click();
await page
.getByRole('textbox', { name: 'Password', exact: true })
.fill('12345678');
await page.getByRole('textbox', { name: 'Confirm Password' }).click();
await page
.getByRole('textbox', { name: 'Confirm Password' })
.fill('12345678');
await page.getByRole('checkbox', { name: 'Admin Access' }).check();
await page.getByRole('button', { name: 'Sign up' }).click();
await expect(
page.getByRole('heading', { name: 'Create Account' })
).toBeVisible();
});

test('login as admin user', async ({ page }) => {
await page.goto('/');
// Expect a title "to contain" a substring.
await page.getByRole('link', { name: 'app logo Progress' }).click();
await page.getByRole('link', { name: 'Log In' }).click();
await page.getByRole('textbox', { name: 'Email' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('admin@gatech.edu');
await page.getByRole('textbox', { name: 'Email' }).press('Tab');
await page.getByRole('textbox', { name: 'Password' }).fill('12345678');
await page.getByRole('button', { name: 'Log In' }).click();
await expect(
page.getByRole('heading', { name: 'Admin Access' })
).toBeVisible();
});
8 changes: 0 additions & 8 deletions e2e/example.spec.ts

This file was deleted.

35 changes: 35 additions & 0 deletions e2e/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { chromium, expect, request, type FullConfig } from '@playwright/test';
import connectDB from '../server/mongodb';
import { User } from '../server/mongodb/models/User';
import { TrainingLog } from '../server/mongodb/models/TrainingLog';
import { Animal } from '../server/mongodb/models/Animal';

async function globalSetup(config: FullConfig) {
// clear the database and seed with users
try {
await connectDB();
await User.collection.drop();
await TrainingLog.collection.drop();
await Animal.collection.drop();
} catch (error) {
console.error('Unable to reset the database');
}
console.log('URL ', `${config.webServer?.url}/api/user/register`);
const requestCtx = await request.newContext();
const response = await requestCtx.post(
`${config.webServer?.url}/api/user/register`,
{
data: {
fullName: 'Bob Johnson',
email: 'alice3@gatech.edu',
password: '12345678',
confirmPassword: '12345678',
admin: true,
},
}
);

console.log('Response ', response);
}

export default globalSetup;
100 changes: 100 additions & 0 deletions e2e/train-logs.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import test, { expect } from '@playwright/test';
test.describe.serial('training log tests ', () => {
test.beforeAll(async ({ browser }) => {
const page = await browser.newPage();
await page.goto('/');
// Expect a title "to contain" a substring.
await page.getByRole('link', { name: 'app logo Progress' }).click();
await page.getByRole('link', { name: 'Log In' }).click();
await page.getByRole('textbox', { name: 'Email' }).click();
await page
.getByRole('textbox', { name: 'Email' })
.fill('alice3@gatech.edu');
await page.getByRole('textbox', { name: 'Email' }).press('Tab');
await page.getByRole('textbox', { name: 'Password' }).fill('12345678');
await page.getByRole('button', { name: 'Log In' }).click();
await page.getByRole('link', { name: 'Animals icon Animals' }).click();
await page
.getByRole('link', { name: 'create new animal Create New' })
.click();
await page.getByRole('textbox', { name: 'Animal Name' }).click();
await page.getByRole('textbox', { name: 'Animal Name' }).fill('Rover');
await page.getByLabel('Breed').selectOption('German Shepherd');
await page
.getByRole('spinbutton', { name: 'Total hours trained' })
.fill('5');

await page.getByRole('button', { name: 'Save' }).click();
await expect(
page.getByText('Animal created successfully!')
).toBeVisible();
});

test('create a new training log', async ({ page }) => {
await page.goto('/');
// Expect a title "to contain" a substring.
await page.getByRole('link', { name: 'app logo Progress' }).click();
await page.getByRole('link', { name: 'Log In' }).click();
await page.getByRole('textbox', { name: 'Email' }).click();
await page
.getByRole('textbox', { name: 'Email' })
.fill('alice3@gatech.edu');
await page.getByRole('textbox', { name: 'Email' }).press('Tab');
await page.getByRole('textbox', { name: 'Password' }).fill('12345678');
await page.getByRole('button', { name: 'Log In' }).click();
await page
.getByRole('link', { name: 'create new training log' })
.click();
await page.getByRole('textbox', { name: 'Title' }).click();
await page
.getByRole('textbox', { name: 'Title' })
.fill('Fetch Practice');

await page.getByLabel('Select Animal').selectOption({ label: 'Rover' });
await page.getByRole('textbox', { name: 'Description' }).click();
await page
.getByRole('textbox', { name: 'Description' })
.fill('Rover played fetch and returned the ball every time.');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByText('Training log created')).toBeVisible();

await page
.getByRole('link', { name: 'Training Logs icon Training' })
.click();
await expect(page.getByRole('main')).toContainText(
'Rover played fetch and returned the ball every time.'
);
});

test('edit a training log', async ({ page }) => {
await page.goto('/');
// Expect a title "to contain" a substring.
await page.getByRole('link', { name: 'app logo Progress' }).click();
await page.getByRole('link', { name: 'Log In' }).click();
await page.getByRole('textbox', { name: 'Email' }).click();
await page
.getByRole('textbox', { name: 'Email' })
.fill('alice3@gatech.edu');
await page.getByRole('textbox', { name: 'Email' }).press('Tab');
await page.getByRole('textbox', { name: 'Password' }).fill('12345678');
await page.getByRole('button', { name: 'Log In' }).click();

const dataLoaded = page.waitForRequest('/api/training-log/*');
await page.getByRole('link', { name: 'edit training log' }).click();

await dataLoaded;
await page.getByRole('textbox', { name: 'Title' }).click();
await page.waitForTimeout(5000);
await page
.getByRole('textbox', { name: 'Title' })
.fill('Running Practice');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.locator('[id="1"]')).toContainText(
'Training log updated successfully.'
);
await page
.getByRole('link', { name: 'Training Logs icon Training' })
.click();
await expect(page.locator('h3')).toContainText('Running Practice');
});
});
13 changes: 13 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"argon2": "^0.44.0",
"axios": "^1.13.2",
"dotenv": "^17.2.3",
"jose": "^6.1.2",
"mongoose": "^8.19.4",
"next": "16.0.1",
Expand Down
Loading