fix: Fix flaky saved search tests (#2079)

## Summary

This PR fixes failing Saved-Search E2E tests by

1. Fixing a bug that caused the saved search's source to sometime not populate when navigating directly to the saved search
2. Updating the saved search modal to wait until the create saved search mutation completes and invalidates saved searches before attempting to navigate (also, added a loading state and error notifications to the modal)
3. Updated a few test assertions to be more explicit about waiting for the saved search to load

### Screenshots or video

### How to test locally or on Vercel

### References



- Linear Issue:
- Related PRs:
This commit is contained in:
Drew Davis 2026-04-09 11:22:54 -04:00 committed by GitHub
parent 337ebff054
commit 6ef3b48e0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 57 additions and 23 deletions

View file

@ -409,7 +409,7 @@ function SaveSearchModalComponent({
const onSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
handleSubmit(({ name }) => {
handleSubmit(async ({ name }) => {
if (isUpdate) {
if (savedSearchId == null) {
throw new Error('savedSearchId is required for update');
@ -432,11 +432,20 @@ function SaveSearchModalComponent({
onSuccess: () => {
onClose();
},
onError: error => {
console.error('Error updating saved search:', error);
notifications.show({
color: 'red',
title: 'Error',
message:
'An error occurred while updating your saved search. Please try again.',
});
},
},
);
} else {
createSavedSearch.mutate(
{
try {
const savedSearch = await createSavedSearch.mutateAsync({
name,
select: effectiveSelect,
where: searchedConfig.where ?? '',
@ -446,18 +455,25 @@ function SaveSearchModalComponent({
orderBy: searchedConfig.orderBy ?? '',
filters: searchedConfig.filters ?? [],
tags: tags,
},
{
onSuccess: savedSearch => {
router.push(`/search/${savedSearch.id}${window.location.search}`);
onClose();
},
},
);
});
router.push(`/search/${savedSearch.id}${window.location.search}`);
onClose();
} catch (error) {
console.error('Error creating saved search:', error);
notifications.show({
color: 'red',
title: 'Error',
message:
'An error occurred while saving your search. Please try again.',
});
}
}
})();
};
const isPending = createSavedSearch.isPending || updateSavedSearch.isPending;
const { data: chartConfig } = useSearchedConfigToChartConfig(searchedConfig);
return (
@ -572,6 +588,7 @@ function SaveSearchModalComponent({
variant="primary"
type="submit"
disabled={!formState.isValid}
loading={isPending}
>
{isUpdate ? 'Update' : 'Save'}
</Button>
@ -869,7 +886,7 @@ function DBSearchPage() {
where: searchedConfig.where || '',
whereLanguage:
searchedConfig.whereLanguage ?? getStoredLanguage() ?? 'lucene',
source: searchedConfig.source || defaultSourceId,
source: searchedConfig.source || (savedSearchId ? '' : defaultSourceId),
filters: searchedConfig.filters ?? [],
orderBy: searchedConfig.orderBy ?? '',
},
@ -1619,16 +1636,18 @@ function DBSearchPage() {
</Text>
</Group>
<Group justify="space-between" align="flex-end">
<EditablePageName
key={savedSearch.id}
name={savedSearch?.name ?? 'Untitled Search'}
onSave={editedName => {
updateSavedSearch.mutate({
id: savedSearch.id,
name: editedName,
});
}}
/>
<div data-testid="saved-search-name">
<EditablePageName
key={savedSearch.id}
name={savedSearch?.name ?? 'Untitled Search'}
onSave={editedName => {
updateSavedSearch.mutate({
id: savedSearch.id,
name: editedName,
});
}}
/>
</div>
<Group gap="xs">
<FavoriteButton

View file

@ -57,7 +57,7 @@ export function useCreateSavedSearch() {
}).json<SavedSearch>();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['saved-search'] });
return queryClient.invalidateQueries({ queryKey: ['saved-search'] });
},
});
}

View file

@ -9,6 +9,7 @@ export class SavedSearchModalComponent {
readonly page: Page;
private readonly modal: Locator;
private readonly nameInput: Locator;
private readonly savedSearchNameTitle: Locator;
private readonly submitButton: Locator;
private readonly addTagButton: Locator;
@ -16,6 +17,9 @@ export class SavedSearchModalComponent {
this.page = page;
this.modal = page.locator('[data-testid="save-search-modal"]');
this.nameInput = page.locator('[data-testid="save-search-name-input"]');
this.savedSearchNameTitle = page.locator(
'[data-testid="saved-search-name"]',
);
this.submitButton = page.locator(
'[data-testid="save-search-submit-button"]',
);
@ -98,6 +102,9 @@ export class SavedSearchModalComponent {
// Wait for modal to fully close
await expect(this.container).toBeHidden();
await expect(this.savedSearchNameTitle).toBeVisible({ timeout: 5000 });
await expect(this.savedSearchNameTitle).toHaveText(name, { timeout: 5000 });
}
/**

View file

@ -263,6 +263,10 @@ test.describe('Saved Search Functionality', () => {
// Wait for the search page to load
await expect(page.getByTestId('search-page')).toBeVisible();
await expect(searchPage.savedSearchNameTitle).toBeVisible();
await expect(searchPage.savedSearchNameTitle).toHaveText(
'Info Logs Navigation Test',
);
});
await test.step('Verify saved search loaded and executed automatically', async () => {

View file

@ -23,6 +23,7 @@ export class SearchPage {
readonly infrastructure: InfrastructurePanelComponent;
readonly filters: FilterComponent;
readonly savedSearchModal: SavedSearchModalComponent;
readonly savedSearchNameTitle: Locator;
readonly alertModal: SearchPageAlertModalComponent;
readonly defaultTimeout: number = 3000;
private readonly alertsButtonLocator: Locator;
@ -53,6 +54,9 @@ export class SearchPage {
this.savedSearchModal = new SavedSearchModalComponent(page);
this.alertModal = new SearchPageAlertModalComponent(page);
this.alertsButtonLocator = page.getByTestId('alerts-button');
this.savedSearchNameTitle = page.locator(
'[data-testid="saved-search-name"]',
);
// Define page-specific locators
this.searchForm = page.getByTestId('search-form');