@reorderjs/reorder 1.0.8 → 1.1.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.
Files changed (65) hide show
  1. package/.medusa/server/e2e/auth.setup.js +26 -0
  2. package/.medusa/server/e2e/cancellation-retention.spec.js +133 -0
  3. package/.medusa/server/e2e/pages/CancellationCaseDetailPage.js +69 -0
  4. package/.medusa/server/e2e/pages/CancellationsListPage.js +34 -0
  5. package/.medusa/server/e2e/pages/PlanFormPage.js +89 -0
  6. package/.medusa/server/e2e/pages/RenewalDetailPage.js +101 -0
  7. package/.medusa/server/e2e/pages/SubscriptionDetailPage.js +102 -0
  8. package/.medusa/server/e2e/plans-offers.spec.js +96 -0
  9. package/.medusa/server/e2e/renewal-force.spec.js +154 -0
  10. package/.medusa/server/e2e/seed.setup.js +80 -0
  11. package/.medusa/server/e2e/subscription-status.spec.js +109 -0
  12. package/.medusa/server/e2e/subscriptions-list.spec.js +84 -0
  13. package/.medusa/server/playwright.config.js +37 -0
  14. package/.medusa/server/scripts/reset-subscriptions-test-data.js +279 -0
  15. package/.medusa/server/scripts/seed-subscriptions-test-data.js +2425 -0
  16. package/.medusa/server/scripts/wipe-test-data.js +44 -0
  17. package/.medusa/server/src/admin/index.js +11106 -9689
  18. package/.medusa/server/src/admin/index.mjs +11099 -9682
  19. package/.medusa/server/src/admin/types/analytics.js +2 -1
  20. package/.medusa/server/src/api/admin/cancellations/validators.js +2 -2
  21. package/.medusa/server/src/api/admin/dunning/validators.js +2 -2
  22. package/.medusa/server/src/api/admin/renewals/validators.js +2 -2
  23. package/.medusa/server/src/api/admin/subscription-analytics/validators.js +2 -2
  24. package/.medusa/server/src/api/admin/subscription-logs/validators.js +2 -2
  25. package/.medusa/server/src/api/admin/subscription-offers/validators.js +2 -2
  26. package/.medusa/server/src/api/admin/subscription-settings/validators.js +2 -2
  27. package/.medusa/server/src/api/admin/subscriptions/[id]/payment-method/route.js +19 -0
  28. package/.medusa/server/src/api/admin/subscriptions/[id]/payment-methods/route.js +10 -0
  29. package/.medusa/server/src/api/admin/subscriptions/middlewares.js +8 -1
  30. package/.medusa/server/src/api/admin/subscriptions/utils.js +5 -1
  31. package/.medusa/server/src/api/admin/subscriptions/validators.js +7 -3
  32. package/.medusa/server/src/api/store/customers/me/subscriptions/[id]/payment-method/route.js +26 -0
  33. package/.medusa/server/src/api/store/customers/me/subscriptions/[id]/payment-methods/route.js +15 -0
  34. package/.medusa/server/src/api/store/customers/me/subscriptions/middlewares.js +8 -1
  35. package/.medusa/server/src/api/store/customers/me/subscriptions/utils.js +72 -1
  36. package/.medusa/server/src/api/store/customers/me/subscriptions/validators.js +7 -3
  37. package/.medusa/server/src/api/store/products/validators.js +2 -2
  38. package/.medusa/server/src/modules/activity-log/__tests__/create-subscription-log-event.spec.js +257 -0
  39. package/.medusa/server/src/modules/activity-log/__tests__/normalize-log-event.spec.js +231 -0
  40. package/.medusa/server/src/modules/activity-log/migrations/Migration20260818120000.js +16 -0
  41. package/.medusa/server/src/modules/activity-log/types/index.js +2 -1
  42. package/.medusa/server/src/modules/analytics/__tests__/admin-query.spec.js +560 -0
  43. package/.medusa/server/src/modules/analytics/index.js +2 -2
  44. package/.medusa/server/src/modules/analytics/utils/admin-query.js +157 -5
  45. package/.medusa/server/src/modules/plan-offer/__tests__/service.spec.js +94 -0
  46. package/.medusa/server/src/modules/renewal/__tests__/service.spec.js +89 -0
  47. package/.medusa/server/src/modules/settings/__tests__/normalize-settings.spec.js +86 -0
  48. package/.medusa/server/src/modules/settings/__tests__/service.spec.js +124 -0
  49. package/.medusa/server/src/modules/subscription/__tests__/payment-methods.spec.js +186 -0
  50. package/.medusa/server/src/modules/subscription/__tests__/service.spec.js +124 -0
  51. package/.medusa/server/src/modules/subscription/utils/admin-query.js +196 -14
  52. package/.medusa/server/src/modules/subscription/utils/payment-methods.js +146 -0
  53. package/.medusa/server/src/workflows/__tests__/cancel-subscription.spec.js +20 -0
  54. package/.medusa/server/src/workflows/__tests__/pause-subscription.spec.js +20 -0
  55. package/.medusa/server/src/workflows/__tests__/update-subscription-shipping-address.spec.js +49 -0
  56. package/.medusa/server/src/workflows/cancel-subscription.js +21 -1
  57. package/.medusa/server/src/workflows/index.js +6 -2
  58. package/.medusa/server/src/workflows/pause-subscription.js +21 -1
  59. package/.medusa/server/src/workflows/steps/rebuild-analytics-daily-snapshots.js +33 -10
  60. package/.medusa/server/src/workflows/steps/update-subscription-payment-method.js +110 -0
  61. package/.medusa/server/src/workflows/steps/validate-subscription-cart.js +7 -22
  62. package/.medusa/server/src/workflows/update-subscription-payment-method.js +65 -0
  63. package/.medusa/server/src/workflows/utils/analytics-incremental.js +1 -1
  64. package/README.md +89 -36
  65. package/package.json +25 -23
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ const ADMIN_EMAIL = process.env.ADMIN_EMAIL ?? "admin@medusa-test.com";
5
+ const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD ?? "supersecret";
6
+ const AUTH_FILE = "e2e/.auth/admin.json";
7
+ (0, test_1.test)("authenticate as admin", async ({ page }) => {
8
+ await page.goto("/app/login");
9
+ // Medusa Admin login form: "Email" label, unlabeled password field,
10
+ // and "Continue with Email" button
11
+ await page.getByRole("textbox", { name: "Email" }).fill(ADMIN_EMAIL);
12
+ // Password field is the second textbox (no accessible name)
13
+ const passwordField = page.getByRole("textbox").nth(1);
14
+ await passwordField.fill(ADMIN_PASSWORD);
15
+ await page
16
+ .getByRole("button", { name: /continue with email/i })
17
+ .click();
18
+ // Wait for redirect to dashboard after successful login
19
+ await (0, test_1.expect)(page).toHaveURL(/\/app/, { timeout: 15_000 });
20
+ // Ensure the sidebar has loaded (proves the session is valid)
21
+ await (0, test_1.expect)(page.getByRole("navigation").first()).toBeVisible({
22
+ timeout: 10_000,
23
+ });
24
+ await page.context().storageState({ path: AUTH_FILE });
25
+ });
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5zZXR1cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2UyZS9hdXRoLnNldHVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsMkNBQXlEO0FBRXpELE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxJQUFJLHVCQUF1QixDQUFDO0FBQ3ZFLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLGFBQWEsQ0FBQztBQUNuRSxNQUFNLFNBQVMsR0FBRyxzQkFBc0IsQ0FBQztBQUV6QyxJQUFBLFdBQUssRUFBQyx1QkFBdUIsRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO0lBQ2hELE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUU5QixvRUFBb0U7SUFDcEUsbUNBQW1DO0lBQ25DLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFFckUsNERBQTREO0lBQzVELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3ZELE1BQU0sYUFBYSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUV6QyxNQUFNLElBQUk7U0FDUCxTQUFTLENBQUMsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLHNCQUFzQixFQUFFLENBQUM7U0FDckQsS0FBSyxFQUFFLENBQUM7SUFFWCx3REFBd0Q7SUFDeEQsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFFM0QsOERBQThEO0lBQzlELE1BQU0sSUFBQSxhQUFNLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLFdBQVcsQ0FBQztRQUM3RCxPQUFPLEVBQUUsTUFBTTtLQUNoQixDQUFDLENBQUM7SUFFSCxNQUFNLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxZQUFZLENBQUMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztBQUN6RCxDQUFDLENBQUMsQ0FBQyJ9
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const child_process_1 = require("child_process");
4
+ const test_1 = require("@playwright/test");
5
+ const CancellationCaseDetailPage_1 = require("./pages/CancellationCaseDetailPage");
6
+ const CancellationsListPage_1 = require("./pages/CancellationsListPage");
7
+ const SubscriptionDetailPage_1 = require("./pages/SubscriptionDetailPage");
8
+ const DB_URL = process.env.DATABASE_URL ??
9
+ "postgres://postgres:Kasperski1@localhost/medusa-my-medusa-store";
10
+ function seedActiveCancellationCase() {
11
+ const timestamp = Date.now();
12
+ const subscriptionId = `sub_e2e_cancellation_${timestamp}`;
13
+ const cancellationCaseId = `case_e2e_cancellation_${timestamp}`;
14
+ const reference = `SUB-E2E-CANCELLATION-${timestamp}`;
15
+ const now = new Date().toISOString();
16
+ const nextRenewalAt = new Date(timestamp + 30 * 24 * 60 * 60 * 1000).toISOString();
17
+ const sql = [
18
+ "INSERT INTO subscription (",
19
+ " id, reference, status,",
20
+ " customer_id, cart_id, product_id, variant_id,",
21
+ " frequency_interval, frequency_value,",
22
+ " started_at, next_renewal_at,",
23
+ " skip_next_cycle, is_trial,",
24
+ " customer_snapshot, product_snapshot, pricing_snapshot,",
25
+ " shipping_address, payment_context,",
26
+ " created_at, updated_at",
27
+ ") VALUES (",
28
+ ` '${subscriptionId}', '${reference}', 'active',`,
29
+ ` 'cus_e2e_cancellation_${timestamp}', 'cart_e2e_cancellation_${timestamp}',`,
30
+ ` 'prod_e2e_cancellation_${timestamp}', 'variant_e2e_cancellation_${timestamp}',`,
31
+ " 'month', 1,",
32
+ ` '${now}', '${nextRenewalAt}',`,
33
+ " false, false,",
34
+ ` '{"email":"e2e-cancellation@test.com","full_name":"E2E Cancellation Test"}'::jsonb,`,
35
+ ` '{"product_id":"prod_e2e_cancellation","product_title":"E2E Cancellation Product","variant_id":"var_e2e_cancellation","variant_title":"Default","sku":"E2E-SKU-CANCELLATION"}'::jsonb,`,
36
+ ` '{"discount_type":"percentage","discount_value":0,"label":null}'::jsonb,`,
37
+ ` '{"first_name":"E2E","last_name":"Cancellation","address_1":"Test St 1","city":"Warsaw","postal_code":"00-001","country_code":"PL"}'::jsonb,`,
38
+ ` '{"payment_provider_id":"pp_stripe_stripe"}'::jsonb,`,
39
+ ` '${now}', '${now}'`,
40
+ ");",
41
+ "INSERT INTO cancellation_case (",
42
+ " id, subscription_id, status, reason, reason_category, metadata,",
43
+ " created_at, updated_at",
44
+ ") VALUES (",
45
+ ` '${cancellationCaseId}', '${subscriptionId}', 'requested',`,
46
+ " 'Customer requested cancellation', 'price', '{}'::jsonb,",
47
+ ` '${now}', '${now}'`,
48
+ ");",
49
+ ].join(" ");
50
+ (0, child_process_1.execFileSync)("psql", [DB_URL, "-c", sql], { stdio: "pipe" });
51
+ return { cancellationCaseId, reference, subscriptionId };
52
+ }
53
+ test_1.test.describe("Cancellation & Retention", () => {
54
+ let cancellationDetailPage;
55
+ let cancellationsListPage;
56
+ let subscriptionDetailPage;
57
+ test_1.test.beforeEach(async ({ page }) => {
58
+ cancellationDetailPage = new CancellationCaseDetailPage_1.CancellationCaseDetailPage(page);
59
+ cancellationsListPage = new CancellationsListPage_1.CancellationsListPage(page);
60
+ subscriptionDetailPage = new SubscriptionDetailPage_1.SubscriptionDetailPage(page);
61
+ });
62
+ (0, test_1.test)("applies a pause retention offer to an active case", async ({ page }) => {
63
+ const seededCase = seedActiveCancellationCase();
64
+ await cancellationsListPage.goto();
65
+ await cancellationsListPage.openCase(seededCase.reference);
66
+ await cancellationDetailPage.waitForLoaded();
67
+ await cancellationDetailPage.expectCaseStatus("Requested");
68
+ const applyOfferResponsePromise = page.waitForResponse((response) => response.url().includes(`/admin/cancellations/${seededCase.cancellationCaseId}/apply-offer`) && response.request().method() === "POST");
69
+ await cancellationDetailPage.openActionMenu();
70
+ await cancellationDetailPage.openApplyRetentionOffer();
71
+ await cancellationDetailPage.selectPauseOffer();
72
+ await cancellationDetailPage.fillPauseCycles("2");
73
+ await cancellationDetailPage.submitDrawer("Apply offer");
74
+ await cancellationDetailPage.confirmPrompt("Apply pause offer");
75
+ const applyOfferResponse = await applyOfferResponsePromise;
76
+ const applyOfferBody = await applyOfferResponse.json();
77
+ (0, test_1.expect)(applyOfferResponse.status(), `Failed with ${JSON.stringify(applyOfferBody)}`).toBe(200);
78
+ (0, test_1.expect)(applyOfferResponse.request().postDataJSON()).toMatchObject({
79
+ offer_type: "pause_offer",
80
+ offer_payload: {
81
+ pause_offer: {
82
+ pause_cycles: 2,
83
+ resume_at: null,
84
+ },
85
+ },
86
+ });
87
+ (0, test_1.expect)(applyOfferBody.cancellation).toMatchObject({
88
+ id: seededCase.cancellationCaseId,
89
+ status: "paused",
90
+ final_outcome: "paused",
91
+ });
92
+ await cancellationDetailPage.expectToast("Retention offer applied");
93
+ await (0, test_1.expect)(cancellationDetailPage.drawer).toBeHidden();
94
+ await cancellationDetailPage.expectCaseStatus("Paused");
95
+ await subscriptionDetailPage.goto(seededCase.subscriptionId);
96
+ await subscriptionDetailPage.expectStatus("Paused");
97
+ });
98
+ (0, test_1.test)("finalizes cancellation when retention is rejected", async ({ page }) => {
99
+ const seededCase = seedActiveCancellationCase();
100
+ const reason = "Customer declined every retention option";
101
+ await cancellationsListPage.goto();
102
+ await cancellationsListPage.openCase(seededCase.reference);
103
+ await cancellationDetailPage.waitForLoaded();
104
+ await cancellationDetailPage.expectCaseStatus("Requested");
105
+ const finalizeResponsePromise = page.waitForResponse((response) => response.url().includes(`/admin/cancellations/${seededCase.cancellationCaseId}/finalize`) && response.request().method() === "POST");
106
+ await cancellationDetailPage.openActionMenu();
107
+ await cancellationDetailPage.openFinalizeCancellation();
108
+ await cancellationDetailPage.fillFinalizeReason(reason);
109
+ await cancellationDetailPage.selectFinalizeReasonCategory("Price");
110
+ await cancellationDetailPage.submitDrawer("Continue");
111
+ await cancellationDetailPage.confirmPrompt("Finalize cancellation");
112
+ const finalizeResponse = await finalizeResponsePromise;
113
+ const finalizeBody = await finalizeResponse.json();
114
+ (0, test_1.expect)(finalizeResponse.status(), `Failed with ${JSON.stringify(finalizeBody)}`).toBe(200);
115
+ (0, test_1.expect)(finalizeResponse.request().postDataJSON()).toMatchObject({
116
+ reason,
117
+ reason_category: "price",
118
+ });
119
+ (0, test_1.expect)(finalizeBody.cancellation).toMatchObject({
120
+ id: seededCase.cancellationCaseId,
121
+ status: "canceled",
122
+ final_outcome: "canceled",
123
+ });
124
+ await cancellationDetailPage.expectToast("Cancellation finalized");
125
+ await (0, test_1.expect)(cancellationDetailPage.drawer).toBeHidden();
126
+ await cancellationDetailPage.expectCaseStatus("Canceled");
127
+ await cancellationsListPage.goto();
128
+ await cancellationsListPage.expectCaseOutcome(seededCase.reference, "Canceled");
129
+ await subscriptionDetailPage.goto(seededCase.subscriptionId);
130
+ await subscriptionDetailPage.expectStatus("Cancelled");
131
+ });
132
+ });
133
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FuY2VsbGF0aW9uLXJldGVudGlvbi5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vZTJlL2NhbmNlbGxhdGlvbi1yZXRlbnRpb24uc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGlEQUE2QztBQUM3QywyQ0FBZ0Q7QUFDaEQsbUZBQWdGO0FBQ2hGLHlFQUFzRTtBQUN0RSwyRUFBd0U7QUFFeEUsTUFBTSxNQUFNLEdBQ1YsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZO0lBQ3hCLGlFQUFpRSxDQUFDO0FBUXBFLFNBQVMsMEJBQTBCO0lBQ2pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUM3QixNQUFNLGNBQWMsR0FBRyx3QkFBd0IsU0FBUyxFQUFFLENBQUM7SUFDM0QsTUFBTSxrQkFBa0IsR0FBRyx5QkFBeUIsU0FBUyxFQUFFLENBQUM7SUFDaEUsTUFBTSxTQUFTLEdBQUcsd0JBQXdCLFNBQVMsRUFBRSxDQUFDO0lBQ3RELE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDckMsTUFBTSxhQUFhLEdBQUcsSUFBSSxJQUFJLENBQzVCLFNBQVMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUNyQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBRWhCLE1BQU0sR0FBRyxHQUFHO1FBQ1YsNEJBQTRCO1FBQzVCLDBCQUEwQjtRQUMxQixpREFBaUQ7UUFDakQsd0NBQXdDO1FBQ3hDLGdDQUFnQztRQUNoQyw4QkFBOEI7UUFDOUIsMERBQTBEO1FBQzFELHNDQUFzQztRQUN0QywwQkFBMEI7UUFDMUIsWUFBWTtRQUNaLE1BQU0sY0FBYyxPQUFPLFNBQVMsY0FBYztRQUNsRCwyQkFBMkIsU0FBUyw2QkFBNkIsU0FBUyxJQUFJO1FBQzlFLDRCQUE0QixTQUFTLGdDQUFnQyxTQUFTLElBQUk7UUFD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
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CancellationCaseDetailPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class CancellationCaseDetailPage {
6
+ constructor(page) {
7
+ this.page = page;
8
+ this.heading = page.getByRole("heading", { level: 1 });
9
+ const headerActions = page
10
+ .locator("div.flex.items-center.gap-x-2")
11
+ .first();
12
+ this.statusBadge = headerActions.locator("span").first();
13
+ this.actionMenuTrigger = headerActions.getByRole("button");
14
+ this.drawer = page.getByRole("dialog");
15
+ }
16
+ async waitForLoaded() {
17
+ await (0, test_1.expect)(this.heading).toBeVisible({ timeout: 15_000 });
18
+ }
19
+ async expectCaseStatus(status) {
20
+ await (0, test_1.expect)(this.statusBadge).toContainText(status, { timeout: 10_000 });
21
+ }
22
+ async openActionMenu() {
23
+ await this.actionMenuTrigger.click();
24
+ await (0, test_1.expect)(this.page.getByRole("menu")).toBeVisible({ timeout: 5_000 });
25
+ }
26
+ async openApplyRetentionOffer() {
27
+ await this.page
28
+ .getByRole("menuitem", { name: "Apply retention offer" })
29
+ .click();
30
+ await (0, test_1.expect)(this.drawer.getByRole("heading", { name: "Apply retention offer" })).toBeVisible();
31
+ }
32
+ async openFinalizeCancellation() {
33
+ await this.page
34
+ .getByRole("menuitem", { name: "Finalize cancellation" })
35
+ .click();
36
+ await (0, test_1.expect)(this.drawer.getByRole("heading", { name: "Finalize cancellation" })).toBeVisible();
37
+ }
38
+ async selectPauseOffer() {
39
+ await this.page.locator("#offer-type").click();
40
+ await this.page.getByRole("option", { name: "Pause offer" }).click();
41
+ }
42
+ async fillPauseCycles(cycles) {
43
+ await this.page.locator("#pause-cycles").fill(cycles);
44
+ }
45
+ async fillFinalizeReason(reason) {
46
+ await this.page.locator("#finalize-reason").fill(reason);
47
+ }
48
+ async selectFinalizeReasonCategory(category) {
49
+ await this.page.locator("#finalize-reason-category").click();
50
+ await this.page.getByRole("option", { name: category }).click();
51
+ }
52
+ async submitDrawer(buttonName) {
53
+ await this.drawer.getByRole("button", { name: buttonName, exact: true }).click();
54
+ }
55
+ async confirmPrompt(confirmText) {
56
+ const prompt = this.page.getByRole("alertdialog", {
57
+ name: new RegExp(`^${confirmText}\\?$`),
58
+ });
59
+ await (0, test_1.expect)(prompt).toBeVisible({ timeout: 5_000 });
60
+ await prompt
61
+ .getByRole("button", { name: confirmText, exact: true })
62
+ .click();
63
+ }
64
+ async expectToast(text) {
65
+ await (0, test_1.expect)(this.page.getByText(text)).toBeVisible({ timeout: 10_000 });
66
+ }
67
+ }
68
+ exports.CancellationCaseDetailPage = CancellationCaseDetailPage;
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FuY2VsbGF0aW9uQ2FzZURldGFpbFBhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9lMmUvcGFnZXMvQ2FuY2VsbGF0aW9uQ2FzZURldGFpbFBhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMkNBQXlEO0FBVXpELE1BQWEsMEJBQTBCO0lBT3JDLFlBQVksSUFBVTtRQUNwQixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFdkQsTUFBTSxhQUFhLEdBQUcsSUFBSTthQUN2QixPQUFPLENBQUMsK0JBQStCLENBQUM7YUFDeEMsS0FBSyxFQUFFLENBQUM7UUFDWCxJQUFJLENBQUMsV0FBVyxHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDekQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLGFBQWEsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRCxLQUFLLENBQUMsYUFBYTtRQUNqQixNQUFNLElBQUEsYUFBTSxFQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLENBQUMsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQsS0FBSyxDQUFDLGdCQUFnQixDQUFDLE1BQThCO1FBQ25ELE1BQU0sSUFBQSxhQUFNLEVBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM1RSxDQUFDO0lBRUQs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
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CancellationsListPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class CancellationsListPage {
6
+ constructor(page) {
7
+ this.page = page;
8
+ this.heading = page.getByRole("heading", {
9
+ name: "Cancellation & Retention",
10
+ });
11
+ this.searchInput = page.getByPlaceholder("Search");
12
+ }
13
+ async goto() {
14
+ await this.page.goto("/app/subscriptions/cancellations");
15
+ await (0, test_1.expect)(this.heading).toBeVisible({ timeout: 15_000 });
16
+ }
17
+ getCaseRow(reference) {
18
+ return this.page.getByRole("row").filter({ hasText: reference });
19
+ }
20
+ async openCase(reference) {
21
+ await this.searchInput.fill(reference);
22
+ const row = this.getCaseRow(reference);
23
+ await (0, test_1.expect)(row).toBeVisible({ timeout: 10_000 });
24
+ await row.click();
25
+ }
26
+ async expectCaseOutcome(reference, outcome) {
27
+ await this.searchInput.fill(reference);
28
+ await (0, test_1.expect)(this.getCaseRow(reference)).toContainText(outcome, {
29
+ timeout: 10_000,
30
+ });
31
+ }
32
+ }
33
+ exports.CancellationsListPage = CancellationsListPage;
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FuY2VsbGF0aW9uc0xpc3RQYWdlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vZTJlL3BhZ2VzL0NhbmNlbGxhdGlvbnNMaXN0UGFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwyQ0FBeUQ7QUFFekQsTUFBYSxxQkFBcUI7SUFLaEMsWUFBWSxJQUFVO1FBQ3BCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUU7WUFDdkMsSUFBSSxFQUFFLDBCQUEwQjtTQUNqQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUk7UUFDUixNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxDQUFDLENBQUM7UUFDekQsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsV0FBVyxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVELFVBQVUsQ0FBQyxTQUFpQjtRQUMxQixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBQ25FLENBQUM7SUFFRCxLQUFLLENBQUMsUUFBUSxDQUFDLFNBQWlCO1FBQzlCLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFdkMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN2QyxNQUFNLElBQUEsYUFBTSxFQUFDLEdBQUcsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELE1BQU0sR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3BCLENBQUM7SUFFRCxLQUFLLENBQUMsaUJBQWlCLENBQ3JCLFNBQWlCLEVBQ2pCLE9BQTJDO1FBRTNDLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDdkMsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRTtZQUM5RCxPQUFPLEVBQUUsTUFBTTtTQUNoQixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUF2Q0Qsc0RBdUNDIn0=
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PlanFormPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class PlanFormPage {
6
+ constructor(page) {
7
+ this.page = page;
8
+ // Page list actions
9
+ this.createPlanButton = page.getByRole("button", { name: "Create" }).filter({ hasText: "Create" });
10
+ // Form fields
11
+ this.nameInput = page.getByRole("textbox", { name: /name/i }).first(); // id="create-name"
12
+ this.scopeSelectTrigger = page.getByRole("combobox", { name: /scope/i }).first();
13
+ // The "Select" or "Change" button for the product selection is the first secondary button in the product section.
14
+ // Let's use a more robust locator based on the Text "Product" above it.
15
+ this.selectProductBtn = page.locator("div.grid.gap-3.rounded-lg").filter({ hasText: "Product" }).getByRole("button", { name: /Select|Change/i }).first();
16
+ // Product picker modal
17
+ this.productSearchInput = page.getByPlaceholder(/Search products/i);
18
+ this.productModalApplyBtn = page.getByRole("button", { name: "Apply" });
19
+ // Frequencies section
20
+ this.addFrequencyBtn = page.getByRole("button", { name: "Add frequency" });
21
+ // Save/Submit
22
+ // It's in the modal header
23
+ this.createSaveBtn = page.getByRole("button", { name: "Create" }).filter({ hasText: "Create" }).last(); // the modal action
24
+ }
25
+ async goto() {
26
+ await this.page.goto("/app/subscriptions/plans-offers");
27
+ await (0, test_1.expect)(this.page.getByRole("heading", { name: "Plans & Offers" })).toBeVisible({ timeout: 15_000 });
28
+ }
29
+ async openCreateModal() {
30
+ await this.createPlanButton.click();
31
+ await (0, test_1.expect)(this.page.getByRole("heading", { name: "Create plan offer" })).toBeVisible({ timeout: 10_000 });
32
+ }
33
+ async fillName(name) {
34
+ await this.nameInput.fill(name);
35
+ }
36
+ async selectScope(scope) {
37
+ await this.scopeSelectTrigger.click();
38
+ await this.page.getByRole("option", { name: scope }).click();
39
+ }
40
+ async setMinimumCycles(cycles) {
41
+ const minCyclesInput = this.page.locator('input#minimum-cycles');
42
+ await minCyclesInput.fill(cycles.toString());
43
+ }
44
+ async selectProduct(productTitle) {
45
+ await this.selectProductBtn.click();
46
+ await (0, test_1.expect)(this.page.getByRole("heading", { name: "Select product" })).toBeVisible({ timeout: 5_000 });
47
+ await this.productSearchInput.fill(productTitle);
48
+ // Wait for the row to appear in the table
49
+ const row = this.page.getByRole("row", { name: productTitle }).first();
50
+ await (0, test_1.expect)(row).toBeVisible({ timeout: 10_000 });
51
+ // Click its checkbox
52
+ const checkbox = row.getByRole("checkbox");
53
+ await checkbox.click();
54
+ await this.productModalApplyBtn.click();
55
+ await (0, test_1.expect)(this.page.getByRole("heading", { name: "Select product" })).toBeHidden({ timeout: 5_000 });
56
+ }
57
+ async setFrequencyRow(index, interval, value) {
58
+ const intervalTrigger = this.page.locator('label').filter({ hasText: /^Interval$/ }).nth(index).locator('..').getByRole("combobox");
59
+ await intervalTrigger.click();
60
+ await this.page.getByRole("option", { name: interval }).click();
61
+ const valueInput = this.page.locator('label').filter({ hasText: /^Value$/ }).nth(index).locator('..').getByRole("spinbutton");
62
+ await valueInput.fill(value.toString());
63
+ }
64
+ async setDiscount(index, discountType, discountValue) {
65
+ // The switch for discount
66
+ // It might be in a parent div that contains "Discount for this frequency" text
67
+ const discountContainer = this.page.locator('div.flex.items-center.justify-between.rounded-lg').filter({ hasText: "Discount for this frequency" }).nth(index);
68
+ const discountSwitch = discountContainer.getByRole("switch");
69
+ const isChecked = await discountSwitch.getAttribute("aria-checked");
70
+ if (isChecked !== "true") {
71
+ await discountSwitch.click();
72
+ }
73
+ // Now type and value appear
74
+ const typeTrigger = this.page.locator('label').filter({ hasText: "Discount type" }).nth(index).locator('..').getByRole("combobox");
75
+ await typeTrigger.click();
76
+ await this.page.getByRole("option", { name: discountType }).click();
77
+ const dValueInput = this.page.locator('label').filter({ hasText: "Discount value" }).nth(index).locator('..').getByRole("spinbutton");
78
+ await dValueInput.fill(discountValue.toString());
79
+ }
80
+ async submit() {
81
+ // Because the "Create" button is the submit button for the form.
82
+ // Note: The form header might have two 'Create' buttons if we aren't careful.
83
+ // Let's use the one in the FocusModal.Header that has type="submit".
84
+ const submitBtn = this.page.locator("form").getByRole("button", { name: "Create" });
85
+ await submitBtn.click();
86
+ }
87
+ }
88
+ exports.PlanFormPage = PlanFormPage;
89
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxhbkZvcm1QYWdlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vZTJlL3BhZ2VzL1BsYW5Gb3JtUGFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwyQ0FBeUQ7QUFFekQsTUFBYSxZQUFZO0lBaUJ2QixZQUFZLElBQVU7UUFDcEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFFakIsb0JBQW9CO1FBQ3BCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBRW5HLGNBQWM7UUFDZCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxtQkFBbUI7UUFDMUYsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFakYsa0hBQWtIO1FBQ2xILHdFQUF3RTtRQUN4RSxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQywyQkFBMkIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRXpKLHVCQUF1QjtRQUN2QixJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDcEUsSUFBSSxD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
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RenewalDetailPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class RenewalDetailPage {
6
+ constructor(page) {
7
+ this.page = page;
8
+ // Header
9
+ this.heading = page.getByRole("heading", { level: 1 });
10
+ // Look for the flex container holding header actions (status badge + dropdown)
11
+ const headerActions = page.locator("div.flex.items-center.gap-x-2").first();
12
+ this.statusBadge = headerActions.locator("span").first();
13
+ this.actionMenuTrigger = headerActions.locator("button").last();
14
+ }
15
+ /** Navigate directly to the renewal detail page by cycle ID */
16
+ async goto(renewalCycleId) {
17
+ await this.page.goto(`/app/subscriptions/renewals/${renewalCycleId}`);
18
+ }
19
+ /** Navigate via the renewals queue — search for a subscription reference, click matching row */
20
+ async gotoFromQueue(subscriptionReference) {
21
+ await this.page.goto("/app/subscriptions/renewals");
22
+ await (0, test_1.expect)(this.page.getByRole("heading", { name: "Renewals" })).toBeVisible({ timeout: 15_000 });
23
+ const searchInput = this.page.getByPlaceholder(/search/i);
24
+ await searchInput.fill(subscriptionReference);
25
+ await this.page.keyboard.press("Enter");
26
+ // Wait for the table to filter (crude but effective: check row content)
27
+ await this.page.waitForTimeout(1000);
28
+ const row = this.page
29
+ .getByRole("row", { name: new RegExp(subscriptionReference, "i") })
30
+ .first();
31
+ await row.click();
32
+ }
33
+ /** Wait for the detail page to fully load (heading "Renewal cycle" visible) */
34
+ async waitForLoaded() {
35
+ await (0, test_1.expect)(this.page.getByText("Renewal cycle", { exact: true })).toBeVisible({ timeout: 15_000 });
36
+ }
37
+ /** Return the current cycle status text from the header StatusBadge */
38
+ async getCycleStatusText() {
39
+ const text = await this.statusBadge.textContent();
40
+ return text?.trim() ?? "";
41
+ }
42
+ /** Assert the header StatusBadge shows the expected cycle status */
43
+ async expectCycleStatus(status) {
44
+ await (0, test_1.expect)(this.statusBadge).toContainText(status, { timeout: 10_000 });
45
+ }
46
+ /** Open the action dropdown (EllipsisHorizontal icon button) */
47
+ async openActionMenu() {
48
+ await this.actionMenuTrigger.click();
49
+ }
50
+ /** Click "Force renewal" in the open dropdown menu */
51
+ async clickForceRenewal() {
52
+ await this.page.getByRole("menuitem", { name: "Force renewal" }).click();
53
+ }
54
+ /** Click "Approve changes" in the open dropdown menu */
55
+ async clickApproveChanges() {
56
+ await this.page.getByRole("menuitem", { name: "Approve changes" }).click();
57
+ }
58
+ /** Click "Reject changes" in the open dropdown menu */
59
+ async clickRejectChanges() {
60
+ await this.page.getByRole("menuitem", { name: "Reject changes" }).click();
61
+ }
62
+ /** Confirm the Medusa usePrompt confirmation dialog by clicking the confirm button */
63
+ async confirmPrompt(confirmText) {
64
+ await this.page
65
+ .getByRole("button", { name: confirmText, exact: true })
66
+ .click();
67
+ }
68
+ /** Assert a toast notification with the given text appears */
69
+ async expectToast(text) {
70
+ await (0, test_1.expect)(this.page.getByText(text)).toBeVisible({ timeout: 10_000 });
71
+ }
72
+ /** Fill the reason textarea in the approval/rejection Drawer */
73
+ async fillDecisionReason(reason) {
74
+ const textarea = this.page
75
+ .locator("#decision-reason")
76
+ .or(this.page.getByLabel("Reason"));
77
+ await textarea.fill(reason);
78
+ }
79
+ /** Click the submit button ("Approve" or "Reject") in the decision Drawer footer */
80
+ async submitDecision(buttonText) {
81
+ const dialog = this.page.getByRole("dialog");
82
+ await dialog.getByRole("button", { name: buttonText, exact: true }).click();
83
+ }
84
+ /** Assert the Approval summary section shows the expected approval status badge */
85
+ async expectApprovalStatus(status) {
86
+ // Look within the Approval summary section
87
+ const section = this.page
88
+ .locator("div", {
89
+ has: this.page.getByRole("heading", { name: "Approval summary" }),
90
+ })
91
+ .first();
92
+ // Use evaluate or generic locator within the section to find the badge
93
+ await (0, test_1.expect)(section).toContainText(status, { timeout: 10_000 });
94
+ }
95
+ /** Assert a row exists in the Attempt history table with the given attempt number */
96
+ async expectAttemptRow(attemptNo) {
97
+ await (0, test_1.expect)(this.page.getByText(`#${attemptNo}`, { exact: true })).toBeVisible({ timeout: 10_000 });
98
+ }
99
+ }
100
+ exports.RenewalDetailPage = RenewalDetailPage;
101
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVuZXdhbERldGFpbFBhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9lMmUvcGFnZXMvUmVuZXdhbERldGFpbFBhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMkNBQXlEO0FBRXpELE1BQWEsaUJBQWlCO0lBbUI1QixZQUFZLElBQVU7UUFDcEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFFakIsU0FBUztRQUNULElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUV2RCwrRUFBK0U7UUFDL0UsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQywrQkFBK0IsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzVFLElBQUksQ0FBQyxXQUFXLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN6RCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNsRSxDQUFDO0lBRUQsK0RBQStEO0lBQy9ELEtBQUssQ0FBQyxJQUFJLENBQUMsY0FBc0I7UUFDL0IsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQywrQkFBK0IsY0FBYyxFQUFFLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQsZ0dBQWdHO0lBQ2hHLEtBQUssQ0FBQyxhQUFhLENBQUMscUJBQTZCO1FBQy9DLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsNkJBQTZCLENBQUMsQ0FBQztRQUNwRCxNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQyxD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
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SubscriptionDetailPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class SubscriptionDetailPage {
6
+ constructor(page) {
7
+ this.page = page;
8
+ // The h1 heading contains the subscription reference (e.g. "SUB-01J…")
9
+ this.heading = page.getByRole("heading", { name: /SUB-/ });
10
+ // StatusBadge sits in the header flex row, to the left of the action trigger.
11
+ // It is the only element containing the status text next to the icon button.
12
+ this.statusBadge = page
13
+ .locator("div.flex.items-center.gap-x-2")
14
+ .first()
15
+ .locator("span")
16
+ .first();
17
+ // The IconButton that triggers the DropdownMenu — the last button in the
18
+ // header actions area (the only transparent icon button there).
19
+ this.actionMenuTrigger = page
20
+ .locator("div.flex.items-center.gap-x-2")
21
+ .first()
22
+ .getByRole("button");
23
+ }
24
+ /** Navigate directly to the subscription detail page by ID. */
25
+ async goto(subscriptionId) {
26
+ await this.page.goto(`/app/subscriptions/${subscriptionId}`);
27
+ await this.waitForLoaded();
28
+ }
29
+ /**
30
+ * Navigate via the list page — searches for `reference` and clicks the
31
+ * matching row.
32
+ */
33
+ async gotoFromList(reference) {
34
+ await this.page.goto("/app/subscriptions");
35
+ await (0, test_1.expect)(this.page.getByRole("heading", { name: "Subscriptions" })).toBeVisible({ timeout: 15_000 });
36
+ // Search for the specific reference
37
+ const searchInput = this.page.getByPlaceholder(/search/i);
38
+ await searchInput.fill(reference);
39
+ // Wait for the row matching this reference to appear and click it
40
+ const matchingRow = this.page.getByRole("row", { name: reference });
41
+ await (0, test_1.expect)(matchingRow).toBeVisible({ timeout: 10_000 });
42
+ await matchingRow.click();
43
+ await this.waitForLoaded();
44
+ }
45
+ /** Wait for the detail page to fully load (heading visible). */
46
+ async waitForLoaded() {
47
+ await (0, test_1.expect)(this.heading).toBeVisible({ timeout: 15_000 });
48
+ }
49
+ /** Return the current status text from the header StatusBadge. */
50
+ async getStatusText() {
51
+ // The StatusBadge in the header: locate it via the container that holds
52
+ // both the badge and the action button.
53
+ const badge = this.page
54
+ .locator("div.flex.items-start.justify-between")
55
+ .getByText(/^(Active|Paused|Cancelled|Past due)$/i)
56
+ .first();
57
+ return (await badge.textContent()) ?? "";
58
+ }
59
+ /** Assert the header StatusBadge shows the expected status. */
60
+ async expectStatus(status) {
61
+ const badge = this.page
62
+ .locator("div.flex.items-start.justify-between")
63
+ .getByText(status)
64
+ .first();
65
+ await (0, test_1.expect)(badge).toBeVisible({ timeout: 10_000 });
66
+ }
67
+ /** Open the action dropdown (EllipsisHorizontal icon button). */
68
+ async openActionMenu() {
69
+ await this.actionMenuTrigger.click();
70
+ await (0, test_1.expect)(this.page.getByRole("menu")).toBeVisible({ timeout: 5_000 });
71
+ }
72
+ /** Click a named action in the open dropdown menu. */
73
+ async clickAction(name) {
74
+ await this.page.getByRole("menuitem", { name }).click();
75
+ }
76
+ /**
77
+ * Confirm the Medusa usePrompt confirmation dialog by clicking the button
78
+ * whose text exactly matches `confirmText`.
79
+ */
80
+ async confirmPrompt(confirmText) {
81
+ // Medusa usePrompt uses Radix AlertDialog which renders as role="alertdialog"
82
+ const dialog = this.page.locator('[role="dialog"], [role="alertdialog"]');
83
+ await (0, test_1.expect)(dialog).toBeVisible({ timeout: 5_000 });
84
+ await dialog.getByRole("button", { name: confirmText, exact: true }).click();
85
+ }
86
+ /** Assert a toast notification containing `text` appears. */
87
+ async expectToast(text) {
88
+ await (0, test_1.expect)(this.page.getByText(text)).toBeVisible({ timeout: 10_000 });
89
+ }
90
+ /**
91
+ * Full action flow: open menu → click action → confirm prompt → wait for
92
+ * toast.
93
+ */
94
+ async executeAction(action, confirmText, toastText) {
95
+ await this.openActionMenu();
96
+ await this.clickAction(action);
97
+ await this.confirmPrompt(confirmText);
98
+ await this.expectToast(toastText);
99
+ }
100
+ }
101
+ exports.SubscriptionDetailPage = SubscriptionDetailPage;
102
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3Vic2NyaXB0aW9uRGV0YWlsUGFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2UyZS9wYWdlcy9TdWJzY3JpcHRpb25EZXRhaWxQYWdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF5RDtBQUV6RCxNQUFhLHNCQUFzQjtJQVFqQyxZQUFZLElBQVU7UUFDcEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFFakIsdUVBQXVFO1FBQ3ZFLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUUzRCw4RUFBOEU7UUFDOUUsNkVBQTZFO1FBQzdFLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSTthQUNwQixPQUFPLENBQUMsK0JBQStCLENBQUM7YUFDeEMsS0FBSyxFQUFFO2FBQ1AsT0FBTyxDQUFDLE1BQU0sQ0FBQzthQUNmLEtBQUssRUFBRSxDQUFDO1FBRVgseUVBQXlFO1FBQ3pFLGdFQUFnRTtRQUNoRSxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSTthQUMxQixPQUFPLENBQUMsK0JBQStCLENBQUM7YUFDeEMsS0FBSyxFQUFFO2FBQ1AsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFFRCwrREFBK0Q7SUFDL0QsS0FBSyxDQUFDLElBQUksQ0FBQyxjQUFzQjtRQUMvQixNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLHNCQUFzQixjQUFjLEVBQUUsQ0FBQyxDQUFDO1FBQzdELE1BQU0sSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsWUFBWSxDQUFDLFNBQWlCO1FBQ2xDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUMzQyxNQUFNLElB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