Skip to content

Commit e5bdd68

Browse files
committed
final touchups
1 parent af043bd commit e5bdd68

2 files changed

Lines changed: 114 additions & 7 deletions

File tree

e2e/tests/notification-channels.spec.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {test, expect} from '@playwright/test';
17+
import {test, expect, type Page} from '@playwright/test';
1818
import {
1919
loginAsUser,
2020
BASE_URL,
@@ -23,6 +23,14 @@ import {
2323
resetUserData,
2424
} from './utils';
2525

26+
function waitForChannelsRefetch(page: Page) {
27+
return page.waitForResponse(
28+
response =>
29+
response.url().includes('/v1/users/me/notification-channels') &&
30+
response.request().method() === 'GET',
31+
);
32+
}
33+
2634
test('redirects unauthenticated user to home and shows toast', async ({
2735
page,
2836
}) => {
@@ -37,8 +45,19 @@ test.describe('Notification Channels Page', () => {
3745
test.beforeEach(async ({page}) => {
3846
await resetUserData();
3947
await loginAsUser(page, 'test user 1');
48+
49+
// Listen for the initial data load GET request
50+
const initialLoad = page.waitForResponse(
51+
response =>
52+
response.url().includes('/v1/users/me/notification-channels') &&
53+
response.request().method() === 'GET',
54+
);
55+
4056
await page.goto(`${BASE_URL}/settings/notification-channels`);
4157
await waitForSidebarLoaded(page);
58+
59+
// Wait for the initial load to complete
60+
await initialLoad;
4261
});
4362

4463
test.afterAll(async () => {
@@ -114,15 +133,24 @@ test.describe('Notification Channels Page', () => {
114133
.getByRole('textbox', {name: 'Slack Webhook URL'})
115134
.fill(webhookUrl);
116135

136+
// Setup refetch listener before click
137+
const refetch = waitForChannelsRefetch(page);
138+
117139
await dialog.getByRole('button', {name: 'Create', exact: true}).click();
118140

141+
// Wait for refetch to complete
142+
await refetch;
143+
119144
// Verify it's in the list.
120145
await expect(dialog.locator('sl-dialog')).not.toBeVisible();
121146
const channelItem = webhookPanel.locator('.channel-item', {
122147
hasText: webhookName,
123148
});
124149
await expect(channelItem).toBeVisible();
125150

151+
// Setup refetch listener before delete click
152+
const deleteRefetch = waitForChannelsRefetch(page);
153+
126154
await channelItem.locator('sl-button[label="Delete"]').click();
127155

128156
const deleteDialog = webhookPanel.locator('sl-dialog[open]');
@@ -131,6 +159,9 @@ test.describe('Notification Channels Page', () => {
131159
.getByRole('button', {name: 'Delete', exact: true})
132160
.click();
133161

162+
// Wait for deletion refetch
163+
await deleteRefetch;
164+
134165
// Verify it's gone.
135166
await expect(channelItem).not.toBeVisible();
136167
});
@@ -165,8 +196,15 @@ test.describe('Notification Channels Page', () => {
165196
await dialog
166197
.getByRole('textbox', {name: 'Slack Webhook URL'})
167198
.fill(originalUrl);
199+
200+
// Setup refetch listener for initial creation
201+
const createRefetch = waitForChannelsRefetch(page);
202+
168203
await dialog.getByRole('button', {name: 'Create', exact: true}).click();
169204

205+
// Wait for creation refetch
206+
await createRefetch;
207+
170208
// Verify it was created.
171209
await expect(dialog.locator('sl-dialog')).not.toBeVisible();
172210
const originalItem = webhookPanel.locator('.channel-item', {
@@ -193,8 +231,14 @@ test.describe('Notification Channels Page', () => {
193231
.getByRole('textbox', {name: 'Slack Webhook URL'})
194232
.fill(updatedUrl);
195233

234+
// Setup refetch listener for save
235+
const saveRefetch = waitForChannelsRefetch(page);
236+
196237
await dialog.getByRole('button', {name: 'Save', exact: true}).click();
197238

239+
// Wait for save refetch
240+
await saveRefetch;
241+
198242
// Verify it was updated.
199243
await expect(dialog.locator('sl-dialog')).not.toBeVisible();
200244
const updatedItem = webhookPanel.locator('.channel-item', {
@@ -209,9 +253,17 @@ test.describe('Notification Channels Page', () => {
209253

210254
const deleteDialog = webhookPanel.locator('sl-dialog[open]');
211255
await expect(deleteDialog).toBeVisible();
256+
257+
// Setup refetch listener for delete
258+
const deleteRefetch = waitForChannelsRefetch(page);
259+
212260
await deleteDialog
213261
.getByRole('button', {name: 'Delete', exact: true})
214262
.click();
263+
264+
// Wait for deletion refetch
265+
await deleteRefetch;
266+
215267
await expect(updatedItem).not.toBeVisible();
216268
});
217269
});

util/cmd/load_fake_data/main.go

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func (h featuresHelper) Features() []gcpspanner.WebFeature {
238238
}
239239

240240
func resetTestData(ctx context.Context, spannerClient *gcpspanner.Client, authClient *auth.Client) error {
241-
slog.InfoContext(ctx, "Resetting test user saved searches and bookmarks...")
241+
slog.InfoContext(ctx, "Resetting test user data...")
242242
userIDs := make([]string, len(testUserEmails))
243243
for idx, email := range testUserEmails {
244244
userID, err := findUserIDByEmail(ctx, email, authClient)
@@ -257,6 +257,30 @@ func resetTestData(ctx context.Context, spannerClient *gcpspanner.Client, authCl
257257
return nil
258258
}
259259

260+
slog.InfoContext(ctx, "Resetting test user saved searches and bookmarks...")
261+
if err := resetSavedSearches(ctx, spannerClient, userIDs); err != nil {
262+
return err
263+
}
264+
slog.InfoContext(ctx, "Deleted saved searches for test users", "count", len(userIDs))
265+
266+
slog.InfoContext(ctx, "Resetting test user subscriptions...")
267+
if err := resetSubscriptions(ctx, spannerClient, userIDs); err != nil {
268+
return err
269+
}
270+
slog.InfoContext(ctx, "Test user subscriptions reset.")
271+
272+
slog.InfoContext(ctx, "Resetting test user notification channels...")
273+
if err := resetNotificationChannels(ctx, spannerClient, userIDs); err != nil {
274+
return err
275+
}
276+
slog.InfoContext(ctx, "Test user notification channels reset.")
277+
278+
slog.InfoContext(ctx, "Test user data reset complete.")
279+
280+
return nil
281+
}
282+
283+
func resetSavedSearches(ctx context.Context, spannerClient *gcpspanner.Client, userIDs []string) error {
260284
for _, userID := range userIDs {
261285
page, err := spannerClient.ListUserSavedSearches(ctx, userID, 1000, nil)
262286
if err != nil {
@@ -275,10 +299,11 @@ func resetTestData(ctx context.Context, spannerClient *gcpspanner.Client, authCl
275299
}
276300
}
277301
}
278-
slog.InfoContext(ctx, "Deleted saved searches for test users", "count", len(userIDs))
279302

280-
// Reset subscriptions for each test user.
281-
slog.InfoContext(ctx, "Resetting test user subscriptions...")
303+
return nil
304+
}
305+
306+
func resetSubscriptions(ctx context.Context, spannerClient *gcpspanner.Client, userIDs []string) error {
282307
for _, userID := range userIDs {
283308
// We don't need to handle pagination here, assuming a test user won't have more than 1000 subscriptions.
284309
req := gcpspanner.ListSavedSearchSubscriptionsRequest{
@@ -300,9 +325,39 @@ func resetTestData(ctx context.Context, spannerClient *gcpspanner.Client, authCl
300325
}
301326
}
302327
}
303-
slog.InfoContext(ctx, "Test user subscriptions reset.")
304328

305-
slog.InfoContext(ctx, "Test user data reset complete.")
329+
return nil
330+
}
331+
332+
func resetNotificationChannels(ctx context.Context, spannerClient *gcpspanner.Client, userIDs []string) error {
333+
for _, userID := range userIDs {
334+
if userID == "" {
335+
continue
336+
}
337+
338+
// List all channels for the user
339+
channels, _, err := spannerClient.ListNotificationChannels(ctx, gcpspanner.ListNotificationChannelsRequest{
340+
UserID: userID,
341+
PageSize: 1000,
342+
PageToken: nil,
343+
})
344+
if err != nil {
345+
return fmt.Errorf("failed to list notification channels for user %s: %w", userID, err)
346+
}
347+
348+
for _, channel := range channels {
349+
// Only delete non-email channels.
350+
if channel.Type == gcpspanner.NotificationChannelTypeEmail {
351+
continue
352+
}
353+
354+
err := spannerClient.DeleteNotificationChannel(ctx, channel.ID, userID)
355+
if err != nil {
356+
slog.WarnContext(ctx, "failed to delete notification channel, continuing",
357+
"channelID", channel.ID, "userID", userID, "error", err)
358+
}
359+
}
360+
}
306361

307362
return nil
308363
}

0 commit comments

Comments
 (0)