Skip to content

Commit 325d5fa

Browse files
committed
WIP
Signed-off-by: zomars <zomars@me.com>
1 parent 9b4c201 commit 325d5fa

File tree

9 files changed

+108
-155
lines changed

9 files changed

+108
-155
lines changed
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { expect, type Page } from "@playwright/test";
2+
3+
import { createHttpServer } from "../lib/testUtils";
4+
5+
export function createWebhookPageFixture(page: Page) {
6+
return {
7+
createTeamReceiver: async () => {
8+
const webhookReceiver = createHttpServer();
9+
await page.goto(`/settings/developer/webhooks`);
10+
await page.click('[data-testid="new_webhook"]');
11+
await page.click('[data-testid="option-team-1"]');
12+
await page.waitForURL((u) => u.pathname === "/settings/developer/webhooks/new");
13+
const url = page.url();
14+
const teamId = Number(new URL(url).searchParams.get("teamId")) as number;
15+
await page.click('[data-testid="new_webhook"]');
16+
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
17+
await page.fill('[name="secret"]', "secret");
18+
await Promise.all([
19+
page.click("[type=submit]"),
20+
page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
21+
]);
22+
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
23+
return { webhookReceiver, teamId };
24+
},
25+
createReceiver: async () => {
26+
const webhookReceiver = createHttpServer();
27+
await page.goto(`/settings/developer/webhooks`);
28+
await page.click('[data-testid="new_webhook"]');
29+
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
30+
await page.fill('[name="secret"]', "secret");
31+
await Promise.all([
32+
page.click("[type=submit]"),
33+
page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
34+
]);
35+
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
36+
return webhookReceiver;
37+
},
38+
};
39+
}

apps/web/playwright/lib/fixtures.ts

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { createBookingPageFixture } from "../fixtures/regularBookings";
1616
import { createRoutingFormsFixture } from "../fixtures/routingForms";
1717
import { createServersFixture } from "../fixtures/servers";
1818
import { createUsersFixture } from "../fixtures/users";
19+
import { createWebhookPageFixture } from "../fixtures/webhooks";
1920
import { createWorkflowPageFixture } from "../fixtures/workflows";
2021

