mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 16:22:16 +01:00
199 lines
7.4 KiB
TypeScript
199 lines
7.4 KiB
TypeScript
import { expect, test } from '../playwright/fixtures';
|
|
import { PLAYWRIGHT_BASE_URL } from '../playwright/config';
|
|
import type { Page } from '@playwright/test';
|
|
import {
|
|
assertThatTimerHasStarted,
|
|
assertThatTimerIsStopped,
|
|
newTimeEntryResponse,
|
|
startOrStopTimerWithButton,
|
|
stoppedTimeEntryResponse,
|
|
} from './utils/currentTimeEntry';
|
|
import {
|
|
createBareTimeEntryViaApi,
|
|
createPublicProjectViaApi,
|
|
createTimeEntryViaApi,
|
|
updateOrganizationSettingViaApi,
|
|
} from './utils/api';
|
|
|
|
async function goToDashboard(page: Page) {
|
|
await page.goto(PLAYWRIGHT_BASE_URL + '/dashboard');
|
|
}
|
|
|
|
test('test that dashboard loads with all expected sections', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await expect(page.getByTestId('dashboard_view')).toBeVisible({ timeout: 10000 });
|
|
|
|
// Timer section (scoped to dashboard_timer to avoid matching sidebar timer)
|
|
await expect(page.getByTestId('time_entry_description')).toBeVisible();
|
|
await expect(
|
|
page
|
|
.getByTestId('dashboard_timer')
|
|
.getByTestId('timer_button')
|
|
.and(page.locator(':visible'))
|
|
).toBeVisible();
|
|
|
|
// Dashboard cards
|
|
await expect(page.getByText('Recent Time Entries', { exact: true })).toBeVisible();
|
|
await expect(page.getByText('Last 7 Days', { exact: true })).toBeVisible();
|
|
await expect(page.getByText('Activity Graph', { exact: true })).toBeVisible();
|
|
await expect(page.getByText('Team Activity', { exact: true })).toBeVisible();
|
|
|
|
// Weekly overview section
|
|
await expect(page.getByText('This Week', { exact: true })).toBeVisible();
|
|
});
|
|
|
|
test('test that dashboard shows time entry data after creating entries', async ({ page, ctx }) => {
|
|
await createBareTimeEntryViaApi(ctx, 'Dashboard test entry', '1h');
|
|
|
|
await goToDashboard(page);
|
|
await expect(page.getByTestId('dashboard_view')).toBeVisible();
|
|
|
|
// The "Last 7 Days" or "This Week" section should reflect tracked time
|
|
await expect(page.getByText('This Week', { exact: true })).toBeVisible();
|
|
});
|
|
|
|
test('test that timer on dashboard can start and stop', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await Promise.all([newTimeEntryResponse(page), startOrStopTimerWithButton(page)]);
|
|
await assertThatTimerHasStarted(page);
|
|
|
|
await page.waitForTimeout(1500);
|
|
|
|
await Promise.all([stoppedTimeEntryResponse(page), startOrStopTimerWithButton(page)]);
|
|
await assertThatTimerIsStopped(page);
|
|
});
|
|
|
|
test('test that weekly overview section displays stat cards', async ({ page, ctx }) => {
|
|
await createBareTimeEntryViaApi(ctx, 'Stats test entry', '2h');
|
|
|
|
await goToDashboard(page);
|
|
|
|
// Verify stat card labels are visible
|
|
await expect(page.getByText('Spent Time')).toBeVisible();
|
|
await expect(page.getByText('Billable Time')).toBeVisible();
|
|
await expect(page.getByText('Billable Amount')).toBeVisible();
|
|
});
|
|
|
|
test('test that stopping timer refreshes dashboard data', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Start timer
|
|
await Promise.all([newTimeEntryResponse(page), startOrStopTimerWithButton(page)]);
|
|
await assertThatTimerHasStarted(page);
|
|
await page.waitForTimeout(1500);
|
|
|
|
// Stop timer and verify dashboard queries are refetched
|
|
await Promise.all([
|
|
stoppedTimeEntryResponse(page),
|
|
page.waitForResponse(
|
|
(response) =>
|
|
response.url().includes('/charts/') &&
|
|
response.request().method() === 'GET' &&
|
|
response.status() === 200
|
|
),
|
|
startOrStopTimerWithButton(page),
|
|
]);
|
|
await assertThatTimerIsStopped(page);
|
|
});
|
|
|
|
// =============================================
|
|
// Employee Permission Tests
|
|
// =============================================
|
|
|
|
test.describe('Employee Dashboard Restrictions', () => {
|
|
test('employee dashboard loads and timer is functional', async ({ employee }) => {
|
|
await employee.page.goto(PLAYWRIGHT_BASE_URL + '/dashboard');
|
|
await expect(employee.page.getByTestId('dashboard_view')).toBeVisible({
|
|
timeout: 10000,
|
|
});
|
|
|
|
// Timer should be available
|
|
await expect(
|
|
employee.page
|
|
.getByTestId('dashboard_timer')
|
|
.getByTestId('timer_button')
|
|
.and(employee.page.locator(':visible'))
|
|
).toBeVisible();
|
|
await expect(employee.page.getByTestId('time_entry_description')).toBeEditable();
|
|
});
|
|
|
|
test('employee cannot see Team Activity card', async ({ employee }) => {
|
|
await employee.page.goto(PLAYWRIGHT_BASE_URL + '/dashboard');
|
|
await expect(employee.page.getByTestId('dashboard_view')).toBeVisible({
|
|
timeout: 10000,
|
|
});
|
|
|
|
// Other dashboard cards should be visible
|
|
await expect(employee.page.getByText('Recent Time Entries', { exact: true })).toBeVisible();
|
|
|
|
// Team Activity should NOT be visible for employees
|
|
await expect(employee.page.getByText('Team Activity', { exact: true })).not.toBeVisible();
|
|
});
|
|
|
|
test('employee cannot see Cost column in This Week table by default', async ({
|
|
ctx,
|
|
employee,
|
|
}) => {
|
|
const project = await createPublicProjectViaApi(ctx, {
|
|
name: 'EmpDashBillProj',
|
|
is_billable: true,
|
|
billable_rate: 10000,
|
|
});
|
|
await createTimeEntryViaApi(
|
|
{ ...ctx, memberId: employee.memberId },
|
|
{
|
|
description: 'Emp dashboard cost entry',
|
|
duration: '1h',
|
|
projectId: project.id,
|
|
billable: true,
|
|
}
|
|
);
|
|
|
|
await employee.page.goto(PLAYWRIGHT_BASE_URL + '/dashboard');
|
|
await expect(employee.page.getByTestId('dashboard_view')).toBeVisible({
|
|
timeout: 10000,
|
|
});
|
|
|
|
// This Week table should be visible
|
|
await expect(employee.page.getByText('This Week', { exact: true })).toBeVisible();
|
|
|
|
// Duration column should be visible, but Cost column should NOT
|
|
await expect(employee.page.getByText('Duration', { exact: true })).toBeVisible();
|
|
await expect(employee.page.getByText('Cost', { exact: true })).not.toBeVisible();
|
|
});
|
|
|
|
test('employee can see Cost column in This Week table when employees_can_see_billable_rates is enabled', async ({
|
|
ctx,
|
|
employee,
|
|
}) => {
|
|
await updateOrganizationSettingViaApi(ctx, { employees_can_see_billable_rates: true });
|
|
|
|
const project = await createPublicProjectViaApi(ctx, {
|
|
name: 'EmpDashBillVisProj',
|
|
is_billable: true,
|
|
billable_rate: 10000,
|
|
});
|
|
await createTimeEntryViaApi(
|
|
{ ...ctx, memberId: employee.memberId },
|
|
{
|
|
description: 'Emp dashboard cost visible entry',
|
|
duration: '1h',
|
|
projectId: project.id,
|
|
billable: true,
|
|
}
|
|
);
|
|
|
|
await employee.page.goto(PLAYWRIGHT_BASE_URL + '/dashboard');
|
|
await expect(employee.page.getByTestId('dashboard_view')).toBeVisible({
|
|
timeout: 10000,
|
|
});
|
|
|
|
// Both Duration and Cost columns should be visible
|
|
await expect(employee.page.getByText('Duration', { exact: true })).toBeVisible();
|
|
await expect(employee.page.getByText('Cost', { exact: true })).toBeVisible();
|
|
|
|
// 1h at 100.00/h = 100.00 EUR cost should be visible
|
|
await expect(employee.page.getByText('100,00 EUR').first()).toBeVisible();
|
|
});
|
|
});
|