| ... | ... | @@ -15,7 +15,7 @@ import { |
| 15 | 15 | import { RouterProvider, createMemoryHistory } from "@tanstack/react-router"; |
| 16 | 16 | import { HttpResponse, http, ws } from "msw"; |
| 17 | 17 | import { setupWorker } from "msw/browser"; |
| 18 | | import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; |
| 18 | import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; |
| 19 | 19 | import { render } from "vitest-browser-react"; |
| 20 | 20 | |
| 21 | 21 | import { getRouter } from "../router"; |
| ... | ... | @@ -301,13 +301,21 @@ async function waitForElement<T extends Element>( |
| 301 | 301 | query: () => T | null, |
| 302 | 302 | errorMessage: string, |
| 303 | 303 | ): Promise<T> { |
| 304 | | const timeoutAt = performance.now() + 8_000; |
| 305 | | while (performance.now() < timeoutAt) { |
| 306 | | const element = query(); |
| 307 | | if (element) return element; |
| 308 | | await nextFrame(); |
| 304 | let element: T | null = null; |
| 305 | await vi.waitFor( |
| 306 | () => { |
| 307 | element = query(); |
| 308 | expect(element, errorMessage).toBeTruthy(); |
| 309 | }, |
| 310 | { |
| 311 | timeout: 8_000, |
| 312 | interval: 16, |
| 313 | }, |
| 314 | ); |
| 315 | if (!element) { |
| 316 | throw new Error(errorMessage); |
| 309 | 317 | } |
| 310 | | throw new Error(errorMessage); |
| 318 | return element; |
| 311 | 319 | } |
| 312 | 320 | |
| 313 | 321 | async function waitForImagesToLoad(scope: ParentNode): Promise<void> { |
| ... | ... | @@ -368,29 +376,29 @@ async function renderAndMeasureUserRow(options: { |
| 368 | 376 | ); |
| 369 | 377 | |
| 370 | 378 | let row: HTMLElement | null = null; |
| 371 | | const timeoutAt = performance.now() + 8_000; |
| 372 | | while (performance.now() < timeoutAt) { |
| 373 | | scrollContainer.scrollTop = 0; |
| 374 | | scrollContainer.dispatchEvent(new Event("scroll")); |
| 375 | | await waitForLayout(); |
| 376 | | row = host.querySelector<HTMLElement>( |
| 377 | | `[data-message-id="${options.targetMessageId}"][data-message-role="user"]`, |
| 378 | | ); |
| 379 | | if (row) { |
| 380 | | break; |
| 381 | | } |
| 382 | | } |
| 383 | | if (!row) { |
| 384 | | throw new Error("Unable to locate targeted user message row."); |
| 385 | | } |
| 379 | await vi.waitFor( |
| 380 | async () => { |
| 381 | scrollContainer.scrollTop = 0; |
| 382 | scrollContainer.dispatchEvent(new Event("scroll")); |
| 383 | await waitForLayout(); |
| 384 | row = host.querySelector<HTMLElement>( |
| 385 | `[data-message-id="${options.targetMessageId}"][data-message-role="user"]`, |
| 386 | ); |
| 387 | expect(row, "Unable to locate targeted user message row.").toBeTruthy(); |
| 388 | }, |
| 389 | { |
| 390 | timeout: 8_000, |
| 391 | interval: 16, |
| 392 | }, |
| 393 | ); |
| 386 | 394 | |
| 387 | | await waitForImagesToLoad(row); |
| 395 | await waitForImagesToLoad(row!); |
| 388 | 396 | scrollContainer.scrollTop = 0; |
| 389 | 397 | scrollContainer.dispatchEvent(new Event("scroll")); |
| 390 | 398 | await nextFrame(); |
| 391 | 399 | |
| 392 | 400 | const timelineRoot = |
| 393 | | row.closest<HTMLElement>('[data-timeline-root="true"]') ?? |
| 401 | row!.closest<HTMLElement>('[data-timeline-root="true"]') ?? |
| 394 | 402 | host.querySelector<HTMLElement>('[data-timeline-root="true"]'); |
| 395 | 403 | if (!(timelineRoot instanceof HTMLElement)) { |
| 396 | 404 | throw new Error("Unable to locate timeline root container."); |
| ... | ... | @@ -400,24 +408,22 @@ async function renderAndMeasureUserRow(options: { |
| 400 | 408 | let measuredRowHeightPx = 0; |
| 401 | 409 | let renderedInVirtualizedRegion = false; |
| 402 | 410 | const rowSelector = `[data-message-id="${options.targetMessageId}"][data-message-role="user"]`; |
| 403 | | const measureTimeoutAt = performance.now() + 4_000; |
| 404 | | while (performance.now() < measureTimeoutAt) { |
| 405 | | scrollContainer.scrollTop = 0; |
| 406 | | scrollContainer.dispatchEvent(new Event("scroll")); |
| 407 | | await nextFrame(); |
| 408 | | const measuredRow = host.querySelector<HTMLElement>(rowSelector); |
| 409 | | if (!measuredRow) { |
| 410 | | continue; |
| 411 | | } |
| 412 | | measuredRowHeightPx = measuredRow.getBoundingClientRect().height; |
| 413 | | renderedInVirtualizedRegion = measuredRow.closest("[data-index]") instanceof HTMLElement; |
| 414 | | if (measuredRowHeightPx > 0) { |
| 415 | | break; |
| 416 | | } |
| 417 | | } |
| 418 | | if (measuredRowHeightPx <= 0) { |
| 419 | | throw new Error("Unable to measure targeted user row height."); |
| 420 | | } |
| 411 | await vi.waitFor( |
| 412 | async () => { |
| 413 | scrollContainer.scrollTop = 0; |
| 414 | scrollContainer.dispatchEvent(new Event("scroll")); |
| 415 | await nextFrame(); |
| 416 | const measuredRow = host.querySelector<HTMLElement>(rowSelector); |
| 417 | expect(measuredRow, "Unable to measure targeted user row height.").toBeTruthy(); |
| 418 | measuredRowHeightPx = measuredRow!.getBoundingClientRect().height; |
| 419 | renderedInVirtualizedRegion = measuredRow!.closest("[data-index]") instanceof HTMLElement; |
| 420 | expect(measuredRowHeightPx, "Unable to measure targeted user row height.").toBeGreaterThan(0); |
| 421 | }, |
| 422 | { |
| 423 | timeout: 4_000, |
| 424 | interval: 16, |
| 425 | }, |
| 426 | ); |
| 421 | 427 | |
| 422 | 428 | return { measuredRowHeightPx, timelineWidthMeasuredPx, renderedInVirtualizedRegion }; |
| 423 | 429 | } finally { |