2122
export interface Fixtures {
@@ -34,6 +35,7 @@ export interface Fixtures {
3435
features: ReturnType<typeof createFeatureFixture>;
3536
eventTypePage: ReturnType<typeof createEventTypeFixture>;
3637
appsPage: ReturnType<typeof createAppsFixture>;
38+
webhooks: ReturnType<typeof createWebhookPageFixture>;
3739
}
3840

3941
declare global {
@@ -110,4 +112,8 @@ export const test = base.extend<Fixtures>({
110112
const appsPage = createAppsFixture(page);
111113
await use(appsPage);
112114
},
115+
webhooks: async ({ page }, use) => {
116+
const webhooks = createWebhookPageFixture(page);
117+
await use(webhooks);
118+
},
113119
});

apps/web/playwright/webhook.e2e.ts

+21-134
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { Page } from "@playwright/test";
21
import { expect } from "@playwright/test";
32
import { v4 as uuidv4 } from "uuid";
43

@@ -10,7 +9,6 @@ import { test } from "./lib/fixtures";
109
import {
1110
bookOptinEvent,
1211
bookTimeSlot,
13-
createHttpServer,
1412
createUserWithSeatedEventAndAttendees,
1513
gotoRoutingLink,
1614
selectFirstAvailableTimeSlotNextMonth,
@@ -24,54 +22,16 @@ test.afterEach(async ({ users }) => {
2422
await users.deleteAll();
2523
});
2624

27-
async function createWebhookReceiver(page: Page) {
28-
const webhookReceiver = createHttpServer();
29-
30-
await page.goto(`/settings/developer/webhooks`);
31-
32-
// --- add webhook
33-
await page.click('[data-testid="new_webhook"]');
34-
35-
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
36-
37-
await page.fill('[name="secret"]', "secret");
38-
39-
await Promise.all([
40-
page.click("[type=submit]"),
41-
page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
42-
]);
43-
44-
// page contains the url
45-
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
46-
47-
return webhookReceiver;
48-
}
49-
5025
test.describe("BOOKING_CREATED", async () => {
5126
test("add webhook & test that creating an event triggers a webhook call", async ({
5227
page,
5328
users,
29+
webhooks,
5430
}, _testInfo) => {
55-
const webhookReceiver = createHttpServer();
5631
const user = await users.create();
5732
const [eventType] = user.eventTypes;
5833
await user.apiLogin();
59-
await page.goto(`/settings/developer/webhooks`);
60-
61-
// --- add webhook
62-
await page.click('[data-testid="new_webhook"]');
63-
64-
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
65-
66-
await page.fill('[name="secret"]', "secret");
67-
68-
await Promise.all([
69-
page.click("[type=submit]"),
70-
page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
71-
]);
72-
73-
// page contains the url
74-
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
34+
const webhookReceiver = await webhooks.createReceiver();
7535

7636
// --- Book the first available day next month in the pro user's "30min"-event
7737
await page.goto(`/${user.username}/${eventType.slug}`);
@@ -169,8 +129,8 @@ test.describe("BOOKING_REJECTED", async () => {
169129
test("can book an event that requires confirmation and then that booking can be rejected by organizer", async ({
170130
page,
171131
users,
132+
webhooks,
172133
}) => {
173-
const webhookReceiver = createHttpServer();
174134
// --- create a user
175135
const user = await users.create();
176136

@@ -182,24 +142,7 @@ test.describe("BOOKING_REJECTED", async () => {
182142

183143
// --- login as that user
184144
await user.apiLogin();
185-
186-
await page.goto(`/settings/developer/webhooks`);
187-
188-
// --- add webhook
189-
await page.click('[data-testid="new_webhook"]');
190-
191-
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
192-
193-
await page.fill('[name="secret"]', "secret");
194-
195-
await Promise.all([
196-
page.click("[type=submit]"),
197-
page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
198-
]);
199-
200-
// page contains the url
201-
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
202-
145+
const webhookReceiver = await webhooks.createReceiver();
203146
await page.goto("/bookings/unconfirmed");
204147
await page.click('[data-testid="reject"]');
205148
await page.click('[data-testid="rejection-confirm"]');
@@ -293,30 +236,14 @@ test.describe("BOOKING_REQUESTED", async () => {
293236
test("can book an event that requires confirmation and get a booking requested event", async ({
294237
page,
295238
users,
239+
webhooks,
296240
}) => {
297-
const webhookReceiver = createHttpServer();
298241
// --- create a user
299242
const user = await users.create();
300243

301244
// --- login as that user
302245
await user.apiLogin();
303-
304-
await page.goto(`/settings/developer/webhooks`);
305-
306-
// --- add webhook
307-
await page.click('[data-testid="new_webhook"]');
308-
309-
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
310-
311-
await page.fill('[name="secret"]', "secret");
312-
313-
await Promise.all([
314-
page.click("[type=submit]"),
315-
page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
316-
]);
317-
318-
// page contains the url
319-
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
246+
const webhookReceiver = await webhooks.createReceiver();
320247

321248
// --- visit user page
322249
await page.goto(`/${user.username}`);
@@ -410,13 +337,18 @@ test.describe("BOOKING_REQUESTED", async () => {
410337
});
411338

412339
test.describe("BOOKING_RESCHEDULED", async () => {
413-
test("can reschedule a booking and get a booking rescheduled event", async ({ page, users, bookings }) => {
340+
test("can reschedule a booking and get a booking rescheduled event", async ({
341+
page,
342+
users,
343+
bookings,
344+
webhooks,
345+
}) => {
414346
const user = await users.create();
415347
const [eventType] = user.eventTypes;
416348

417349
await user.apiLogin();
418350

419-
const webhookReceiver = await createWebhookReceiver(page);
351+
const webhookReceiver = await webhooks.createReceiver();
420352

421353
const booking = await bookings.create(user.id, user.username, eventType.id, {
422354
status: BookingStatus.ACCEPTED,
@@ -451,6 +383,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
451383
page,
452384
users,
453385
bookings,
386+
webhooks,
454387
}) => {
455388
const { user, eventType, booking } = await createUserWithSeatedEventAndAttendees({ users, bookings }, [
456389
{ name: "John First", email: "first+seats@cal.com", timeZone: "Europe/Berlin" },
@@ -464,7 +397,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
464397

465398
await user.apiLogin();
466399

467-
const webhookReceiver = await createWebhookReceiver(page);
400+
const webhookReceiver = await webhooks.createReceiver();
468401

469402
const bookingAttendees = await prisma.attendee.findMany({
470403
where: { bookingId: booking.id },
@@ -670,24 +603,13 @@ test.describe("MEETING_ENDED, MEETING_STARTED", async () => {
670603
});
671604

672605
test.describe("FORM_SUBMITTED", async () => {
673-
test("on submitting user form, triggers user webhook", async ({ page, users, routingForms }) => {
674-
const webhookReceiver = createHttpServer();
606+
test("on submitting user form, triggers user webhook", async ({ page, users, routingForms, webhooks }) => {
675607
const user = await users.create(null, {
676608
hasTeam: true,
677609
});
678610

679611
await user.apiLogin();
680-
681-
await page.goto(`/settings/developer/webhooks/new`);
682-
683-
// Add webhook
684-
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
685-
await page.fill('[name="secret"]', "secret");
686-
await page.click("[type=submit]");
687-
688-
// Page contains the url
689-
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
690-
612+
const webhookReceiver = await webhooks.createReceiver();
691613
await page.waitForLoadState("networkidle");
692614

693615
const form = await routingForms.create({
@@ -736,21 +658,12 @@ test.describe("FORM_SUBMITTED", async () => {
736658
webhookReceiver.close();
737659
});
738660

739-
test("on submitting team form, triggers team webhook", async ({ page, users, routingForms }) => {
740-
const webhookReceiver = createHttpServer();
661+
test("on submitting team form, triggers team webhook", async ({ page, users, routingForms, webhooks }) => {
741662
const user = await users.create(null, {
742663
hasTeam: true,
743664
});
744665
await user.apiLogin();
745-
746-
await page.goto(`/settings/developer/webhooks`);
747-
const teamId = await clickFirstTeamWebhookCta(page);
748-
749-
// Add webhook
750-
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
751-
await page.fill('[name="secret"]', "secret");
752-
await page.click("[type=submit]");
753-
666+
const { webhookReceiver, teamId } = await webhooks.createTeamReceiver();
754667
const form = await routingForms.create({
755668
name: "Test Form",
756669
userId: user.id,
@@ -798,40 +711,14 @@ test.describe("FORM_SUBMITTED", async () => {
798711
});
799712
});
800713

801-
async function clickFirstTeamWebhookCta(page: Page) {
802-
await page.click('[data-testid="new_webhook"]');
803-
await page.click('[data-testid="option-team-1"]');
804-
await page.waitForURL((u) => u.pathname === "/settings/developer/webhooks/new");
805-
const url = page.url();
806-
const teamId = Number(new URL(url).searchParams.get("teamId")) as number;
807-
return teamId;
808-
}
809-
810714
test.describe("BOOKING_NO_SHOW_UPDATED", async () => {
811-
test("on marking an attendee as no-show, triggers webhook", async ({ page, users }) => {
812-
const webhookReceiver = createHttpServer();
715+
test("on marking an attendee as no-show, triggers webhook", async ({ page, users, webhooks }) => {
813716
// --- create a user
814717
const user = await users.create();
815718

816719
// --- login as that user
817720
await user.apiLogin();
818-
819-
await page.goto(`/settings/developer/webhooks`);
820-
821-
// --- add webhook
822-
await page.click('[data-testid="new_webhook"]');
823-
824-
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
825-
826-
await page.fill('[name="secret"]', "secret");
827-
828-
await Promise.all([
829-
page.click("[type=submit]"),
830-
page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
831-
]);
832-
833-
// page contains the url
834-
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
721+
const webhookReceiver = await webhooks.createReceiver();
835722

836723
// --- visit user page
837724
await page.goto(`/${user.username}`);

apps/web/public/static/locales/en/common.json

+1
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@
471471
"meeting_ended": "Meeting Ended",
472472
"form_submitted": "Form Submitted",
473473
"booking_paid": "Booking Paid",
474+
"booking_no_show_updated": "Booking No-Show Updated",
474475
"event_triggers": "Event Triggers",
475476
"subscriber_url": "Subscriber URL",
476477
"create_new_webhook": "Create a new webhook",

packages/features/webhooks/components/WebhookForm.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2: Record<string, WebhookTriggerEve
3838
{ value: WebhookTriggerEvents.BOOKING_PAYMENT_INITIATED, label: "booking_payment_initiated" },
3939
{ value: WebhookTriggerEvents.BOOKING_RESCHEDULED, label: "booking_rescheduled" },
4040
{ value: WebhookTriggerEvents.BOOKING_PAID, label: "booking_paid" },
41+
{ value: WebhookTriggerEvents.BOOKING_NO_SHOW_UPDATED, label: "booking_no_show_updated" },
4142
{ value: WebhookTriggerEvents.MEETING_ENDED, label: "meeting_ended" },
4243
{ value: WebhookTriggerEvents.MEETING_STARTED, label: "meeting_started" },
4344
{ value: WebhookTriggerEvents.RECORDING_READY, label: "recording_ready" },

0 commit comments

Comments
 (0)