diff --git a/backend/src/routes/userRoutes.ts b/backend/src/routes/userRoutes.ts index 70057011..45ebffcd 100644 --- a/backend/src/routes/userRoutes.ts +++ b/backend/src/routes/userRoutes.ts @@ -52,8 +52,9 @@ router.post('/api/users', async (req, res) => { } }); -router.delete('/api/users/:id', authenticateToken, async (req, res) => { - const { id } = req.params; +router.delete('/api/users/', authenticateToken, async (req, res) => { + // get id from decoded jwt token + const id = req.user.userId; try { await prisma.user.delete({ where: { id } }); diff --git a/backend/tests/unit/users.spec.ts b/backend/tests/unit/users.spec.ts index eb60a088..af2e34b0 100644 --- a/backend/tests/unit/users.spec.ts +++ b/backend/tests/unit/users.spec.ts @@ -145,7 +145,7 @@ describe('Delete User', () => { updatedAt: new Date('2024-02-05T23:33:42.252Z'), }); const response = await request(app).delete( - '/api/users/gcf89a7e-b941-4f17-bbe0-4e0c8b2cd272' + '/api/users/' ); expect(response.status).toBe(204); }); @@ -155,7 +155,7 @@ describe('Delete User', () => { throw new Error('Test error'); }); const response = await request(app).delete( - '/api/users/gcf89a7e-b941-4f17-bbe0-4e0c8b2cd272' + '/api/users/' ); expect(response.status).toBe(500); expect(response.body).toStrictEqual({ diff --git a/frontend/src/api/apiService.ts b/frontend/src/api/apiService.ts index 6037d62f..6579cb14 100644 --- a/frontend/src/api/apiService.ts +++ b/frontend/src/api/apiService.ts @@ -84,7 +84,11 @@ export const createUser = async ( user: return response; } -export const deleteUser = async (id: string) => { - const response = await api.delete(`users/${id}`); +export const deleteUser = async () => { + const response = await api.delete('users', { + headers: { + "Content-Type": "application/json", + }, + }); return response; } \ No newline at end of file diff --git a/playwright/helpers/apiLogin.ts b/playwright/helpers/apiLogin.ts new file mode 100644 index 00000000..cc6dffb3 --- /dev/null +++ b/playwright/helpers/apiLogin.ts @@ -0,0 +1,31 @@ +import { request, expect, APIResponse } from '@playwright/test'; +import getApiUrl from './getApiUrl'; + +const apiLogin = async (options: { + username: string; + password: string; +}): Promise => { + if (!options.username || !options.password) { + throw new Error('Username and Password is required to login'); + } + + const context = await request.newContext({ + baseURL: await getApiUrl(), + }); + + const loginResponse = await context.post('/api/login', { + headers: { + 'Content-Type': 'application/json', + }, + data: { + username: options.username, + password: options.password, + }, + }); + + expect(loginResponse.ok()).toBeTruthy(); + expect(loginResponse.status()).toBe(200); + return loginResponse; +}; + +export default apiLogin; diff --git a/playwright/helpers/deleteUser.ts b/playwright/helpers/deleteUser.ts new file mode 100644 index 00000000..03480281 --- /dev/null +++ b/playwright/helpers/deleteUser.ts @@ -0,0 +1,26 @@ +import { request, expect, APIResponse } from '@playwright/test'; +import getApiUrl from './getApiUrl'; + +const deleteUser = async (token: string | null): Promise => { + if (!token) { + throw new Error('Token is required to delete user'); + } + + const context = await request.newContext({ + baseURL: await getApiUrl(), + }); + + const deleteResponse = await context.delete('/api/users', { + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }); + + expect(deleteResponse.ok()).toBeTruthy(); + expect(deleteResponse.status()).toBe(204); + + return deleteResponse; +}; + +export default deleteUser; diff --git a/playwright/helpers/getApiUrl.ts b/playwright/helpers/getApiUrl.ts new file mode 100644 index 00000000..57da5cdd --- /dev/null +++ b/playwright/helpers/getApiUrl.ts @@ -0,0 +1,17 @@ +import playwrightConfig from '../playwright.config'; + +const getApiUrl = async () => { + const baseURL = playwrightConfig.use?.baseURL; + + const apiURL = baseURL?.includes('localhost') + ? 'http://localhost:5000' + : 'https://notes-app-full-stack-be.onrender.com'; + + if (!baseURL) { + throw new Error('Base URL is required to make API requests'); + } + + return apiURL; +}; + +export default getApiUrl; diff --git a/playwright/pages/RegistrationPage.ts b/playwright/pages/RegistrationPage.ts index 8f71753f..073ec434 100644 --- a/playwright/pages/RegistrationPage.ts +++ b/playwright/pages/RegistrationPage.ts @@ -22,6 +22,7 @@ class RegistrationPage { accountHeader = () => this.page.getByRole('heading', { name: 'Register new account' }); errorMessage = () => this.page.locator('.registration-form-error'); + spinnerContainer = () => this.page.getByTestId('spinner-container'); goto = async () => { await this.page.goto('/register'); @@ -56,6 +57,10 @@ class RegistrationPage { }); } }; + + getLocalStorage = async () => { + return await this.page.evaluate(() => JSON.stringify(window.localStorage)); + }; } export default RegistrationPage; diff --git a/playwright/tests/registration.spec.ts b/playwright/tests/registration.spec.ts index 346f1c9a..247faf00 100644 --- a/playwright/tests/registration.spec.ts +++ b/playwright/tests/registration.spec.ts @@ -1,11 +1,14 @@ -import { test, expect, Page } from '@playwright/test'; +import { test, expect, Page, APIResponse } from '@playwright/test'; import { faker } from '@faker-js/faker'; import { allure } from 'allure-playwright'; import RegistrationPage from '../pages/RegistrationPage'; +import deleteUser from '../helpers/deleteUser'; +import apiLogin from '../helpers/apiLogin'; let page: Page; let registrationPage: RegistrationPage; const timeout = 60 * 1000; // Render.com free tier may take 60 seconds to startup +let token: string; const username = faker.internet.userName().toLowerCase(); const email = faker.internet.email(); @@ -19,7 +22,7 @@ test.beforeAll(async ({ browser }) => { await registrationPage.goto(); }); -test.describe('User Registration', async () => { +test.describe('User Registration', { tag: ['@PRODUCTION'] }, async () => { test('Should be able to register new user', async () => { await expect(registrationPage.accountHeader()).toBeVisible(); @@ -30,7 +33,24 @@ test.describe('User Registration', async () => { }); await expect(registrationPage.successMessage()).toBeVisible({ timeout }); + + await test.step('Should be able to login with newly registered user', async () => { + const loginResponse: APIResponse = await apiLogin({ username, password }); + + expect(loginResponse.ok()).toBeTruthy(); + + const json = await loginResponse.json(); + token = json.token; + + expect(json.token).toBeTruthy(); + }); + + await test.step('Cleanup: Delete User', async () => { + const deleteUserResponse = await deleteUser(token); + expect(deleteUserResponse.ok()).toBeTruthy(); + }); }); + test('Should not be able to register with existing username', async () => { await registrationPage.goto(); diff --git a/playwright/tsconfig.json b/playwright/tsconfig.json index 72292c7a..b8e72960 100644 --- a/playwright/tsconfig.json +++ b/playwright/tsconfig.json @@ -12,7 +12,7 @@ "strict": true, "skipLibCheck": true }, - "include": ["src", "tests", "pages", "./.eslintrc.js", "./playwright.config.ts"], + "include": ["src", "tests", "pages", "helpers", "./.eslintrc.js", "./playwright.config.ts", "cleanup/Cleanup.ts"], "exclude": ["node_modules", "dist"], "overrides": [ {