import {test, expect} from '../../support/fixtures' import {openWs, waitForMessage, authenticateWs, subscribeWs, closeWs} from '../../support/websocket' import {UserFactory} from '../../factories/user' import {ProjectFactory} from '../../factories/project' import {ProjectViewFactory} from '../../factories/project_view' import {TaskFactory} from '../../factories/task' import {UserProjectFactory} from '../../factories/users_project' import {TEST_PASSWORD} from '../../support/constants' import type {APIRequestContext} from '@playwright/test' async function loginRaw(apiContext: APIRequestContext, user: {username: string}): Promise<{token: string}> { const response = await apiContext.post('login', { data: {username: user.username, password: TEST_PASSWORD}, }) return response.json() } test.describe('WebSocket Comment Notifications', () => { test('receives notification when mentioned in a task comment', async ({apiContext, userToken, currentUser}) => { const ws = await openWs() try { await authenticateWs(ws, userToken) subscribeWs(ws, 'notification.created') // Create a second user who will post the comment const [commenter] = await UserFactory.create(1, {id: 100}, false) const {token: commenterToken} = await loginRaw(apiContext, commenter) // Seed a project owned by the commenter with a task await ProjectFactory.create(1, {id: 100, owner_id: 100}, false) await ProjectViewFactory.create(1, {id: 100, project_id: 100}, false) await TaskFactory.create(1, {id: 100, project_id: 100, created_by_id: 100}, false) // Share the project with currentUser so the mention access check passes await UserProjectFactory.create(1, {id: 100, project_id: 100, user_id: 1}, false) // Commenter posts a comment mentioning currentUser const commentBody = `

Hey @${currentUser.username} check this out

` const commentResponse = await apiContext.put('tasks/100/comments', { data: {comment: commentBody}, headers: {Authorization: `Bearer ${commenterToken}`}, }) expect(commentResponse.ok()).toBe(true) // currentUser should receive the notification via WebSocket const msg = await waitForMessage(ws, 15000) expect(msg.event).toBe('notification.created') expect(msg.data).toBeDefined() // The notification payload must include a valid created timestamp (not zero) const created = new Date(msg.data.created) expect(created.getFullYear()).toBeGreaterThanOrEqual(2020) } finally { closeWs(ws) } }) })