@@ -493,4 +493,58 @@ describeControlUiE2e("Control UI Workboard mocked Gateway E2E", () => {
|
493 | 493 | "utf-8", |
494 | 494 | ); |
495 | 495 | }); |
| 496 | + |
| 497 | +it("keeps card titles visible when a column overflows its height", async () => { |
| 498 | +const artifacts: ProofArtifacts = { screenshots: [], videos: [] }; |
| 499 | +const crowdedColumnCardCount = 8; |
| 500 | +const overflowTitle = (index: number) => |
| 501 | +`Overflowing backlog card ${index + 1} with a long title that wraps onto two lines`; |
| 502 | +const crowdedCards = Array.from({ length: crowdedColumnCardCount }, (_, index) => |
| 503 | +card({ |
| 504 | +id: `overflow-card-${index + 1}`, |
| 505 | +notes: "Acceptance: title stays visible while the column scrolls.", |
| 506 | +position: 1000 + index, |
| 507 | +status: "todo", |
| 508 | +title: overflowTitle(index), |
| 509 | +updatedAt: baseTime + index, |
| 510 | +}), |
| 511 | +); |
| 512 | + |
| 513 | +const recorded = await newRecordedPage("workboard-overflow"); |
| 514 | +await installMockGateway(recorded.page, { |
| 515 | +methodResponses: { |
| 516 | +"config.get": workboardConfigSnapshot(), |
| 517 | +"sessions.list": sessionsListResponse([sessionRow()]), |
| 518 | +"tasks.list": { nextCursor: null, tasks: [] }, |
| 519 | +"workboard.cards.list": cardsListResponse(crowdedCards), |
| 520 | +}, |
| 521 | +}); |
| 522 | + |
| 523 | +try { |
| 524 | +// Constrain the height so the Todo column must overflow its visible area. |
| 525 | +await recorded.page.setViewportSize({ height: 720, width: 1400 }); |
| 526 | +const response = await recorded.page.goto(`${server.baseUrl}workboard`); |
| 527 | +expect(response?.status()).toBe(200); |
| 528 | +const column = statusColumn(recorded.page, "Todo"); |
| 529 | +await column.waitFor({ state: "visible" }); |
| 530 | +await cardInColumn(recorded.page, "Todo", overflowTitle(0)).waitFor({ state: "visible" }); |
| 531 | +await captureScreenshot(recorded.page, artifacts, "09-overflow-column"); |
| 532 | + |
| 533 | +const titleHeights = await column |
| 534 | +.locator(".workboard-card h3") |
| 535 | +.evaluateAll((titles) => titles.map((title) => title.getBoundingClientRect().height)); |
| 536 | +expect(titleHeights).toHaveLength(crowdedColumnCardCount); |
| 537 | +for (const height of titleHeights) { |
| 538 | +// Squeezed implicit grid rows previously collapsed the line-clamped title to 0px. |
| 539 | +expect(height).toBeGreaterThan(0); |
| 540 | +} |
| 541 | + |
| 542 | +const columnScrolls = await column |
| 543 | +.locator(".workboard-column__cards") |
| 544 | +.evaluate((cards) => cards.scrollHeight > cards.clientHeight + 1); |
| 545 | +expect(columnScrolls).toBe(true); |
| 546 | +} finally { |
| 547 | +await closeRecordedPage(recorded, artifacts, "workboard-overflow"); |
| 548 | +} |
| 549 | +}); |
496 | 550 | }); |