Skip to content

Commit b4c0ded

Browse files
committed
fix: Fix flaky E2E tests
1 parent d57df21 commit b4c0ded

4 files changed

Lines changed: 128 additions & 86 deletions

File tree

packages/app/src/components/DBSearchPageFilters.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export function cleanedFacetName(key: string): string {
100100
}
101101

102102
type FilterCheckboxProps = {
103+
columnName: string;
103104
label: string;
104105
value?: 'included' | 'excluded' | false;
105106
pinned: boolean;
@@ -160,6 +161,7 @@ const FilterPercentage = ({ percentage, isLoading }: FilterPercentageProps) => {
160161
};
161162

162163
const FilterCheckbox = ({
164+
columnName,
163165
value,
164166
label,
165167
pinned,
@@ -171,10 +173,11 @@ const FilterCheckbox = ({
171173
percentage,
172174
isPercentageLoading,
173175
}: FilterCheckboxProps) => {
176+
const testIdPrefix = `filter-checkbox-${columnName}-${label}`;
174177
return (
175178
<div
176179
className={cx(classes.filterCheckbox, className)}
177-
data-testid={`filter-checkbox-${label}`}
180+
data-testid={testIdPrefix}
178181
>
179182
<Group
180183
gap={8}
@@ -189,7 +192,7 @@ const FilterCheckbox = ({
189192
// taken care by the onClick in the group
190193
}}
191194
indeterminate={value === 'excluded'}
192-
data-testid={`filter-checkbox-input-${label}`}
195+
data-testid={`${testIdPrefix}-input`}
193196
/>
194197
<Tooltip
195198
openDelay={label.length > 22 ? 0 : 1500}
@@ -234,14 +237,14 @@ const FilterCheckbox = ({
234237
<TextButton
235238
onClick={onClickOnly}
236239
label="Only"
237-
data-testid={`filter-only-${label}`}
240+
data-testid={`${testIdPrefix}-only`}
238241
/>
239242
)}
240243
{onClickExclude && (
241244
<TextButton
242245
onClick={onClickExclude}
243246
label="Exclude"
244-
data-testid={`filter-exclude-${label}`}
247+
data-testid={`${testIdPrefix}-exclude`}
245248
/>
246249
)}
247250
<ActionIcon
@@ -252,14 +255,14 @@ const FilterCheckbox = ({
252255
aria-label={pinned ? 'Unpin field' : 'Pin field'}
253256
role="checkbox"
254257
aria-checked={pinned}
255-
data-testid={`filter-pin-${label}`}
258+
data-testid={`${testIdPrefix}-pin`}
256259
>
257260
{pinned ? <IconPinFilled size={12} /> : <IconPin size={12} />}
258261
</ActionIcon>
259262
</div>
260263
{pinned && (
261264
<Center me="1px">
262-
<IconPinFilled size={12} data-testid={`filter-pin-${label}-pinned`} />
265+
<IconPinFilled size={12} data-testid={`${testIdPrefix}-pin-pinned`} />
263266
</Center>
264267
)}
265268
</div>
@@ -755,6 +758,7 @@ export const FilterGroup = ({
755758
{displayedOptions.map(option => (
756759
<FilterCheckbox
757760
key={option.value.toString()}
761+
columnName={name}
758762
label={option.label}
759763
pinned={isPinned(option.value)}
760764
className={

packages/app/tests/e2e/components/FilterComponent.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,50 +49,59 @@ export class FilterComponent {
4949
}
5050

5151
/**
52-
* Get checkbox for a specific filter value
52+
* Get checkbox for a specific filter value within a column
53+
* @param columnName - e.g., 'ServiceName', 'SeverityText'
5354
* @param valueName - e.g., 'info', 'error', 'debug'
5455
*/
55-
getFilterCheckbox(valueName: string) {
56-
return this.page.getByTestId(`filter-checkbox-${valueName}`);
56+
getFilterCheckbox(columnName: string, valueName: string) {
57+
return this.page.getByTestId(`filter-checkbox-${columnName}-${valueName}`);
5758
}
5859

5960
/**
60-
* Get checkbox input element
61+
* Get checkbox input element within a column
6162
*/
62-
getFilterCheckboxInput(valueName: string) {
63-
return this.page.getByTestId(`filter-checkbox-input-${valueName}`);
63+
getFilterCheckboxInput(columnName: string, valueName: string) {
64+
return this.page.getByTestId(
65+
`filter-checkbox-${columnName}-${valueName}-input`,
66+
);
6467
}
6568

6669
/**
6770
* Apply/select a filter value
6871
*/
69-
async applyFilter(valueName: string) {
70-
const checkbox = this.getFilterCheckbox(valueName);
72+
async applyFilter(columnName: string, valueName: string) {
73+
const checkbox = this.getFilterCheckbox(columnName, valueName);
7174
await checkbox.click();
7275
}
7376

7477
/**
7578
* Exclude a filter value (invert the filter)
7679
*/
77-
async excludeFilter(valueName: string) {
78-
const filterCheckbox = this.getFilterCheckbox(valueName);
79-
await this.scrollAndClick(filterCheckbox, `filter-exclude-${valueName}`);
80+
async excludeFilter(columnName: string, valueName: string) {
81+
const filterCheckbox = this.getFilterCheckbox(columnName, valueName);
82+
await this.scrollAndClick(
83+
filterCheckbox,
84+
`filter-checkbox-${columnName}-${valueName}-exclude`,
85+
);
8086
}
8187

8288
/**
8389
* Pin a filter value to persist it
8490
*/
85-
async pinFilter(valueName: string) {
86-
const filterCheckbox = this.getFilterCheckbox(valueName);
87-
await this.scrollAndClick(filterCheckbox, `filter-pin-${valueName}`);
91+
async pinFilter(columnName: string, valueName: string) {
92+
const filterCheckbox = this.getFilterCheckbox(columnName, valueName);
93+
await this.scrollAndClick(
94+
filterCheckbox,
95+
`filter-checkbox-${columnName}-${valueName}-pin`,
96+
);
8897
}
8998

9099
/**
91100
* Clear/unselect a filter
92101
*/
93-
async clearFilter(valueName: string) {
94-
const input = this.getFilterCheckboxInput(valueName);
95-
const checkbox = this.getFilterCheckbox(valueName);
102+
async clearFilter(columnName: string, valueName: string) {
103+
const input = this.getFilterCheckboxInput(columnName, valueName);
104+
const checkbox = this.getFilterCheckbox(columnName, valueName);
96105
await checkbox.click();
97106
await input.click();
98107
}
@@ -160,8 +169,11 @@ export class FilterComponent {
160169
/**
161170
* Check if filter checkbox is indeterminate (excluded state)
162171
*/
163-
async isFilterExcluded(valueName: string): Promise<boolean> {
164-
const input = this.getFilterCheckboxInput(valueName);
172+
async isFilterExcluded(
173+
columnName: string,
174+
valueName: string,
175+
): Promise<boolean> {
176+
const input = this.getFilterCheckboxInput(columnName, valueName);
165177
const indeterminate = await input.getAttribute('data-indeterminate');
166178
return indeterminate === 'true';
167179
}
@@ -170,7 +182,9 @@ export class FilterComponent {
170182
* Get all filter values for a specific filter group
171183
*/
172184
getFilterValues(filterGroupName: string) {
173-
return this.page.getByTestId(`filter-checkbox-${filterGroupName}`);
185+
return this.page.getByTestId(
186+
new RegExp(`^filter-checkbox-${filterGroupName}-`),
187+
);
174188
}
175189

176190
/**
@@ -223,7 +237,9 @@ export class FilterComponent {
223237
// Wait for initial facet options to load
224238
const group = this.getFilterGroup(filterGroupName);
225239
await group
226-
.locator('[data-testid^="filter-checkbox-input-"]')
240+
.locator(
241+
`[data-testid^="filter-checkbox-${filterGroupName}-"][data-testid$="-input"]`,
242+
)
227243
.first()
228244
.waitFor({ state: 'visible', timeout: 10000 });
229245

@@ -232,7 +248,7 @@ export class FilterComponent {
232248
const visible: string[] = [];
233249
for (const value of candidates) {
234250
if (visible.length >= count) break;
235-
const input = this.getFilterCheckboxInput(value);
251+
const input = this.getFilterCheckboxInput(filterGroupName, value);
236252
if (await input.isVisible()) visible.push(value);
237253
}
238254
if (visible.length < count) {

0 commit comments

Comments
 (0)