Skip to content

Commit bbe05ca

Browse files
committed
improve time estimate input, responsive time entry create modal fixes,
fixes #460, #800
1 parent d264411 commit bbe05ca

16 files changed

+760
-301
lines changed

e2e/projects.spec.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,149 @@ test('test that custom billable rate is displayed correctly on project detail pa
366366
);
367367
});
368368

369+
// Tests for estimated time input (Issue #460)
370+
test('test that creating a project with estimated time in human-readable format works', async ({
371+
page,
372+
}) => {
373+
const newProjectName = 'Estimated Time Project ' + Math.floor(1 + Math.random() * 10000);
374+
await goToProjectsOverview(page);
375+
await page.getByRole('button', { name: 'Create Project' }).click();
376+
await page.getByLabel('Project Name').fill(newProjectName);
377+
378+
// Fill in estimated time using human-readable format
379+
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
380+
await estimatedTimeInput.fill('2h 30m');
381+
await estimatedTimeInput.press('Tab');
382+
383+
await Promise.all([
384+
page.getByRole('button', { name: 'Create Project' }).click(),
385+
page.waitForResponse(
386+
async (response) =>
387+
response.url().includes('/projects') &&
388+
response.request().method() === 'POST' &&
389+
response.status() === 201 &&
390+
// 2h 30m = 9000 seconds
391+
(await response.json()).data.estimated_time === 9000
392+
),
393+
]);
394+
395+
await expect(page.getByTestId('project_table')).toContainText(newProjectName);
396+
});
397+
398+
test('test that creating a project with estimated time using decimal notation works', async ({
399+
page,
400+
}) => {
401+
const newProjectName = 'Decimal Estimated Project ' + Math.floor(1 + Math.random() * 10000);
402+
await goToProjectsOverview(page);
403+
await page.getByRole('button', { name: 'Create Project' }).click();
404+
await page.getByLabel('Project Name').fill(newProjectName);
405+
406+
// Fill in estimated time using decimal notation (1.5 hours = 1h 30m)
407+
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
408+
await estimatedTimeInput.fill('1.5');
409+
await estimatedTimeInput.press('Tab');
410+
411+
await Promise.all([
412+
page.getByRole('button', { name: 'Create Project' }).click(),
413+
page.waitForResponse(
414+
async (response) =>
415+
response.url().includes('/projects') &&
416+
response.request().method() === 'POST' &&
417+
response.status() === 201 &&
418+
// 1.5 hours = 5400 seconds
419+
(await response.json()).data.estimated_time === 5400
420+
),
421+
]);
422+
423+
await expect(page.getByTestId('project_table')).toContainText(newProjectName);
424+
});
425+
426+
test('test that creating a project with estimated time using comma decimal notation works', async ({
427+
page,
428+
}) => {
429+
const newProjectName = 'Comma Decimal Project ' + Math.floor(1 + Math.random() * 10000);
430+
await goToProjectsOverview(page);
431+
await page.getByRole('button', { name: 'Create Project' }).click();
432+
await page.getByLabel('Project Name').fill(newProjectName);
433+
434+
// Fill in estimated time using comma decimal notation (2,5 hours = 2h 30m)
435+
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
436+
await estimatedTimeInput.fill('2,5');
437+
await estimatedTimeInput.press('Tab');
438+
439+
await Promise.all([
440+
page.getByRole('button', { name: 'Create Project' }).click(),
441+
page.waitForResponse(
442+
async (response) =>
443+
response.url().includes('/projects') &&
444+
response.request().method() === 'POST' &&
445+
response.status() === 201 &&
446+
// 2.5 hours = 9000 seconds
447+
(await response.json()).data.estimated_time === 9000
448+
),
449+
]);
450+
451+
await expect(page.getByTestId('project_table')).toContainText(newProjectName);
452+
});
453+
454+
test('test that updating estimated time on existing project works', async ({ page }) => {
455+
const newProjectName = 'Update Estimated Project ' + Math.floor(1 + Math.random() * 10000);
456+
await goToProjectsOverview(page);
457+
458+
// Create a project first
459+
await page.getByRole('button', { name: 'Create Project' }).click();
460+
await page.getByLabel('Project Name').fill(newProjectName);
461+
await Promise.all([
462+
page.getByRole('button', { name: 'Create Project' }).click(),
463+
page.waitForResponse(
464+
(response) =>
465+
response.url().includes('/projects') &&
466+
response.request().method() === 'POST' &&
467+
response.status() === 201
468+
),
469+
]);
470+
await expect(page.getByText(newProjectName)).toBeVisible({ timeout: 10000 });
471+
472+
// Edit the project to add estimated time
473+
await page.getByRole('row').first().getByRole('button').click();
474+
await page.getByRole('menuitem').getByText('Edit').first().click();
475+
476+
// Fill in estimated time
477+
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
478+
await estimatedTimeInput.fill('4h 15m');
479+
await estimatedTimeInput.press('Tab');
480+
481+
await Promise.all([
482+
page.getByRole('button', { name: 'Update Project' }).click(),
483+
page.waitForResponse(
484+
async (response) =>
485+
response.url().includes('/projects/') &&
486+
response.request().method() === 'PUT' &&
487+
response.status() === 200 &&
488+
// 4h 15m = 15300 seconds
489+
(await response.json()).data.estimated_time === 15300
490+
),
491+
]);
492+
});
493+
494+
test('test that estimated time input displays formatted value after blur', async ({ page }) => {
495+
await goToProjectsOverview(page);
496+
await page.getByRole('button', { name: 'Create Project' }).click();
497+
498+
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
499+
500+
// Enter time in various formats and check the displayed value
501+
await estimatedTimeInput.fill('90');
502+
await estimatedTimeInput.press('Tab');
503+
// 90 hours should be displayed as "90h 00min" (default format)
504+
await expect(estimatedTimeInput).toHaveValue(/90h/);
505+
506+
await estimatedTimeInput.fill('1:30');
507+
await estimatedTimeInput.press('Tab');
508+
// 1:30 should be displayed as "1h 30min"
509+
await expect(estimatedTimeInput).toHaveValue(/1h.*30/);
510+
});
511+
369512
// Create new project with new Client
370513

371514
// Create new project with existing Client

0 commit comments

Comments
 (0)