mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 00:02:15 +01:00
add context menus to calendar view + ui package
This commit is contained in:
@@ -13,6 +13,13 @@ async function goToCalendar(page: Page) {
|
||||
await page.goto(PLAYWRIGHT_BASE_URL + '/calendar');
|
||||
}
|
||||
|
||||
async function openContextMenu(page: Page, description: string) {
|
||||
const event = page.locator('.fc-event').filter({ hasText: description }).first();
|
||||
await expect(event).toBeVisible();
|
||||
await event.click({ button: 'right' });
|
||||
await expect(page.getByRole('menu')).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* These tests verify that changing the project on a time entry via the calendar
|
||||
* updates the billable status to match the new project's is_billable setting.
|
||||
@@ -290,6 +297,124 @@ test('test that deleting time entry from calendar modal works', async ({ page, c
|
||||
await expect(page.locator('.fc-event').filter({ hasText: description })).not.toBeVisible();
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// Context Menu Tests
|
||||
// =============================================
|
||||
|
||||
test('test that context menu edit opens the edit modal', async ({ page, ctx }) => {
|
||||
const description = 'Context edit test ' + Math.floor(1 + Math.random() * 10000);
|
||||
await createBareTimeEntryViaApi(ctx, description, '1h');
|
||||
|
||||
await goToCalendar(page);
|
||||
await openContextMenu(page, description);
|
||||
|
||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||
await expect(page.getByRole('dialog')).toBeVisible();
|
||||
await expect(page.getByRole('dialog').getByPlaceholder('What did you work on?')).toHaveValue(
|
||||
description
|
||||
);
|
||||
});
|
||||
|
||||
test('test that context menu duplicate preserves project and billable status', async ({
|
||||
page,
|
||||
ctx,
|
||||
}) => {
|
||||
const description = 'Context dup test ' + Math.floor(1 + Math.random() * 10000);
|
||||
const project = await createProjectViaApi(ctx, {
|
||||
name: 'Dup Project ' + Math.floor(1 + Math.random() * 10000),
|
||||
is_billable: true,
|
||||
});
|
||||
await createTimeEntryViaApi(ctx, {
|
||||
description,
|
||||
duration: '1h',
|
||||
projectId: project.id,
|
||||
billable: true,
|
||||
});
|
||||
|
||||
await goToCalendar(page);
|
||||
await expect(page.locator('.fc-event').filter({ hasText: description })).toHaveCount(1);
|
||||
await openContextMenu(page, description);
|
||||
|
||||
const [createResponse] = await Promise.all([
|
||||
page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/time-entries') &&
|
||||
response.request().method() === 'POST' &&
|
||||
response.status() === 201
|
||||
),
|
||||
page.getByRole('menuitem', { name: 'Duplicate' }).click(),
|
||||
]);
|
||||
|
||||
const body = await createResponse.json();
|
||||
expect(body.data.description).toBe(description);
|
||||
expect(body.data.project_id).toBe(project.id);
|
||||
expect(body.data.billable).toBe(true);
|
||||
await expect(page.locator('.fc-event').filter({ hasText: description })).toHaveCount(2);
|
||||
});
|
||||
|
||||
test('test that context menu delete removes the time entry', async ({ page, ctx }) => {
|
||||
const description = 'Context delete test ' + Math.floor(1 + Math.random() * 10000);
|
||||
await createBareTimeEntryViaApi(ctx, description, '1h');
|
||||
|
||||
await goToCalendar(page);
|
||||
await openContextMenu(page, description);
|
||||
|
||||
await Promise.all([
|
||||
page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/time-entries/') &&
|
||||
response.request().method() === 'DELETE' &&
|
||||
response.status() === 204
|
||||
),
|
||||
page.getByRole('menuitem', { name: 'Delete' }).click(),
|
||||
]);
|
||||
|
||||
await expect(page.locator('.fc-event').filter({ hasText: description })).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('test that context menu split divides time entry into two', async ({ page, ctx }) => {
|
||||
const description = 'Context split test ' + Math.floor(1 + Math.random() * 10000);
|
||||
await createBareTimeEntryViaApi(ctx, description, '2h');
|
||||
|
||||
await goToCalendar(page);
|
||||
await expect(page.locator('.fc-event').filter({ hasText: description })).toHaveCount(1);
|
||||
await openContextMenu(page, description);
|
||||
|
||||
const [updateResponse, createResponse] = await Promise.all([
|
||||
page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/time-entries/') &&
|
||||
response.request().method() === 'PUT' &&
|
||||
response.status() === 200
|
||||
),
|
||||
page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/time-entries') &&
|
||||
response.request().method() === 'POST' &&
|
||||
response.status() === 201
|
||||
),
|
||||
page.getByRole('menuitem', { name: 'Split' }).click(),
|
||||
]);
|
||||
|
||||
const updateBody = await updateResponse.json();
|
||||
const createBody = await createResponse.json();
|
||||
expect(updateBody.data.end).toBe(createBody.data.start);
|
||||
await expect(page.locator('.fc-event').filter({ hasText: description })).toHaveCount(2);
|
||||
});
|
||||
|
||||
test('test that context menu create time entry opens the create modal', async ({ page }) => {
|
||||
await goToCalendar(page);
|
||||
await expect(page.locator('.fc')).toBeVisible();
|
||||
|
||||
const slotLane = page.locator('.fc-timegrid-slot-lane').first();
|
||||
await expect(slotLane).toBeVisible();
|
||||
await slotLane.click({ button: 'right' });
|
||||
|
||||
await expect(page.getByRole('menu')).toBeVisible();
|
||||
await page.getByRole('menuitem', { name: 'Create Time Entry' }).click();
|
||||
await expect(page.getByRole('dialog')).toBeVisible();
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// Employee Permission Tests
|
||||
// =============================================
|
||||
|
||||
Reference in New Issue
Block a user