test: add comprehensive user isolation tests for tasks (#1067)

* test: add comprehensive user isolation tests for tasks

Add integration tests to verify that users cannot see each other's tasks.
Tests cover:
- Task creation without projects
- Inbox items
- Direct task access by UID
- Search functionality
- Today view filtering

All tests pass, confirming that user isolation is working correctly in
the current codebase.

Related to #1063

* style: fix linting errors in task-user-isolation test
This commit is contained in:
Chris 2026-04-25 01:16:19 +03:00 committed by GitHub
parent aafb1877ae
commit dd9c298089
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -0,0 +1,174 @@
const request = require('supertest');
const app = require('../../app');
const { sequelize } = require('../../models');
const { createTestUser } = require('../helpers/testUtils');
describe('Task User Isolation', () => {
let agentA;
let agentB;
let userA;
let userB;
beforeAll(async () => {
await sequelize.sync({ force: true });
});
afterAll(async () => {
await sequelize.close();
});
beforeEach(async () => {
// Create User A and authenticate
userA = await createTestUser({
email: 'usera@test.com',
});
agentA = request.agent(app);
await agentA.post('/api/login').send({
email: 'usera@test.com',
password: 'password123',
});
// Create User B and authenticate
userB = await createTestUser({
email: 'userb@test.com',
});
agentB = request.agent(app);
await agentB.post('/api/login').send({
email: 'userb@test.com',
password: 'password123',
});
});
describe('Task creation and visibility', () => {
it('should NOT allow User B to see User A tasks without a project', async () => {
// User A creates a task without a project
const taskResponse = await agentA.post('/api/task').send({
name: 'User A Private Task',
status: 'not_started',
});
expect(taskResponse.status).toBe(201);
const taskA = taskResponse.body;
// User B tries to fetch all tasks
const tasksResponse = await agentB.get('/api/tasks');
expect(tasksResponse.status).toBe(200);
const tasks = tasksResponse.body.tasks;
// User B should NOT see User A's task
const userATask = tasks.find((t) => t.uid === taskA.uid);
expect(userATask).toBeUndefined();
});
it('should NOT allow User B to see User A tasks created via inbox', async () => {
// User A creates an inbox item
const inboxResponse = await agentA.post('/api/inbox').send({
content: 'User A Inbox Item',
});
expect(inboxResponse.status).toBe(201);
// User B tries to fetch inbox items
const inboxListResponse = await agentB.get('/api/inbox');
expect(inboxListResponse.status).toBe(200);
const inboxItems =
inboxListResponse.body.items || inboxListResponse.body;
// User B should NOT see User A's inbox item
const userAInboxItem = Array.isArray(inboxItems)
? inboxItems.find((i) => i.content === 'User A Inbox Item')
: undefined;
expect(userAInboxItem).toBeUndefined();
});
it('should NOT allow User B to access User A task by UID', async () => {
// User A creates a task
const taskResponse = await agentA.post('/api/task').send({
name: 'User A Secret Task',
status: 'not_started',
});
expect(taskResponse.status).toBe(201);
const taskA = taskResponse.body;
// User B tries to access the task by UID
const getTaskResponse = await agentB.get(`/api/task/${taskA.uid}`);
// Should return 403 Forbidden or 404 Not Found
expect([403, 404]).toContain(getTaskResponse.status);
});
it('should allow User A to see their own tasks', async () => {
// User A creates a task
const taskResponse = await agentA.post('/api/task').send({
name: 'User A Own Task',
status: 'not_started',
});
expect(taskResponse.status).toBe(201);
const taskA = taskResponse.body;
// User A fetches all tasks
const tasksResponse = await agentA.get('/api/tasks');
expect(tasksResponse.status).toBe(200);
const tasks = tasksResponse.body.tasks;
// User A should see their own task
const ownTask = tasks.find((t) => t.uid === taskA.uid);
expect(ownTask).toBeDefined();
expect(ownTask.name).toBe('User A Own Task');
});
it('should NOT allow User B to see User A tasks in search', async () => {
// User A creates a unique task
const taskResponse = await agentA.post('/api/task').send({
name: 'UniqueTaskNameXYZ123',
status: 'not_started',
});
expect(taskResponse.status).toBe(201);
// User B searches for the task
const searchResponse = await agentB.get(
'/api/search?q=UniqueTaskNameXYZ123'
);
expect(searchResponse.status).toBe(200);
const results = searchResponse.body.results;
// User B should NOT see User A's task in search results
const foundTask = results.find(
(r) => r.name === 'UniqueTaskNameXYZ123'
);
expect(foundTask).toBeUndefined();
});
it('should NOT allow User B to see User A tasks in today view', async () => {
// User A creates a task with today's date
const today = new Date().toISOString().split('T')[0];
const taskResponse = await agentA.post('/api/task').send({
name: 'User A Today Task',
status: 'planned',
due_date: today,
});
expect(taskResponse.status).toBe(201);
const taskA = taskResponse.body;
// User B fetches today tasks
const todayResponse = await agentB.get('/api/tasks?type=today');
expect(todayResponse.status).toBe(200);
const tasks = todayResponse.body.tasks;
// User B should NOT see User A's task
const userATask = tasks.find((t) => t.uid === taskA.uid);
expect(userATask).toBeUndefined();
});
});
});