import { expect, test } from '../playwright/fixtures'; import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { assertThatTimerHasStarted, assertThatTimerIsStopped, newTimeEntryResponse, startOrStopTimerWithButton, stoppedTimeEntryResponse, } from './utils/currentTimeEntry'; import { Page } from '@playwright/test'; import { newTagResponse } from './utils/tags'; async function goToDashboard(page: Page) { await page.goto(PLAYWRIGHT_BASE_URL + '/dashboard'); } test('test that starting and stopping a timer without description and project works', async ({ page, }) => { await goToDashboard(page); await Promise.all([ newTimeEntryResponse(page), startOrStopTimerWithButton(page), assertThatTimerHasStarted(page), ]); await page.waitForTimeout(1500); await Promise.all([ stoppedTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await assertThatTimerIsStopped(page); }); test('test that starting and stopping a timer with a description works', async ({ page, }) => { await goToDashboard(page); // TODO: Fix flakyness by disabling description input field until timer is loaded await page.waitForTimeout(500); await page .getByTestId('time_entry_description') .fill('New Time Entry Description'); await Promise.all([ newTimeEntryResponse(page, { description: 'New Time Entry Description', }), startOrStopTimerWithButton(page), ]); await assertThatTimerHasStarted(page); await page.waitForTimeout(1500); await Promise.all([ stoppedTimeEntryResponse(page, { description: 'New Time Entry Description', }), await startOrStopTimerWithButton(page), ]); await assertThatTimerIsStopped(page); }); test('test that starting the time entry starts the live timer and that it keeps running after reload', async ({ page, }) => { await goToDashboard(page); await Promise.all([ newTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await assertThatTimerHasStarted(page); await page.waitForTimeout(500); const beforeTimerValue = await page .getByTestId('time_entry_time') .inputValue(); await page.waitForTimeout(2000); const afterWaitTimeValue = await page .getByTestId('time_entry_time') .inputValue(); expect(afterWaitTimeValue).not.toEqual(beforeTimerValue); await page.reload(); await page.waitForTimeout(500); const afterReloadTimerValue = await page .getByTestId('time_entry_time') .inputValue(); await page.waitForTimeout(2000); const afterReloadAfterWaitTimerValue = await page .getByTestId('time_entry_time') .inputValue(); expect(afterReloadTimerValue).not.toEqual(afterReloadAfterWaitTimerValue); }); test('test that starting and updating the description while running works', async ({ page, }) => { await goToDashboard(page); await Promise.all([ newTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await assertThatTimerHasStarted(page); await page.waitForTimeout(500); await page .getByTestId('time_entry_description') .fill('New Time Entry Description'); await Promise.all([ newTimeEntryResponse(page, { status: 200, description: 'New Time Entry Description', }), page.getByTestId('time_entry_description').press('Tab'), ]); await page.waitForTimeout(500); await Promise.all([ stoppedTimeEntryResponse(page, { description: 'New Time Entry Description', }), startOrStopTimerWithButton(page), ]); await assertThatTimerIsStopped(page); }); test('test that starting and updating the time while running works', async ({ page, }) => { await goToDashboard(page); const [createResponse] = await Promise.all([ newTimeEntryResponse(page), await startOrStopTimerWithButton(page), ]); await assertThatTimerHasStarted(page); await page.waitForTimeout(500); await page.getByTestId('time_entry_time').fill('20min'); await Promise.all([ page.waitForResponse(async (response) => { return ( response.url().includes('/time-entries') && response.status() === 200 && (await response.headerValue('Content-Type')) === 'application/json' && (await response.json()).data.id !== null && (await response.json()).data.start !== null && (await response.json()).data.start !== (await createResponse.json()).data.start && (await response.json()).data.end === null && (await response.json()).data.project_id === null && (await response.json()).data.description === '' && (await response.json()).data.task_id === null && (await response.json()).data.user_id !== null && JSON.stringify((await response.json()).data.tags) === JSON.stringify([]) ); }), page.getByTestId('time_entry_time').press('Enter'), ]); await expect(page.getByTestId('time_entry_time')).toHaveValue(/00:20/); await page.waitForTimeout(500); await Promise.all([ stoppedTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await assertThatTimerIsStopped(page); }); test('test that entering a human readable time starts the timer on blur', async ({ page, }) => { await goToDashboard(page); await page.getByTestId('time_entry_time').fill('20min'); await Promise.all([ newTimeEntryResponse(page), page.getByTestId('time_entry_time').press('Tab'), ]); await expect(page.getByTestId('time_entry_time')).toHaveValue(/00:20:/); await assertThatTimerHasStarted(page); await Promise.all([ stoppedTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await page.locator( '[data-testid="dashboard_timer"] [data-testid="timer_button"].bg-accent-300/70' ); }); test('test that entering a number in the time range starts the timer on blur', async ({ page, }) => { await goToDashboard(page); await page.getByTestId('time_entry_time').fill('5'); await Promise.all([ newTimeEntryResponse(page), page.getByTestId('time_entry_time').press('Tab'), ]); await expect(page.getByTestId('time_entry_time')).toHaveValue(/00:05:/); await assertThatTimerHasStarted(page); await Promise.all([ stoppedTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await page.locator( '[data-testid="dashboard_timer"] [data-testid="timer_button"].bg-accent-300/70' ); }); test('test that entering a value with the format hh:mm in the time range starts the timer on blur', async ({ page, }) => { await goToDashboard(page); await page.getByTestId('time_entry_time').fill('12:30'); await Promise.all([ newTimeEntryResponse(page), page.getByTestId('time_entry_time').press('Tab'), ]); await expect(page.getByTestId('time_entry_time')).toHaveValue(/12:30:/); await assertThatTimerHasStarted(page); await Promise.all([ stoppedTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await page.locator( '[data-testid="dashboard_timer"] [data-testid="timer_button"].bg-accent-300/70' ); }); test('test that entering a random value in the time range does not start the timer on blur', async ({ page, }) => { await goToDashboard(page); await page.getByTestId('time_entry_time').fill('asdasdasd'); await page.getByTestId('time_entry_time').press('Tab'), await page.locator( '[data-testid="dashboard_timer"] [data-testid="timer_button"].bg-accent-300/70' ); }); test('test that entering a time starts the timer on enter', async ({ page, }) => { await goToDashboard(page); await page.getByTestId('time_entry_time').fill('20min'); await Promise.all([ newTimeEntryResponse(page), page.getByTestId('time_entry_time').press('Enter'), ]); await assertThatTimerHasStarted(page); await Promise.all([ stoppedTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await assertThatTimerIsStopped(page); }); test('test that adding a new tag works', async ({ page }) => { const newTagName = 'New Tag' + Math.floor(Math.random() * 10000); await goToDashboard(page); await page.getByTestId('tag_dropdown').click(); await page.getByText('Create new tag').click(); await page.getByPlaceholder('Tag Name').fill(newTagName); await Promise.all([ newTagResponse(page, { name: newTagName }), page.getByRole('button', { name: 'Create Tag' }).click(), ]); await page.getByTestId('tag_dropdown').click(); await expect(page.getByRole('option', { name: newTagName })).toBeVisible(); }); test('test that adding a new tag when the timer is running', async ({ page, }) => { const newTagName = 'New Tag' + Math.floor(Math.random() * 10000); await goToDashboard(page); await Promise.all([ newTimeEntryResponse(page), startOrStopTimerWithButton(page), ]); await assertThatTimerHasStarted(page); await page.getByTestId('tag_dropdown').click(); await page.getByText('Create new tag').click(); await page.getByPlaceholder('Tag Name').fill(newTagName); const [tagCreateResponse] = await Promise.all([ newTagResponse(page, { name: newTagName }), page.getByRole('button', { name: 'Create Tag' }).click(), ]); const tagId = (await tagCreateResponse.json()).data.id; await newTimeEntryResponse(page, { status: 200, tags: [tagId] }); await page.getByTestId('tag_dropdown').click(); await expect(page.getByRole('option', { name: newTagName })).toBeVisible(); await page.getByTestId('tag_dropdown_search').press('Escape'); await page.waitForTimeout(1000); await Promise.all([ stoppedTimeEntryResponse(page, { tags: [tagId] }), startOrStopTimerWithButton(page), ]); await assertThatTimerIsStopped(page); }); // test that search is working // test that adding a tag and project and starting the timer afterwards works and sets the project and tag correctly // test that changing the project works // test that sidebar timetracker starts and stops timer // test that sidebar timetracker changes state when tmer on dashboard is started // test billable toggle // TODO: Test that project can be created in the time tracker row // Add Test that time tracker starts on enter with description