@axinom/mosaic-e2e-page-model 0.2.5-rc.9 → 0.3.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,560 @@
1
+ import { ActionLabel } from '@axinom/mosaic-e2e-ui-selectors';
2
+ import { ManagedServiceModel } from '../managed-service-model';
3
+ import { ClaimsEditor } from './claim-set-control';
4
+
5
+ export interface SubscriptionPlanFilters {
6
+ subscriptionPlanTitle: string;
7
+ }
8
+
9
+ export interface ClaimSetFilters {
10
+ uniqueKey: string;
11
+ }
12
+
13
+ /** A model for the managed monetization service. */
14
+ export class MonetizationService extends ManagedServiceModel {
15
+ /**
16
+ * This method navigates to the subscription plans explorer station.
17
+ * The management system must be loaded & signed in before using this method.
18
+ *
19
+ * The following steps will be taken:
20
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Subscription Plans'
21
+ * - Wait for data to load
22
+ */
23
+ async navigateToSubscriptionPlans(): Promise<void> {
24
+ const { uiShell, uiManagedWorkflows } = this;
25
+ await uiShell.navigateToLandingPageTile('Monetization');
26
+
27
+ // click subscription plans tile
28
+ const label = 'Subscription Plans';
29
+ const tile = uiManagedWorkflows.hub.getTileByLabel(label);
30
+ try {
31
+ await tile.waitFor({ state: 'visible' });
32
+ } catch {
33
+ throw new Error(`Monetization hub tile '${label}' is not visible.`);
34
+ }
35
+ await uiShell.waitForPageTransition(tile.click());
36
+ await uiManagedWorkflows.list.waitForData();
37
+ }
38
+
39
+ /**
40
+ * This method navigates to the claim sets explorer station.
41
+ * The management system must be loaded & signed in before using this method.
42
+ *
43
+ * The following steps will be taken:
44
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
45
+ * - Wait for data to load
46
+ */
47
+ async navigateToClaimSets(): Promise<void> {
48
+ const { uiShell, uiManagedWorkflows } = this;
49
+ await uiShell.navigateToLandingPageTile('Monetization');
50
+
51
+ // click claim sets tile
52
+ const label = 'Claim Sets';
53
+ const tile = uiManagedWorkflows.hub.getTileByLabel(label);
54
+ try {
55
+ await tile.waitFor({ state: 'visible' });
56
+ } catch {
57
+ throw new Error(`Monetization hub tile '${label}' is not visible.`);
58
+ }
59
+ await uiShell.waitForPageTransition(tile.click());
60
+ await uiManagedWorkflows.list.waitForData();
61
+ }
62
+
63
+ /**
64
+ * This method navigates to a subscription plan details station by title.
65
+ * The management system must be loaded & signed in before using this method.
66
+ * If there is not exactly one matching subscription plan an exception will be raised.
67
+ *
68
+ * The following steps will be taken:
69
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Subscription Plans'
70
+ * - Filter by title and click the subscription plan row action
71
+ * - Wait for the subscription plan details page to load
72
+ */
73
+ async navigateToSubscriptionPlanDetails(filterBy: {
74
+ /** A unique subscription plan title. */
75
+ title: string;
76
+ }): Promise<void> {
77
+ const { uiShell, uiManagedWorkflows } = this;
78
+ await this.navigateToSubscriptionPlans();
79
+
80
+ // filter to the item
81
+ await uiManagedWorkflows.filters
82
+ .getFilterByName('title')
83
+ .asFreeTextFilter()
84
+ .setValue(filterBy.title);
85
+ await uiManagedWorkflows.list.waitForData();
86
+
87
+ // Verify that there is exactly one matching row
88
+ if ((await uiManagedWorkflows.list.allVisibleRows.count()) !== 1) {
89
+ throw new Error(
90
+ `Failed to find exactly one subscription plan with title '${filterBy.title}'.`,
91
+ );
92
+ }
93
+
94
+ // navigate
95
+ await uiShell.waitForPageTransition(
96
+ uiManagedWorkflows.list.getRow(1).actionButton.click(),
97
+ );
98
+ await uiManagedWorkflows.form.waitForData();
99
+ }
100
+
101
+ /**
102
+ * This method navigates to a claim set details station by unique key.
103
+ * The management system must be loaded & signed in before using this method.
104
+ * If there is not exactly one matching claim set an exception will be raised.
105
+ *
106
+ * The following steps will be taken:
107
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
108
+ * - Filter by unique key and click the claim set row action
109
+ * - Wait for the claim set details station to load
110
+ */
111
+ async navigateToClaimSetDetails(args: {
112
+ /** The claim set unique key. */
113
+ uniqueKey: string;
114
+ }): Promise<void> {
115
+ const { uiShell, uiManagedWorkflows } = this;
116
+
117
+ if (this.page.url().endsWith(`/monetization/claimsets/${args.uniqueKey}`)) {
118
+ // already on the correct page. do nothing
119
+ return;
120
+ }
121
+ await this.navigateToClaimSets();
122
+
123
+ // filter to the item
124
+ await uiManagedWorkflows.filters
125
+ .getFilterByName('key')
126
+ .asFreeTextFilter()
127
+ .setValue(args.uniqueKey);
128
+ await uiManagedWorkflows.list.waitForData();
129
+
130
+ // Verify that there is exactly one matching row
131
+ if ((await uiManagedWorkflows.list.allVisibleRows.count()) !== 1) {
132
+ throw new Error(
133
+ `Failed to find exactly one claim set with unique key '${args.uniqueKey}'.`,
134
+ );
135
+ }
136
+
137
+ // navigate
138
+ await uiShell.waitForPageTransition(
139
+ uiManagedWorkflows.list.getRow(1).actionButton.click(),
140
+ );
141
+ await uiManagedWorkflows.form.waitForData();
142
+ }
143
+
144
+ /**
145
+ * This method assigns a claim set to the subscription plan.
146
+ * The management system must be loaded & signed in before using this method.
147
+ * If the claim set does not exist, or is already added to this subscription plan then an exception will be raised.
148
+ *
149
+ * The following steps will be taken:
150
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Subscription Plans'
151
+ * - Filter by title and click the subscription plan row action
152
+ * - Click the 'Claim Sets' action
153
+ * - Open the claim sets explorer modal, filter by key and select the first result
154
+ * - Click the 'previous' breadcrumb and wait for the subscription plan details station to load
155
+ */
156
+ async assignClaimSetToSubscriptionPlan(args: {
157
+ /** A unique subscription plan title. */
158
+ subscriptionPlanTitle: string;
159
+ /** The claim set unique key. */
160
+ claimSetUniqueKey: string;
161
+ }): Promise<void> {
162
+ const { uiShell, uiManagedWorkflows } = this;
163
+ await this.navigateToSubscriptionPlanDetails({
164
+ title: args.subscriptionPlanTitle,
165
+ });
166
+
167
+ await uiShell.waitForPageTransition(
168
+ uiManagedWorkflows.actions.getActionByLabel('Manage Claim Sets').click(),
169
+ );
170
+ await uiManagedWorkflows.form.waitForData();
171
+
172
+ // open modal
173
+ await uiManagedWorkflows.form
174
+ .getFieldByLabel('Claim Sets')
175
+ .asDynamicDataListField()
176
+ .dataList.dataEntryRow.addButton.click();
177
+ const modal = uiManagedWorkflows.form.modal.asSelectionExplorer();
178
+ await modal.waitToOpen();
179
+ await modal.list.waitForData();
180
+
181
+ // filter to the claim set
182
+ await modal.filters
183
+ .getFilterByName('key')
184
+ .asFreeTextFilter()
185
+ .setValue(args.claimSetUniqueKey);
186
+ await modal.list.waitForData();
187
+ if ((await modal.list.allVisibleRows.count()) !== 1) {
188
+ throw new Error('The claim set was not found or is already assigned.');
189
+ }
190
+
191
+ // assign the claim set
192
+ await modal.list.getRow(1).selectButton.click();
193
+ await modal.waitToClose();
194
+
195
+ // Back to subscription plan details
196
+ await uiShell.navigateToBreadcrumbPrevious();
197
+ await uiManagedWorkflows.form.waitForData();
198
+ }
199
+
200
+ /**
201
+ * This method removes a claim set assignment from a subscription plan.
202
+ * The management system must be loaded & signed in before using this method.
203
+ * If the claim set is not assigned to this subscription plan then an exception will be raised.
204
+ *
205
+ * The following steps will be taken:
206
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Subscription Plans'
207
+ * - Filter by title and click the subscription plan row action
208
+ * - Click the 'Claim Sets' action
209
+ * - Unassign the claim set using the inline menu
210
+ * - Click the 'previous' breadcrumb and wait for the subscription plan details station to load
211
+ */
212
+ async removeClaimSetFromSubscriptionPlan(args: {
213
+ /** A unique subscription plan title. */
214
+ subscriptionPlanTitle: string;
215
+ /** The claim set unique key. */
216
+ claimSetUniqueKey: string;
217
+ }): Promise<void> {
218
+ const { uiShell, uiManagedWorkflows } = this;
219
+ await this.navigateToSubscriptionPlanDetails({
220
+ title: args.subscriptionPlanTitle,
221
+ });
222
+
223
+ await uiShell.waitForPageTransition(
224
+ uiManagedWorkflows.actions.getActionByLabel('Manage Claim Sets').click(),
225
+ );
226
+ await uiManagedWorkflows.form.waitForData();
227
+
228
+ // Find and remove the claim set
229
+ const dataList = uiManagedWorkflows.form
230
+ .getFieldByLabel('Claim Sets')
231
+ .asDynamicDataListField().dataList;
232
+ const row = dataList.getRowByPropertyValue('key', args.claimSetUniqueKey);
233
+ try {
234
+ await row.getLocator().waitFor({ state: 'visible' });
235
+ } catch {
236
+ throw new Error('The claim set was not found on the subscription plan.');
237
+ }
238
+ await row.inlineMenu.openButton.click();
239
+ await row.inlineMenu.getActionByLabel('Unassign').click();
240
+ await dataList.waitForData();
241
+
242
+ // Back to subscription plan details
243
+ await uiShell.navigateToBreadcrumbPrevious();
244
+ await uiManagedWorkflows.form.waitForData();
245
+ }
246
+
247
+ /**
248
+ * This method sets subscription plan status and publishes the subscription plan.
249
+ * The management system must be loaded & signed in before using this method.
250
+ * If the subscription plan cannot be published then an exception will be raised.
251
+ *
252
+ * The following steps will be taken:
253
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Subscription Plans'
254
+ * - Filter by title and click the subscription plan row action
255
+ * - Set the Status field
256
+ * - Click 'Publishing'
257
+ * - Click 'Publish' and confirm
258
+ * - Wait for the subscription plan details station to load and verify that the publication state is 'PUBLISHED'
259
+ */
260
+ async publishSubscriptionPlan(args: {
261
+ /** A unique subscription plan title. */
262
+ title: string;
263
+ /** The subscription plan status to be set. If omitted no change will be made. */
264
+ status?: 'Active' | 'Inactive';
265
+ }): Promise<void> {
266
+ const { uiShell, uiManagedWorkflows } = this;
267
+ await this.navigateToSubscriptionPlanDetails(args);
268
+
269
+ if (args.status !== undefined) {
270
+ await uiManagedWorkflows.form
271
+ .getFieldByName('isActive')
272
+ .asRadioField()
273
+ .setValue(args.status === 'Active' ? 'true' : 'false');
274
+ }
275
+
276
+ await uiShell.waitForPageTransition(
277
+ uiManagedWorkflows.actions.getActionByLabel('Publishing').click(),
278
+ );
279
+ await uiManagedWorkflows.form.waitForData();
280
+
281
+ const publishButton =
282
+ uiManagedWorkflows.actions.getActionByLabel('Publish');
283
+ try {
284
+ await publishButton.waitFor({ state: 'visible' });
285
+ } catch {
286
+ throw new Error(
287
+ 'Subscription plan could not be published. Are there validation errors?',
288
+ );
289
+ }
290
+ await publishButton.click();
291
+ await uiManagedWorkflows.actions.confirmButton.click();
292
+ await uiManagedWorkflows.form.waitForData();
293
+ }
294
+
295
+ /**
296
+ * This method creates a new claim set.
297
+ * The management system must be loaded & signed in before using this method.
298
+ * When this method completes, the new claim set details station will be loaded.
299
+ *
300
+ * The following steps will be taken:
301
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
302
+ * - Click 'NEW', enter the title and key then click 'Proceed'
303
+ * - Wait for the claim set details station to load
304
+ */
305
+ async createClaimSet(properties: {
306
+ /** A unique subscription plan title. */
307
+ title: string;
308
+ /** The claim set unique key. */
309
+ uniqueKey: string;
310
+ }): Promise<void> {
311
+ const { uiShell, uiManagedWorkflows } = this;
312
+ await this.navigateToClaimSets();
313
+
314
+ await uiShell.waitForPageTransition(
315
+ uiManagedWorkflows.pageHeader.actions.getActionByLabel('NEW').click(),
316
+ );
317
+ await uiManagedWorkflows.form.waitForData();
318
+
319
+ await uiManagedWorkflows.form
320
+ .getFieldByName('title')
321
+ .asSingleLineTextField()
322
+ .setValue(properties.title);
323
+ await uiManagedWorkflows.form
324
+ .getFieldByName('key')
325
+ .asSingleLineTextField()
326
+ .setValue(properties.uniqueKey);
327
+ await uiShell.waitForPageTransition(
328
+ uiManagedWorkflows.actions.getActionByLabel(ActionLabel.Proceed).click(),
329
+ );
330
+ await uiManagedWorkflows.form.waitForData();
331
+ }
332
+
333
+ /**
334
+ * This method assigns claims to a claim set.
335
+ * The management system must be loaded & signed in before using this method.
336
+ * NOTE: This method does not support adding claims by mod*a*l.
337
+ *
338
+ * The following steps will be taken:
339
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
340
+ * - Filter by unique key and click the claim set row action
341
+ * - Click 'Claims'
342
+ * - Add each claim by checkbox or radio button
343
+ * - Click the 'previous' breadcrumb and wait for the claim set details station to load
344
+ */
345
+ async assignClaimsToClaimSet(args: {
346
+ /** The claim set unique key. */
347
+ uniqueKey: string;
348
+ /** The list of claim values to be assigned. Each claim input will be clicked. */
349
+ claims: string[];
350
+ }): Promise<void> {
351
+ const { uiShell, uiManagedWorkflows } = this;
352
+ await this.navigateToClaimSetDetails(args);
353
+
354
+ // Open claims editor
355
+ await uiShell.waitForPageTransition(
356
+ uiManagedWorkflows.actions.getActionByLabel('Claims').click(),
357
+ );
358
+
359
+ // Select each claim
360
+ const claimsEditor = new ClaimsEditor(this.page);
361
+ for (const claim of args.claims) {
362
+ const row = claimsEditor.getClaimRow(claim);
363
+ try {
364
+ await row.getLocator().waitFor({ state: 'visible' });
365
+ } catch (e) {
366
+ throw new Error(
367
+ `A radio or checkbox for for claim '${claim}' is not visible. NOTE: selecting claims by mod*a*l is not supported by this method.` +
368
+ (e instanceof Error ? `\n${e.message}` : ''),
369
+ );
370
+ }
371
+ await row.toggle();
372
+ }
373
+ // Back to claim set details
374
+ await uiShell.navigateToBreadcrumbPrevious();
375
+ await uiManagedWorkflows.form.waitForData();
376
+ }
377
+
378
+ /**
379
+ * This method assigns claims to a claim set.
380
+ * The management system must be loaded & signed in before using this method.
381
+ * NOTE: This method *does* support adding claims by mod*a*l.
382
+ *
383
+ * The following steps will be taken:
384
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
385
+ * - Filter by unique key and click the claim set row action
386
+ * - Click 'Claims'
387
+ * - Add each claim by checkbox or radio button
388
+ * - Click the 'previous' breadcrumb and wait for the claim set details station to load
389
+ */
390
+ async assignClaimsToClaimSetByLabel(args: {
391
+ /** The claim set unique key. */
392
+ uniqueKey: string;
393
+ /** The label of the claim group. */
394
+ claimGroupLabel: string;
395
+ /** The claim labels in the claim group. Each will be clicked or added by modal as required. */
396
+ claimLabels: string[];
397
+ }): Promise<void> {
398
+ const { uiShell, uiManagedWorkflows } = this;
399
+ await this.navigateToClaimSetDetails(args);
400
+
401
+ // Open claims editor
402
+ await uiShell.waitForPageTransition(
403
+ uiManagedWorkflows.actions.getActionByLabel('Claims').click(),
404
+ );
405
+
406
+ // Select each claim
407
+ const claimsEditor = new ClaimsEditor(this.page);
408
+ const group = claimsEditor.getClaimGroup(args.claimGroupLabel);
409
+ try {
410
+ await group.row.waitFor({ state: 'visible' });
411
+ } catch (e) {
412
+ throw new Error(
413
+ `A claim group with label ${args.claimGroupLabel} is not visible.` +
414
+ (e instanceof Error ? `\n${e.message}` : ''),
415
+ );
416
+ }
417
+ await group.expand();
418
+ if (await group.isDataListEntry()) {
419
+ // Select each claim with selection explorer
420
+ const modal = group.explorerModal;
421
+ for (const claimLabel of args.claimLabels) {
422
+ await group.dataList.dataEntryRow.addButton.click();
423
+ await modal.waitToOpen();
424
+ await modal.list.waitForData();
425
+
426
+ // filter to the claim
427
+ await modal.filters
428
+ .getFilterByName('title')
429
+ .asFreeTextFilter()
430
+ .setValue(claimLabel);
431
+ await modal.list.waitForData();
432
+ if ((await modal.list.allVisibleRows.count()) !== 1) {
433
+ throw new Error(
434
+ `A entry for claim with label '${claimLabel}' is not visible in the modal for group '${args.claimGroupLabel}'.`,
435
+ );
436
+ }
437
+
438
+ // assign the claim
439
+ await modal.list.getRow(1).selectButton.click();
440
+ await modal.waitToClose();
441
+ }
442
+ } else {
443
+ // Select each claim
444
+ for (const claimLabel of args.claimLabels) {
445
+ const row = group.getClaimRowByLabel(claimLabel);
446
+ try {
447
+ await row.getLocator().waitFor({ state: 'visible' });
448
+ } catch (e) {
449
+ throw new Error(
450
+ `A radio or checkbox for claim with label '${claimLabel}' is not visible in group '${args.claimGroupLabel}'.` +
451
+ (e instanceof Error ? `\n${e.message}` : ''),
452
+ );
453
+ }
454
+ await row.toggle();
455
+ }
456
+ }
457
+ // Back to claim set details
458
+ await uiShell.navigateToBreadcrumbPrevious();
459
+ await uiManagedWorkflows.form.waitForData();
460
+ }
461
+
462
+ /**
463
+ * This method publishes a claim set.
464
+ * The management system must be loaded & signed in before using this method.
465
+ * If the claim set cannot be published then an exception will be raised.
466
+ *
467
+ * The following steps will be taken:
468
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
469
+ * - Filter by unique key and click the claim set row action
470
+ * - Click 'Publishing'
471
+ * - Click 'Publish' and confirm
472
+ * - Wait for the claim set details station to load
473
+ */
474
+ async publishClaimSet(args: {
475
+ /** The claim set unique key. */
476
+ uniqueKey: string;
477
+ }): Promise<void> {
478
+ const { uiShell, uiManagedWorkflows } = this;
479
+ await this.navigateToClaimSetDetails(args);
480
+
481
+ await uiShell.waitForPageTransition(
482
+ uiManagedWorkflows.actions.getActionByLabel('Publishing').click(),
483
+ );
484
+ await uiManagedWorkflows.form.waitForData();
485
+
486
+ const action = uiManagedWorkflows.actions.getActionByLabel('Publish');
487
+ try {
488
+ await action.waitFor({ state: 'visible' });
489
+ } catch {
490
+ throw new Error(
491
+ 'Claim set could not be published. Are there validation errors?',
492
+ );
493
+ }
494
+ await action.click();
495
+ await uiShell.waitForPageTransition(
496
+ uiManagedWorkflows.actions.confirmButton.click(),
497
+ );
498
+ await uiManagedWorkflows.form.waitForData();
499
+ }
500
+
501
+ /**
502
+ * This method unpublishes a claim set by unique key.
503
+ * The management system must be loaded & signed in before using this method.
504
+ * If the claim set cannot be unpublished then an exception will be raised.
505
+ *
506
+ * The following steps will be taken:
507
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
508
+ * - Filter by unique key and click the claim set row action
509
+ * - Click 'Unpublish' and confirm
510
+ * - Wait for the claim sets details station to load
511
+ */
512
+ async unpublishClaimSet(args: { uniqueKey: string }): Promise<void> {
513
+ const { uiShell, uiManagedWorkflows } = this;
514
+ await this.navigateToClaimSetDetails(args);
515
+
516
+ const action = uiManagedWorkflows.actions.getActionByLabel('Unpublish');
517
+ try {
518
+ await action.waitFor({ state: 'visible' });
519
+ } catch {
520
+ throw new Error('The "Unpublish" action is not visible.');
521
+ }
522
+ await action.click();
523
+ await uiShell.waitForPageTransition(
524
+ uiManagedWorkflows.actions.confirmButton.click(),
525
+ );
526
+ await uiManagedWorkflows.form.waitForData();
527
+ }
528
+
529
+ /**
530
+ * This method deletes a claim set by unique key.
531
+ * The management system must be loaded & signed in before using this method.
532
+ * If the claim set cannot be deleted then an exception will be raised.
533
+ *
534
+ * The following steps will be taken:
535
+ * - Navigate to the home breadcrumb, then tiles: 'Monetization', 'Claim Sets'
536
+ * - Filter by unique key and click the claim set row action
537
+ * - Click 'Delete' and confirm
538
+ * - Wait for the claim sets explorer to load
539
+ */
540
+ async deleteClaimSet(args: {
541
+ /** The claim set unique key. */
542
+ uniqueKey: string;
543
+ }): Promise<void> {
544
+ const { uiShell, uiManagedWorkflows } = this;
545
+ await this.navigateToClaimSetDetails(args);
546
+
547
+ // Delete the claim set
548
+ const action = uiManagedWorkflows.actions.getActionByLabel('Delete');
549
+ try {
550
+ await action.waitFor({ state: 'visible' });
551
+ } catch {
552
+ throw new Error('The "Delete" action is not visible.');
553
+ }
554
+ await action.click();
555
+ await uiShell.waitForPageTransition(
556
+ uiManagedWorkflows.actions.confirmButton.click(),
557
+ );
558
+ await uiManagedWorkflows.list.waitForData();
559
+ }
560
+ }
@@ -0,0 +1,43 @@
1
+ import { GenericField } from '@axinom/mosaic-e2e-ui-selectors';
2
+
3
+ /**
4
+ * A model for a "Recurrence Period" form field which can be used to configure
5
+ * the "Recurrence Period" field on payment plans. This is a custom FormField component.
6
+ *
7
+ * It is advised not to use this model directly but to use fixed pre-configured
8
+ * subscription plans for end-to-end testing of payment provider integrations.
9
+ *
10
+ * Example usage:
11
+ * ```
12
+ * await uiManagedWorkflows.form
13
+ * .getFieldByLabel('Recurrence Period')
14
+ * .as(PaymentPlanRecurrencePeriodField)
15
+ * .setValues(1, 'WEEK');
16
+ * ```
17
+ */
18
+ export class PaymentPlanRecurrencePeriodField extends GenericField {
19
+ /** @inheritdoc */
20
+ protected override get fieldTypeValidator(): string {
21
+ return '[@data-test-type="PaymentProviderRecurrencePeriod"]';
22
+ }
23
+
24
+ readonly quantityInput = this.content.locator(
25
+ '//input[@name="periodQuantity"]',
26
+ );
27
+ readonly unitInput = this.content.locator('//select[@name="periodUnit"]');
28
+
29
+ /**
30
+ * Sets values for both inputs of the recurrence period field.
31
+ *
32
+ * @param quantity Value for the number entry input
33
+ * @param unit The dropdown label to select
34
+ */
35
+ async setValues(
36
+ quantity: number,
37
+ unit: 'day(s)' | 'week(s)' | 'month(s)' | 'year(s)',
38
+ ): Promise<void> {
39
+ await this.verifyFieldType();
40
+ await this.quantityInput.fill(quantity.toString());
41
+ await this.unitInput.selectOption({ label: unit });
42
+ }
43
+ }
@@ -0,0 +1,76 @@
1
+ import { GenericField } from '@axinom/mosaic-e2e-ui-selectors';
2
+
3
+ /** A model for a payment provider settings form field which can
4
+ * be used to configure payment provider settings on subscription plans and
5
+ * payment plans. This is a custom FormField component.
6
+ *
7
+ * It is advised not to use this model directly but to use fixed pre-configured
8
+ * subscription plans for end-to-end testing of payment provider integrations.
9
+ *
10
+ * Example usage:
11
+ * ```
12
+ * const field = uiManagedWorkflows.form
13
+ * .getFieldByLabel('Payment Providers & Settings')
14
+ * .as(PaymentProviderSettingsField);
15
+ * await field.addPaymentProvider('PAYPAL');
16
+ * await field.setExternalId('PAYPAL', 'P-123XYZ');
17
+ * ```
18
+ */
19
+ export class PaymentProviderSettingsField extends GenericField {
20
+ /** @inheritdoc */
21
+ protected override get fieldTypeValidator(): string {
22
+ return '[@data-test-type="SubscriptionPlanProviderConfigs" or @data-test-type="PaymentPlanProviderConfigs"]';
23
+ }
24
+
25
+ /**
26
+ * Add a payment provider.
27
+ *
28
+ * @param paymentProviderTitle Label for the payment provider. e.g. 'PayPal'
29
+ */
30
+ async addPaymentProvider(paymentProviderTitle: string): Promise<void> {
31
+ const providerSelect = this.getLocator(
32
+ '//*[@data-test-id="payment-provider-selection-row"]//select',
33
+ );
34
+ const providerAddButton = this.getLocator(
35
+ '//*[@data-test-id="payment-provider-selection-row"]//button',
36
+ );
37
+
38
+ await this.verifyFieldType();
39
+ try {
40
+ await providerSelect
41
+ .locator(`//option[text()="${paymentProviderTitle}"]`)
42
+ .waitFor({ state: 'attached' });
43
+ } catch {
44
+ throw new Error(
45
+ `Could not add payment provider '${paymentProviderTitle}'. Is the payment provider enabled for this environment and not already added to this plan?`,
46
+ );
47
+ }
48
+ await providerSelect.selectOption({ label: paymentProviderTitle });
49
+ await providerAddButton.click();
50
+ }
51
+
52
+ /**
53
+ * Set the external ID of an added payment provider.
54
+ *
55
+ * @param paymentProviderTitle Label for the payment provider. e.g. 'PayPal'
56
+ * @param externalId A value to set as the external Id.
57
+ */
58
+ async setExternalId(
59
+ paymentProviderTitle: string,
60
+ externalId: string,
61
+ ): Promise<void> {
62
+ const input = this.getLocator(
63
+ `//*[@data-test-id="payment-provider-config:${paymentProviderTitle}"]//input[contains(@name, "externalId")]`,
64
+ );
65
+
66
+ await this.verifyFieldType();
67
+ try {
68
+ await input.waitFor({ state: 'visible' });
69
+ } catch {
70
+ throw new Error(
71
+ `Could not set 'externalId' for payment provider '${paymentProviderTitle}'. Is the payment provider enabled and not published for this plan?`,
72
+ );
73
+ }
74
+ await input.fill(externalId);
75
+ }
76
+ }