feat(planning): ship holiday-aware planning and assistant upgrades
This commit is contained in:
@@ -1,4 +1,12 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
|
||||
async function signInAsAdmin(page: Page) {
|
||||
await page.goto("/auth/signin");
|
||||
await page.fill('input[type="email"]', "admin@capakraken.dev");
|
||||
await page.fill('input[type="password"]', "admin123");
|
||||
await page.click('button[type="submit"]');
|
||||
await expect(page).toHaveURL(/\/(dashboard|resources)/);
|
||||
}
|
||||
|
||||
test.describe("Timeline", () => {
|
||||
test.describe.configure({ mode: "serial" });
|
||||
@@ -7,11 +15,7 @@ test.describe("Timeline", () => {
|
||||
await page.addInitScript(() => {
|
||||
localStorage.setItem("capakraken_theme", JSON.stringify({ mode: "dark" }));
|
||||
});
|
||||
await page.goto("/auth/signin");
|
||||
await page.fill('input[type="email"]', "admin@capakraken.dev");
|
||||
await page.fill('input[type="password"]', "admin123");
|
||||
await page.click('button[type="submit"]');
|
||||
await expect(page).toHaveURL(/\/(dashboard|resources)/);
|
||||
await signInAsAdmin(page);
|
||||
await page.goto("/timeline");
|
||||
});
|
||||
|
||||
@@ -87,8 +91,13 @@ test.describe("Timeline", () => {
|
||||
.first();
|
||||
const allocationPopoverField = page.getByText("Hours / day");
|
||||
|
||||
const resourceHoverTarget = page.locator(".relative.overflow-hidden.touch-none").first();
|
||||
await resourceHoverTarget.hover({ position: { x: 120, y: 20 } });
|
||||
const resourceHoverTarget = page.getByTestId("timeline-resource-row-canvas").first();
|
||||
const resourceHoverBox = await resourceHoverTarget.boundingBox();
|
||||
expect(resourceHoverBox).not.toBeNull();
|
||||
if (!resourceHoverBox) {
|
||||
throw new Error("Expected a resource timeline row canvas to be available");
|
||||
}
|
||||
await page.mouse.move(resourceHoverBox.x + 120, resourceHoverBox.y + 20);
|
||||
await expect(heatmapTooltip).toBeVisible();
|
||||
await expect
|
||||
.poll(async () => {
|
||||
@@ -109,8 +118,19 @@ test.describe("Timeline", () => {
|
||||
await expect(page.getByText(/projects/)).toBeVisible();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const projectHoverTarget = page.locator(".relative.overflow-hidden.touch-none").first();
|
||||
await projectHoverTarget.hover({ position: { x: 120, y: 20 } });
|
||||
const projectHoverTarget = page.getByTestId("timeline-project-resource-row-canvas").first();
|
||||
const projectHoverBox = await projectHoverTarget.boundingBox();
|
||||
const projectAllocation = page.locator("div[style*='top: 2px'][style*='bottom: 2px']").nth(1);
|
||||
const projectAllocationBox = await projectAllocation.boundingBox();
|
||||
expect(projectHoverBox).not.toBeNull();
|
||||
expect(projectAllocationBox).not.toBeNull();
|
||||
if (!projectHoverBox) {
|
||||
throw new Error("Expected a project timeline row canvas to be available");
|
||||
}
|
||||
if (!projectAllocationBox) {
|
||||
throw new Error("Expected a project allocation block to be available");
|
||||
}
|
||||
await page.mouse.move(projectAllocationBox.x + (projectAllocationBox.width / 2), projectHoverBox.y + 20);
|
||||
await expect(heatmapTooltip).toBeVisible();
|
||||
await expect
|
||||
.poll(async () => {
|
||||
@@ -118,8 +138,48 @@ test.describe("Timeline", () => {
|
||||
})
|
||||
.toBe("rgba(3, 7, 18, 0.96)");
|
||||
|
||||
const projectAllocation = page.locator("div[style*='top: 2px'][style*='bottom: 2px']").nth(1);
|
||||
await projectAllocation.click({ button: "right" });
|
||||
await expect(allocationPopoverField).toBeVisible();
|
||||
});
|
||||
|
||||
test("shows resolved holiday overlays in the resource timeline and exposes the holiday name in the tooltip", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/timeline?startDate=2026-04-01&days=14&eids=bruce.banner", {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
|
||||
const row = page.locator('[data-testid="timeline-resource-row-canvas"][data-resource-eid="bruce.banner"]').first();
|
||||
await expect(row).toBeVisible();
|
||||
|
||||
const holidayBlock = row.locator(
|
||||
'[data-testid="timeline-vacation-block"][data-vacation-type="PUBLIC_HOLIDAY"][data-vacation-note="Karfreitag"]',
|
||||
).first();
|
||||
await expect(holidayBlock).toBeVisible();
|
||||
|
||||
const rowBox = await row.boundingBox();
|
||||
const holidayBox = await holidayBlock.boundingBox();
|
||||
expect(rowBox).not.toBeNull();
|
||||
expect(holidayBox).not.toBeNull();
|
||||
|
||||
if (!rowBox || !holidayBox) {
|
||||
throw new Error("Expected timeline row and holiday block bounding boxes to be available");
|
||||
}
|
||||
|
||||
await row.hover({
|
||||
position: {
|
||||
x: holidayBox.x - rowBox.x + holidayBox.width / 2,
|
||||
y: holidayBox.y - rowBox.y + Math.min(holidayBox.height / 2, rowBox.height - 4),
|
||||
},
|
||||
});
|
||||
|
||||
const holidayTooltip = page
|
||||
.locator("div.fixed.pointer-events-none.rounded-xl.border.border-amber-700\\/50")
|
||||
.or(page.locator("div.fixed.pointer-events-none.rounded-xl").filter({ hasText: "Karfreitag" }))
|
||||
.first();
|
||||
|
||||
await expect(holidayTooltip).toBeVisible();
|
||||
await expect(holidayTooltip).toContainText("Karfreitag");
|
||||
await expect(holidayTooltip).toContainText("3 April 2026");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user