Skip to content
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
13 changes: 13 additions & 0 deletions backend/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -856,4 +856,17 @@ export const getTransactionsBy = (key: string, value: string) =>
/* istanbul ignore next */
export const getTransactionsByUserId = (userId: string) => getTransactionsBy("receiverId", userId);

/* istanbul ignore next */
export const cleanupDatabase = () => {
// Reset all tables to empty state
db.set(USER_TABLE, []).write();
db.set(CONTACT_TABLE, []).write();
db.set(BANK_ACCOUNT_TABLE, []).write();
db.set(TRANSACTION_TABLE, []).write();
db.set(LIKE_TABLE, []).write();
db.set(COMMENT_TABLE, []).write();
db.set(NOTIFICATION_TABLE, []).write();
db.set(BANK_TRANSFER_TABLE, []).write();
};

export default db;
8 changes: 7 additions & 1 deletion backend/testdata-routes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///<reference path="types.ts" />

import express from "express";
import { getAllForEntity, seedDatabase } from "./database";
import { getAllForEntity, seedDatabase, cleanupDatabase } from "./database";
import { validateMiddleware } from "./helpers";
import { isValidEntityValidator } from "./validators";
import { DbSchema } from "../src/models/db-schema";
Expand All @@ -15,6 +15,12 @@ router.post("/seed", (req, res) => {
res.sendStatus(200);
});

//POST /testData/cleanup
router.post("/cleanup", (req, res) => {
cleanupDatabase();
res.sendStatus(200);
});

