@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,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ const PlanFormPage_1 = require("./pages/PlanFormPage");
5
+ const BASE_URL = process.env.ADMIN_BASE_URL ?? "http://localhost:9000";
6
+ const ADMIN_EMAIL = process.env.ADMIN_EMAIL ?? "admin@medusa-test.com";
7
+ const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD ?? "supersecret";
8
+ test_1.test.describe("Plans & Offers - Subscription Plan Creation", () => {
9
+ let seededProductId;
10
+ let seededProductTitle;
11
+ test_1.test.beforeEach(async ({ page }) => {
12
+ const api = await test_1.request.newContext({ baseURL: BASE_URL });
13
+ // 1. Authenticate to get a JWT
14
+ const authRes = await api.post("/auth/user/emailpass", {
15
+ data: { email: ADMIN_EMAIL, password: ADMIN_PASSWORD },
16
+ });
17
+ (0, test_1.expect)(authRes.ok()).toBeTruthy();
18
+ const { token } = await authRes.json();
19
+ // 2. Seed a test product via Medusa API
20
+ seededProductTitle = `E2E Plan Product ${Date.now()}`;
21
+ const productRes = await api.post("/admin/products", {
22
+ headers: { Authorization: `Bearer ${token}` },
23
+ data: {
24
+ title: seededProductTitle,
25
+ options: [{ title: "Default", values: ["Default"] }],
26
+ variants: [
27
+ {
28
+ title: "Default Variant",
29
+ prices: [{ currency_code: "usd", amount: 1000 }],
30
+ options: { "Default": "Default" }
31
+ }
32
+ ]
33
+ }
34
+ });
35
+ // Sometimes Medusa API requires specific fields, let's keep it minimal but valid.
36
+ // Let's ensure product was created
37
+ (0, test_1.expect)(productRes.ok()).toBeTruthy();
38
+ const productData = await productRes.json();
39
+ seededProductId = productData.product.id;
40
+ await api.dispose();
41
+ });
42
+ (0, test_1.test)("creates a product-level subscription plan successfully", async ({ page }) => {
43
+ const planForm = new PlanFormPage_1.PlanFormPage(page);
44
+ // 1. Setup API Intercept before action
45
+ const apiPromise = page.waitForResponse((response) => response.url().includes("/admin/subscription-offers") && response.request().method() === "POST");
46
+ // 2. Navigate and Open form
47
+ await planForm.goto();
48
+ await planForm.openCreateModal();
49
+ // 3. Fill the form
50
+ const planName = `E2E Plan ${Date.now()}`;
51
+ await planForm.fillName(planName);
52
+ // Default scope is Product in the UI, but we can re-select it
53
+ await planForm.selectScope("Product");
54
+ await planForm.selectProduct(seededProductTitle);
55
+ // 4. Fill frequency row (index 0 is already present by default)
56
+ await planForm.setFrequencyRow(0, "Monthly", 1);
57
+ // 5. Fill discount for frequency row 0
58
+ await planForm.setDiscount(0, "Percentage", 10);
59
+ // 6. Save
60
+ await planForm.submit();
61
+ // 7. Verify API payload
62
+ const response = await apiPromise;
63
+ (0, test_1.expect)(response.ok()).toBeTruthy();
64
+ const requestPayload = response.request().postDataJSON();
65
+ (0, test_1.expect)(requestPayload).toMatchObject({
66
+ name: planName,
67
+ scope: "product",
68
+ product_id: seededProductId,
69
+ allowed_frequencies: [
70
+ {
71
+ interval: "month",
72
+ value: 1
73
+ }
74
+ ],
75
+ discounts: [
76
+ {
77
+ interval: "month",
78
+ frequency_value: 1,
79
+ type: "percentage",
80
+ value: 10
81
+ }
82
+ ],
83
+ });
84
+ // 8. Verify UI Toast
85
+ await (0, test_1.expect)(page.getByText("Plan offer created")).toBeVisible({ timeout: 5_000 });
86
+ // 9. Verify the created plan appears in the table
87
+ // It should navigate back or modal should close, and data table should show the plan name
88
+ await (0, test_1.expect)(page.getByRole("heading", { name: "Create plan offer" })).toBeHidden({ timeout: 5_000 });
89
+ // Search for the plan in the list to ensure it's there
90
+ const searchInput = page.getByPlaceholder(/search/i);
91
+ await searchInput.fill(planName);
92
+ const row = page.getByRole("row", { name: planName });
93
+ await (0, test_1.expect)(row).toBeVisible({ timeout: 10_000 });
94
+ });
95
+ });
96
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhbnMtb2ZmZXJzLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9lMmUvcGxhbnMtb2ZmZXJzLnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQ0FBeUQ7QUFDekQsdURBQW9EO0FBRXBELE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLHVCQUF1QixDQUFDO0FBQ3ZFLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxJQUFJLHVCQUF1QixDQUFDO0FBQ3ZFLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLGFBQWEsQ0FBQztBQUVuRSxXQUFJLENBQUMsUUFBUSxDQUFDLDZDQUE2QyxFQUFFLEdBQUcsRUFBRTtJQUNoRSxJQUFJLGVBQXVCLENBQUM7SUFDNUIsSUFBSSxrQkFBMEIsQ0FBQztJQUUvQixXQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUU7UUFDakMsTUFBTSxHQUFHLEdBQUcsTUFBTSxjQUFPLENBQUMsVUFBVSxDQUFDLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFFNUQsK0JBQStCO1FBQy9CLE1BQU0sT0FBTyxHQUFHLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxzQkFBc0IsRUFBRTtZQUNyRCxJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxjQUFjLEVBQUU7U0FDdkQsQ0FBQyxDQUFDO1FBQ0gsSUFBQSxhQUFNLEVBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDbEMsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO1FBRXZDLHdDQUF3QztRQUN4QyxrQkFBa0IsR0FBRyxvQkFBb0IsSUFBSSxDQUFD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
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ const child_process_1 = require("child_process");
5
+ const RenewalDetailPage_1 = require("./pages/RenewalDetailPage");
6
+ const DB_URL = process.env.DATABASE_URL ??
7
+ "postgres://postgres:Kasperski1@localhost/medusa-my-medusa-store";
8
+ /**
9
+ * Seed a fresh active subscription and linked renewal cycle via psql.
10
+ * Returns the generated reference and cycle ID for navigation.
11
+ */
12
+ function seedSubscriptionWithRenewalCycle(options) {
13
+ const ts = Date.now();
14
+ const subId = `sub_${ts}`;
15
+ const cycleId = `cycle_${ts}`;
16
+ const reference = `SUB-E2E-RENEWAL-${ts}`;
17
+ const now = new Date();
18
+ const nowStr = now.toISOString();
19
+ const futureRenewal = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000).toISOString();
20
+ const pastScheduled = new Date(now.getTime() - 24 * 60 * 60 * 1000).toISOString();
21
+ const cycleStatus = options.cycleStatus || "scheduled";
22
+ const approvalStatusVal = options.approvalStatus
23
+ ? `'${options.approvalStatus}'`
24
+ : "NULL";
25
+ const sql = [
26
+ `INSERT INTO subscription (`,
27
+ ` id, reference, status,`,
28
+ ` customer_id, cart_id, product_id, variant_id,`,
29
+ ` frequency_interval, frequency_value,`,
30
+ ` started_at, next_renewal_at,`,
31
+ ` skip_next_cycle, is_trial,`,
32
+ ` customer_snapshot, product_snapshot, pricing_snapshot,`,
33
+ ` shipping_address, payment_context,`,
34
+ ` created_at, updated_at`,
35
+ `) VALUES (`,
36
+ ` '${subId}', '${reference}', 'active',`,
37
+ ` 'cus_e2e_renewal_${ts}', 'cart_e2e_renewal_${ts}',`,
38
+ ` 'prod_e2e_renewal_${ts}', 'variant_e2e_renewal_${ts}',`,
39
+ ` 'month', 1,`,
40
+ ` '${nowStr}', '${futureRenewal}',`,
41
+ ` true, false,`,
42
+ ` '{"email":"e2e-renewal@test.com","full_name":"E2E Renewal Test"}'::jsonb,`,
43
+ ` '{"product_id":"prod_e2e","product_title":"E2E Renewal Product","variant_id":"var_e2e","variant_title":"Default","sku":"E2E-SKU-RENEWAL"}'::jsonb,`,
44
+ ` '{"discount_type":"percentage","discount_value":0,"label":null}'::jsonb,`,
45
+ ` '{"first_name":"E2E","last_name":"Renewal","address_1":"Test St 1","city":"Warsaw","postal_code":"00-001","country_code":"PL"}'::jsonb,`,
46
+ ` '{"payment_provider_id":"pp_stripe_stripe"}'::jsonb,`,
47
+ ` '${nowStr}', '${nowStr}'`,
48
+ `);`,
49
+ `INSERT INTO renewal_cycle (`,
50
+ ` id, subscription_id, scheduled_for,`,
51
+ ` status, approval_required, approval_status,`,
52
+ ` attempt_count,`,
53
+ ` created_at, updated_at`,
54
+ `) VALUES (`,
55
+ ` '${cycleId}', '${subId}', '${pastScheduled}',`,
56
+ ` '${cycleStatus}', ${options.approvalRequired}, ${approvalStatusVal},`,
57
+ ` 0,`,
58
+ ` '${nowStr}', '${nowStr}'`,
59
+ `);`,
60
+ ].join(" ");
61
+ (0, child_process_1.execFileSync)("psql", [DB_URL, "-c", sql], { stdio: "pipe" });
62
+ return { reference, cycleId };
63
+ }
64
+ test_1.test.describe("Renewal force execution & approval", () => {
65
+ let detailPage;
66
+ test_1.test.beforeEach(async ({ page }) => {
67
+ detailPage = new RenewalDetailPage_1.RenewalDetailPage(page);
68
+ // Login flow is handled globally via Playwright setup/auth state in this repo.
69
+ });
70
+ (0, test_1.test)("forces a scheduled renewal cycle", async ({ page }) => {
71
+ // 1. Seed subscription + renewal_cycle (scheduled, no approval)
72
+ const { reference, cycleId } = seedSubscriptionWithRenewalCycle({
73
+ approvalRequired: false,
74
+ approvalStatus: null,
75
+ cycleStatus: "scheduled",
76
+ });
77
+ // 2-6. Navigate via queue and wait for load
78
+ await detailPage.gotoFromQueue(reference);
79
+ await detailPage.waitForLoaded();
80
+ // 7. Assert initial status
81
+ await detailPage.expectCycleStatus("Scheduled");
82
+ // 8. Set up API intercept
83
+ const forceResponsePromise = page.waitForResponse((response) => response.url().includes(`/admin/renewals/${cycleId}/force`) &&
84
+ response.request().method() === "POST");
85
+ // 9-11. Open action dropdown and click Force renewal
86
+ await detailPage.openActionMenu();
87
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Force renewal" })).toBeVisible();
88
+ await detailPage.clickForceRenewal();
89
+ // 12. Confirm prompt
90
+ await detailPage.confirmPrompt("Force renewal");
91
+ // 13. Assert API response 200
92
+ const forceResponse = await forceResponsePromise;
93
+ const responseBody = await forceResponse.json();
94
+ (0, test_1.expect)(forceResponse.status(), `Failed with ${JSON.stringify(responseBody)}`).toBe(200);
95
+ // 14. Assert API response body
96
+ (0, test_1.expect)(responseBody.renewal).toBeDefined();
97
+ (0, test_1.expect)(responseBody.renewal.status).toBeDefined();
98
+ // 15. Assert toast
99
+ await detailPage.expectToast("Renewal forced");
100
+ // 16. Assert StatusBadge updates (wait for it NOT to be Scheduled)
101
+ await (0, test_1.expect)(detailPage.statusBadge).not.toContainText("Scheduled", {
102
+ timeout: 10_000,
103
+ });
104
+ // 17. Assert attempt history shows row #1
105
+ await detailPage.expectAttemptRow(1);
106
+ });
107
+ (0, test_1.test)("approves pending changes on a renewal cycle", async ({ page }) => {
108
+ // 1. Seed subscription + renewal_cycle (approval pending)
109
+ const { reference, cycleId } = seedSubscriptionWithRenewalCycle({
110
+ approvalRequired: true,
111
+ approvalStatus: "pending",
112
+ cycleStatus: "scheduled",
113
+ });
114
+ // 2-4. Navigate via queue and wait for load
115
+ await detailPage.gotoFromQueue(reference);
116
+ await detailPage.waitForLoaded();
117
+ // 5. Assert initial status
118
+ await detailPage.expectCycleStatus("Scheduled");
119
+ // 6-8. Open action dropdown and assert items
120
+ await detailPage.openActionMenu();
121
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Approve changes" })).toBeVisible();
122
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Reject changes" })).toBeVisible();
123
+ // 9-10. Click Approve and check drawer
124
+ await detailPage.clickApproveChanges();
125
+ await (0, test_1.expect)(page.getByRole("heading", { name: "Approve changes" })).toBeVisible();
126
+ // 11. Fill reason
127
+ await detailPage.fillDecisionReason("Approved by E2E test");
128
+ // 12. Set up API intercept
129
+ const approveResponsePromise = page.waitForResponse((response) => response.url().includes(`/admin/renewals/${cycleId}/approve-changes`) &&
130
+ response.request().method() === "POST");
131
+ // 13. Submit drawer
132
+ await detailPage.submitDecision("Approve");
133
+ // 14. Confirm prompt
134
+ await detailPage.confirmPrompt("Approve");
135
+ // 15-16. Assert API response 200 and request payload
136
+ const approveResponse = await approveResponsePromise;
137
+ const approveResponseBody = await approveResponse.json();
138
+ (0, test_1.expect)(approveResponse.status(), `Failed with ${JSON.stringify(approveResponseBody)}`).toBe(200);
139
+ const requestPayload = approveResponse.request().postDataJSON();
140
+ (0, test_1.expect)(requestPayload).toMatchObject({ reason: "Approved by E2E test" });
141
+ // 17. Assert toast
142
+ await detailPage.expectToast("Pending changes approved");
143
+ // 18. Assert drawer closes
144
+ await (0, test_1.expect)(page.getByRole("dialog")).toBeHidden();
145
+ // 19. Assert approval summary
146
+ await detailPage.expectApprovalStatus("Approved");
147
+ // 20-21. Open action dropdown and verify item visibility
148
+ await detailPage.openActionMenu();
149
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Approve changes" })).toBeHidden();
150
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Reject changes" })).toBeHidden();
151
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Force renewal" })).toBeVisible();
152
+ });
153
+ });
154
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuZXdhbC1mb3JjZS5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vZTJlL3JlbmV3YWwtZm9yY2Uuc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDJDQUFnRDtBQUNoRCxpREFBNkM7QUFDN0MsaUVBQThEO0FBRTlELE1BQU0sTUFBTSxHQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWTtJQUN4QixpRUFBaUUsQ0FBQztBQVFwRTs7O0dBR0c7QUFDSCxTQUFTLGdDQUFnQyxDQUFDLE9BQW9CO0lBQzVELE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUN0QixNQUFNLEtBQUssR0FBRyxPQUFPLEVBQUUsRUFBRSxDQUFDO0lBQzFCLE1BQU0sT0FBTyxHQUFHLFNBQVMsRUFBRSxFQUFFLENBQUM7SUFDOUIsTUFBTSxTQUFTLEdBQUcsbUJBQW1CLEVBQUUsRUFBRSxDQUFDO0lBRTFDLE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7SUFDdkIsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBRWpDLE1BQU0sYUFBYSxHQUFHLElBQUksSUFBSSxDQUM1QixHQUFHLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FDekMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNoQixNQUFNLGFBQWEsR0FBRyxJQUFJLElBQUksQ0FDNUIsR0FBRyxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FDcEMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUVoQixNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsV0FBVyxJQUFJLFdBQVcsQ0FBQztJQUN2RCxNQUFNLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxjQUFjO1FBQzlDLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxjQUFjLEdBQUc7UUFDL0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUVYLE1BQU0sR0FBRyxHQUFHO1FBQ1YsNEJBQTRCO1FBQzVCLDBCQUEwQjtRQUMxQixpREFBaUQ7UUFDakQsd0NBQXdDO1FBQ3hDLGdDQUFnQztRQUNoQyw4QkFBOEI7UUFDOUIsMERBQTBEO1FBQzFELHNDQUFzQztRQUN0QywwQkFBMEI7UUFDMUIsWUFBWTtRQUNaLE1BQU0sS0FBSyxPQUFPLFNBQVMsY0FBYztRQUN6QyxzQkFBc0IsRUFBRSx3QkFBd0IsRUFBRSxJQUFJO1FBQ3RELHVCQUF1QixFQUFFLDJCQUEyQixFQUFFLElBQUk7UUFDMUQsZUFBZTtRQUNmLE1BQU0sTUFBTSxPQUFPLGFBQWEsSUFBSTtRQUNwQyxnQkFBZ0I7UUFDaEIsNkVBQTZFO1FBQzdFLHNKQUFzSjtRQUN0Siw0RUFBNEU7UUFDNUUsMklBQTJJO1FBQzNJLHdEQUF3RDtRQUN4RCxNQUFNLE1BQU0sT0FBTyxNQUFNLEdBQUc7UUFDNUIsSUFBSTtRQUVKLDZCQUE2QjtRQUM3Qix1Q0FBdUM7UUFDdkMsK0NBQStDO1FBQy9DLGtCQUFrQjtRQUNsQiwwQkFBMEI7UUFDMUIsWUFBWTtRQUNaLE1BQU0sT0FBTyxPQUFPLEtBQUssT0FBTyxhQUFhLElBQUk7UUFDakQsTUFBTSxXQUFXLE1BQU0sT0FBTyxDQUFDLGdCQUFnQixLQUFLLGlCQUFpQixHQUFHO1FBQ3hFLE1BQU07UUFDTixNQUFNLE1BQU0sT0FBTyxNQUFNLEdBQUc7UUFDNUIsSUFBSTtLQUNMLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRVosSUFBQSw0QkFBWSxFQUFDLE1BQU0sRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM3RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxDQUFDO0FBQ2hDLENBQUM7QUFFRCxXQUFJLENBQUMsUUFBUSxDQUFDLG9DQUFvQyxFQUFFLEdBQUcsRUFBRTtJQUN2RCxJQUFJLFVBQTZCLENBQUM7SUFFbEMsV0FBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1FBQ2pDLFVBQVUsR0FBRyxJQUFJLHFDQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3pDLCtFQUErRTtJQUNqRixDQUFDLENBQUMsQ0FBQztJQUVILElBQUEsV0FBSSxFQUFDLGtDQUFrQyxFQUFFLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUU7UUFDMUQsZ0VBQWdFO1FBQ2hFLE1BQU0sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEdBQUcsZ0NBQWdDLENBQUM7WUFDOUQsZ0JBQWdCLEVBQUUsS0FBSztZQUN2QixjQUFjLEVBQUUsSUFBSTtZQUNwQixXQUFXLEVBQUUsV0FBVztTQUN6QixDQUFDLENBQUM7UUFFSCw0Q0FBNEM7UUFDNUMsTUFBTSxVQUFVLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzFDLE1BQU0sVUFBVSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRWpDLDJCQUEyQjtRQUMzQixNQUFNLFVBQVUsQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVoRCwwQkFBMEI7UUFDMUIsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUMvQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQ1gsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsT0FBTyxRQUFRLENBQUM7WUFDM0QsUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDLE1BQU0sRUFBRSxLQUFLLE1BQU0sQ0FDekMsQ0FBQztRQUVGLHFEQUFxRDtRQUNyRCxNQUFNLFVBQVUsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNsQyxNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLGVBQWUsRUFBRSxDQUFDLENBQ3RELENBQUMsV0FBVyxFQUFFLENBQUM7UUFDaEIsTUFBTSxVQUFVLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUVyQyxxQkFBcUI7UUFDckIsTUFBTSxVQUFVLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBRWhELDhCQUE4QjtRQUM5QixNQUFNLGFBQWEsR0FBRyxNQUFNLG9CQUFvQixDQUFDO1FBQ2pELE1BQU0sWUFBWSxHQUFHLE1BQU0sYUFBYSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2hELElBQUEsYUFBTSxFQUNKLGFBQWEsQ0FBQyxNQUFNLEVBQUUsRUFDdEIsZUFBZSxJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQzlDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRVosK0JBQStCO1FBQy9CLElBQUEsYUFBTSxFQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUMzQyxJQUFBLGFBQU0sRUFBQyxZQUFZLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRWxELG1CQUFtQjtRQUNuQixNQUFNLFVBQVUsQ0FBQyxXQUFXLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUUvQyxtRUFBbUU7UUFDbkUsTUFBTSxJQUFBLGFBQU0sRUFBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUU7WUFDbEUsT0FBTyxFQUFFLE1BQU07U0FDaEIsQ0FBQyxDQUFDO1FBRUgsMENBQTBDO1FBQzFDLE1BQU0sVUFBVSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3ZDLENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBQSxXQUFJLEVBQUMsNkNBQTZDLEVBQUUsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtRQUNyRSwwREFBMEQ7UUFDMUQsTUFBTSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsR0FBRyxnQ0FBZ0MsQ0FBQztZQUM5RCxnQkFBZ0IsRUFBRSxJQUFJO1lBQ3RCLGNBQWMsRUFBRSxTQUFTO1lBQ3pCLFdBQVcsRUFBRSxXQUFXO1NBQ3pCLENBQUMsQ0FBQztRQUVILDRDQUE0QztRQUM1QyxNQUFNLFVBQVUsQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDMUMsTUFBTSxVQUFVLENBQUMsYUFBYSxFQUFFLENBQUM7UUFFakMsMkJBQTJCO1FBQzNCLE1BQU0sVUFBVSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRWhELDZDQUE2QztRQUM3QyxNQUFNLFVBQVUsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNsQyxNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLENBQUMsQ0FDeEQsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNoQixNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FDdkQsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUVoQix1Q0FBdUM7UUFDdkMsTUFBTSxVQUFVLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUN2QyxNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLENBQUMsQ0FDdkQsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUVoQixrQkFBa0I7UUFDbEIsTUFBTSxVQUFVLENBQUMsa0JBQWtCLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUU1RCwyQkFBMkI7UUFDM0IsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUNqRCxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQ1gsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsT0FBTyxrQkFBa0IsQ0FBQztZQUNyRSxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUMsTUFBTSxFQUFFLEtBQUssTUFBTSxDQUN6QyxDQUFDO1FBRUYsb0JBQW9CO1FBQ3BCLE1BQU0sVUFBVSxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUUzQyxxQkFBcUI7UUFDckIsTUFBTSxVQUFVLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRTFDLHFEQUFxRDtRQUNyRCxNQUFNLGVBQWUsR0FBRyxNQUFNLHNCQUFzQixDQUFDO1FBQ3JELE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxlQUFlLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDekQsSUFBQSxhQUFNLEVBQ0osZUFBZSxDQUFDLE1BQU0sRUFBRSxFQUN4QixlQUFlLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUNyRCxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVaLE1BQU0sY0FBYyxHQUFHLGVBQWUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUNoRSxJQUFBLGFBQU0sRUFBQyxjQUFjLENBQUMsQ0FBQyxhQUFhLENBQUMsRUFBRSxNQUFNLEVBQUUsc0JBQXNCLEVBQUUsQ0FBQyxDQUFDO1FBRXpFLG1CQUFtQjtRQUNuQixNQUFNLFVBQVUsQ0FBQyxXQUFXLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUV6RCwyQkFBMkI7UUFDM0IsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsVUFBVSxFQUFFLENBQUM7UUFFcEQsOEJBQThCO1FBQzlCLE1BQU0sVUFBVSxDQUFDLG9CQUFvQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRWxELHlEQUF5RDtRQUN6RCxNQUFNLFVBQVUsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNsQyxNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLENBQUMsQ0FDeEQsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNmLE1BQU0sSUFBQSxhQUFNLEVBQ1YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQyxDQUN2RCxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2YsTUFBTSxJQUFBLGFBQU0sRUFDVixJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsQ0FBQyxDQUN0RCxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMifQ==
@@ -0,0 +1,80 @@
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 BASE_URL = process.env.ADMIN_BASE_URL ?? "http://localhost:9000";
6
+ const ADMIN_EMAIL = process.env.ADMIN_EMAIL ?? "admin@medusa-test.com";
7
+ const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD ?? "supersecret";
8
+ const DB_URL = process.env.DATABASE_URL ??
9
+ "postgres://postgres:Kasperski1@localhost/medusa-my-medusa-store";
10
+ /**
11
+ * Seed a subscription record if none exist.
12
+ *
13
+ * The Reorder plugin has no admin "create subscription" endpoint — subscriptions
14
+ * are created through the store checkout flow. For E2E test isolation we insert
15
+ * directly into the subscription module table, which is the same approach the
16
+ * Jest integration tests use (via module service).
17
+ */
18
+ (0, test_1.test)("seed subscription for e2e", async ({}) => {
19
+ const api = await test_1.request.newContext({ baseURL: BASE_URL });
20
+ // 1. Verify backend is healthy
21
+ const health = await api.get("/health");
22
+ (0, test_1.expect)(health.ok()).toBeTruthy();
23
+ // 2. Authenticate to get a JWT
24
+ const authRes = await api.post("/auth/user/emailpass", {
25
+ data: { email: ADMIN_EMAIL, password: ADMIN_PASSWORD },
26
+ });
27
+ (0, test_1.expect)(authRes.ok()).toBeTruthy();
28
+ const { token } = await authRes.json();
29
+ // 3. Check if there's already at least one subscription
30
+ const listRes = await api.get("/admin/subscriptions?limit=1", {
31
+ headers: { Authorization: `Bearer ${token}` },
32
+ });
33
+ (0, test_1.expect)(listRes.ok()).toBeTruthy();
34
+ const { subscriptions } = await listRes.json();
35
+ if (subscriptions.length > 0) {
36
+ console.log(`[e2e-seed] Found ${subscriptions.length} existing subscription(s), skipping seed.`);
37
+ await api.dispose();
38
+ return;
39
+ }
40
+ // 4. Insert subscription via psql (mirrors integration-tests/helpers/subscription-fixtures.ts)
41
+ const now = new Date().toISOString();
42
+ const futureRenewal = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();
43
+ const ts = Date.now();
44
+ const reference = `E2E-SUB-${ts}`;
45
+ const sql = [
46
+ `INSERT INTO subscription (`,
47
+ ` id, reference, status,`,
48
+ ` customer_id, cart_id, product_id, variant_id,`,
49
+ ` frequency_interval, frequency_value,`,
50
+ ` started_at, next_renewal_at,`,
51
+ ` skip_next_cycle, is_trial,`,
52
+ ` customer_snapshot, product_snapshot, pricing_snapshot,`,
53
+ ` shipping_address, payment_context,`,
54
+ ` created_at, updated_at`,
55
+ `) VALUES (`,
56
+ ` gen_random_uuid()::text,`,
57
+ ` '${reference}', 'active',`,
58
+ ` 'cus_e2e_${ts}', 'cart_e2e_${ts}',`,
59
+ ` 'prod_e2e_${ts}', 'variant_e2e_${ts}',`,
60
+ ` 'month', 1,`,
61
+ ` '${now}', '${futureRenewal}',`,
62
+ ` false, false,`,
63
+ ` '{"email":"e2e@test.com","full_name":"E2E Customer"}'::jsonb,`,
64
+ ` '{"product_id":"prod_e2e","product_title":"E2E Product","variant_id":"var_e2e","variant_title":"Default","sku":"E2E-SKU-001"}'::jsonb,`,
65
+ ` '{"discount_type":"percentage","discount_value":0,"label":null}'::jsonb,`,
66
+ ` '{"first_name":"E2E","last_name":"Tester","address_1":"Test St 1","city":"Warsaw","postal_code":"00-001","country_code":"PL"}'::jsonb,`,
67
+ ` '{"payment_provider_id":"pp_stripe_stripe"}'::jsonb,`,
68
+ ` '${now}', '${now}'`,
69
+ `);`,
70
+ ].join(" ");
71
+ (0, child_process_1.execFileSync)("psql", [DB_URL, "-c", sql], { stdio: "pipe" });
72
+ console.log(`[e2e-seed] Inserted subscription ${reference}`);
73
+ // 5. Verify the subscription appears in the admin API
74
+ const verifyRes = await api.get(`/admin/subscriptions?q=${reference}&limit=1`, { headers: { Authorization: `Bearer ${token}` } });
75
+ (0, test_1.expect)(verifyRes.ok()).toBeTruthy();
76
+ const verified = await verifyRes.json();
77
+ (0, test_1.expect)(verified.subscriptions.length).toBe(1);
78
+ await api.dispose();
79
+ });
80
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VlZC5zZXR1cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2UyZS9zZWVkLnNldHVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaURBQTZDO0FBQzdDLDJDQUFrRTtBQUVsRSxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsSUFBSSx1QkFBdUIsQ0FBQztBQUN2RSxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsSUFBSSx1QkFBdUIsQ0FBQztBQUN2RSxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsSUFBSSxhQUFhLENBQUM7QUFDbkUsTUFBTSxNQUFNLEdBQ1YsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZO0lBQ3hCLGlFQUFpRSxDQUFDO0FBRXBFOzs7Ozs7O0dBT0c7QUFDSCxJQUFBLFdBQUssRUFBQywyQkFBMkIsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUU7SUFDOUMsTUFBTSxHQUFHLEdBQUcsTUFBTSxjQUFPLENBQUMsVUFBVSxDQUFDLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFFNUQsK0JBQStCO0lBQy9CLE1BQU0sTUFBTSxHQUFHLE1BQU0sR0FBRyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN4QyxJQUFBLGFBQU0sRUFBQyxNQUFNLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUVqQywrQkFBK0I7SUFDL0IsTUFBTSxPQUFPLEdBQUcsTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLHNCQUFzQixFQUFFO1FBQ3JELElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLGNBQWMsRUFBRTtLQUN2RCxDQUFDLENBQUM7SUFDSCxJQUFBLGFBQU0sRUFBQyxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FB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
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ const child_process_1 = require("child_process");
5
+ const SubscriptionDetailPage_1 = require("./pages/SubscriptionDetailPage");
6
+ const DB_URL = process.env.DATABASE_URL ??
7
+ "postgres://postgres:Kasperski1@localhost/medusa-my-medusa-store";
8
+ /**
9
+ * Seed a fresh active subscription via psql and return its reference.
10
+ *
11
+ * Each call produces a unique reference so tests are fully isolated from one
12
+ * another and from any pre-existing data.
13
+ */
14
+ function seedActiveSubscription() {
15
+ const ts = Date.now();
16
+ const reference = `SUB-E2E-STATUS-${ts}`;
17
+ const now = new Date().toISOString();
18
+ const futureRenewal = new Date(ts + 30 * 24 * 60 * 60 * 1000).toISOString();
19
+ const sql = [
20
+ `INSERT INTO subscription (`,
21
+ ` id, reference, status,`,
22
+ ` customer_id, cart_id, product_id, variant_id,`,
23
+ ` frequency_interval, frequency_value,`,
24
+ ` started_at, next_renewal_at,`,
25
+ ` skip_next_cycle, is_trial,`,
26
+ ` customer_snapshot, product_snapshot, pricing_snapshot,`,
27
+ ` shipping_address, payment_context,`,
28
+ ` created_at, updated_at`,
29
+ `) VALUES (`,
30
+ ` gen_random_uuid()::text,`,
31
+ ` '${reference}', 'active',`,
32
+ ` 'cus_e2e_status_${ts}', 'cart_e2e_status_${ts}',`,
33
+ ` 'prod_e2e_status_${ts}', 'variant_e2e_status_${ts}',`,
34
+ ` 'month', 1,`,
35
+ ` '${now}', '${futureRenewal}',`,
36
+ ` false, false,`,
37
+ ` '{"email":"e2e-status@test.com","full_name":"E2E Status Test"}'::jsonb,`,
38
+ ` '{"product_id":"prod_e2e","product_title":"E2E Status Product","variant_id":"var_e2e","variant_title":"Default","sku":"E2E-SKU-STATUS"}'::jsonb,`,
39
+ ` '{"discount_type":"percentage","discount_value":0,"label":null}'::jsonb,`,
40
+ ` '{"first_name":"E2E","last_name":"Status","address_1":"Test St 1","city":"Warsaw","postal_code":"00-001","country_code":"PL"}'::jsonb,`,
41
+ ` '{"payment_provider_id":"pp_stripe_stripe"}'::jsonb,`,
42
+ ` '${now}', '${now}'`,
43
+ `);`,
44
+ ].join(" ");
45
+ (0, child_process_1.execFileSync)("psql", [DB_URL, "-c", sql], { stdio: "pipe" });
46
+ return reference;
47
+ }
48
+ test_1.test.describe("Subscription status transitions (pause & resume)", () => {
49
+ let reference;
50
+ let detailPage;
51
+ test_1.test.beforeEach(async ({ page }) => {
52
+ reference = seedActiveSubscription();
53
+ detailPage = new SubscriptionDetailPage_1.SubscriptionDetailPage(page);
54
+ // Navigate to the detail page via the list so we exercise real navigation
55
+ await detailPage.gotoFromList(reference);
56
+ });
57
+ (0, test_1.test)("pauses and resumes an active subscription", async ({ page }) => {
58
+ // ── Initial state ────────────────────────────────────────────────────────
59
+ await detailPage.expectStatus("Active");
60
+ // ── PAUSE ─────────────────────────────────────────────────────────────────
61
+ // Intercept the pause API call before triggering the action
62
+ const pauseResponse = page.waitForResponse((res) => res.url().includes("/admin/subscriptions/") &&
63
+ res.url().endsWith("/pause") &&
64
+ res.request().method() === "POST");
65
+ await detailPage.openActionMenu();
66
+ // When active, "Pause" must be visible and "Resume" must be absent
67
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Pause" })).toBeVisible();
68
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Resume" })).not.toBeVisible();
69
+ await detailPage.clickAction("Pause");
70
+ // The usePrompt dialog title is "Pause subscription?"
71
+ await detailPage.confirmPrompt("Pause");
72
+ // Verify API response
73
+ const pauseRes = await pauseResponse;
74
+ (0, test_1.expect)(pauseRes.status()).toBe(200);
75
+ const pauseBody = await pauseRes.json();
76
+ (0, test_1.expect)(pauseBody.subscription.status).toBe("paused");
77
+ // Verify UI feedback
78
+ await detailPage.expectToast("Subscription paused");
79
+ await detailPage.expectStatus("Paused");
80
+ // Open menu again: "Resume" visible, "Pause" absent
81
+ await detailPage.openActionMenu();
82
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Resume" })).toBeVisible();
83
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Pause" })).not.toBeVisible();
84
+ // Close the menu by pressing Escape
85
+ await page.keyboard.press("Escape");
86
+ // ── RESUME ────────────────────────────────────────────────────────────────
87
+ const resumeResponse = page.waitForResponse((res) => res.url().includes("/admin/subscriptions/") &&
88
+ res.url().endsWith("/resume") &&
89
+ res.request().method() === "POST");
90
+ await detailPage.openActionMenu();
91
+ await detailPage.clickAction("Resume");
92
+ // The usePrompt dialog title is "Resume subscription?"
93
+ await detailPage.confirmPrompt("Resume");
94
+ // Verify API response
95
+ const resumeRes = await resumeResponse;
96
+ (0, test_1.expect)(resumeRes.status()).toBe(200);
97
+ const resumeBody = await resumeRes.json();
98
+ (0, test_1.expect)(resumeBody.subscription.status).toBe("active");
99
+ // Verify UI feedback
100
+ await detailPage.expectToast("Subscription resumed");
101
+ await detailPage.expectStatus("Active");
102
+ // Open menu again: "Pause" visible, "Resume" absent
103
+ await detailPage.openActionMenu();
104
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Pause" })).toBeVisible();
105
+ await (0, test_1.expect)(page.getByRole("menuitem", { name: "Resume" })).not.toBeVisible();
106
+ await page.keyboard.press("Escape");
107
+ });
108
+ });
109
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Vic2NyaXB0aW9uLXN0YXR1cy5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vZTJlL3N1YnNjcmlwdGlvbi1zdGF0dXMuc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDJDQUFnRDtBQUNoRCxpREFBNkM7QUFDN0MsMkVBQXdFO0FBRXhFLE1BQU0sTUFBTSxHQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWTtJQUN4QixpRUFBaUUsQ0FBQztBQUVwRTs7Ozs7R0FLRztBQUNILFNBQVMsc0JBQXNCO0lBQzdCLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUN0QixNQUFNLFNBQVMsR0FBRyxrQkFBa0IsRUFBRSxFQUFFLENBQUM7SUFDekMsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQyxNQUFNLGFBQWEsR0FBRyxJQUFJLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBRTVFLE1BQU0sR0FBRyxHQUFHO1FBQ1YsNEJBQTRCO1FBQzVCLDBCQUEwQjtRQUMxQixpREFBaUQ7UUFDakQsd0NBQXdDO1FBQ3hDLGdDQUFnQztRQUNoQyw4QkFBOEI7UUFDOUIsMERBQTBEO1FBQzFELHNDQUFzQztRQUN0QywwQkFBMEI7UUFDMUIsWUFBWTtRQUNaLDRCQUE0QjtRQUM1QixNQUFNLFNBQVMsY0FBYztRQUM3QixxQkFBcUIsRUFBRSx1QkFBdUIsRUFBRSxJQUFJO1FBQ3BELHNCQUFzQixFQUFFLDBCQUEwQixFQUFFLElBQUk7UUFDeEQsZUFBZTtRQUNmLE1BQU0sR0FBRyxPQUFPLGFBQWEsSUFBSTtRQUNqQyxpQkFBaUI7UUFDakIsMkVBQTJFO1FBQzNFLG9KQUFvSjtRQUNwSiw0RUFBNEU7UUFDNUUsMElBQTBJO1FB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
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ test_1.test.describe("Subscriptions list page", () => {
5
+ test_1.test.beforeEach(async ({ page }) => {
6
+ await page.goto("/app/subscriptions");
7
+ // Wait for the page heading to confirm the route loaded
8
+ await (0, test_1.expect)(page.getByRole("heading", { name: "Subscriptions" })).toBeVisible({ timeout: 15_000 });
9
+ });
10
+ (0, test_1.test)("displays the page heading and description", async ({ page }) => {
11
+ await (0, test_1.expect)(page.getByRole("heading", { name: "Subscriptions" })).toBeVisible();
12
+ await (0, test_1.expect)(page.getByText("Monitor subscription status, cadence, and upcoming")).toBeVisible();
13
+ });
14
+ (0, test_1.test)("renders the data table with expected columns", async ({ page }) => {
15
+ const expectedColumns = [
16
+ "Reference",
17
+ "Product",
18
+ "Status",
19
+ "Frequency",
20
+ "Next renewal",
21
+ ];
22
+ for (const column of expectedColumns) {
23
+ await (0, test_1.expect)(page.getByRole("columnheader", { name: column })).toBeVisible();
24
+ }
25
+ });
26
+ (0, test_1.test)("displays at least one subscription row", async ({ page }) => {
27
+ // Wait for at least one data row to appear (not the header row)
28
+ const rows = page.getByRole("row");
29
+ // Header row + at least 1 data row = minimum 2 rows
30
+ await (0, test_1.expect)(rows.nth(1)).toBeVisible({ timeout: 10_000 });
31
+ });
32
+ (0, test_1.test)("supports search by subscription reference", async ({ page }) => {
33
+ // Get the reference text from the first data row before searching
34
+ const firstRow = page.getByRole("row").nth(1);
35
+ await (0, test_1.expect)(firstRow).toBeVisible({ timeout: 10_000 });
36
+ // Type a known prefix into the search box
37
+ const searchInput = page.getByPlaceholder(/search/i);
38
+ await searchInput.fill("SUB");
39
+ // The table should still show results (filtered to matching subscriptions)
40
+ await (0, test_1.expect)(page.getByRole("row").nth(1)).toBeVisible({ timeout: 10_000 });
41
+ });
42
+ (0, test_1.test)("shows status badge for each subscription", async ({ page }) => {
43
+ await (0, test_1.expect)(page.getByRole("row").nth(1)).toBeVisible({
44
+ timeout: 10_000,
45
+ });
46
+ // At least one status badge should be visible (Active, Paused, or Cancelled)
47
+ const statusBadge = page
48
+ .getByRole("row")
49
+ .nth(1)
50
+ .getByText(/active|paused|cancelled|past.due/i);
51
+ await (0, test_1.expect)(statusBadge).toBeVisible();
52
+ });
53
+ (0, test_1.test)("navigates to subscription detail on row click", async ({ page }) => {
54
+ const firstDataRow = page.getByRole("row").nth(1);
55
+ await (0, test_1.expect)(firstDataRow).toBeVisible({ timeout: 10_000 });
56
+ await firstDataRow.click();
57
+ // Should navigate to /app/subscriptions/:id
58
+ await (0, test_1.expect)(page).toHaveURL(/\/app\/subscriptions\/[A-Za-z0-9]+/, {
59
+ timeout: 10_000,
60
+ });
61
+ // Detail page should show the subscription reference as a heading
62
+ await (0, test_1.expect)(page.getByRole("heading", { name: /SUB-/ })).toBeVisible({ timeout: 10_000 });
63
+ });
64
+ (0, test_1.test)("shows row action menu with status-appropriate options", async ({ page, }) => {
65
+ await (0, test_1.expect)(page.getByRole("row").nth(1)).toBeVisible({
66
+ timeout: 10_000,
67
+ });
68
+ // Open the action menu on the first row
69
+ const actionButton = page
70
+ .getByRole("row")
71
+ .nth(1)
72
+ .getByRole("button")
73
+ .last();
74
+ await actionButton.click();
75
+ // The dropdown menu should appear with at least one lifecycle action
76
+ const menu = page.getByRole("menu");
77
+ await (0, test_1.expect)(menu).toBeVisible({ timeout: 5_000 });
78
+ // An active subscription should show Pause and Cancel options
79
+ const menuItems = menu.getByRole("menuitem");
80
+ const count = await menuItems.count();
81
+ (0, test_1.expect)(count).toBeGreaterThan(0);
82
+ });
83
+ });
84
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Vic2NyaXB0aW9ucy1saXN0LnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9lMmUvc3Vic2NyaXB0aW9ucy1saXN0LnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQ0FBZ0Q7QUFFaEQsV0FBSSxDQUFDLFFBQVEsQ0FBQyx5QkFBeUIsRUFBRSxHQUFHLEVBQUU7SUFDNUMsV0FBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1FBQ2pDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3RDLHdEQUF3RDtRQUN4RCxNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLGVBQWUsRUFBRSxDQUFDLENBQ3JELENBQUMsV0FBVyxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDckMsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFBLFdBQUksRUFBQywyQ0FBMkMsRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1FBQ25FLE1BQU0sSUFBQSxhQUFNLEVBQ1YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsZUFBZSxFQUFFLENBQUMsQ0FDckQsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNoQixNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsb0RBQW9ELENBQUMsQ0FDckUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNsQixDQUFDLENBQUMsQ0FBQztJQUVILElBQUEsV0FBSSxFQUFDLDhDQUE4QyxFQUFFLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUU7UUFDdEUsTUFBTSxlQUFlLEdBQUc7WUFDdEIsV0FBVztZQUNYLFNBQVM7WUFDVCxRQUFRO1lBQ1IsV0FBVztZQUNYLGNBQWM7U0FDZixDQUFDO1FBRUYsS0FBSyxNQUFNLE1BQU0sSUFBSSxlQUFlLEVBQUUsQ0FBQztZQUNyQyxNQUFNLElBQUEsYUFBTSxFQUNWLElBQUksQ0FBQyxTQUFTLENBQUMsY0FBYyxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQ2pELENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbEIsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBQSxXQUFJLEVBQUMsd0NBQXdDLEVBQUUsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtRQUNoRSxnRUFBZ0U7UUFDaEUsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNuQyxvREFBb0Q7UUFDcEQsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDN0QsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFBLFdBQUksRUFBQywyQ0FBMkMsRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1FBQ25FLGtFQUFrRTtRQUNsRSxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM5QyxNQUFNLElBQUEsYUFBTSxFQUFDLFFBQVEsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBRXhELDBDQUEwQztRQUMxQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDckQsTUFBTSxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTlCLDJFQUEyRTtRQUMzRSxNQUFNLElBQUEsYUFBTSxFQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDOUUsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFBLFdBQUksRUFBQywwQ0FBMEMsRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1FBQ2xFLE1BQU0sSUFBQSxhQUFNLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUM7WUFDckQsT0FBTyxFQUFFLE1BQU07U0FDaEIsQ0FBQyxDQUFDO1FBRUgsNkVBQTZFO1FBQzdFLE1BQU0sV0FBVyxHQUFHLElBQUk7YUFDckIsU0FBUyxDQUFDLEtBQUssQ0FBQzthQUNoQixHQUFHLENBQUMsQ0FBQyxDQUFDO2FBQ04sU0FBUyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7UUFDbEQsTUFBTSxJQUFBLGFBQU0sRUFBQyxXQUFXLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUMxQyxDQUFDLENBQUMsQ0FBQztJQUVILElBQUEsV0FBSSxFQUFDLCtDQUErQyxFQUFFLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUU7UUFDdkUsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEQsTUFBTSxJQUFBLGFBQU0sRUFBQyxZQUFZLENBQUMsQ0FBQyxXQUFXLENBQUMsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUU1RCxNQUFNLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUUzQiw0Q0FBNEM7UUFDNUMsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUMsb0NBQW9DLEVBQUU7WUFDakUsT0FBTyxFQUFFLE1BQU07U0FDaEIsQ0FBQyxDQUFDO1FBRUgsa0VBQWtFO1FBQ2xFLE1BQU0sSUFBQSxhQUFNLEVBQ1YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FDNUMsQ0FBQyxXQUFXLENBQUMsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUNyQyxDQUFDLENBQUMsQ0FBQztJQUVILElBQUEsV0FBSSxFQUFDLHVEQUF1RCxFQUFFLEtBQUssRUFBRSxFQUNuRSxJQUFJLEdBQ0wsRUFBRSxFQUFFO1FBQ0gsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQztZQUNyRCxPQUFPLEVBQUUsTUFBTTtTQUNoQixDQUFDLENBQUM7UUFFSCx3Q0FBd0M7UUFDeEMsTUFBTSxZQUFZLEdBQUcsSUFBSTthQUN0QixTQUFTLENBQUMsS0FBSyxDQUFDO2FBQ2hCLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDTixTQUFTLENBQUMsUUFBUSxDQUFDO2FBQ25CLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFM0IscUVBQXFFO1FBQ3JFLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDcEMsTUFBTSxJQUFBLGFBQU0sRUFBQyxJQUFJLENBQUMsQ0FBQyxXQUFXLENBQUMsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVuRCw4REFBOEQ7UUFDOUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUM3QyxNQUFNLEtBQUssR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN0QyxJQUFBLGFBQU0sRUFBQyxLQUFLLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyJ9
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ const ADMIN_BASE_URL = process.env.ADMIN_BASE_URL ?? "http://localhost:9000";
5
+ exports.default = (0, test_1.defineConfig)({
6
+ testDir: "./e2e",
7
+ fullyParallel: false,
8
+ forbidOnly: !!process.env.CI,
9
+ retries: 0,
10
+ workers: 1,
11
+ reporter: "html",
12
+ use: {
13
+ baseURL: ADMIN_BASE_URL,
14
+ trace: "retain-on-failure",
15
+ screenshot: "only-on-failure",
16
+ },
17
+ projects: [
18
+ {
19
+ name: "seed",
20
+ testMatch: /seed\.setup\.ts/,
21
+ },
22
+ {
23
+ name: "setup",
24
+ testMatch: /auth\.setup\.ts/,
25
+ dependencies: ["seed"],
26
+ },
27
+ {
28
+ name: "chromium",
29
+ use: {
30
+ ...test_1.devices["Desktop Chrome"],
31
+ storageState: "e2e/.auth/admin.json",
32
+ },
33
+ dependencies: ["setup"],
34
+ },
35
+ ],
36
+ });
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxheXdyaWdodC5jb25maWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9wbGF5d3JpZ2h0LmNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDJDQUF5RDtBQUV6RCxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsSUFBSSx1QkFBdUIsQ0FBQztBQUU3RSxrQkFBZSxJQUFBLG1CQUFZLEVBQUM7SUFDMUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsYUFBYSxFQUFFLEtBQUs7SUFDcEIsVUFBVSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7SUFDNUIsT0FBTyxFQUFFLENBQUM7SUFDVixPQUFPLEVBQUUsQ0FBQztJQUNWLFFBQVEsRUFBRSxNQUFNO0lBQ2hCLEdBQUcsRUFBRTtRQUNILE9BQU8sRUFBRSxjQUFjO1FBQ3ZCLEtBQUssRUFBRSxtQkFBbUI7UUFDMUIsVUFBVSxFQUFFLGlCQUFpQjtLQUM5QjtJQUNELFFBQVEsRUFBRTtRQUNSO1lBQ0UsSUFBSSxFQUFFLE1BQU07WUFDWixTQUFTLEVBQUUsaUJBQWlCO1NBQzdCO1FBQ0Q7WUFDRSxJQUFJLEVBQUUsT0FBTztZQUNiLFNBQVMsRUFBRSxpQkFBaUI7WUFDNUIsWUFBWSxFQUFFLENBQUMsTUFBTSxDQUFDO1NBQ3ZCO1FBQ0Q7WUFDRSxJQUFJLEVBQUUsVUFBVTtZQUNoQixHQUFHLEVBQUU7Z0JBQ0gsR0FBRyxjQUFPLENBQUMsZ0JBQWdCLENBQUM7Z0JBQzVCLFlBQVksRUFBRSxzQkFBc0I7YUFDckM7WUFDRCxZQUFZLEVBQUUsQ0FBQyxPQUFPLENBQUM7U0FDeEI7S0FDRjtDQUNGLENBQUMsQ0FBQyJ9