diff --git a/package.json b/package.json
index c7f521f05fef..5f2acf287e2e 100644
--- a/package.json
+++ b/package.json
@@ -132,7 +132,7 @@
"@tanstack/react-query": "5.96.0",
"@tanstack/react-query-devtools": "5.96.0",
"@tanstack/react-query-persist-client": "5.96.0",
- "@tanstack/react-virtual": "^3.13.6",
+ "@tanstack/react-virtual": "3.14.6",
"@types/gtag.js": "^0.0.12",
"@types/history": "^3.2.5",
"@types/invariant": "^2.2.35",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c2200119cdd3..2be038eac0be 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -257,8 +257,8 @@ importers:
specifier: 5.96.0
version: 5.96.0(@tanstack/react-query@5.96.0(react@19.2.3))(react@19.2.3)
'@tanstack/react-virtual':
- specifier: ^3.13.6
- version: 3.13.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: 3.14.6
+ version: 3.14.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@types/gtag.js':
specifier: ^0.0.12
version: 0.0.12
@@ -3718,8 +3718,8 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- '@tanstack/react-virtual@3.13.6':
- resolution: {integrity: sha512-WT7nWs8ximoQ0CDx/ngoFP7HbQF9Q2wQe4nh2NB+u2486eX3nZRE40P9g6ccCVq7ZfTSH5gFOuCoVH5DLNS/aA==}
+ '@tanstack/react-virtual@3.14.6':
+ resolution: {integrity: sha512-4+Uq8m0/gzO4kMCHUEpTtGX1RnONK0C+g88b2ltwPMWUBiaVarBuWKoPJaz7gj1cKCVRAdyu+U8GcKhwCc2beA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -3741,8 +3741,8 @@ packages:
'@tanstack/store@0.9.3':
resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==}
- '@tanstack/virtual-core@3.13.6':
- resolution: {integrity: sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==}
+ '@tanstack/virtual-core@3.17.4':
+ resolution: {integrity: sha512-nGm5KteqxasUdThLc2izl6dHUqLv0LQj7Nuyo5gYalTPf/U8a9ermvsl7reT+6ioBW1l8WfpP/mcU338nLXpqw==}
'@testing-library/dom@10.4.1':
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
@@ -12559,9 +12559,9 @@ snapshots:
react-dom: 19.2.3(react@19.2.3)
use-sync-external-store: 1.6.0(react@19.2.3)
- '@tanstack/react-virtual@3.13.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ '@tanstack/react-virtual@3.14.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
- '@tanstack/virtual-core': 3.13.6
+ '@tanstack/virtual-core': 3.17.4
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
@@ -12578,7 +12578,7 @@ snapshots:
'@tanstack/store@0.9.3': {}
- '@tanstack/virtual-core@3.13.6': {}
+ '@tanstack/virtual-core@3.17.4': {}
'@testing-library/dom@10.4.1':
dependencies:
diff --git a/static/app/components/events/breadcrumbs/breadcrumbsDataSection.spec.tsx b/static/app/components/events/breadcrumbs/breadcrumbsDataSection.spec.tsx
index 7a5eb9bed49d..89c43fce8c34 100644
--- a/static/app/components/events/breadcrumbs/breadcrumbsDataSection.spec.tsx
+++ b/static/app/components/events/breadcrumbs/breadcrumbsDataSection.spec.tsx
@@ -15,19 +15,9 @@ import {
MOCK_EXCEPTION_ENTRY,
} from 'sentry/components/events/breadcrumbs/testUtils';
import {EntryType} from 'sentry/types/event';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
-// Needed to mock useVirtualizer lists.
-jest.spyOn(window.Element.prototype, 'getBoundingClientRect').mockImplementation(() => ({
- x: 0,
- y: 0,
- width: 0,
- height: 30,
- left: 0,
- top: 0,
- right: 0,
- bottom: 0,
- toJSON: jest.fn(),
-}));
+mockElementSize({width: 0, height: 30});
describe('BreadcrumbsDataSection', () => {
it('renders a summary of breadcrumbs with a button to view them all', async () => {
diff --git a/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx b/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx
index 79afc887a407..1b8aef335430 100644
--- a/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx
+++ b/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx
@@ -5,22 +5,10 @@ import {
MOCK_BREADCRUMBS,
MOCK_DATA_SECTION_PROPS,
} from 'sentry/components/events/breadcrumbs/testUtils';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
async function renderBreadcrumbDrawer() {
- // Needed to mock useVirtualizer lists.
- jest
- .spyOn(window.Element.prototype, 'getBoundingClientRect')
- .mockImplementation(() => ({
- x: 0,
- y: 0,
- width: 0,
- height: 30,
- left: 0,
- top: 0,
- right: 0,
- bottom: 0,
- toJSON: jest.fn(),
- }));
+ mockElementSize({width: 0, height: 30});
render();
await userEvent.click(screen.getByRole('button', {name: 'View 2 more'}));
return screen.getByRole('complementary', {name: 'breadcrumb drawer'});
diff --git a/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx b/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx
index 475ae7eccea0..7252b2c6de93 100644
--- a/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx
+++ b/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx
@@ -8,23 +8,11 @@ import {
MOCK_DATA_SECTION_PROPS_ONE_EXTRA_FLAG,
MOCK_FLAGS,
} from 'sentry/components/events/featureFlags/testUtils';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import {GroupDataContextProvider} from 'sentry/views/issueDetails/groupDataContext';
async function renderFlagDrawer() {
- // Needed to mock useVirtualizer lists.
- jest
- .spyOn(window.Element.prototype, 'getBoundingClientRect')
- .mockImplementation(() => ({
- x: 0,
- y: 0,
- width: 0,
- height: 30,
- left: 0,
- top: 0,
- right: 0,
- bottom: 0,
- toJSON: jest.fn(),
- }));
+ mockElementSize({width: 0, height: 30});
render(
({
- x: 0,
- y: 0,
- width: 0,
- height: 30,
- left: 0,
- top: 0,
- right: 0,
- bottom: 0,
- toJSON: jest.fn(),
-}));
+mockElementSize({width: 0, height: 30});
describe('EventFeatureFlagList', () => {
beforeEach(() => {
diff --git a/static/app/utils/fixtures/virtualization.ts b/static/app/utils/fixtures/virtualization.ts
index 3c092e1fe7da..4d0a41a8c9d3 100644
--- a/static/app/utils/fixtures/virtualization.ts
+++ b/static/app/utils/fixtures/virtualization.ts
@@ -1,18 +1,31 @@
+interface MockElementSizeOptions {
+ height?: number;
+ width?: number;
+}
+
/**
- * Tanstack Virtual renders zero items in the default zero-sized JSDom environment.
- * This forces all elements to have a non-zero size to render at least a few rows.
- * https://github.com/TanStack/virtual/issues/641
+ * TanStack Virtual renders zero items in the default zero-sized JSDOM environment.
+ * Mock the element dimensions read by the virtualizer so it can calculate a range.
+ * The bounding rect remains mocked for components that perform their own layout reads.
*/
-export function mockGetBoundingClientRect() {
- Element.prototype.getBoundingClientRect = jest.fn(() => ({
- width: 500,
- height: 500,
+export function mockElementSize({
+ width = 500,
+ height = 500,
+}: MockElementSizeOptions = {}) {
+ // TanStack Virtual uses offset dimensions to measure its viewport and items.
+ jest.spyOn(HTMLElement.prototype, 'offsetWidth', 'get').mockReturnValue(width);
+ jest.spyOn(HTMLElement.prototype, 'offsetHeight', 'get').mockReturnValue(height);
+
+ // Keep component layout reads consistent with the dimensions seen by the virtualizer.
+ jest.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({
+ width,
+ height,
top: 0,
left: 0,
- bottom: 500,
- right: 500,
+ bottom: height,
+ right: width,
x: 0,
y: 0,
toJSON: () => {},
- }));
+ });
}
diff --git a/static/app/views/explore/logs/content.spec.tsx b/static/app/views/explore/logs/content.spec.tsx
index e7a775b3d50e..253902241473 100644
--- a/static/app/views/explore/logs/content.spec.tsx
+++ b/static/app/views/explore/logs/content.spec.tsx
@@ -16,13 +16,15 @@ import {ProjectsStore} from 'sentry/stores/projectsStore';
import {TeamStore} from 'sentry/stores/teamStore';
import type {Organization} from 'sentry/types/organization';
import type {Project} from 'sentry/types/project';
-import {mockGetBoundingClientRect} from 'sentry/utils/fixtures/virtualization';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import {LOGS_AUTO_REFRESH_KEY} from 'sentry/views/explore/contexts/logs/logsAutoRefreshContext';
import type {OurLogsResponseItem} from 'sentry/views/explore/logs/types';
import LogsPage from './content';
-beforeEach(mockGetBoundingClientRect);
+beforeEach(() => {
+ mockElementSize();
+});
describe('LogsPage', () => {
let organization: Organization;
diff --git a/static/app/views/explore/logs/logsTab.spec.tsx b/static/app/views/explore/logs/logsTab.spec.tsx
index 953b31a28e11..7c685bdaeedd 100644
--- a/static/app/views/explore/logs/logsTab.spec.tsx
+++ b/static/app/views/explore/logs/logsTab.spec.tsx
@@ -5,7 +5,7 @@ import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrar
import type {DatePageFilterProps} from 'sentry/components/pageFilters/date/datePageFilter';
import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent';
-import {mockGetBoundingClientRect} from 'sentry/utils/fixtures/virtualization';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import {LOGS_AUTO_REFRESH_KEY} from 'sentry/views/explore/contexts/logs/logsAutoRefreshContext';
import {LogsPageDataProvider} from 'sentry/views/explore/contexts/logs/logsPageData';
import {
@@ -37,7 +37,9 @@ const datePageFilterProps: DatePageFilterProps = {
}),
};
-beforeEach(mockGetBoundingClientRect);
+beforeEach(() => {
+ mockElementSize();
+});
describe('LogsTabContent', () => {
const {organization, project, setupPageFilters} = initializeLogsTest();
diff --git a/static/app/views/explore/logs/tables/logsInfiniteTable.tsx b/static/app/views/explore/logs/tables/logsInfiniteTable.tsx
index e2726585ec3e..c57ed1f50d2b 100644
--- a/static/app/views/explore/logs/tables/logsInfiniteTable.tsx
+++ b/static/app/views/explore/logs/tables/logsInfiniteTable.tsx
@@ -303,12 +303,17 @@ export function LogsInfiniteTable({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchString, localOnlyItemFilters?.filterText]);
+ const getItemKey = useCallback(
+ (index: number) => data?.[index]?.[OurLogKnownFieldKey.ID] ?? index,
+ [data]
+ );
+
const virtualizer = useVirtualizer({
count: data?.length ?? 0,
estimateSize,
overscan: 35,
getScrollElement: () => tableBodyRef?.current,
- getItemKey: (index: number) => data?.[index]?.[OurLogKnownFieldKey.ID] ?? index,
+ getItemKey,
});
useLayoutEffect(() => {
diff --git a/static/app/views/explore/replays/detail/console/index.tsx b/static/app/views/explore/replays/detail/console/index.tsx
index 904690e304e5..1521dd0e1bc3 100644
--- a/static/app/views/explore/replays/detail/console/index.tsx
+++ b/static/app/views/explore/replays/detail/console/index.tsx
@@ -49,13 +49,17 @@ export function Console() {
const clearSearchTerm = () => setSearchTerm('');
const scrollContainerRef = useRef(null);
+ const getItemKey = useCallback(
+ (index: number) => getVirtualItemKey(items[index], index),
+ [items]
+ );
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => scrollContainerRef.current,
estimateSize: () => ESTIMATED_ROW_HEIGHT,
overscan: 12,
- getItemKey: index => getVirtualItemKey(items[index], index),
+ getItemKey,
useAnimationFrameWithResizeObserver: true,
});
diff --git a/static/app/views/performance/newTraceDetails/traceOurlogs.spec.tsx b/static/app/views/performance/newTraceDetails/traceOurlogs.spec.tsx
index 9bbedf108a29..2a8ac0fbe32e 100644
--- a/static/app/views/performance/newTraceDetails/traceOurlogs.spec.tsx
+++ b/static/app/views/performance/newTraceDetails/traceOurlogs.spec.tsx
@@ -8,7 +8,7 @@ import {
within,
} from 'sentry-test/reactTestingLibrary';
-import {mockGetBoundingClientRect} from 'sentry/utils/fixtures/virtualization';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import {LOGS_QUERY_KEY} from 'sentry/views/explore/contexts/logs/logsPageParams';
import {OurLogKnownFieldKey} from 'sentry/views/explore/logs/types';
import {
@@ -26,7 +26,9 @@ function Component({traceSlug}: {traceSlug: string}) {
);
}
-beforeEach(mockGetBoundingClientRect);
+beforeEach(() => {
+ mockElementSize();
+});
describe('TraceViewLogsSection', () => {
beforeEach(() => {
diff --git a/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx b/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx
index 610f7e169f70..695183962187 100644
--- a/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx
+++ b/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx
@@ -1,5 +1,6 @@
import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import type {
SidebarItem,
SnapshotDiffPair,
@@ -69,17 +70,7 @@ const erroredItem: SidebarItem = {
describe('SnapshotListView', () => {
beforeEach(() => {
jest.clearAllMocks();
- jest.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({
- width: 900,
- height: 600,
- top: 0,
- left: 0,
- bottom: 600,
- right: 900,
- x: 0,
- y: 0,
- toJSON: jest.fn(),
- });
+ mockElementSize({width: 900, height: 600});
// jsdom returns empty padding strings; parseFloat('') is NaN, which would
// propagate into the virtualizer's height math. Force numeric padding.
jest
diff --git a/static/app/views/preprod/snapshots/main/snapshotListView.tsx b/static/app/views/preprod/snapshots/main/snapshotListView.tsx
index 68807669216e..72be351cb59f 100644
--- a/static/app/views/preprod/snapshots/main/snapshotListView.tsx
+++ b/static/app/views/preprod/snapshots/main/snapshotListView.tsx
@@ -234,12 +234,13 @@ export const SnapshotListView = memo(function SnapshotListView({
}, []);
const groups = useMemo(() => buildGroups(items, contentWidth), [items, contentWidth]);
+ const getItemKey = useCallback((index: number) => groups[index]!.id, [groups]);
const virtualizer = useVirtualizer({
count: groups.length,
getScrollElement: () => scrollRef.current,
estimateSize: i => groups[i]!.estimatedHeight,
- getItemKey: i => groups[i]!.id,
+ getItemKey,
overscan: 5,
scrollPaddingEnd: 8,
});
diff --git a/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx b/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx
index b8ac23da9086..f330f930933d 100644
--- a/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx
+++ b/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx
@@ -1,5 +1,6 @@
import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import {DiffStatus} from 'sentry/views/preprod/types/snapshotTypes';
import {SnapshotSidebarContent, type SidebarSection} from './snapshotSidebarContent';
@@ -7,17 +8,7 @@ import {SnapshotSidebarContent, type SidebarSection} from './snapshotSidebarCont
const noop = () => {};
beforeEach(() => {
- jest.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({
- width: 350,
- height: 600,
- top: 0,
- left: 0,
- bottom: 600,
- right: 350,
- x: 0,
- y: 0,
- toJSON: jest.fn(),
- });
+ mockElementSize({width: 350, height: 600});
});
const statusCounts: Record = {
diff --git a/static/app/views/settings/dynamicSampling/projectsTable.spec.tsx b/static/app/views/settings/dynamicSampling/projectsTable.spec.tsx
index ff53bd07cb9b..d65175f33000 100644
--- a/static/app/views/settings/dynamicSampling/projectsTable.spec.tsx
+++ b/static/app/views/settings/dynamicSampling/projectsTable.spec.tsx
@@ -3,21 +3,12 @@ import {ProjectFixture} from 'sentry-fixture/project';
import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import type {ProjectionSamplePeriod} from 'sentry/views/settings/dynamicSampling/utils/useProjectSampleCounts';
import {ProjectsTable} from './projectsTable';
-jest.spyOn(window.Element.prototype, 'getBoundingClientRect').mockReturnValue({
- height: 400,
- width: 500,
- x: 0,
- y: 0,
- top: 0,
- left: 0,
- right: 500,
- bottom: 400,
- toJSON: jest.fn(),
-});
+mockElementSize({width: 500, height: 400});
describe('ProjectsTable', () => {
const organization = OrganizationFixture({
diff --git a/static/app/views/settings/dynamicSampling/projectsTable.tsx b/static/app/views/settings/dynamicSampling/projectsTable.tsx
index 523e71de106f..4de006e54b7d 100644
--- a/static/app/views/settings/dynamicSampling/projectsTable.tsx
+++ b/static/app/views/settings/dynamicSampling/projectsTable.tsx
@@ -105,6 +105,11 @@ export function ProjectsTable({
return itemsWithExpanded;
}, [items, expandedItems, tableSort]);
+ const getItemKey = useCallback(
+ (index: number) => sortedItems[index]?.project.id ?? index,
+ [sortedItems]
+ );
+
const virtualizer = useVirtualizer({
count: sortedItems.length,
getScrollElement: () => scrollContainerRef.current,
@@ -113,7 +118,7 @@ export function ProjectsTable({
? BASE_ROW_HEIGHT + (sortedItems[index].subProjects.length + 1) * 21
: BASE_ROW_HEIGHT,
overscan: 5,
- getItemKey: index => sortedItems[index]?.project.id ?? index,
+ getItemKey,
});
return (
diff --git a/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.spec.tsx b/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.spec.tsx
index 1f118d1ed898..d9bcc6922e9e 100644
--- a/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.spec.tsx
+++ b/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.spec.tsx
@@ -5,29 +5,11 @@ import {RepositoryFixture} from 'sentry-fixture/repository';
import {render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary';
import type {Repository} from 'sentry/types/integrations';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import type {ScmInstallation} from 'sentry/views/settings/organizationRepositories/types';
import {InstallationOverrideProvider, ScmRepositoryTable} from './scmRepositoryTable';
-// `useVirtualizer` only renders rows whose computed bounding rect overlaps
-// the scroll container. Without a stub it sees a 0×0 viewport and renders
-// nothing — fake a non-zero box on every element so the rows mount.
-function stubBoundingClientRect() {
- jest
- .spyOn(window.Element.prototype, 'getBoundingClientRect')
- .mockImplementation(() => ({
- x: 0,
- y: 0,
- width: 600,
- height: 400,
- left: 0,
- top: 0,
- right: 600,
- bottom: 400,
- toJSON: jest.fn(),
- }));
-}
-
function makeRepo(id: string, name: string): Repository {
return RepositoryFixture({
id,
@@ -55,7 +37,7 @@ const provider = GitHubIntegrationProviderFixture();
describe('ScmRepositoryTable', () => {
beforeEach(() => {
- stubBoundingClientRect();
+ mockElementSize({width: 600, height: 400});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/projects/',
body: [
diff --git a/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.tsx b/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.tsx
index 9658b63d5db3..e2bd9b36a2bd 100644
--- a/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.tsx
+++ b/static/app/views/settings/organizationRepositories/components/scmRepositoryTable.tsx
@@ -527,12 +527,17 @@ function VirtualizedRepoList({
return sortBy(filtered, [r => !hasMapping(r.id), r => r.name]);
}, [repositories, repoMatches, mappedProjectSlugsByRepoId]);
+ const getItemKey = useCallback(
+ (index: number) => visibleRepos[index]!.id,
+ [visibleRepos]
+ );
+
const virtualizer = useVirtualizer({
count: visibleRepos.length,
getScrollElement: () => scrollRef.current,
estimateSize: () => ESTIMATED_REPO_ROW_HEIGHT,
overscan: 6,
- getItemKey: i => visibleRepos[i]!.id,
+ getItemKey,
});
const renderEmptyMessage = () => {
diff --git a/static/app/views/settings/organizationRepositories/index.spec.tsx b/static/app/views/settings/organizationRepositories/index.spec.tsx
index 5f4c3e9b4759..3cb824a9241a 100644
--- a/static/app/views/settings/organizationRepositories/index.spec.tsx
+++ b/static/app/views/settings/organizationRepositories/index.spec.tsx
@@ -11,27 +11,9 @@ import {
waitFor,
} from 'sentry-test/reactTestingLibrary';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import OrganizationRepositories from 'sentry/views/settings/organizationRepositories';
-// ScmRepositoryTable uses @tanstack/react-virtual, which only renders rows
-// whose bounding rect overlaps the scroll container. Without this stub it
-// sees a 0×0 viewport and renders nothing.
-function stubBoundingClientRect() {
- jest
- .spyOn(window.Element.prototype, 'getBoundingClientRect')
- .mockImplementation(() => ({
- x: 0,
- y: 0,
- width: 600,
- height: 400,
- left: 0,
- top: 0,
- right: 600,
- bottom: 400,
- toJSON: jest.fn(),
- }));
-}
-
const GITHUB_PROVIDER = GitHubIntegrationProviderFixture();
const GITHUB_INTEGRATION = OrganizationIntegrationsFixture({
id: '1',
@@ -72,7 +54,7 @@ function setupDefaultMocks() {
describe('OrganizationRepositories', () => {
beforeEach(() => {
- stubBoundingClientRect();
+ mockElementSize({width: 600, height: 400});
});
it('shows a loading indicator while queries are pending', async () => {
diff --git a/static/app/views/settings/projectSeer/index.spec.tsx b/static/app/views/settings/projectSeer/index.spec.tsx
index 6442a750de80..6985df1ceb4a 100644
--- a/static/app/views/settings/projectSeer/index.spec.tsx
+++ b/static/app/views/settings/projectSeer/index.spec.tsx
@@ -16,20 +16,10 @@ import type {SeerPreferencesResponse} from 'sentry/components/events/autofix/pre
import {CodingAgentProvider} from 'sentry/components/events/autofix/types';
import type {Organization} from 'sentry/types/organization';
import type {DetailedProject} from 'sentry/types/project';
+import {mockElementSize} from 'sentry/utils/fixtures/virtualization';
import {ProjectSeerContainer as ProjectSeer} from 'sentry/views/settings/projectSeer';
-// Needed to mock useVirtualizer lists.
-jest.spyOn(window.Element.prototype, 'getBoundingClientRect').mockImplementation(() => ({
- x: 0,
- y: 0,
- width: 0,
- height: 30,
- left: 0,
- top: 0,
- right: 0,
- bottom: 0,
- toJSON: jest.fn(),
-}));
+mockElementSize({width: 0, height: 30});
describe('ProjectSeer', () => {
let project: DetailedProject;