Add backend unit/integration tests, Playwright e2e tests, README, cookie Secure fix
SonarQube Analysis / sonarqube (push) Successful in 4m20s

This commit is contained in:
2026-08-13 22:35:38 +00:00
parent 2adbf24b23
commit 921022c658
25 changed files with 6600 additions and 57 deletions
+5 -2
View File
@@ -3,7 +3,9 @@
"version": "1.0.0",
"private": true,
"scripts": {
"build": "tsc && vite build"
"dev": "vite",
"build": "tsc && vite build",
"test:e2e": "playwright test"
},
"dependencies": {
"react": "^18.3.1",
@@ -20,6 +22,7 @@
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"typescript": "^5.5.4",
"vite": "^5.4.0"
"vite": "^5.4.0",
"@playwright/test": "^1.47.0"
}
}
+19
View File
@@ -0,0 +1,19 @@
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
retries: process.env.CI ? 1 : 0,
reporter: [['list']],
use: {
baseURL: 'http://localhost:5173',
trace: 'on-first-retry'
},
webServer: {
command: 'npm run dev',
url: 'http://localhost:5173',
reuseExistingServer: !process.env.CI,
timeout: 30000
},
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }]
});
+38
View File
@@ -0,0 +1,38 @@
import { test, expect } from '@playwright/test';
function uniqueEmail(): string {
return `playwright-${Date.now()}-${Math.floor(Math.random() * 10000)}@example.com`;
}
test.describe('Customer accounts', () => {
test('marketing consent checkbox is unchecked by default', async ({ page }) => {
await page.goto('/register');
await expect(page.getByRole('checkbox')).not.toBeChecked();
});
test('registers a new account and lands on the account page', async ({ page }) => {
const email = uniqueEmail();
await page.goto('/register');
await page.getByLabel('Email').fill(email);
await page.getByLabel('Password').fill('supersecret123');
await page.getByRole('button', { name: 'Create account' }).click();
await expect(page).toHaveURL(/\/account/);
await expect(page.getByText(email)).toBeVisible();
});
test('rejects login with the wrong password', async ({ page }) => {
const email = uniqueEmail();
await page.goto('/register');
await page.getByLabel('Email').fill(email);
await page.getByLabel('Password').fill('supersecret123');
await page.getByRole('button', { name: 'Create account' }).click();
await expect(page).toHaveURL(/\/account/);
await page.getByRole('button', { name: 'Log out' }).click();
await page.goto('/login');
await page.getByLabel('Email').fill(email);
await page.getByLabel('Password').fill('wrong-password');
await page.getByRole('button', { name: 'Log in' }).click();
await expect(page.getByText('invalid email or password')).toBeVisible();
});
});
+21
View File
@@ -0,0 +1,21 @@
import { test, expect } from '@playwright/test';
test.describe('Storefront', () => {
test('loads and shows the site title', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Redefined Designs')).toBeVisible();
});
test('links to the privacy policy from the footer', async ({ page }) => {
await page.goto('/');
await page.getByRole('link', { name: 'Privacy Policy' }).click();
await expect(page).toHaveURL(/\/privacy/);
await expect(page.getByText('What we collect')).toBeVisible();
});
test('offers login and sign up when logged out', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('button', { name: 'Log in' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Sign up' })).toBeVisible();
});
});
+25
View File
@@ -0,0 +1,25 @@
import { test, expect } from '@playwright/test';
test.describe('Theme switching', () => {
test('toggling the switch changes the body theme attribute', async ({ page }) => {
await page.goto('/');
const body = page.locator('body');
const initial = await body.getAttribute('data-theme');
await page.getByRole('switch').click();
await expect(async () => {
const updated = await body.getAttribute('data-theme');
expect(updated).not.toBe(initial);
}).toPass();
});
test('theme preference persists across a reload', async ({ page }) => {
await page.goto('/');
await page.getByRole('switch').click();
const chosen = await page.locator('body').getAttribute('data-theme');
await page.reload();
await expect(page.locator('body')).toHaveAttribute('data-theme', chosen || '');
});
});
+8 -1
View File
@@ -3,5 +3,12 @@ import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: { outDir: 'dist' }
build: { outDir: 'dist' },
server: {
proxy: {
'/api': 'http://localhost:3000',
'/uploads': 'http://localhost:3000',
'/webhooks': 'http://localhost:3000'
}
}
});