You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 5 дни
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # Webhook Provider Patterns
  2. ## Principle
  3. Three built-in providers ship with playwright-utils. Each wraps a different mock server API. For any backend not covered, implement the `WebhookProvider` interface. The registry only cares about the contract — not the backend technology.
  4. ## WireMockWebhookProvider
  5. Uses `GET /__admin/requests` to fetch the webhook log and `DELETE /__admin/requests` to reset. Supports `deleteById` for `matched-only` cleanup.
  6. **Works with any backend implementing the `/__admin/requests` format** — not just actual WireMock. The playwright-utils sample app's Express backend uses this exact format.
  7. ```typescript
  8. import { WireMockWebhookProvider } from '@seontechnologies/playwright-utils/webhook';
  9. import { API_URL } from '../config/local.config';
  10. const webhookProviderFixture = base.extend<{
  11. webhookProvider: WireMockWebhookProvider;
  12. }>({
  13. webhookProvider: async ({ request }, use) => {
  14. const provider = new WireMockWebhookProvider(API_URL, request);
  15. await use(provider);
  16. },
  17. });
  18. ```
  19. Supports both cleanup strategies. Use `matched-only` when running `fullyParallel: true`.
  20. ## MockServerWebhookProvider
  21. Uses `PUT /mockserver/retrieve` to fetch logs with client-side `since` filtering.
  22. **Limitation**: `deleteById` is a no-op — MockServer does not support deleting individual log entries by ID. The `startedAt` timestamp filter handles per-test isolation. Use `full-reset` for explicit journal cleanup.
  23. ```typescript
  24. import { MockServerWebhookProvider } from '@seontechnologies/playwright-utils/webhook';
  25. const webhookProviderFixture = base.extend<{
  26. webhookProvider: MockServerWebhookProvider;
  27. }>({
  28. webhookProvider: async ({ request }, use) => {
  29. await use(new MockServerWebhookProvider(API_URL, request));
  30. },
  31. });
  32. const test = mergeTests(base, /* ...other fixtures... */ webhookFixture, webhookProviderFixture);
  33. // MockServer has no delete-by-ID on log entries — use full-reset
  34. test.use({ webhookConfig: { cleanupStrategy: 'full-reset' } });
  35. ```
  36. ## MockoonWebhookProvider
  37. Uses `GET /mockoon-admin/logs` to fetch logs. The admin API is enabled by default in `@mockoon/cli`. Default log limit is 100 entries — increase with `--max-transaction-logs` if your suite generates more.
  38. **Limitation**: `deleteById` is a no-op for the same reason as MockServer. Use `full-reset`.
  39. ```typescript
  40. import { MockoonWebhookProvider } from '@seontechnologies/playwright-utils/webhook';
  41. const webhookProviderFixture = base.extend<{
  42. webhookProvider: MockoonWebhookProvider;
  43. }>({
  44. webhookProvider: async ({ request }, use) => {
  45. await use(new MockoonWebhookProvider(API_URL, request));
  46. },
  47. });
  48. const test = mergeTests(base, /* ...other fixtures... */ webhookFixture, webhookProviderFixture);
  49. // Mockoon has no delete-by-ID on log entries — use full-reset
  50. test.use({ webhookConfig: { cleanupStrategy: 'full-reset' } });
  51. ```
  52. Start Mockoon with an increased log limit if needed:
  53. ```bash
  54. mockoon-cli start --data ./mockoon-config.json --max-transaction-logs 500
  55. ```
  56. ## Custom Provider
  57. Implement `WebhookProvider` for any backend that exposes a queryable request log:
  58. ```typescript
  59. // support/providers/custom-webhook-provider.ts
  60. import type { WebhookProvider, ReceivedWebhook, WebhookQueryFilter } from '@seontechnologies/playwright-utils/webhook';
  61. import type { APIRequestContext } from '@playwright/test';
  62. export class CustomWebhookProvider implements WebhookProvider {
  63. constructor(
  64. private readonly baseUrl: string,
  65. private readonly request: APIRequestContext,
  66. ) {}
  67. async getReceivedWebhooks(filter?: WebhookQueryFilter): Promise<ReceivedWebhook[]> {
  68. const params = new URLSearchParams();
  69. if (filter?.since) params.set('since', filter.since.toISOString());
  70. if (filter?.method) params.set('method', filter.method);
  71. const response = await this.request.get(`${this.baseUrl}/webhooks/received?${params}`);
  72. const { webhooks } = await response.json();
  73. return webhooks.map((w: Record<string, unknown>) => ({
  74. id: String(w.id),
  75. url: String(w.url),
  76. method: String(w.method),
  77. headers: (w.headers as Record<string, string>) ?? {},
  78. body: w.body,
  79. receivedAt: new Date(String(w.receivedAt)),
  80. }));
  81. }
  82. async resetJournal(): Promise<void> {
  83. await this.request.delete(`${this.baseUrl}/webhooks/received`);
  84. }
  85. async deleteById(id: string): Promise<void> {
  86. await this.request.delete(`${this.baseUrl}/webhooks/received/${id}`);
  87. }
  88. async getCount(): Promise<number> {
  89. const response = await this.request.get(`${this.baseUrl}/webhooks/count`);
  90. const { count } = await response.json();
  91. return count as number;
  92. }
  93. }
  94. ```
  95. ## WebhookProvider Interface
  96. ```typescript
  97. interface WebhookProvider {
  98. getReceivedWebhooks(filter?: WebhookQueryFilter): Promise<ReceivedWebhook[]>;
  99. resetJournal(): Promise<void>;
  100. deleteById(id: string): Promise<void>;
  101. getCount(criteria?: Record<string, unknown>): Promise<number>;
  102. removeByCriteria?(criteria: Record<string, unknown>): Promise<void>;
  103. setup?(): Promise<void>; // optional — called before test
  104. teardown?(): Promise<void>; // optional — called after test
  105. }
  106. ```
  107. ## Provider Comparison
  108. | Provider | deleteById | resetJournal | Parallel-safe (shared journal) | Recommended strategy | API endpoint |
  109. | ------------------------- | ---------- | ------------ | ----------------------------------- | ----------------------------------------------------- | ---------------------- |
  110. | WireMockWebhookProvider | ✅ Yes | ✅ Yes | ✅ Yes (`matched-only`) | `matched-only` | `/__admin/requests` |
  111. | MockServerWebhookProvider | ❌ No-op | ✅ Yes | ⚠️ No — serial or isolated instance | `full-reset` (serial or isolated provider per worker) | `/mockserver/retrieve` |
  112. | MockoonWebhookProvider | ❌ No-op | ✅ Yes | ⚠️ No — serial or isolated instance | `full-reset` (serial or isolated provider per worker) | `/mockoon-admin/logs` |
  113. | Custom | Depends | Depends | Depends on implementation | Depends | Your API |
  114. ## Related Fragments
  115. - `webhook-module-setup.md` — Full fixture wiring for each provider
  116. - `webhook-testing-fundamentals.md` — Cleanup strategy rationale