Fix an issue with tasks appearing in today without a flag (#640)
This commit is contained in:
parent
08be7f8eda
commit
270a80f71b
8 changed files with 49 additions and 53 deletions
|
|
@ -116,6 +116,7 @@ async function filterTasksByParams(
|
|||
};
|
||||
whereClause[Op.or] = [
|
||||
{
|
||||
// Non-recurring tasks that are marked for today
|
||||
[Op.and]: [
|
||||
{
|
||||
[Op.or]: [
|
||||
|
|
@ -124,16 +125,20 @@ async function filterTasksByParams(
|
|||
],
|
||||
},
|
||||
{ recurring_parent_id: null },
|
||||
{ today: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Recurring parent tasks that are marked for today
|
||||
[Op.and]: [
|
||||
{ recurrence_type: { [Op.ne]: 'none' } },
|
||||
{ recurrence_type: { [Op.ne]: null } },
|
||||
{ recurring_parent_id: null },
|
||||
{ today: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Recurring task instances that are due today (regardless of today flag)
|
||||
[Op.and]: [
|
||||
{ recurring_parent_id: { [Op.ne]: null } },
|
||||
{
|
||||
|
|
|
|||
|
|
@ -152,19 +152,19 @@ describe('Project Sharing Integration Tests', () => {
|
|||
});
|
||||
const taskDueToday = taskDueTodayResponse.body;
|
||||
|
||||
// Fetch today's tasks as shared user
|
||||
const response = await sharedUserAgent.get('/api/tasks?type=today');
|
||||
// Fetch today's tasks as shared user with include_lists to get tasks_due_today
|
||||
const response = await sharedUserAgent.get(
|
||||
'/api/tasks?type=today&include_lists=true'
|
||||
);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.tasks).toBeDefined();
|
||||
|
||||
// Check if the task appears in the main tasks or metrics
|
||||
const allTasks = [
|
||||
...response.body.tasks,
|
||||
...(response.body.metrics?.tasks_due_today || []),
|
||||
];
|
||||
|
||||
const foundTask = allTasks.find((t) => t.id === taskDueToday.id);
|
||||
// Task should appear in tasks_due_today since it has a due date but today=false
|
||||
expect(response.body.tasks_due_today).toBeDefined();
|
||||
const foundTask = response.body.tasks_due_today.find(
|
||||
(t) => t.id === taskDueToday.id
|
||||
);
|
||||
expect(foundTask).toBeDefined();
|
||||
expect(foundTask.name).toBe('Task due today in shared project');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -99,13 +99,13 @@ describe('Tasks Routes', () => {
|
|||
expect(response.body.tasks.map((t) => t.id)).toContain(task2.id);
|
||||
});
|
||||
|
||||
it('should filter today tasks (returns all user tasks)', async () => {
|
||||
it('should filter today tasks (returns only tasks with today=true)', async () => {
|
||||
const response = await agent.get('/api/tasks?type=today');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.tasks).toBeDefined();
|
||||
expect(response.body.tasks.length).toBe(2);
|
||||
// Both tasks should be returned as "today" doesn't filter by the today field
|
||||
expect(response.body.tasks.length).toBe(1);
|
||||
expect(response.body.tasks[0].id).toBe(task1.id);
|
||||
});
|
||||
|
||||
it('should require authentication', async () => {
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ const slowMoMs = Number(process.env.E2E_SLOWMO || '0') || 0;
|
|||
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
timeout: 60_000,
|
||||
expect: { timeout: 10_000 },
|
||||
timeout: 30_000, // Reduced from 60s to 30s
|
||||
expect: { timeout: 5_000 }, // Reduced from 10s to 5s
|
||||
fullyParallel: true,
|
||||
workers: process.env.CI ? 1 : undefined, // Use default workers locally, 1 in CI
|
||||
workers: process.env.CI ? 1 : 4, // Use 4 workers locally for speed
|
||||
reporter: [['list']],
|
||||
use: {
|
||||
baseURL,
|
||||
trace: 'on-first-retry',
|
||||
video: 'retain-on-failure',
|
||||
video: 'off', // Disable video for speed (was 'retain-on-failure')
|
||||
screenshot: 'only-on-failure',
|
||||
viewport: { width: 1280, height: 800 },
|
||||
launchOptions: { slowMo: slowMoMs },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe.serial('User Registration', () => {
|
||||
test.describe.serial('User Registration - Enabled', () => {
|
||||
test.describe.serial('Registration', () => {
|
||||
test.describe.serial('Enabled', () => {
|
||||
test.beforeAll(async ({ request, baseURL }) => {
|
||||
const appUrl = baseURL ?? process.env.APP_URL ?? 'http://localhost:8080';
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ test.describe.serial('User Registration - Enabled', () => {
|
|||
await page.goto(appUrl + '/register');
|
||||
});
|
||||
|
||||
test('should display registration form', async ({ page }) => {
|
||||
test('Shows form', async ({ page }) => {
|
||||
await expect(page.getByTestId('register-heading')).toBeVisible();
|
||||
await expect(page.getByTestId('register-email')).toBeVisible();
|
||||
await expect(page.getByTestId('register-password')).toBeVisible();
|
||||
|
|
@ -45,7 +45,7 @@ test.describe.serial('User Registration - Enabled', () => {
|
|||
await expect(page.getByTestId('register-submit')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should show error when passwords do not match', async ({ page }) => {
|
||||
test('Password mismatch error', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
const email = `test${timestamp}@example.com`;
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ test.describe.serial('User Registration - Enabled', () => {
|
|||
await expect(page.getByTestId('register-error')).toContainText(/passwords do not match/i);
|
||||
});
|
||||
|
||||
test('should prevent submission when password is too short (HTML5 validation)', async ({ page }) => {
|
||||
test('Password too short', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
const email = `test${timestamp}@example.com`;
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ test.describe.serial('User Registration - Enabled', () => {
|
|||
expect(validationMessage).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should successfully register a new user or show email error', async ({ page }) => {
|
||||
test('Register successfully', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
const email = `test${timestamp}@example.com`;
|
||||
const password = 'password123';
|
||||
|
|
@ -107,13 +107,13 @@ test.describe.serial('User Registration - Enabled', () => {
|
|||
}
|
||||
});
|
||||
|
||||
test('should navigate to login page from link', async ({ page }) => {
|
||||
test('Link to login', async ({ page }) => {
|
||||
await page.getByTestId('register-login-link').click();
|
||||
|
||||
await expect(page).toHaveURL(/\/login$/);
|
||||
});
|
||||
|
||||
test('should show error for duplicate email registration', async ({ page }) => {
|
||||
test('Duplicate email error', async ({ page }) => {
|
||||
const email = process.env.E2E_EMAIL || 'test@tududi.com';
|
||||
const password = 'password123';
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ test.describe.serial('User Registration - Enabled', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test.describe.serial('User Registration - Disabled', () => {
|
||||
test.describe.serial('Disabled', () => {
|
||||
test.beforeAll(async ({ request, baseURL }) => {
|
||||
const appUrl = baseURL ?? process.env.APP_URL ?? 'http://localhost:8080';
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ test.describe.serial('User Registration - Disabled', () => {
|
|||
await page.goto(appUrl + '/register');
|
||||
});
|
||||
|
||||
test('should show registration disabled error', async ({ page }) => {
|
||||
test('Shows disabled error', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
const email = `test${timestamp}@example.com`;
|
||||
const password = 'password123';
|
||||
|
|
|
|||
|
|
@ -1,27 +1,25 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe.serial('Today View', () => {
|
||||
test.describe('Today', () => {
|
||||
// Helper function to login via UI
|
||||
async function loginViaUI(page, baseURL) {
|
||||
const appUrl =
|
||||
baseURL ?? process.env.APP_URL ?? 'http://localhost:8080';
|
||||
await page.goto(`${appUrl}/login`);
|
||||
|
||||
await page.fill(
|
||||
'input[type="email"]',
|
||||
process.env.E2E_EMAIL || 'test@tududi.com'
|
||||
);
|
||||
await page.fill(
|
||||
'input[type="password"]',
|
||||
process.env.E2E_PASSWORD || 'password123'
|
||||
);
|
||||
await page.click('button[type="submit"]');
|
||||
await page
|
||||
.getByTestId('login-email')
|
||||
.fill(process.env.E2E_EMAIL || 'test@tududi.com');
|
||||
await page
|
||||
.getByTestId('login-password')
|
||||
.fill(process.env.E2E_PASSWORD || 'password123');
|
||||
await page.getByTestId('login-submit').click();
|
||||
|
||||
// Wait for redirect to dashboard or today page
|
||||
await page.waitForURL(/\/(dashboard|today)/, { timeout: 10000 });
|
||||
}
|
||||
|
||||
test('should only show tasks with today flag in Planned section', async ({
|
||||
test('Planned: only today=true tasks', async ({
|
||||
page,
|
||||
context,
|
||||
baseURL,
|
||||
|
|
@ -62,11 +60,10 @@ test.describe.serial('Today View', () => {
|
|||
}
|
||||
}
|
||||
|
||||
// Navigate to today page and wait for metrics to load
|
||||
// Navigate to today page
|
||||
await page.goto(`${appUrl}/today`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Check if Planned section exists using data-testid
|
||||
// Wait for Planned section to appear (indicates page loaded)
|
||||
const plannedSection = page.getByTestId('planned-section');
|
||||
await expect(plannedSection).toBeVisible({ timeout: 10000 });
|
||||
|
||||
|
|
@ -88,7 +85,7 @@ test.describe.serial('Today View', () => {
|
|||
}
|
||||
});
|
||||
|
||||
test('should show overdue tasks in Overdue section', async ({
|
||||
test('Overdue: shows overdue tasks', async ({
|
||||
page,
|
||||
context,
|
||||
baseURL,
|
||||
|
|
@ -122,10 +119,6 @@ test.describe.serial('Today View', () => {
|
|||
|
||||
// Navigate to today page
|
||||
await page.goto(`${appUrl}/today`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Wait a bit for React to render the sections
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Check if Overdue section exists using data-testid
|
||||
const overdueSection = page.getByTestId('overdue-section');
|
||||
|
|
@ -153,7 +146,7 @@ test.describe.serial('Today View', () => {
|
|||
}
|
||||
});
|
||||
|
||||
test('should show tasks due today in Due Today section', async ({
|
||||
test('Due Today: shows tasks', async ({
|
||||
page,
|
||||
context,
|
||||
baseURL,
|
||||
|
|
@ -187,10 +180,6 @@ test.describe.serial('Today View', () => {
|
|||
|
||||
// Navigate to today page
|
||||
await page.goto(`${appUrl}/today`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Wait a bit for React to render the sections
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Check if Due Today section exists using data-testid
|
||||
const dueTodaySection = page.getByTestId('due-today-section');
|
||||
|
|
@ -217,7 +206,7 @@ test.describe.serial('Today View', () => {
|
|||
}
|
||||
});
|
||||
|
||||
test('should allow collapsing and expanding sections', async ({
|
||||
test('Collapse/expand sections', async ({
|
||||
page,
|
||||
baseURL,
|
||||
}) => {
|
||||
|
|
@ -227,7 +216,6 @@ test.describe.serial('Today View', () => {
|
|||
const appUrl =
|
||||
baseURL ?? process.env.APP_URL ?? 'http://localhost:8080';
|
||||
await page.goto(`${appUrl}/today`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Test Planned section collapse/expand if it exists using data-testid
|
||||
const plannedHeader = page.getByTestId('planned-section-header');
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ const Login: React.FC = () => {
|
|||
setEmail(e.target.value)
|
||||
}
|
||||
className="w-full px-4 py-2 border dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
|
||||
data-testid="login-email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -202,12 +203,14 @@ const Login: React.FC = () => {
|
|||
setPassword(e.target.value)
|
||||
}
|
||||
className="w-full px-4 py-2 border dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
|
||||
data-testid="login-password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-500 text-white py-2 rounded-lg hover:bg-blue-600 transition-colors"
|
||||
data-testid="login-submit"
|
||||
>
|
||||
{t('auth.login', 'Login')}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@
|
|||
"unknownProject": "Άγνωστο έργο",
|
||||
"tasks": "εργασίες",
|
||||
"showingItems": "Εμφάνιση {{current}} από {{total}} στοιχεία",
|
||||
"overdue": "Υπερβολικό",
|
||||
"overdue": "Εκπρόθεσμο",
|
||||
"planned": "Προγραμματισμένο",
|
||||
"open": "Άνοιγμα",
|
||||
"completed": "Ολοκληρώθηκε"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue