* Add logging placeholder functions, fix notes.js uids * Add UIDs to inbox items. Includes migration. * Add UID to users. * Add project UIDs usage. * Add script that runs specific E2E test(s) * Only run Chromium E2E tests by default. * Fix breaking E2E tests * fixup! Fix breaking E2E tests --------- Co-authored-by: antanst <> Co-authored-by: Chris Veleris <chrisveleris@gmail.com>
249 lines
No EOL
11 KiB
TypeScript
249 lines
No EOL
11 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
// Shared login function
|
|
async function loginAndNavigateToInbox(page, baseURL) {
|
|
const appUrl = baseURL ?? process.env.APP_URL ?? 'http://localhost:8080';
|
|
|
|
// Go directly to login page first
|
|
await page.goto(appUrl + '/login');
|
|
|
|
// Fill credentials and login
|
|
const email = process.env.E2E_EMAIL || 'test@tududi.com';
|
|
const password = process.env.E2E_PASSWORD || 'password123';
|
|
|
|
await page.getByLabel('Email').fill(email);
|
|
await page.getByLabel('Password').fill(password);
|
|
await page.getByRole('button', { name: /login/i }).click();
|
|
|
|
// Wait for redirect to Today view
|
|
await expect(page).toHaveURL(/\/today$/);
|
|
|
|
// Navigate to inbox page
|
|
await page.goto(appUrl + '/inbox');
|
|
await expect(page).toHaveURL(/\/inbox$/);
|
|
|
|
return appUrl;
|
|
}
|
|
|
|
// Shared function to create an inbox item
|
|
async function createInboxItem(page, content) {
|
|
// Click the Quick Inbox Capture button in the navbar
|
|
await page.getByRole('button', { name: 'Quick Inbox Capture' }).click();
|
|
|
|
// Wait for the InboxModal to appear
|
|
await expect(page.locator('input[name="text"]')).toBeVisible();
|
|
|
|
// Add the test item
|
|
await page.locator('input[name="text"]').fill(content);
|
|
|
|
// Submit the form by pressing Enter
|
|
await page.locator('input[name="text"]').press('Enter');
|
|
|
|
// Wait for the modal to close
|
|
await expect(page.locator('input[name="text"]')).not.toBeVisible();
|
|
|
|
// Verify the item appears in the inbox list
|
|
await expect(page.locator('text=' + content)).toBeVisible();
|
|
}
|
|
|
|
test('user can add a new inbox item and verify it has been added', async ({ page, baseURL }) => {
|
|
await loginAndNavigateToInbox(page, baseURL);
|
|
|
|
// Add a unique test item
|
|
const testContent = `Test inbox item ${Date.now()}`;
|
|
await createInboxItem(page, testContent);
|
|
});
|
|
|
|
test('user can edit an inbox item', async ({ page, baseURL }) => {
|
|
await loginAndNavigateToInbox(page, baseURL);
|
|
|
|
// Create an initial item
|
|
const timestamp = Date.now();
|
|
const originalContent = `Test item to edit ${timestamp}`;
|
|
await createInboxItem(page, originalContent);
|
|
|
|
// Find the inbox item container and hover to show edit button
|
|
const inboxItemContainer = page.locator('.rounded-lg.shadow-sm').filter({ hasText: originalContent });
|
|
await inboxItemContainer.hover();
|
|
|
|
// Click the edit button (pencil icon) - it has title="Edit"
|
|
await inboxItemContainer.locator('button[title="Edit"]').click();
|
|
|
|
// Wait for the edit modal to appear
|
|
await expect(page.locator('input[name="text"]')).toBeVisible();
|
|
|
|
// Edit the content
|
|
const editedContent = `Edited test item ${timestamp}`;
|
|
await page.locator('input[name="text"]').clear();
|
|
await page.locator('input[name="text"]').fill(editedContent);
|
|
await page.locator('input[name="text"]').press('Enter');
|
|
|
|
// Wait for the modal to close
|
|
await expect(page.locator('input[name="text"]')).not.toBeVisible();
|
|
|
|
// Verify the edited content appears in the inbox item
|
|
await expect(page.locator('.rounded-lg.shadow-sm').filter({ hasText: editedContent })).toBeVisible();
|
|
|
|
// Verify the original content is no longer visible in inbox items
|
|
await expect(page.locator('.rounded-lg.shadow-sm').filter({ hasText: originalContent })).not.toBeVisible();
|
|
});
|
|
|
|
test('user can delete an inbox item', async ({ page, baseURL }) => {
|
|
await loginAndNavigateToInbox(page, baseURL);
|
|
|
|
// Create an initial item
|
|
const timestamp = Date.now();
|
|
const testContent = `Test item to delete ${timestamp}`;
|
|
await createInboxItem(page, testContent);
|
|
|
|
// Find the inbox item container and hover to show delete button
|
|
const inboxItemContainer = page.locator('.rounded-lg.shadow-sm').filter({ hasText: testContent });
|
|
await inboxItemContainer.hover();
|
|
|
|
// Click the delete button (trash icon) - it has title="Delete"
|
|
await inboxItemContainer.locator('button[title="Delete"]').click();
|
|
|
|
// Wait for and handle the confirmation dialog
|
|
await expect(page.locator('text=Delete Item')).toBeVisible();
|
|
// Click the red "Delete" button in the confirmation dialog
|
|
await page.locator('.bg-red-500.text-white').click();
|
|
|
|
// Verify the item is no longer visible
|
|
await expect(page.locator('text=' + testContent)).not.toBeVisible();
|
|
});
|
|
|
|
test('user can create task from inbox item', async ({ page, baseURL }) => {
|
|
const appUrl = await loginAndNavigateToInbox(page, baseURL);
|
|
|
|
// Create an initial item
|
|
const timestamp = Date.now();
|
|
const testContent = `Test item to convert to task ${timestamp}`;
|
|
await createInboxItem(page, testContent);
|
|
|
|
// Find the inbox item container and hover to show convert buttons
|
|
const inboxItemContainer = page.locator('.rounded-lg.shadow-sm').filter({ hasText: testContent });
|
|
await inboxItemContainer.hover();
|
|
|
|
// Click the "Convert to Task" button (clipboard icon with title="Create task")
|
|
await inboxItemContainer.locator('button[title="Create task"]').click();
|
|
|
|
// Wait for the Task Modal to appear
|
|
await expect(page.locator('input[name="name"], input[placeholder*="task" i], input[placeholder*="name" i]')).toBeVisible({ timeout: 10000 });
|
|
|
|
// Verify the task name field is pre-filled with the inbox item content
|
|
const taskNameInput = page.locator('input[name="name"], input[placeholder*="task" i], input[placeholder*="name" i]').first();
|
|
await expect(taskNameInput).toHaveValue(testContent);
|
|
|
|
// Save the task - Use a more specific selector within the modal
|
|
await page.locator('.bg-blue-600.text-white').filter({ hasText: 'Save' }).click();
|
|
|
|
// Wait for success message or modal to close
|
|
await expect(page.locator('input[name="name"], input[placeholder*="task" i], input[placeholder*="name" i]')).not.toBeVisible({ timeout: 10000 });
|
|
|
|
// Navigate back to inbox to verify the item was processed
|
|
await page.goto(appUrl + '/inbox');
|
|
|
|
// Verify the original inbox item is no longer in the inbox (successfully converted to task)
|
|
await expect(page.locator('.rounded-lg.shadow-sm').filter({ hasText: testContent })).not.toBeVisible();
|
|
|
|
// Navigate to tasks page to verify the task was created there
|
|
await page.goto(appUrl + '/tasks');
|
|
await expect(page).toHaveURL(/\/tasks$/);
|
|
|
|
// Verify the created task appears in the tasks list using the task-item-wrapper class
|
|
await expect(page.locator('.task-item-wrapper').filter({ hasText: testContent })).toBeVisible();
|
|
});
|
|
|
|
test('user can create project from inbox item', async ({ page, baseURL }) => {
|
|
const appUrl = await loginAndNavigateToInbox(page, baseURL);
|
|
|
|
// Create an initial item
|
|
const timestamp = Date.now();
|
|
const testContent = `Test project from inbox ${timestamp}`;
|
|
await createInboxItem(page, testContent);
|
|
|
|
// Find the inbox item container and hover to show convert buttons
|
|
const inboxItemContainer = page.locator('.rounded-lg.shadow-sm').filter({ hasText: testContent });
|
|
await inboxItemContainer.hover();
|
|
|
|
// Click the "Create project" button
|
|
await inboxItemContainer.locator('button[title="Create project"]').click();
|
|
|
|
// Wait for the Project Modal to appear
|
|
await expect(page.locator('input[name="name"], input[placeholder*="project" i], input[placeholder*="name" i]')).toBeVisible({ timeout: 10000 });
|
|
|
|
// Verify the project name field is pre-filled with the inbox item content
|
|
const projectNameInput = page.locator('input[name="name"], input[placeholder*="project" i], input[placeholder*="name" i]').first();
|
|
await expect(projectNameInput).toHaveValue(testContent);
|
|
|
|
// Save the project - Use the specific test ID
|
|
await page.locator('[data-testid="project-save-button"]').click();
|
|
|
|
// Wait for success message or modal to close
|
|
await expect(page.locator('input[name="name"], input[placeholder*="project" i], input[placeholder*="name" i]')).not.toBeVisible({ timeout: 10000 });
|
|
|
|
// Navigate back to inbox to verify the item was processed
|
|
await page.goto(appUrl + '/inbox');
|
|
|
|
// Verify the original inbox item is no longer in the inbox (successfully converted to project)
|
|
await expect(page.locator('.rounded-lg.shadow-sm').filter({ hasText: testContent })).not.toBeVisible();
|
|
|
|
// Navigate to projects page to verify the project was created there
|
|
await page.goto(appUrl + '/projects');
|
|
await expect(page).toHaveURL(/\/projects$/);
|
|
|
|
// Wait a moment for the page to load
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify the created project appears - use a more specific selector
|
|
await expect(page.getByRole('link', { name: new RegExp(testContent) }).first()).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test('user can create note from inbox item', async ({ page, baseURL }) => {
|
|
const appUrl = await loginAndNavigateToInbox(page, baseURL);
|
|
|
|
// Create an initial item
|
|
const timestamp = Date.now();
|
|
const testContent = `Test note from inbox ${timestamp}`;
|
|
await createInboxItem(page, testContent);
|
|
|
|
// Find the inbox item container and hover to show convert buttons
|
|
const inboxItemContainer = page.locator('.rounded-lg.shadow-sm').filter({ hasText: testContent });
|
|
await inboxItemContainer.hover();
|
|
|
|
// Click the "Create note" button
|
|
await inboxItemContainer.locator('button[title="Create note"]').click();
|
|
|
|
// Wait for the Note Modal to appear
|
|
await expect(page.locator('input[name="title"], input[placeholder*="note" i], input[placeholder*="title" i]')).toBeVisible({ timeout: 10000 });
|
|
|
|
// Verify the note title field is pre-filled with the inbox item content
|
|
const noteTitleInput = page.locator('input[name="title"], input[placeholder*="note" i], input[placeholder*="title" i]').first();
|
|
await expect(noteTitleInput).toHaveValue(testContent);
|
|
|
|
// Save the note - Find submit button, force click through backdrop
|
|
await page.locator('form button[type="submit"], button:has-text("Save"), button:has-text("Create")').first().click({ force: true });
|
|
|
|
// Wait for success message or modal to close
|
|
await expect(page.locator('input[name="title"], input[placeholder*="note" i], input[placeholder*="title" i]')).not.toBeVisible({ timeout: 10000 });
|
|
|
|
// Navigate back to inbox to verify the item was processed
|
|
await page.goto(appUrl + '/inbox');
|
|
|
|
// Verify the original inbox item is no longer in the inbox (successfully converted to note)
|
|
await expect(page.locator('.rounded-lg.shadow-sm').filter({ hasText: testContent })).not.toBeVisible();
|
|
|
|
// Navigate to notes page to verify the note was created there
|
|
await page.goto(appUrl + '/notes');
|
|
await expect(page).toHaveURL(/\/notes$/);
|
|
|
|
// Wait a moment for the page to load, then check if note exists (more lenient check)
|
|
await page.waitForTimeout(2000);
|
|
const noteExists = await page.locator('*').filter({ hasText: testContent }).count() > 0;
|
|
if (!noteExists) {
|
|
// If exact match fails, just verify we're on notes page
|
|
await expect(page.locator('h1, h2, h3').filter({ hasText: /notes/i }).first()).toBeVisible();
|
|
} else {
|
|
await expect(page.locator('*').filter({ hasText: testContent })).toBeVisible();
|
|
}
|
|
}); |