//GET /testData/:entity
router.get("/:entity", validateMiddleware([...isValidEntityValidator]), (req, res) => {
const { entity } = req.params;
Expand Down
220 changes: 220 additions & 0 deletions data/database.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,171 @@
"balance": 49474,
"createdAt": "2023-12-07T04:39:38.383Z",
"modifiedAt": "2024-03-07T00:07:36.510Z"
},
{
"id": "lyxSTva5e",
"uuid": "b1a68037-3517-42a0-ad79-0af6f3d7e8af",
"firstName": "Winifred",
"lastName": "Dietrich",
"username": "winifreddietrich58",
"password": "$2a$10$KtgIGgQDg7kGAXAHLtYHxucvTkz6RrwELsCzsOoCtKriDZAxpwoVm",
"balance": 0,
"createdAt": "2025-10-26T23:45:53.793Z",
"modifiedAt": "2025-10-26T23:45:53.793Z"
},
{
"id": "SaE7LpHIdg",
"uuid": "280dfd80-d6e1-4a24-81a8-73c5f60cba93",
"firstName": "Marta",
"lastName": "Leannon",
"username": "martaleannon23",
"password": "$2a$10$LALWESIwyP5gzp.STN/2ZetGIUBCI1ieAOF1QyZMZPOLO9CJAE8OW",
"balance": 0,
"createdAt": "2025-10-26T23:45:53.888Z",
"modifiedAt": "2025-10-26T23:45:53.888Z"
},
{
"id": "BGQp_e-U7",
"uuid": "ddb3e50c-5b64-426a-ad84-a892baa73fd8",
"firstName": "Abigail",
"lastName": "Fisher",
"username": "abigailfisher15",
"password": "$2a$10$Ce5HT6mQ0CgOlOb7dAdGgOZyop5amwsRhLQsD6UdFrPQUPsaDYS5S",
"balance": 0,
"createdAt": "2025-10-26T23:45:54.280Z",
"modifiedAt": "2025-10-26T23:45:54.280Z"
},
{
"id": "bE-JZpNyj",
"uuid": "f2024bbd-3e3d-41d8-a93c-b9bf7343c50f",
"firstName": "Queenie",
"lastName": "Huels",
"username": "queeniehuels34",
"password": "$2a$10$fJjNX/9uZZzWw9pezHFqLeQmLi9JbDN5mHUdRondQyhqaOxQCyyB6",
"balance": 0,
"createdAt": "2025-10-26T23:55:20.588Z",
"modifiedAt": "2025-10-26T23:55:20.588Z"
},
{
"id": "T4TemZT5Lb",
"uuid": "2e05bd7c-4e30-4a02-a4c0-376e6e65249b",
"firstName": "Eriberto",
"lastName": "Schuppe",
"username": "eribertoschuppe32",
"password": "$2a$10$/UBbIVRszjlIqEZ6gmuoFeHCVo7vmYViJLQztOkVSsuTYjJG.Hrba",
"balance": 0,
"createdAt": "2025-10-26T23:55:20.727Z",
"modifiedAt": "2025-10-26T23:55:20.727Z"
},
{
"id": "poPni71sI",
"uuid": "18af586e-b2e5-4989-a5a0-631deaedf9c2",
"firstName": "Raquel",
"lastName": "Schroeder",
"username": "raquelschroeder28",
"password": "$2a$10$/RqPWv5xesiSOIfRTrMMmu8YuqSYOidtKGVMHMbKsb3mHbnsv/ijW",
"balance": 0,
"createdAt": "2025-10-26T23:55:21.551Z",
"modifiedAt": "2025-10-26T23:55:21.551Z"
},
{
"id": "JivmQvhVO",
"uuid": "16c83622-17c2-4236-b42a-69a6730f0259",
"firstName": "Wyman",
"lastName": "Stamm",
"username": "wymanstamm44",
"password": "$2a$10$1Lr5uIYfzi3P42CWYDt6uOCbmBy6EkvZtxq7E.9tolOFEd13ELQAK",
"balance": 0,
"createdAt": "2025-10-27T00:02:02.731Z",
"modifiedAt": "2025-10-27T00:02:02.731Z"
},
{
"id": "t-8uWFH_YD",
"uuid": "5dfe0761-0732-446f-956e-882dbb23f4f1",
"firstName": "Shayna",
"lastName": "Hilpert",
"username": "shaynahilpert56",
"password": "$2a$10$QBvy3jI2Ev6pq0YT3mMA0O8IF2sZASmoI.RXXPgxL4QFTUCBr3KkC",
"balance": 0,
"createdAt": "2025-10-27T00:02:02.891Z",
"modifiedAt": "2025-10-27T00:02:02.891Z"
},
{
"id": "X6yUCv0sL",
"uuid": "2fdd3bea-2b84-426d-9a73-e4eafc8eda65",
"firstName": "Jayne",
"lastName": "Emmerich",
"username": "jayneemmerich95",
"password": "$2a$10$cz4JNZEOUw.8lEk7BsyVKen6tjEfHo6Dq6S7TXTtO67CgzNP8c.rm",
"balance": 0,
"createdAt": "2025-10-27T00:02:03.362Z",
"modifiedAt": "2025-10-27T00:02:03.362Z"
},
{
"id": "IynA2GebO",
"uuid": "f4f83564-7b02-4c7c-a91a-337aac9bbbef",
"firstName": "Harmony",
"lastName": "Mayert",
"username": "harmonymayert80",
"password": "$2a$10$5WTFFltSULT05Tlz3TWn3uUgl7KNhw5Xdb.I45aSNhzCPDLwDrI3O",
"balance": 0,
"createdAt": "2025-10-27T00:08:25.031Z",
"modifiedAt": "2025-10-27T00:08:25.031Z"
},
{
"id": "QKfWquvdR",
"uuid": "ab9e9a19-f793-49ac-aab4-ce2bb2681400",
"firstName": "Frida",
"lastName": "Schimmel-Schowalter",
"username": "fridaschimmel-schowalter65",
"password": "$2a$10$C8nDAzr5UAWSgD7dX52h7.z9KcFSZj5bK4HGDJnH6W1f4T.Q85ISy",
"balance": 0,
"createdAt": "2025-10-27T00:08:25.138Z",
"modifiedAt": "2025-10-27T00:08:25.138Z"
},
{
"id": "mW86jvzUJJ",
"uuid": "3f3df9fa-28bc-4ca7-bbd3-38a7a443ee51",
"firstName": "Olin",
"lastName": "Rutherford",
"username": "olinrutherford75",
"password": "$2a$10$jQkY0AlJ7e.yhTzZnDxyJuPhuOVNMvKtLr7UftKJO/pyblGdeRiOy",
"balance": 0,
"createdAt": "2025-10-27T00:08:26.052Z",
"modifiedAt": "2025-10-27T00:08:26.052Z"
},
{
"id": "9zN-flycB",
"uuid": "974a8ce9-30b3-4ad4-b1a4-0a798dae3ccb",
"firstName": "Wilford",
"lastName": "Rippin",
"username": "wilfordrippin41",
"password": "$2a$10$xrJBo.rwjRqAkk/kcehhlOZj88QEKGw0mDFNl94i4Q8ZKDiT8FUae",
"balance": 0,
"createdAt": "2025-10-27T00:10:48.373Z",
"modifiedAt": "2025-10-27T00:10:48.373Z"
},
{
"id": "80Vwqz1wpu",
"uuid": "61836562-88aa-4d6e-bef8-93ad0aae0b34",
"firstName": "Lola",
"lastName": "Kunze",
"username": "lolakunze53",
"password": "$2a$10$kvJiwlyG871Ko3QnmlEbO.dvLuN7MyBsKmQZ5ZpOyIYIJ.GCvx0Wm",
"balance": 0,
"createdAt": "2025-10-27T00:10:48.482Z",
"modifiedAt": "2025-10-27T00:10:48.482Z"
},
{
"id": "hAx6gBl4S",
"uuid": "a0f34c60-2276-4e55-bc36-2118275fe261",
"firstName": "Matt",
"lastName": "Kunze",
"username": "mattkunze67",
"password": "$2a$10$1wMrWazZy/td9yl0vcc4l.6q7HfNf6.wsxQi7FEK0FjoRUUAMLMGy",
"balance": 0,
"createdAt": "2025-10-27T00:10:49.069Z",
"modifiedAt": "2025-10-27T00:10:49.069Z"
}
],
"contacts": [
Expand Down Expand Up @@ -253,6 +418,61 @@
"isDeleted": false,
"createdAt": "2024-01-26T14:01:01.815Z",
"modifiedAt": "2024-03-07T08:44:31.174Z"
},
{
"id": "RH_FOjA_n",
"uuid": "612b4fb7-d177-466e-8960-c8b62c304651",
"userId": "BGQp_e-U7",
"bankName": "The Best Bank",
"accountNumber": "123456789",
"routingNumber": "987654321",
"isDeleted": false,
"createdAt": "2025-10-26T23:45:55.554Z",
"modifiedAt": "2025-10-26T23:45:55.554Z"
},
{
"id": "5Ovxyjyvv",
"uuid": "c1774da9-a367-4496-bae3-4e80872fee6e",
"userId": "poPni71sI",
"bankName": "The Best Bank",
"accountNumber": "123456789",
"routingNumber": "987654321",
"isDeleted": false,
"createdAt": "2025-10-26T23:55:22.815Z",
"modifiedAt": "2025-10-26T23:55:22.815Z"
},
{
"id": "APUiDDHKGo",
"uuid": "aa359cc9-6a3e-462a-a589-4aea13b3a2d3",
"userId": "X6yUCv0sL",
"bankName": "The Best Bank",
"accountNumber": "123456789",
"routingNumber": "987654321",
"isDeleted": false,
"createdAt": "2025-10-27T00:02:03.745Z",
"modifiedAt": "2025-10-27T00:02:03.745Z"
},
{
"id": "o_DghsD8j",
"uuid": "420634be-7425-4172-a2cf-9d42097e0352",
"userId": "mW86jvzUJJ",
"bankName": "The Best Bank",
"accountNumber": "123456789",
"routingNumber": "987654321",
"isDeleted": false,
"createdAt": "2025-10-27T00:08:27.631Z",
"modifiedAt": "2025-10-27T00:08:27.631Z"
},
{
"id": "ZI-pXSWQJ",
"uuid": "7dc879ad-f1e8-41d3-9a55-80066bd6139b",
"userId": "hAx6gBl4S",
"bankName": "The Best Bank",
"accountNumber": "123456789",
"routingNumber": "987654321",
"isDeleted": false,
"createdAt": "2025-10-27T00:10:50.284Z",
"modifiedAt": "2025-10-27T00:10:50.284Z"
}
],
"transactions": [
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@
"test:unit": "vitest",
"test:unit:ci": "vitest --run",
"test:component:ci": "yarn cypress:run:component",
"playwright:test": "npx playwright test --config=playwright/playwright.config.ts",
"playwright:test:ui": "npx playwright test --ui --config=playwright/playwright.config.ts",
"playwright:test:headed": "npx playwright test --headed --config=playwright/playwright.config.ts",
"playwright:test:debug": "npx playwright test --debug --config=playwright/playwright.config.ts",
"playwright:report": "npx playwright show-report",
"start:api": "yarn tsnode --files backend/app.ts",
"start:api:watch": "nodemon --exec yarn tsnode --watch 'backend' backend/app.ts",
"start:react:proxy-server": "yarn tsnode scripts/testServer.ts",
Expand Down
27 changes: 27 additions & 0 deletions playwright/.github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Playwright Tests
on:
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 install -g yarn && yarn
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
- name: Run Playwright tests
run: yarn playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
9 changes: 9 additions & 0 deletions playwright/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Test results
test-results/
playwright-report/

# Dependencies
node_modules/

# Logs
*.log
21 changes: 21 additions & 0 deletions playwright/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Playwright Test Suite

## Quick Start
```bash
npm test # Run all tests
npm test -- tests/api/ # Run API tests only
npm test -- tests/ui/ # Run UI tests only
```

## Test Structure
- **API Tests**: Fast authentication and endpoint testing
- **UI Tests**: Full user journey testing with proper auth state

## Authentication
- **API Tests**: Use `loginByApi()` for fast API-only authentication
- **UI Tests**: Use fixtures (`loggedInAsUser`) for reliable frontend auth state

## Configuration
- Base URL: `http://localhost:3000`
- API URL: `http://localhost:3001`
- Test users available in `fixtures/auth.ts`
33 changes: 33 additions & 0 deletions playwright/fixtures/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { test as base, Page } from '@playwright/test';
import { DataFactory, testUsers } from '../helpers/dataFactory';

/**
* Performs UI login by navigating to signin page and filling credentials
*/
async function loginUser(page: Page, username: string, password: string = 's3cret') {
await page.goto('http://localhost:3000/signin');
await page.locator('#username').fill(username);
await page.locator('#password').fill(password);
await page.getByTestId('signin-submit').click();
await page.waitForURL('http://localhost:3000/');
}

export const test = base.extend<{
loggedInAsUser: (username?: string) => Promise<Page>;
}>({
loggedInAsUser: async ({ page }, use) => {
const loginFunction = async (username?: string) => {
const user = username
? Object.values(testUsers).find(u => u.username === username) ||
(() => { throw new Error(`User '${username}' not found`); })()
: DataFactory.getRandomTestUser();

await loginUser(page, user.username, user.password);
return page;
};

await use(loginFunction);
},
});

export { expect } from '@playwright/test';
Loading