feat: re-introduce regression testing suite with pnpm
This commit is contained in:
@@ -26,15 +26,21 @@
|
|||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.57.0",
|
||||||
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
|
"@testing-library/react": "^16.3.1",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
|
"@vitejs/plugin-react": "^5.1.2",
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.23",
|
"eslint-config-next": "14.2.23",
|
||||||
|
"jsdom": "^27.3.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.3.0",
|
"tailwindcss": "^3.3.0",
|
||||||
"typescript": "^5"
|
"typescript": "^5",
|
||||||
|
"vitest": "^4.0.16"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
25
playwright.config.ts
Normal file
25
playwright.config.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests/e2e',
|
||||||
|
fullyParallel: true,
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
reporter: 'html',
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://localhost:3000',
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
webServer: {
|
||||||
|
command: 'npm run dev',
|
||||||
|
url: 'http://localhost:3000',
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
},
|
||||||
|
});
|
||||||
1653
pnpm-lock.yaml
generated
1653
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
80
src/services/__tests__/save-tasting.test.ts
Normal file
80
src/services/__tests__/save-tasting.test.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
import { saveTasting } from '../save-tasting';
|
||||||
|
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||||
|
|
||||||
|
// Mock Supabase
|
||||||
|
vi.mock('@supabase/auth-helpers-nextjs', () => ({
|
||||||
|
createServerActionClient: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock next/headers
|
||||||
|
vi.mock('next/headers', () => ({
|
||||||
|
cookies: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock next/cache
|
||||||
|
vi.mock('next/cache', () => ({
|
||||||
|
revalidatePath: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('saveTasting', () => {
|
||||||
|
const mockInsert = vi.fn();
|
||||||
|
const mockSelect = vi.fn();
|
||||||
|
const mockSingle = vi.fn();
|
||||||
|
const mockGetSession = vi.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
|
||||||
|
const mockSupabase = {
|
||||||
|
auth: {
|
||||||
|
getSession: mockGetSession,
|
||||||
|
},
|
||||||
|
from: vi.fn().mockReturnValue({
|
||||||
|
insert: mockInsert,
|
||||||
|
select: mockSelect,
|
||||||
|
eq: vi.fn(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
mockInsert.mockReturnValue({ select: mockSelect });
|
||||||
|
mockSelect.mockReturnValue({ single: mockSingle });
|
||||||
|
|
||||||
|
(createServerActionClient as any).mockReturnValue(mockSupabase);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should save a tasting note and tags with user_id', async () => {
|
||||||
|
const userId = 'user-123';
|
||||||
|
mockGetSession.mockResolvedValue({
|
||||||
|
data: { session: { user: { id: userId } } },
|
||||||
|
});
|
||||||
|
|
||||||
|
mockSingle.mockResolvedValue({
|
||||||
|
data: { id: 'tasting-456' },
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mock the different tables
|
||||||
|
const mockTagInsert = vi.fn().mockResolvedValue({ error: null });
|
||||||
|
(createServerActionClient({ cookies: {} as any }).from as any).mockImplementation((table: string) => {
|
||||||
|
if (table === 'tastings') {
|
||||||
|
return { insert: mockInsert, select: mockSelect };
|
||||||
|
}
|
||||||
|
return { insert: mockTagInsert };
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await saveTasting({
|
||||||
|
bottle_id: 'bottle-789',
|
||||||
|
rating: 90,
|
||||||
|
buddy_ids: ['buddy-1', 'buddy-2'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
|
||||||
|
// Crucial: Check that tags were inserted with the correct user_id to prevent RLS recursion
|
||||||
|
expect(mockTagInsert).toHaveBeenCalledWith(expect.arrayContaining([
|
||||||
|
expect.objectContaining({ buddy_id: 'buddy-1', user_id: userId }),
|
||||||
|
expect.objectContaining({ buddy_id: 'buddy-2', user_id: userId }),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
});
|
||||||
10
src/tests/setup.ts
Normal file
10
src/tests/setup.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import { expect, afterEach } from 'vitest';
|
||||||
|
import { cleanup } from '@testing-library/react';
|
||||||
|
import * as matchers from '@testing-library/jest-dom/matchers';
|
||||||
|
|
||||||
|
expect.extend(matchers);
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
cleanup();
|
||||||
|
});
|
||||||
11
tests/e2e/landing.test.ts
Normal file
11
tests/e2e/landing.test.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('has title and login form', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
// Expect a title "to contain" a substring.
|
||||||
|
await expect(page.locator('h1')).toContainText('WHISKYVAULT');
|
||||||
|
|
||||||
|
// Expect login form to be visible
|
||||||
|
await expect(page.getByPlaceholder('name@beispiel.de')).toBeVisible();
|
||||||
|
});
|
||||||
18
vitest.config.ts
Normal file
18
vitest.config.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
test: {
|
||||||
|
environment: 'jsdom',
|
||||||
|
globals: true,
|
||||||
|
setupFiles: ['./src/tests/setup.ts'],
|
||||||
|
exclude: ['**/node_modules/**', '**/tests/e2e/**', '**/dist/**'],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user