-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathdata-table-row-click.test.tsx
More file actions
104 lines (95 loc) · 3.46 KB
/
Copy pathdata-table-row-click.test.tsx
File metadata and controls
104 lines (95 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* ObjectUI
* Copyright (c) 2024-present ObjectStack Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Regression: row.onClick must NOT fire when the click originates from a
* Radix overlay (DropdownMenu, Dialog, etc.) rendered in a Portal but still
* bubbling up the React virtual tree.
*
* Bug context: in the CRM list page (e.g. /apps/crm_enterprise/lead) clicking
* "Edit" inside a row's "..." dropdown used to navigate to the record detail
* page because the click event bubbled up through React's synthetic tree to
* the <TableRow> onClick handler which calls onRowClick.
*/
import { describe, it, expect, vi } from 'vitest';
import { fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import React from 'react';
import { renderComponent } from './test-utils';
// Registers the renderers at module scope, NOT inside a `beforeAll` — there the
// cold transform is billed to `hookTimeout`, which is why this carried a raised
// timeout. See object-ui/no-dynamic-import-in-test-hook (objectui#3010/#3021).
import '../renderers';
describe('data-table — row click heuristic ignores overlay items', () => {
const baseSchema = {
type: 'data-table' as const,
columns: [
{ header: 'Name', accessorKey: 'name' },
{
header: 'Actions',
accessorKey: '_actions',
// Render a portal-like menu item directly inside the row to mimic
// a Radix DropdownMenuItem that has bubbled into the row React tree.
cell: () => (
<div role="menu">
<div role="menuitem" data-testid="row-edit-item">
Edit
</div>
</div>
),
},
],
data: [{ id: '1', name: 'Alice' }],
} as any;
it('clicking [role="menuitem"] does not call onRowClick', () => {
const onRowClick = vi.fn();
const { container } = renderComponent({ ...baseSchema, onRowClick });
const item = container.querySelector('[data-testid="row-edit-item"]') as HTMLElement;
expect(item).toBeTruthy();
fireEvent.click(item);
expect(onRowClick).not.toHaveBeenCalled();
});
it('clicking a [role="dialog"] descendant inside the row does not call onRowClick', () => {
const onRowClick = vi.fn();
const schema = {
...baseSchema,
columns: [
baseSchema.columns[0],
{
header: 'Confirm',
accessorKey: '_dialog',
cell: () => (
<div role="dialog">
<span data-testid="dialog-text">Are you sure?</span>
</div>
),
},
],
onRowClick,
};
const r = renderComponent(schema);
const dialogText = r.container.querySelector('[data-testid="dialog-text"]') as HTMLElement;
fireEvent.click(dialogText);
expect(onRowClick).not.toHaveBeenCalled();
});
it('clicking a plain text cell still calls onRowClick (sanity)', () => {
const onRowClick = vi.fn();
const { container } = renderComponent({
type: 'data-table',
columns: [{ header: 'Name', accessorKey: 'name' }],
data: [{ id: '1', name: 'Alice' }],
onRowClick,
});
// Click on the name cell text (not a button/link/menu).
const cell = Array.from(container.querySelectorAll('td')).find((td) =>
td.textContent?.includes('Alice')
) as HTMLElement;
expect(cell).toBeTruthy();
fireEvent.click(cell);
expect(onRowClick).toHaveBeenCalledTimes(1);
});
});