Add .prettierrc.json and refactor test files for improved formatting consistency:
- Introduced `.prettierrc.json` to enforce consistent code formatting across the project. - Updated unit and e2e test files to address formatting issues, improve readability, and ensure alignment with the new Prettier configuration.
This commit is contained in:
+198
-174
@@ -1,5 +1,5 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { bookingTestData, loginAsOperator } from './fixtures';
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { bookingTestData, loginAsOperator } from "./fixtures";
|
||||
|
||||
type GoalProgressBucket = {
|
||||
count: number;
|
||||
@@ -16,22 +16,22 @@ type MockGoal = {
|
||||
departments: number[];
|
||||
criteria: {
|
||||
label: string;
|
||||
type: 'REVENUE' | 'PRODUCT' | 'VISITS';
|
||||
type: "REVENUE" | "PRODUCT" | "VISITS";
|
||||
target: number;
|
||||
start: string;
|
||||
end: string;
|
||||
products: number[];
|
||||
users: number[];
|
||||
departments: number[];
|
||||
progress_alert_frequency: 'NONE' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'CHANGED';
|
||||
progress_alert_destination: 'NONE' | 'SLACK' | 'EMAIL' | 'SMS';
|
||||
progress_alert_frequency: "NONE" | "DAILY" | "WEEKLY" | "MONTHLY" | "CHANGED";
|
||||
progress_alert_destination: "NONE" | "SLACK" | "EMAIL" | "SMS";
|
||||
progress_alert_progress_type: string;
|
||||
progress_alert_style: string;
|
||||
progress_alert_format: string | null;
|
||||
progress_alert_weekdays: string[];
|
||||
progress_alert_time_of_day: string | null;
|
||||
department_daily_targets: Record<string, number>;
|
||||
target_duration?: 'ENTIRE_DURATION' | 'WEEKS' | 'MONTHS' | 'YEARS' | null;
|
||||
target_duration?: "ENTIRE_DURATION" | "WEEKS" | "MONTHS" | "YEARS" | null;
|
||||
target_duration_every?: number | null;
|
||||
};
|
||||
progress: GoalProgressByKey & {
|
||||
@@ -64,17 +64,17 @@ const makeMockGoal = (params: {
|
||||
departments: [params.departmentId],
|
||||
criteria: {
|
||||
label: params.label,
|
||||
type: 'REVENUE',
|
||||
type: "REVENUE",
|
||||
target: params.target,
|
||||
start: params.start,
|
||||
end: params.end,
|
||||
products: [],
|
||||
users: [],
|
||||
departments: [params.departmentId],
|
||||
progress_alert_frequency: 'NONE',
|
||||
progress_alert_destination: 'NONE',
|
||||
progress_alert_progress_type: 'ALL',
|
||||
progress_alert_style: 'NONE',
|
||||
progress_alert_frequency: "NONE",
|
||||
progress_alert_destination: "NONE",
|
||||
progress_alert_progress_type: "ALL",
|
||||
progress_alert_style: "NONE",
|
||||
progress_alert_format: null,
|
||||
progress_alert_weekdays: [],
|
||||
progress_alert_time_of_day: null,
|
||||
@@ -108,51 +108,51 @@ const setupGoalsApiMock = async (page: Page, departmentId: number) => {
|
||||
makeMockGoal({
|
||||
id: 1,
|
||||
departmentId,
|
||||
label: 'Mock Active Goal',
|
||||
label: "Mock Active Goal",
|
||||
target: 100,
|
||||
allCount: 45,
|
||||
todayCount: 10,
|
||||
weekCount: 28,
|
||||
monthCount: 45,
|
||||
start: '2026-01-01',
|
||||
end: '2099-01-01',
|
||||
start: "2026-01-01",
|
||||
end: "2099-01-01",
|
||||
}),
|
||||
makeMockGoal({
|
||||
id: 2,
|
||||
departmentId,
|
||||
label: 'Mock Expired Goal',
|
||||
label: "Mock Expired Goal",
|
||||
target: 200,
|
||||
allCount: 180,
|
||||
todayCount: 0,
|
||||
weekCount: 0,
|
||||
monthCount: 0,
|
||||
start: '2024-01-01',
|
||||
end: '2024-02-01',
|
||||
start: "2024-01-01",
|
||||
end: "2024-02-01",
|
||||
}),
|
||||
];
|
||||
|
||||
await page.route('**/goals/department/progress-alert/test**', async (route) => {
|
||||
await page.route("**/goals/department/progress-alert/test**", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ data: { destination: 'EMAIL' } }),
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ data: { destination: "EMAIL" } }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route('**/goals/department**', async (route) => {
|
||||
await page.route("**/goals/department**", async (route) => {
|
||||
const request = route.request();
|
||||
const method = request.method();
|
||||
|
||||
if (method === 'GET') {
|
||||
if (method === "GET") {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ data: goals }),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (method === 'PUT') {
|
||||
if (method === "PUT") {
|
||||
const body = request.postDataJSON() as { id: number; departments: number[]; criteria: Record<string, unknown> };
|
||||
const id = Number(body.id);
|
||||
const departments = (body.departments || [departmentId]).map((x) => Number(x));
|
||||
@@ -173,19 +173,19 @@ const setupGoalsApiMock = async (page: Page, departmentId: number) => {
|
||||
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ data: goals.find((g) => g.id === id) || null }),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (method === 'DELETE') {
|
||||
const id = Number(new URL(request.url()).searchParams.get('id'));
|
||||
if (method === "DELETE") {
|
||||
const id = Number(new URL(request.url()).searchParams.get("id"));
|
||||
goals = goals.filter((goal) => goal.id !== id);
|
||||
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ data: { success: true } }),
|
||||
});
|
||||
return;
|
||||
@@ -193,36 +193,46 @@ const setupGoalsApiMock = async (page: Page, departmentId: number) => {
|
||||
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ data: {} }),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
test.describe('Admin Module - Goals', () => {
|
||||
test.describe("Admin Module - Goals", () => {
|
||||
const getGoalsUrl = (departmentId: string) => `/admin/${departmentId}/modules/goals`;
|
||||
|
||||
const openGoalAction = async (page: Page, label: string, actionLabel: string) => {
|
||||
const card = page.locator('.goal-card', { hasText: label }).first();
|
||||
const card = page.locator(".goal-card", { hasText: label }).first();
|
||||
await expect(card).toBeVisible({ timeout: 15000 });
|
||||
|
||||
const dropdown = card.locator('.dropdown.is-hoverable').first();
|
||||
const dropdown = card.locator(".dropdown.is-hoverable").first();
|
||||
await dropdown.hover();
|
||||
await card.locator('.dropdown-item', { hasText: actionLabel }).click({ force: true });
|
||||
await card.locator(".dropdown-item", { hasText: actionLabel }).click({ force: true });
|
||||
};
|
||||
|
||||
const openCreateGoalModalProgrammatically = async (page: Page, departmentId: number) => {
|
||||
await page.evaluate(async ({ targetDepartmentId }) => {
|
||||
const modalModule = await import('/src/views/dashboards/departmentDashboard/modules/goals/functions/showGoalFormModal.js');
|
||||
void modalModule.showGoalCreateModal(null, { departments: [targetDepartmentId] });
|
||||
}, { targetDepartmentId: departmentId });
|
||||
await page.evaluate(
|
||||
async ({ targetDepartmentId }) => {
|
||||
const modalModule = await import(
|
||||
"/src/views/dashboards/departmentDashboard/modules/goals/functions/showGoalFormModal.js"
|
||||
);
|
||||
void modalModule.showGoalCreateModal(null, { departments: [targetDepartmentId] });
|
||||
},
|
||||
{ targetDepartmentId: departmentId }
|
||||
);
|
||||
};
|
||||
|
||||
const openEditGoalModalProgrammatically = async (page: Page, goal: MockGoal) => {
|
||||
await page.evaluate(async ({ editableGoal }) => {
|
||||
const modalModule = await import('/src/views/dashboards/departmentDashboard/modules/goals/functions/showGoalFormModal.js');
|
||||
void modalModule.showGoalEditModal(null, editableGoal);
|
||||
}, { editableGoal: goal });
|
||||
await page.evaluate(
|
||||
async ({ editableGoal }) => {
|
||||
const modalModule = await import(
|
||||
"/src/views/dashboards/departmentDashboard/modules/goals/functions/showGoalFormModal.js"
|
||||
);
|
||||
void modalModule.showGoalEditModal(null, editableGoal);
|
||||
},
|
||||
{ editableGoal: goal }
|
||||
);
|
||||
};
|
||||
|
||||
const overrideSessionPermissionsForNextReload = async (
|
||||
@@ -235,32 +245,33 @@ test.describe('Admin Module - Goals', () => {
|
||||
const removeSet = new Set((options.remove || []).map((permission) => String(permission)));
|
||||
const addList = (options.add || []).map((permission) => String(permission));
|
||||
|
||||
await page.route('**/auth/session', async (route) => {
|
||||
await page.route("**/auth/session", async (route) => {
|
||||
const response = await route.fetch();
|
||||
const status = response.status();
|
||||
const headers = response.headers();
|
||||
const body = await response.json();
|
||||
const responseDataRoot = body && typeof body === 'object' ? body : {};
|
||||
const responseDataRoot = body && typeof body === "object" ? body : {};
|
||||
|
||||
const nestedData = responseDataRoot?.data?.data;
|
||||
const flatData = responseDataRoot?.data;
|
||||
const sessionPayload = (nestedData && typeof nestedData === 'object')
|
||||
? nestedData
|
||||
: (flatData && typeof flatData === 'object' ? flatData : responseDataRoot);
|
||||
const sessionPayload =
|
||||
nestedData && typeof nestedData === "object"
|
||||
? nestedData
|
||||
: flatData && typeof flatData === "object"
|
||||
? flatData
|
||||
: responseDataRoot;
|
||||
|
||||
const currentPermissions = Array.isArray(sessionPayload?.permissions)
|
||||
? sessionPayload.permissions.map((permission) => String(permission))
|
||||
: [];
|
||||
|
||||
const nextPermissions = Array.from(new Set(
|
||||
currentPermissions
|
||||
.filter((permission) => !removeSet.has(permission))
|
||||
.concat(addList)
|
||||
));
|
||||
const nextPermissions = Array.from(
|
||||
new Set(currentPermissions.filter((permission) => !removeSet.has(permission)).concat(addList))
|
||||
);
|
||||
|
||||
if (nestedData && typeof nestedData === 'object') {
|
||||
if (nestedData && typeof nestedData === "object") {
|
||||
responseDataRoot.data.data.permissions = nextPermissions;
|
||||
} else if (flatData && typeof flatData === 'object') {
|
||||
} else if (flatData && typeof flatData === "object") {
|
||||
responseDataRoot.data.permissions = nextPermissions;
|
||||
} else {
|
||||
responseDataRoot.permissions = nextPermissions;
|
||||
@@ -275,8 +286,11 @@ test.describe('Admin Module - Goals', () => {
|
||||
};
|
||||
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
test.skip(testInfo.project.name.toLowerCase().includes('mobile'), 'Goals admin suite is desktop-focused');
|
||||
test.skip(!testInfo.project.name.toLowerCase().includes('chromium'), 'Goals admin suite is stabilized for Chromium in this environment.');
|
||||
test.skip(testInfo.project.name.toLowerCase().includes("mobile"), "Goals admin suite is desktop-focused");
|
||||
test.skip(
|
||||
!testInfo.project.name.toLowerCase().includes("chromium"),
|
||||
"Goals admin suite is stabilized for Chromium in this environment."
|
||||
);
|
||||
|
||||
await loginAsOperator(page);
|
||||
|
||||
@@ -285,43 +299,43 @@ test.describe('Admin Module - Goals', () => {
|
||||
|
||||
await page.goto(getGoalsUrl(String(departmentId)));
|
||||
await expect(page).toHaveURL(new RegExp(`/admin/${departmentId}/modules/goals`));
|
||||
await expect(page.locator('nav.level.box')).toBeVisible({ timeout: 15000 });
|
||||
await expect(page.locator("nav.level.box")).toBeVisible({ timeout: 15000 });
|
||||
});
|
||||
|
||||
test('loads goals page and supports status/timeframe tab switching', async ({ page }) => {
|
||||
const statusTabs = page.locator('.tabs.is-toggle').first();
|
||||
const timeframeTabs = page.locator('.tabs.is-toggle').nth(1);
|
||||
test("loads goals page and supports status/timeframe tab switching", async ({ page }) => {
|
||||
const statusTabs = page.locator(".tabs.is-toggle").first();
|
||||
const timeframeTabs = page.locator(".tabs.is-toggle").nth(1);
|
||||
|
||||
await expect(page.locator('.goal-card')).toHaveCount(1);
|
||||
await expect(page.locator(".goal-card")).toHaveCount(1);
|
||||
|
||||
await statusTabs.locator('li').nth(1).click();
|
||||
await expect(statusTabs.locator('li').nth(1)).toHaveClass(/is-active/);
|
||||
await expect(page.locator('.goal-card')).toHaveCount(1);
|
||||
await statusTabs.locator("li").nth(1).click();
|
||||
await expect(statusTabs.locator("li").nth(1)).toHaveClass(/is-active/);
|
||||
await expect(page.locator(".goal-card")).toHaveCount(1);
|
||||
|
||||
await statusTabs.locator('li').nth(2).click();
|
||||
await expect(statusTabs.locator('li').nth(2)).toHaveClass(/is-active/);
|
||||
await expect(page.locator('.goal-card')).toHaveCount(2);
|
||||
await statusTabs.locator("li").nth(2).click();
|
||||
await expect(statusTabs.locator("li").nth(2)).toHaveClass(/is-active/);
|
||||
await expect(page.locator(".goal-card")).toHaveCount(2);
|
||||
|
||||
await statusTabs.locator('li').nth(0).click();
|
||||
await expect(statusTabs.locator('li').nth(0)).toHaveClass(/is-active/);
|
||||
await statusTabs.locator("li").nth(0).click();
|
||||
await expect(statusTabs.locator("li").nth(0)).toHaveClass(/is-active/);
|
||||
|
||||
await timeframeTabs.locator('li', { hasText: 'Indtil nu' }).click();
|
||||
await expect(timeframeTabs.locator('li', { hasText: 'Indtil nu' })).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li", { hasText: "Indtil nu" }).click();
|
||||
await expect(timeframeTabs.locator("li", { hasText: "Indtil nu" })).toHaveClass(/is-active/);
|
||||
|
||||
await timeframeTabs.locator('li').nth(2).click();
|
||||
await expect(timeframeTabs.locator('li').nth(2)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(2).click();
|
||||
await expect(timeframeTabs.locator("li").nth(2)).toHaveClass(/is-active/);
|
||||
|
||||
await timeframeTabs.locator('li').nth(3).click();
|
||||
await expect(timeframeTabs.locator('li').nth(3)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(3).click();
|
||||
await expect(timeframeTabs.locator("li").nth(3)).toHaveClass(/is-active/);
|
||||
|
||||
await timeframeTabs.locator('li').nth(4).click();
|
||||
await expect(timeframeTabs.locator('li').nth(4)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(4).click();
|
||||
await expect(timeframeTabs.locator("li").nth(4)).toHaveClass(/is-active/);
|
||||
|
||||
await timeframeTabs.locator('li').nth(0).click();
|
||||
await expect(timeframeTabs.locator('li').nth(0)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(0).click();
|
||||
await expect(timeframeTabs.locator("li").nth(0)).toHaveClass(/is-active/);
|
||||
});
|
||||
|
||||
test('updates progress target when timeframe changes for cadence goals', async ({ page }) => {
|
||||
test("updates progress target when timeframe changes for cadence goals", async ({ page }) => {
|
||||
const departmentId = bookingTestData.departmentId;
|
||||
const nowIso = new Date().toISOString();
|
||||
|
||||
@@ -330,33 +344,38 @@ test.describe('Admin Module - Goals', () => {
|
||||
created_by: 11,
|
||||
departments: [departmentId],
|
||||
criteria: {
|
||||
label: 'Cadence Biweekly Goal',
|
||||
type: 'PRODUCT',
|
||||
label: "Cadence Biweekly Goal",
|
||||
type: "PRODUCT",
|
||||
target: 7,
|
||||
start: '2026-03-24T00:00:00+01:00',
|
||||
end: '2026-07-24T23:59:59+01:00',
|
||||
start: "2026-03-24T00:00:00+01:00",
|
||||
end: "2026-07-24T23:59:59+01:00",
|
||||
products: [1],
|
||||
users: [],
|
||||
departments: [departmentId],
|
||||
progress_alert_frequency: 'NONE',
|
||||
progress_alert_destination: 'NONE',
|
||||
progress_alert_progress_type: 'ALL',
|
||||
progress_alert_style: 'NONE',
|
||||
progress_alert_frequency: "NONE",
|
||||
progress_alert_destination: "NONE",
|
||||
progress_alert_progress_type: "ALL",
|
||||
progress_alert_style: "NONE",
|
||||
progress_alert_format: null,
|
||||
progress_alert_weekdays: ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY'],
|
||||
progress_alert_weekdays: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"],
|
||||
progress_alert_time_of_day: null,
|
||||
department_daily_targets: {},
|
||||
target_duration: 'WEEKS',
|
||||
target_duration: "WEEKS",
|
||||
target_duration_every: 2,
|
||||
},
|
||||
progress: {
|
||||
all: { count: 11, target: 63, date_from: '2026-03-24T00:00:00+01:00', date_end: '2026-07-24T23:59:59+01:00' },
|
||||
to_date: { count: 6, target: 7, date_from: '2026-03-24T00:00:00+01:00', date_end: '2026-03-24T23:59:59+01:00' },
|
||||
today: { count: 1, target: 2, date_from: '2026-04-04T00:00:00+01:00', date_end: '2026-04-04T23:59:59+01:00' },
|
||||
week: { count: 4, target: 7, date_from: '2026-03-23T00:00:00+01:00', date_end: '2026-03-29T23:59:59+01:00' },
|
||||
month: { count: 9, target: 7, date_from: '2026-04-01T00:00:00+01:00', date_end: '2026-04-30T23:59:59+01:00' },
|
||||
year: { count: 20, target: 7, date_from: '2026-01-01T00:00:00+01:00', date_end: '2026-12-31T23:59:59+01:00' },
|
||||
every_2_weeks: { count: 5, target: 14, date_from: '2026-03-12T00:00:00+01:00', date_end: '2026-03-25T23:59:59+01:00' },
|
||||
all: { count: 11, target: 63, date_from: "2026-03-24T00:00:00+01:00", date_end: "2026-07-24T23:59:59+01:00" },
|
||||
to_date: { count: 6, target: 7, date_from: "2026-03-24T00:00:00+01:00", date_end: "2026-03-24T23:59:59+01:00" },
|
||||
today: { count: 1, target: 2, date_from: "2026-04-04T00:00:00+01:00", date_end: "2026-04-04T23:59:59+01:00" },
|
||||
week: { count: 4, target: 7, date_from: "2026-03-23T00:00:00+01:00", date_end: "2026-03-29T23:59:59+01:00" },
|
||||
month: { count: 9, target: 7, date_from: "2026-04-01T00:00:00+01:00", date_end: "2026-04-30T23:59:59+01:00" },
|
||||
year: { count: 20, target: 7, date_from: "2026-01-01T00:00:00+01:00", date_end: "2026-12-31T23:59:59+01:00" },
|
||||
every_2_weeks: {
|
||||
count: 5,
|
||||
target: 14,
|
||||
date_from: "2026-03-12T00:00:00+01:00",
|
||||
date_end: "2026-03-25T23:59:59+01:00",
|
||||
},
|
||||
departmental_distribution: {
|
||||
[String(departmentId)]: {
|
||||
all: { count: 11, target: 63 },
|
||||
@@ -373,13 +392,13 @@ test.describe('Admin Module - Goals', () => {
|
||||
updated_at: nowIso,
|
||||
};
|
||||
|
||||
await page.unroute('**/goals/department**');
|
||||
await page.route('**/goals/department**', async (route) => {
|
||||
await page.unroute("**/goals/department**");
|
||||
await page.route("**/goals/department**", async (route) => {
|
||||
const method = route.request().method();
|
||||
if (method === 'GET') {
|
||||
if (method === "GET") {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ data: [cadenceGoal] }),
|
||||
});
|
||||
return;
|
||||
@@ -387,90 +406,94 @@ test.describe('Admin Module - Goals', () => {
|
||||
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ data: {} }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.reload();
|
||||
const timeframeTabs = page.locator('.tabs.is-toggle').nth(1);
|
||||
const card = page.locator('.goal-card', { hasText: 'Cadence Biweekly Goal' }).first();
|
||||
const progressBar = card.locator('progress.progress').first();
|
||||
const timeframeTabs = page.locator(".tabs.is-toggle").nth(1);
|
||||
const card = page.locator(".goal-card", { hasText: "Cadence Biweekly Goal" }).first();
|
||||
const progressBar = card.locator("progress.progress").first();
|
||||
|
||||
const expectProgress = async (value: number, max: number) => {
|
||||
await expect(progressBar).toHaveAttribute('value', new RegExp(`^${value}(?:\\.0+)?$`));
|
||||
await expect(progressBar).toHaveAttribute('max', new RegExp(`^${max}(?:\\.0+)?$`));
|
||||
await expect(progressBar).toHaveAttribute("value", new RegExp(`^${value}(?:\\.0+)?$`));
|
||||
await expect(progressBar).toHaveAttribute("max", new RegExp(`^${max}(?:\\.0+)?$`));
|
||||
};
|
||||
|
||||
await expectProgress(11, 63);
|
||||
|
||||
await timeframeTabs.locator('li').nth(1).click(); // Indtil nu
|
||||
await expect(timeframeTabs.locator('li').nth(1)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(1).click(); // Indtil nu
|
||||
await expect(timeframeTabs.locator("li").nth(1)).toHaveClass(/is-active/);
|
||||
await expectProgress(6, 7);
|
||||
|
||||
await timeframeTabs.locator('li').nth(2).click(); // I dag
|
||||
await expect(timeframeTabs.locator('li').nth(2)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(2).click(); // I dag
|
||||
await expect(timeframeTabs.locator("li").nth(2)).toHaveClass(/is-active/);
|
||||
await expectProgress(1, 2);
|
||||
|
||||
await timeframeTabs.locator('li').nth(3).click(); // Denne uge
|
||||
await expect(timeframeTabs.locator('li').nth(3)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(3).click(); // Denne uge
|
||||
await expect(timeframeTabs.locator("li").nth(3)).toHaveClass(/is-active/);
|
||||
await expectProgress(5, 14);
|
||||
|
||||
await timeframeTabs.locator('li').nth(4).click(); // Denne måned
|
||||
await expect(timeframeTabs.locator('li').nth(4)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(4).click(); // Denne måned
|
||||
await expect(timeframeTabs.locator("li").nth(4)).toHaveClass(/is-active/);
|
||||
await expectProgress(9, 7);
|
||||
|
||||
await timeframeTabs.locator('li').nth(5).click(); // År
|
||||
await expect(timeframeTabs.locator('li').nth(5)).toHaveClass(/is-active/);
|
||||
await timeframeTabs.locator("li").nth(5).click(); // År
|
||||
await expect(timeframeTabs.locator("li").nth(5)).toHaveClass(/is-active/);
|
||||
await expectProgress(20, 63);
|
||||
});
|
||||
|
||||
test('opens create goal modal and supports cancel', async ({ page }) => {
|
||||
test("opens create goal modal and supports cancel", async ({ page }) => {
|
||||
await openCreateGoalModalProgrammatically(page, bookingTestData.departmentId);
|
||||
|
||||
const modal = page.locator('.swal2-popup');
|
||||
const modal = page.locator(".swal2-popup");
|
||||
await expect(modal).toBeVisible({ timeout: 15000 });
|
||||
|
||||
await expect(modal.locator('input[placeholder*="f.eks."]').first()).toBeVisible();
|
||||
await expect(modal.locator('input[type="number"]').first()).toBeVisible();
|
||||
await expect(modal.locator('input[type="date"]').first()).toBeVisible();
|
||||
await modal.locator('.tabs li', { hasText: 'Alert Configuration' }).click();
|
||||
await expect(modal.locator('textarea').first()).toBeVisible();
|
||||
await modal.locator(".tabs li", { hasText: "Alert Configuration" }).click();
|
||||
await expect(modal.locator("textarea").first()).toBeVisible();
|
||||
|
||||
await modal.locator('button.button:has-text("Annuller")').click();
|
||||
await expect(page.locator('.swal2-popup')).toBeHidden({ timeout: 10000 });
|
||||
await expect(page.locator(".swal2-popup")).toBeHidden({ timeout: 10000 });
|
||||
});
|
||||
|
||||
test('submits edit modal and sends expected update payload', async ({ page }) => {
|
||||
test("submits edit modal and sends expected update payload", async ({ page }) => {
|
||||
const editableGoal = makeMockGoal({
|
||||
id: 1,
|
||||
departmentId: bookingTestData.departmentId,
|
||||
label: 'Mock Active Goal',
|
||||
label: "Mock Active Goal",
|
||||
target: 100,
|
||||
allCount: 45,
|
||||
todayCount: 10,
|
||||
weekCount: 28,
|
||||
monthCount: 45,
|
||||
start: '2026-01-01',
|
||||
end: '2099-01-01',
|
||||
start: "2026-01-01",
|
||||
end: "2099-01-01",
|
||||
});
|
||||
await openEditGoalModalProgrammatically(page, editableGoal);
|
||||
|
||||
const modal = page.locator('.swal2-popup');
|
||||
const modal = page.locator(".swal2-popup");
|
||||
await expect(modal).toBeVisible({ timeout: 15000 });
|
||||
|
||||
await modal.locator('input[placeholder*="f.eks."]').first().fill('Mock Active Goal Updated');
|
||||
await modal.locator('input[type="number"]').first().fill('321');
|
||||
await modal.locator('input[type="date"]').first().fill('2026-02-01');
|
||||
await modal.locator('input[type="date"]').nth(1).fill('2026-03-15');
|
||||
await modal.locator('select').filter({ has: page.locator('option[value="LEGACY"]') }).first().selectOption('WEEKS');
|
||||
await modal.locator('input[type="number"]').nth(1).fill('2');
|
||||
await modal.locator('input[placeholder*="f.eks."]').first().fill("Mock Active Goal Updated");
|
||||
await modal.locator('input[type="number"]').first().fill("321");
|
||||
await modal.locator('input[type="date"]').first().fill("2026-02-01");
|
||||
await modal.locator('input[type="date"]').nth(1).fill("2026-03-15");
|
||||
await modal
|
||||
.locator("select")
|
||||
.filter({ has: page.locator('option[value="LEGACY"]') })
|
||||
.first()
|
||||
.selectOption("WEEKS");
|
||||
await modal.locator('input[type="number"]').nth(1).fill("2");
|
||||
|
||||
const putRequestPromise = page.waitForRequest((request) =>
|
||||
request.method() === 'PUT' && request.url().includes('/goals/department')
|
||||
const putRequestPromise = page.waitForRequest(
|
||||
(request) => request.method() === "PUT" && request.url().includes("/goals/department")
|
||||
);
|
||||
|
||||
await modal.locator('.buttons.is-right .button.is-dark').click({ force: true });
|
||||
await modal.locator(".buttons.is-right .button.is-dark").click({ force: true });
|
||||
|
||||
const putRequest = await putRequestPromise;
|
||||
const putPayload = putRequest.postDataJSON() as {
|
||||
@@ -484,9 +507,9 @@ test.describe('Admin Module - Goals', () => {
|
||||
};
|
||||
};
|
||||
|
||||
expect(putPayload.criteria?.label).toBe('Mock Active Goal Updated');
|
||||
expect(putPayload.criteria?.label).toBe("Mock Active Goal Updated");
|
||||
expect(Number(putPayload.criteria?.target)).toBe(321);
|
||||
expect(putPayload.criteria?.target_duration).toBe('WEEKS');
|
||||
expect(putPayload.criteria?.target_duration).toBe("WEEKS");
|
||||
expect(Number(putPayload.criteria?.target_duration_every)).toBe(2);
|
||||
expect(putPayload.criteria?.start).toMatch(/^2026-02-01T00:00:00(?:Z|[+-]\d{2}:\d{2})$/);
|
||||
expect(putPayload.criteria?.end).toMatch(/^2026-03-15T23:59:59(?:Z|[+-]\d{2}:\d{2})$/);
|
||||
@@ -496,24 +519,24 @@ test.describe('Admin Module - Goals', () => {
|
||||
await expect(successDialog).toBeHidden({ timeout: 15000 });
|
||||
});
|
||||
|
||||
test('supports test-alert action and delete request flow', async ({ page }) => {
|
||||
test("supports test-alert action and delete request flow", async ({ page }) => {
|
||||
await overrideSessionPermissionsForNextReload(page, {
|
||||
add: ['goals_department_progress_alert_test', 'admin', `department_access_${bookingTestData.departmentId}`],
|
||||
add: ["goals_department_progress_alert_test", "admin", `department_access_${bookingTestData.departmentId}`],
|
||||
});
|
||||
await page.reload();
|
||||
await expect(page.locator('nav.level.box')).toBeVisible({ timeout: 15000 });
|
||||
await expect(page.locator("nav.level.box")).toBeVisible({ timeout: 15000 });
|
||||
|
||||
const testAlertRequestPromise = page.waitForRequest((request) =>
|
||||
request.method() === 'POST' && request.url().includes('/goals/department/progress-alert/test')
|
||||
const testAlertRequestPromise = page.waitForRequest(
|
||||
(request) => request.method() === "POST" && request.url().includes("/goals/department/progress-alert/test")
|
||||
);
|
||||
|
||||
await openGoalAction(page, 'Mock Active Goal', 'Test alert');
|
||||
const modal = page.locator('.swal2-popup');
|
||||
await openGoalAction(page, "Mock Active Goal", "Test alert");
|
||||
const modal = page.locator(".swal2-popup");
|
||||
await expect(modal).toBeVisible({ timeout: 10000 });
|
||||
await modal.locator('#goal-test-alert-destination').selectOption('EMAIL');
|
||||
await modal.locator('#goal-test-alert-email-to').fill('tester@example.com');
|
||||
await modal.locator('#goal-test-alert-subject').fill('Dept Goal Progress Test');
|
||||
await modal.locator('.swal2-confirm').click();
|
||||
await modal.locator("#goal-test-alert-destination").selectOption("EMAIL");
|
||||
await modal.locator("#goal-test-alert-email-to").fill("tester@example.com");
|
||||
await modal.locator("#goal-test-alert-subject").fill("Dept Goal Progress Test");
|
||||
await modal.locator(".swal2-confirm").click();
|
||||
|
||||
const testAlertRequest = await testAlertRequestPromise;
|
||||
const testAlertPayload = testAlertRequest.postDataJSON() as {
|
||||
@@ -524,49 +547,50 @@ test.describe('Admin Module - Goals', () => {
|
||||
};
|
||||
|
||||
expect(Number(testAlertPayload.id)).toBe(1);
|
||||
expect(testAlertPayload.overrideDestination).toBe('EMAIL');
|
||||
expect(testAlertPayload.email_to).toBe('tester@example.com');
|
||||
expect(testAlertPayload.subject).toBe('Dept Goal Progress Test');
|
||||
expect(testAlertPayload.overrideDestination).toBe("EMAIL");
|
||||
expect(testAlertPayload.email_to).toBe("tester@example.com");
|
||||
expect(testAlertPayload.subject).toBe("Dept Goal Progress Test");
|
||||
|
||||
await openGoalAction(page, 'Mock Active Goal', 'Slet');
|
||||
await expect(page.locator('.swal2-popup')).toBeVisible({ timeout: 10000 });
|
||||
await openGoalAction(page, "Mock Active Goal", "Slet");
|
||||
await expect(page.locator(".swal2-popup")).toBeVisible({ timeout: 10000 });
|
||||
|
||||
const deleteRequestPromise = page.waitForRequest((request) =>
|
||||
request.method() === 'DELETE' && request.url().includes('/goals/department')
|
||||
const deleteRequestPromise = page.waitForRequest(
|
||||
(request) => request.method() === "DELETE" && request.url().includes("/goals/department")
|
||||
);
|
||||
|
||||
await page.locator('.swal2-popup .swal2-confirm').click();
|
||||
await page.locator(".swal2-popup .swal2-confirm").click();
|
||||
|
||||
const deleteRequest = await deleteRequestPromise;
|
||||
expect(deleteRequest.url()).toContain('id=');
|
||||
await expect(page.locator('.swal2-popup')).toBeHidden({ timeout: 10000 });
|
||||
expect(deleteRequest.url()).toContain("id=");
|
||||
await expect(page.locator(".swal2-popup")).toBeHidden({ timeout: 10000 });
|
||||
});
|
||||
|
||||
test('hides create and test-alert controls when permission is missing and reports COMPONENT entries', async ({ page }) => {
|
||||
test("hides create and test-alert controls when permission is missing and reports COMPONENT entries", async ({
|
||||
page,
|
||||
}) => {
|
||||
await overrideSessionPermissionsForNextReload(page, {
|
||||
remove: ['goals_department_create', 'goals_department_progress_alert_test', 'superuser'],
|
||||
add: ['admin', `department_access_${bookingTestData.departmentId}`],
|
||||
remove: ["goals_department_create", "goals_department_progress_alert_test", "superuser"],
|
||||
add: ["admin", `department_access_${bookingTestData.departmentId}`],
|
||||
});
|
||||
await page.reload();
|
||||
await expect(page.locator('nav.level.box')).toBeVisible({ timeout: 15000 });
|
||||
await expect(page.locator("nav.level.box")).toBeVisible({ timeout: 15000 });
|
||||
|
||||
await expect(page.locator('button.button.is-dark:has(.fa-plus)')).toHaveCount(0);
|
||||
await expect(page.locator('button.button.is-dark.mt-2')).toHaveCount(0);
|
||||
await expect(page.locator("button.button.is-dark:has(.fa-plus)")).toHaveCount(0);
|
||||
await expect(page.locator("button.button.is-dark.mt-2")).toHaveCount(0);
|
||||
|
||||
const card = page.locator('.goal-card', { hasText: 'Mock Active Goal' }).first();
|
||||
const card = page.locator(".goal-card", { hasText: "Mock Active Goal" }).first();
|
||||
await expect(card).toBeVisible({ timeout: 15000 });
|
||||
await card.locator('.dropdown.is-hoverable').first().hover();
|
||||
await expect(card.locator('.dropdown-item', { hasText: 'Test alert' })).toHaveCount(0);
|
||||
await card.locator(".dropdown.is-hoverable").first().hover();
|
||||
await expect(card.locator(".dropdown-item", { hasText: "Test alert" })).toHaveCount(0);
|
||||
|
||||
await page.keyboard.press('Shift');
|
||||
await page.keyboard.press('Shift');
|
||||
await page.keyboard.press('Shift');
|
||||
await page.keyboard.press("Shift");
|
||||
await page.keyboard.press("Shift");
|
||||
await page.keyboard.press("Shift");
|
||||
|
||||
const missingPermissionsBox = page.locator("[data-testid='request-queue-missing-permissions-box']");
|
||||
await expect(missingPermissionsBox).toBeVisible({ timeout: 10000 });
|
||||
await expect(missingPermissionsBox).toContainText('goals_department_create');
|
||||
await expect(missingPermissionsBox).toContainText('goals_department_progress_alert_test');
|
||||
await expect(missingPermissionsBox).toContainText('COMPONENT');
|
||||
await expect(missingPermissionsBox).toContainText("goals_department_create");
|
||||
await expect(missingPermissionsBox).toContainText("goals_department_progress_alert_test");
|
||||
await expect(missingPermissionsBox).toContainText("COMPONENT");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user