|
5 | 5 | screen, |
6 | 6 | waitFor, |
7 | 7 | } from "@testing-library/react"; |
8 | | -import { afterEach, describe, expect, test, vi } from "vitest"; |
| 8 | +import { afterEach, describe, expect, onTestFinished, test, vi } from "vitest"; |
9 | 9 |
|
10 | 10 | import { BENCH_RESULT_KEY } from "../bench-runtime"; |
11 | 11 | import * as benchRuntime from "../bench-runtime"; |
@@ -525,6 +525,121 @@ describe("BenchApp", () => { |
525 | 525 | expect(groupRowsAtCallTime).toBeGreaterThan(0); |
526 | 526 | }, 20_000); |
527 | 527 |
|
| 528 | + test("groups the TANSTACK grid BEFORE the group-expand measurement window opens", async () => { |
| 529 | + // The comparator twin of the pretable test above (#478): the setup wait |
| 530 | + // is DOM-only and reads the per-profile groupRowSelector, so the same |
| 531 | + // invariant must hold with tanstack's painted rows. |
| 532 | + // |
| 533 | + // jsdom reports zero offsetWidth/offsetHeight and ships no |
| 534 | + // ResizeObserver, so @tanstack/react-virtual collapses to an empty |
| 535 | + // viewport and paints nothing — the same shim |
| 536 | + // tanstack-adapter.test.tsx installs, here scoped to this test so the |
| 537 | + // pretable paint tests keep jsdom's real (zero) layout. |
| 538 | + if (!("ResizeObserver" in globalThis)) { |
| 539 | + class StubResizeObserver { |
| 540 | + observe() {} |
| 541 | + unobserve() {} |
| 542 | + disconnect() {} |
| 543 | + } |
| 544 | + ( |
| 545 | + globalThis as unknown as { ResizeObserver: typeof StubResizeObserver } |
| 546 | + ).ResizeObserver = StubResizeObserver; |
| 547 | + } |
| 548 | + const baseOffsetWidth = Object.getOwnPropertyDescriptor( |
| 549 | + HTMLElement.prototype, |
| 550 | + "offsetWidth", |
| 551 | + ); |
| 552 | + const baseOffsetHeight = Object.getOwnPropertyDescriptor( |
| 553 | + HTMLElement.prototype, |
| 554 | + "offsetHeight", |
| 555 | + ); |
| 556 | + Object.defineProperty(HTMLElement.prototype, "offsetWidth", { |
| 557 | + configurable: true, |
| 558 | + get(this: HTMLElement) { |
| 559 | + if (this.hasAttribute?.("data-pretable-bench-tanstack-viewport")) |
| 560 | + return 720; |
| 561 | + return (baseOffsetWidth?.get?.call(this) as number | undefined) ?? 0; |
| 562 | + }, |
| 563 | + }); |
| 564 | + Object.defineProperty(HTMLElement.prototype, "offsetHeight", { |
| 565 | + configurable: true, |
| 566 | + get(this: HTMLElement) { |
| 567 | + if (this.hasAttribute?.("data-pretable-bench-tanstack-viewport")) |
| 568 | + return 320; |
| 569 | + return (baseOffsetHeight?.get?.call(this) as number | undefined) ?? 0; |
| 570 | + }, |
| 571 | + }); |
| 572 | + onTestFinished(() => { |
| 573 | + if (baseOffsetWidth) { |
| 574 | + Object.defineProperty(HTMLElement.prototype, "offsetWidth", { |
| 575 | + ...baseOffsetWidth, |
| 576 | + configurable: true, |
| 577 | + }); |
| 578 | + } |
| 579 | + if (baseOffsetHeight) { |
| 580 | + Object.defineProperty(HTMLElement.prototype, "offsetHeight", { |
| 581 | + ...baseOffsetHeight, |
| 582 | + configurable: true, |
| 583 | + }); |
| 584 | + } |
| 585 | + }); |
| 586 | + |
| 587 | + let groupRowsAtCallTime = -1; |
| 588 | + let modeAtCallTime: string | null = null; |
| 589 | + |
| 590 | + vi.spyOn(benchRuntime, "measureBenchInteractionRun").mockImplementation( |
| 591 | + async (_root, _adapterId, mode) => { |
| 592 | + modeAtCallTime = mode; |
| 593 | + groupRowsAtCallTime = document.querySelectorAll( |
| 594 | + "[data-tanstack-group-row]", |
| 595 | + ).length; |
| 596 | + |
| 597 | + return { |
| 598 | + status: "completed", |
| 599 | + notes: [`interaction mode: ${mode}`], |
| 600 | + metrics: { |
| 601 | + interaction_latency_ms: 9, |
| 602 | + settle_duration_ms: 8, |
| 603 | + post_interaction_blank_gap_frames: 0, |
| 604 | + post_interaction_anchor_shift_px: 0, |
| 605 | + post_interaction_row_height_error_p95_px: 0, |
| 606 | + post_interaction_row_height_error_measurable_rows: 11, |
| 607 | + result_row_count: 40, |
| 608 | + selected_row_preserved: 1, |
| 609 | + focused_row_preserved: 1, |
| 610 | + dom_nodes_peak: 400, |
| 611 | + rendered_rows_peak: 11, |
| 612 | + rendered_cells_peak: 440, |
| 613 | + }, |
| 614 | + }; |
| 615 | + }, |
| 616 | + ); |
| 617 | + |
| 618 | + render( |
| 619 | + <BenchApp |
| 620 | + search="?adapter=tanstack&scenario=S2&scale=smoke&script=group-expand&autorun=1" |
| 621 | + browserVersion="123.0" |
| 622 | + />, |
| 623 | + ); |
| 624 | + |
| 625 | + await waitFor( |
| 626 | + () => { |
| 627 | + expect(window[BENCH_RESULT_KEY]).toMatchObject({ |
| 628 | + status: "completed", |
| 629 | + adapterId: "tanstack", |
| 630 | + scenarioId: "S2", |
| 631 | + scriptName: "group-expand", |
| 632 | + }); |
| 633 | + }, |
| 634 | + { timeout: 15_000 }, |
| 635 | + ); |
| 636 | + |
| 637 | + expect(modeAtCallTime).toBe("group-expand"); |
| 638 | + // Row virtualization means only the group rows inside the viewport are in |
| 639 | + // the DOM, so this is "at least one", not "all". |
| 640 | + expect(groupRowsAtCallTime).toBeGreaterThan(0); |
| 641 | + }, 20_000); |
| 642 | + |
528 | 643 | test("declines to measure group-expand when the grouping never paints", async () => { |
529 | 644 | // The CI failure this pins: the row MODEL settles several frames before |
530 | 645 | // React commits the paint, so gating the wait on the model alone opened the |
|
0 commit comments