tududi/backend/tests/integration/users.test.js
Chris 00eda4b936
Fix/descriptive ai feat (#464)
* fix AI feature not working

* fixup! fix AI feature not working
2025-11-02 14:14:55 +02:00

435 lines
16 KiB
JavaScript

const request = require('supertest');
const app = require('../../app');
const { User } = require('../../models');
const { createTestUser } = require('../helpers/testUtils');
describe('Users Routes', () => {
let user, agent;
beforeEach(async () => {
user = await createTestUser({
email: `test_${Date.now()}@example.com`,
});
// Create authenticated agent
agent = request.agent(app);
await agent.post('/api/login').send({
email: user.email,
password: 'password123',
});
});
describe('GET /api/profile', () => {
it('should get user profile', async () => {
const response = await agent.get('/api/profile');
expect(response.status).toBe(200);
expect(response.body.uid).toBe(user.uid);
expect(response.body).not.toHaveProperty('id');
expect(response.body.email).toBe(user.email);
expect(response.body).toHaveProperty('appearance');
expect(response.body).toHaveProperty('language');
expect(response.body).toHaveProperty('timezone');
expect(response.body).toHaveProperty('avatar_image');
expect(response.body).toHaveProperty('telegram_bot_token');
expect(response.body).toHaveProperty('telegram_chat_id');
expect(response.body).toHaveProperty('task_summary_enabled');
expect(response.body).toHaveProperty('task_summary_frequency');
});
it('should require authentication', async () => {
const response = await request(app).get('/api/profile');
expect(response.status).toBe(401);
expect(response.body.error).toBe('Authentication required');
});
it('should return 401 when session user no longer exists', async () => {
await User.destroy({ where: { id: user.id } });
const response = await agent.get('/api/profile');
expect(response.status).toBe(401);
expect(response.body.error).toBe('User not found');
});
});
describe('PATCH /api/profile', () => {
it('should update user profile', async () => {
const updateData = {
appearance: 'dark',
language: 'es',
timezone: 'UTC',
avatar_image: 'new-avatar.png',
telegram_bot_token: 'new-token',
};
const response = await agent.patch('/api/profile').send(updateData);
expect(response.status).toBe(200);
expect(response.body.uid).toBe(user.uid);
expect(response.body).not.toHaveProperty('id');
expect(response.body.appearance).toBe(updateData.appearance);
expect(response.body.language).toBe(updateData.language);
expect(response.body.timezone).toBe(updateData.timezone);
expect(response.body.avatar_image).toBe(updateData.avatar_image);
expect(response.body.telegram_bot_token).toBe(
updateData.telegram_bot_token
);
});
it('should allow partial updates', async () => {
const updateData = {
appearance: 'dark',
};
const response = await agent.patch('/api/profile').send(updateData);
expect(response.status).toBe(200);
expect(response.body.appearance).toBe(updateData.appearance);
expect(response.body.language).toBe(user.language);
});
it('should require authentication', async () => {
const updateData = {
appearance: 'dark',
};
const response = await request(app)
.patch('/api/profile')
.send(updateData);
expect(response.status).toBe(401);
expect(response.body.error).toBe('Authentication required');
});
it('should return 401 when session user no longer exists', async () => {
await User.destroy({ where: { id: user.id } });
const response = await agent
.patch('/api/profile')
.send({ appearance: 'dark' });
expect(response.status).toBe(401);
expect(response.body.error).toBe('User not found');
});
});
describe('Task Intelligence Settings', () => {
describe('GET /api/profile - task_intelligence_enabled field', () => {
it('should return task_intelligence_enabled in profile', async () => {
const response = await agent.get('/api/profile');
expect(response.status).toBe(200);
expect(response.body).toHaveProperty(
'task_intelligence_enabled'
);
expect(typeof response.body.task_intelligence_enabled).toBe(
'boolean'
);
});
it('should default to true for new users', async () => {
const response = await agent.get('/api/profile');
expect(response.status).toBe(200);
// New users should have task intelligence enabled by default
expect(response.body.task_intelligence_enabled).toBe(true);
});
});
describe('PATCH /api/profile - disable task intelligence', () => {
it('should disable task intelligence (AI popups)', async () => {
const response = await agent
.patch('/api/profile')
.send({ task_intelligence_enabled: false });
expect(response.status).toBe(200);
expect(response.body.task_intelligence_enabled).toBe(false);
// Verify it persisted
const getResponse = await agent.get('/api/profile');
expect(getResponse.body.task_intelligence_enabled).toBe(false);
});
it('should enable task intelligence (AI popups)', async () => {
// First disable it
await user.update({ task_intelligence_enabled: false });
// Then enable it via API
const response = await agent
.patch('/api/profile')
.send({ task_intelligence_enabled: true });
expect(response.status).toBe(200);
expect(response.body.task_intelligence_enabled).toBe(true);
// Verify it persisted
const getResponse = await agent.get('/api/profile');
expect(getResponse.body.task_intelligence_enabled).toBe(true);
});
it('should allow updating task intelligence with other fields', async () => {
const response = await agent.patch('/api/profile').send({
task_intelligence_enabled: false,
appearance: 'dark',
language: 'es',
});
expect(response.status).toBe(200);
expect(response.body.task_intelligence_enabled).toBe(false);
expect(response.body.appearance).toBe('dark');
expect(response.body.language).toBe('es');
});
it('should handle boolean conversion from string', async () => {
// Test that "false" string gets converted to boolean false
const response = await agent
.patch('/api/profile')
.send({ task_intelligence_enabled: 'false' });
expect(response.status).toBe(200);
// Should handle string to boolean conversion
expect([false, 'false']).toContain(
response.body.task_intelligence_enabled
);
});
});
describe('Task Intelligence Feature Verification', () => {
it('should respect disabled setting - no AI suggestions shown', async () => {
// Disable task intelligence
await agent
.patch('/api/profile')
.send({ task_intelligence_enabled: false });
// Verify the setting is stored correctly
const response = await agent.get('/api/profile');
expect(response.body.task_intelligence_enabled).toBe(false);
// This verifies that the backend correctly stores the setting
// Frontend tests verify that popups are actually hidden
});
it('should persist across sessions', async () => {
// Disable task intelligence
await agent
.patch('/api/profile')
.send({ task_intelligence_enabled: false });
// Simulate new session by creating new agent
const newAgent = request.agent(app);
await newAgent.post('/api/login').send({
email: user.email,
password: 'password123',
});
// Verify setting persisted
const response = await newAgent.get('/api/profile');
expect(response.body.task_intelligence_enabled).toBe(false);
});
});
});
describe('POST /api/profile/task-summary/toggle', () => {
beforeEach(async () => {
await user.update({ task_summary_enabled: false });
});
it('should toggle task summary on', async () => {
const response = await agent.post(
'/api/profile/task-summary/toggle'
);
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.enabled).toBe(true);
expect(response.body.message).toBe(
'Task summary notifications have been enabled.'
);
});
it('should toggle task summary off', async () => {
await user.update({ task_summary_enabled: true });
const response = await agent.post(
'/api/profile/task-summary/toggle'
);
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.enabled).toBe(false);
expect(response.body.message).toBe(
'Task summary notifications have been disabled.'
);
});
it('should require authentication', async () => {
const response = await request(app).post(
'/api/profile/task-summary/toggle'
);
expect(response.status).toBe(401);
expect(response.body.error).toBe('Authentication required');
});
it('should return 401 when session user no longer exists', async () => {
await User.destroy({ where: { id: user.id } });
const response = await agent.post(
'/api/profile/task-summary/toggle'
);
expect(response.status).toBe(401);
expect(response.body.error).toBe('User not found');
});
});
describe('POST /api/profile/task-summary/frequency', () => {
it('should update task summary frequency', async () => {
const response = await agent
.post('/api/profile/task-summary/frequency')
.send({ frequency: 'daily' });
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.frequency).toBe('daily');
expect(response.body.message).toBe(
'Task summary frequency has been set to daily.'
);
});
it('should require frequency parameter', async () => {
const response = await agent
.post('/api/profile/task-summary/frequency')
.send({});
expect(response.status).toBe(400);
expect(response.body.error).toBe('Frequency is required.');
});
it('should validate frequency value', async () => {
const response = await agent
.post('/api/profile/task-summary/frequency')
.send({ frequency: 'invalid' });
expect(response.status).toBe(400);
expect(response.body.error).toBe('Invalid frequency value.');
});
it('should accept valid frequencies', async () => {
const validFrequencies = [
'daily',
'weekdays',
'weekly',
'1h',
'2h',
'4h',
'8h',
'12h',
];
for (const frequency of validFrequencies) {
const response = await agent
.post('/api/profile/task-summary/frequency')
.send({ frequency });
expect(response.status).toBe(200);
expect(response.body.frequency).toBe(frequency);
}
});
it('should require authentication', async () => {
const response = await request(app)
.post('/api/profile/task-summary/frequency')
.send({ frequency: 'daily' });
expect(response.status).toBe(401);
expect(response.body.error).toBe('Authentication required');
});
it('should return 401 when session user no longer exists', async () => {
await User.destroy({ where: { id: user.id } });
const response = await agent
.post('/api/profile/task-summary/frequency')
.send({ frequency: 'daily' });
expect(response.status).toBe(401);
expect(response.body.error).toBe('User not found');
});
});
describe('POST /api/profile/task-summary/send-now', () => {
it('should require telegram configuration', async () => {
const response = await agent.post(
'/api/profile/task-summary/send-now'
);
expect(response.status).toBe(400);
expect(response.body.error).toBe(
'Telegram bot is not properly configured.'
);
});
it('should require authentication', async () => {
const response = await request(app).post(
'/api/profile/task-summary/send-now'
);
expect(response.status).toBe(401);
expect(response.body.error).toBe('Authentication required');
});
it('should return 401 when session user no longer exists', async () => {
await User.destroy({ where: { id: user.id } });
const response = await agent.post(
'/api/profile/task-summary/send-now'
);
expect(response.status).toBe(401);
expect(response.body.error).toBe('User not found');
});
});
describe('GET /api/profile/task-summary/status', () => {
it('should get task summary status', async () => {
await user.update({
task_summary_enabled: true,
task_summary_frequency: 'daily',
});
const response = await agent.get(
'/api/profile/task-summary/status'
);
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.enabled).toBe(true);
expect(response.body.frequency).toBe('daily');
expect(response.body).toHaveProperty('last_run');
expect(response.body).toHaveProperty('next_run');
});
it('should require authentication', async () => {
const response = await request(app).get(
'/api/profile/task-summary/status'
);
expect(response.status).toBe(401);
expect(response.body.error).toBe('Authentication required');
});
it('should return 401 when session user no longer exists', async () => {
await User.destroy({ where: { id: user.id } });
const response = await agent.get(
'/api/profile/task-summary/status'
);
expect(response.status).toBe(401);
expect(response.body.error).toBe('User not found');
});
});
});