backend-manager 5.9.5 → 5.9.6
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.
- package/package.json +8 -1
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/metadata.json +14 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/newsletter.html +486 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/newsletter.md +41 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/newsletter.mjml +97 -0
- package/{test/email/fixtures/clean.json → src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/structure.json} +16 -4
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/summary.md +1 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/metadata.json +14 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/newsletter.html +486 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/newsletter.md +41 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/newsletter.mjml +97 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/structure.json +42 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/summary.md +1 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/metadata.json +14 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/newsletter.html +486 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/newsletter.md +41 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/newsletter.mjml +97 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/structure.json +42 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/summary.md +1 -0
- package/src/test/fixtures/firebase-project/.temp/test-mode.json +6 -0
- package/src/test/fixtures/firebase-project/database-debug.log +12 -0
- package/src/test/fixtures/firebase-project/firestore-debug.log +136 -0
- package/src/test/fixtures/firebase-project/pubsub-debug.log +17 -0
- package/.codeclimate.yml +0 -32
- package/.nvmrc +0 -1
- package/CHANGELOG.md +0 -1440
- package/PROGRESS.md +0 -93
- package/TODO-2.md +0 -121
- package/TODO-CHARGEBLAST.md +0 -32
- package/TODO-WEBHOOK-KEY-LEGACY-REMOVAL.md +0 -15
- package/TODO-WEBHOOK-KEY-UPGRADE.md +0 -138
- package/TODO-email-auth.md +0 -14
- package/TODO.md +0 -187
- package/plans/mcp2.md +0 -247
- package/plans/suspended-subscription-dead-zone.md +0 -97
- package/scripts/test-helper-providers.js +0 -162
- package/scripts/update-disposable-domains.js +0 -44
- package/templates/_.env +0 -42
- package/templates/_.gitignore +0 -60
- package/templates/backend-manager-config.json +0 -249
- package/templates/database.rules.json +0 -83
- package/templates/firebase.json +0 -66
- package/templates/firestore.indexes.json +0 -4
- package/templates/firestore.rules +0 -112
- package/templates/public/404.html +0 -26
- package/templates/public/index.html +0 -24
- package/templates/remoteconfig.template.json +0 -1
- package/templates/storage-lifecycle-config-1-day.json +0 -9
- package/templates/storage-lifecycle-config-30-days.json +0 -9
- package/templates/storage.rules +0 -8
- package/test/_init/accounts-validation.js +0 -58
- package/test/_legacy/ai/index.js +0 -231
- package/test/_legacy/ai/test.jpg +0 -0
- package/test/_legacy/ai/test.pdf +0 -0
- package/test/_legacy/index.js +0 -31
- package/test/_legacy/payment-resolver/chargebee/orders/refunded.json +0 -0
- package/test/_legacy/payment-resolver/chargebee/orders/unpaid.json +0 -98
- package/test/_legacy/payment-resolver/chargebee/subscriptions/active.json +0 -578
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-in-trial.json +0 -38
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-skipped-to-active.json +0 -135
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-active-to-cancelled.json +0 -42
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-active.json +0 -44
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-cancelled.json +0 -39
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-refund.json +0 -143
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-suspended.json +0 -48
- package/test/_legacy/payment-resolver/coinbase/orders/regular.json +0 -204
- package/test/_legacy/payment-resolver/coinbase/subscriptions/cancelled.json +0 -204
- package/test/_legacy/payment-resolver/coinbase/subscriptions/paid-2.json +0 -125
- package/test/_legacy/payment-resolver/index.js +0 -1558
- package/test/_legacy/payment-resolver/paypal/orders/refunded.json +0 -0
- package/test/_legacy/payment-resolver/paypal/orders/regular.json +0 -120
- package/test/_legacy/payment-resolver/paypal/subscriptions/active-refund-previous-stmnt.json +0 -323
- package/test/_legacy/payment-resolver/paypal/subscriptions/active.json +0 -192
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-in-trial.json +0 -125
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-not-complete.json +0 -76
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-overdue-2.json +0 -114
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-overdue.json +0 -114
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-active-to-cancelled.json +0 -111
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-active.json +0 -132
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-cancelled.json +0 -107
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-expired.json +0 -91
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-refund.json +0 -147
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-suspended.json +0 -120
- package/test/_legacy/payment-resolver/stripe/orders/refunded.json +0 -0
- package/test/_legacy/payment-resolver/stripe/orders/regular.json +0 -91
- package/test/_legacy/payment-resolver/stripe/subscriptions/active.json +0 -421
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-in-trial.json +0 -349
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-active-failed-authorization.json +0 -430
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-active.json +0 -319
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-cancelled.json +0 -319
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-refund.json +0 -414
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-suspended.json +0 -319
- package/test/_legacy/payment-resolver/stripe/subscriptions/unsure.json +0 -339
- package/test/_legacy/test-new +0 -1178
- package/test/_legacy/test.md +0 -89
- package/test/_legacy/usage.js +0 -175
- package/test/_legacy/user.js +0 -31
- package/test/ai/tools-live.js +0 -170
- package/test/boot/emulator-boots.js +0 -37
- package/test/content/blog-generate.js +0 -160
- package/test/email/campaign-send.js +0 -45
- package/test/email/consent-lifecycle.js +0 -257
- package/test/email/feedback-and-plain-send.js +0 -52
- package/test/email/fixtures/editorial.json +0 -30
- package/test/email/fixtures/field-report.json +0 -53
- package/test/email/marketing-lifecycle.js +0 -132
- package/test/email/newsletter-generate.js +0 -819
- package/test/email/newsletter-templates.js +0 -491
- package/test/email/templates.js +0 -207
- package/test/email/transactional-send.js +0 -34
- package/test/email/transactional.js +0 -560
- package/test/email/validation.js +0 -710
- package/test/events/auth-delete-race.js +0 -201
- package/test/events/payments/journey-payments-cancel-endpoint.js +0 -100
- package/test/events/payments/journey-payments-cancel.js +0 -182
- package/test/events/payments/journey-payments-discount.js +0 -89
- package/test/events/payments/journey-payments-failure.js +0 -146
- package/test/events/payments/journey-payments-legacy-product.js +0 -149
- package/test/events/payments/journey-payments-one-time-failure.js +0 -111
- package/test/events/payments/journey-payments-one-time.js +0 -136
- package/test/events/payments/journey-payments-plan-change.js +0 -144
- package/test/events/payments/journey-payments-refund-webhook.js +0 -180
- package/test/events/payments/journey-payments-suspend.js +0 -181
- package/test/events/payments/journey-payments-trial-cancel.js +0 -130
- package/test/events/payments/journey-payments-trial.js +0 -171
- package/test/events/payments/journey-payments-uid-resolution.js +0 -132
- package/test/events/payments/journey-payments-upgrade.js +0 -135
- package/test/fixtures/chargebee/invoice-one-time.json +0 -27
- package/test/fixtures/chargebee/subscription-active.json +0 -44
- package/test/fixtures/chargebee/subscription-cancelled.json +0 -42
- package/test/fixtures/chargebee/subscription-in-trial.json +0 -41
- package/test/fixtures/chargebee/subscription-legacy-plan.json +0 -41
- package/test/fixtures/chargebee/subscription-non-renewing.json +0 -41
- package/test/fixtures/chargebee/subscription-paused.json +0 -42
- package/test/fixtures/chargebee/webhook-payment-failed.json +0 -51
- package/test/fixtures/chargebee/webhook-subscription-created.json +0 -47
- package/test/fixtures/paypal/order-approved.json +0 -62
- package/test/fixtures/paypal/order-completed.json +0 -110
- package/test/fixtures/paypal/subscription-active.json +0 -76
- package/test/fixtures/paypal/subscription-cancelled.json +0 -50
- package/test/fixtures/paypal/subscription-suspended.json +0 -65
- package/test/fixtures/stripe/checkout-session-completed.json +0 -130
- package/test/fixtures/stripe/invoice-payment-failed.json +0 -148
- package/test/fixtures/stripe/invoice-subscription-payment-failed.json +0 -28
- package/test/fixtures/stripe/subscription-active.json +0 -161
- package/test/fixtures/stripe/subscription-canceled.json +0 -161
- package/test/fixtures/stripe/subscription-trialing.json +0 -161
- package/test/functions/admin/database-read.js +0 -134
- package/test/functions/admin/database-write.js +0 -159
- package/test/functions/admin/edit-post.js +0 -366
- package/test/functions/admin/firestore-query.js +0 -207
- package/test/functions/admin/firestore-read.js +0 -129
- package/test/functions/admin/firestore-write.js +0 -105
- package/test/functions/admin/get-stats.js +0 -115
- package/test/functions/admin/send-email.js +0 -119
- package/test/functions/admin/send-notification.js +0 -208
- package/test/functions/admin/write-repo-content.js +0 -223
- package/test/functions/general/add-marketing-contact.js +0 -335
- package/test/functions/general/fetch-post.js +0 -54
- package/test/functions/general/generate-uuid.js +0 -114
- package/test/functions/test/authenticate.js +0 -64
- package/test/functions/user/create-custom-token.js +0 -73
- package/test/functions/user/delete.js +0 -135
- package/test/functions/user/get-active-sessions.js +0 -111
- package/test/functions/user/get-subscription-info.js +0 -99
- package/test/functions/user/regenerate-api-keys.js +0 -156
- package/test/functions/user/resolve.js +0 -52
- package/test/functions/user/sign-out-all-sessions.js +0 -94
- package/test/functions/user/sign-up.js +0 -252
- package/test/functions/user/submit-feedback.js +0 -104
- package/test/functions/user/validate-settings.js +0 -82
- package/test/helpers/ai-request-payload.js +0 -300
- package/test/helpers/ai-test-provider.js +0 -202
- package/test/helpers/ai-tools-format.js +0 -383
- package/test/helpers/content/blog-auto-publisher.js +0 -484
- package/test/helpers/content/feed-parser.js +0 -528
- package/test/helpers/content/ghostii-blocks.js +0 -134
- package/test/helpers/content/ghostii-feed-integration.js +0 -404
- package/test/helpers/content/ghostii-write-article.js +0 -243
- package/test/helpers/environment.js +0 -230
- package/test/helpers/infer-contact.js +0 -113
- package/test/helpers/merge-line-files.js +0 -271
- package/test/helpers/payment/chargebee/parse-webhook.js +0 -413
- package/test/helpers/payment/chargebee/to-unified-one-time.js +0 -147
- package/test/helpers/payment/chargebee/to-unified-subscription.js +0 -648
- package/test/helpers/payment/paypal/parse-webhook.js +0 -539
- package/test/helpers/payment/paypal/to-unified-one-time.js +0 -382
- package/test/helpers/payment/paypal/to-unified-subscription.js +0 -820
- package/test/helpers/payment/stripe/parse-webhook.js +0 -447
- package/test/helpers/payment/stripe/to-unified-one-time.js +0 -306
- package/test/helpers/payment/stripe/to-unified-subscription.js +0 -708
- package/test/helpers/sanitize.js +0 -222
- package/test/helpers/slugify.js +0 -394
- package/test/helpers/storage.js +0 -194
- package/test/helpers/user.js +0 -755
- package/test/helpers/webhook-forward.js +0 -418
- package/test/mcp/discovery.js +0 -53
- package/test/mcp/oauth.js +0 -161
- package/test/mcp/protocol.js +0 -268
- package/test/mcp/roles.js +0 -188
- package/test/mcp/utils.js +0 -245
- package/test/routes/admin/create-post.js +0 -364
- package/test/routes/admin/database.js +0 -131
- package/test/routes/admin/deduplicate-image-alts.js +0 -190
- package/test/routes/admin/email.js +0 -114
- package/test/routes/admin/firestore-query.js +0 -204
- package/test/routes/admin/firestore.js +0 -127
- package/test/routes/admin/infer-contact.js +0 -218
- package/test/routes/admin/notification.js +0 -198
- package/test/routes/admin/post-resize-image.js +0 -184
- package/test/routes/admin/post.js +0 -368
- package/test/routes/admin/repo-content.js +0 -223
- package/test/routes/admin/stats.js +0 -112
- package/test/routes/content/post.js +0 -54
- package/test/routes/general/uuid.js +0 -115
- package/test/routes/marketing/campaign.js +0 -125
- package/test/routes/marketing/contact.js +0 -370
- package/test/routes/marketing/email-preferences.js +0 -292
- package/test/routes/marketing/push-send.js +0 -32
- package/test/routes/marketing/webhook-forward.js +0 -61
- package/test/routes/marketing/webhook.js +0 -639
- package/test/routes/payments/cancel.js +0 -163
- package/test/routes/payments/discount.js +0 -80
- package/test/routes/payments/dispute-alert.js +0 -320
- package/test/routes/payments/intent.js +0 -336
- package/test/routes/payments/portal.js +0 -92
- package/test/routes/payments/refund.js +0 -179
- package/test/routes/payments/trial-eligibility.js +0 -71
- package/test/routes/payments/webhook.js +0 -107
- package/test/routes/test/authenticate.js +0 -59
- package/test/routes/test/schema.js +0 -554
- package/test/routes/test/usage.js +0 -342
- package/test/routes/user/api-keys.js +0 -156
- package/test/routes/user/delete.js +0 -136
- package/test/routes/user/feedback.js +0 -104
- package/test/routes/user/sessions.js +0 -199
- package/test/routes/user/settings-validate.js +0 -82
- package/test/routes/user/signup.js +0 -542
- package/test/routes/user/subscription.js +0 -99
- package/test/routes/user/token.js +0 -73
- package/test/routes/user/user.js +0 -157
- package/test/rules/notifications.js +0 -410
- package/test/rules/payments-carts.js +0 -371
- package/test/rules/user.js +0 -396
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
const { TEST_ACCOUNTS } = require('../../../src/test/test-accounts.js');
|
|
2
|
-
|
|
3
|
-
// SSOT: Affiliate code from referrer account definition
|
|
4
|
-
const REFERRER_AFFILIATE_CODE = TEST_ACCOUNTS.referrer.properties.affiliate.code;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Test Suite: User Signup Flow
|
|
8
|
-
* Tests the complete user signup flow including:
|
|
9
|
-
* - Using pre-created referrer with an affiliate code
|
|
10
|
-
* - Calling user:sign-up with that referral code
|
|
11
|
-
* - Verifying the referral tracking works
|
|
12
|
-
* - Edge cases: unauthenticated, signing up for another user, invalid affiliate code
|
|
13
|
-
*
|
|
14
|
-
* Note: referrer and referred accounts are pre-created by the test runner
|
|
15
|
-
* The referrer has affiliate.code set at creation time (see test-accounts.js)
|
|
16
|
-
*/
|
|
17
|
-
module.exports = {
|
|
18
|
-
description: 'User signup flow with affiliate tracking',
|
|
19
|
-
type: 'suite',
|
|
20
|
-
timeout: 60000, // Longer timeout for auth events to process
|
|
21
|
-
|
|
22
|
-
tests: [
|
|
23
|
-
// --- Edge case tests ---
|
|
24
|
-
{
|
|
25
|
-
name: 'signup-with-invalid-affiliate-code',
|
|
26
|
-
async run({ http, assert }) {
|
|
27
|
-
// Try to sign up with a non-existent affiliate code
|
|
28
|
-
// Use dedicated account so it doesn't affect other tests
|
|
29
|
-
const signupResponse = await http.as('referred-invalid').command('user:sign-up', {
|
|
30
|
-
attribution: {
|
|
31
|
-
affiliate: { code: 'INVALID_CODE_12345' },
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Should succeed but without referral tracking (invalid code is ignored)
|
|
36
|
-
assert.isSuccess(signupResponse, 'Signup should succeed even with invalid affiliate code');
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
// --- Main signup flow tests ---
|
|
41
|
-
{
|
|
42
|
-
name: 'verify-referrer-exists',
|
|
43
|
-
async run({ firestore, assert, state, accounts }) {
|
|
44
|
-
// Use the pre-created static referrer account
|
|
45
|
-
state.referrerUid = accounts.referrer.uid;
|
|
46
|
-
state.referrerEmail = accounts.referrer.email;
|
|
47
|
-
state.referrerAffiliateCode = REFERRER_AFFILIATE_CODE;
|
|
48
|
-
|
|
49
|
-
// Verify the referrer account exists and has the affiliate code
|
|
50
|
-
const referrerDoc = await firestore.get(`users/${state.referrerUid}`);
|
|
51
|
-
|
|
52
|
-
assert.ok(referrerDoc, 'Referrer user doc should exist');
|
|
53
|
-
assert.equal(
|
|
54
|
-
referrerDoc?.affiliate?.code,
|
|
55
|
-
state.referrerAffiliateCode,
|
|
56
|
-
'Referrer should have affiliate code set'
|
|
57
|
-
);
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
name: 'verify-referred-exists',
|
|
63
|
-
async run({ firestore, assert, state, accounts }) {
|
|
64
|
-
// Use the pre-created static referred account
|
|
65
|
-
state.referredUid = accounts.referred.uid;
|
|
66
|
-
state.referredEmail = accounts.referred.email;
|
|
67
|
-
|
|
68
|
-
// Verify the referred account exists
|
|
69
|
-
const referredDoc = await firestore.get(`users/${state.referredUid}`);
|
|
70
|
-
|
|
71
|
-
assert.ok(referredDoc, 'Referred user doc should exist');
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
name: 'call-user-signup-with-affiliate',
|
|
77
|
-
async run({ http, assert, state }) {
|
|
78
|
-
// Call user:sign-up as the referred user with the new attribution format
|
|
79
|
-
// This triggers the referral tracking logic
|
|
80
|
-
// Use .as('referred') to authenticate as that specific user via privateKey
|
|
81
|
-
const signupResponse = await http.as('referred').command('user:sign-up', {
|
|
82
|
-
attribution: {
|
|
83
|
-
affiliate: {
|
|
84
|
-
code: state.referrerAffiliateCode,
|
|
85
|
-
timestamp: new Date().toISOString(),
|
|
86
|
-
url: `https://example.com/?ref=${REFERRER_AFFILIATE_CODE}`,
|
|
87
|
-
page: '/',
|
|
88
|
-
},
|
|
89
|
-
utm: {
|
|
90
|
-
tags: {
|
|
91
|
-
utm_source: 'test',
|
|
92
|
-
utm_medium: 'referral',
|
|
93
|
-
utm_campaign: 'signup-test',
|
|
94
|
-
},
|
|
95
|
-
timestamp: new Date().toISOString(),
|
|
96
|
-
url: 'https://example.com/?utm_source=test',
|
|
97
|
-
page: '/',
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
context: {
|
|
101
|
-
referrer: 'https://google.com',
|
|
102
|
-
landingPage: 'https://example.com/',
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
assert.isSuccess(signupResponse, `user:sign-up should succeed: ${JSON.stringify(signupResponse, null, 2)}`);
|
|
107
|
-
|
|
108
|
-
// BEM API returns { data: { signedUp: true } }, http-client wraps in { data: response }
|
|
109
|
-
const signedUp = signupResponse.data?.data?.signedUp || signupResponse.data?.signedUp;
|
|
110
|
-
assert.ok(signedUp === true, `Should return signedUp: true (got: ${JSON.stringify(signupResponse.data)})`);
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
{
|
|
115
|
-
name: 'duplicate-signup-blocked',
|
|
116
|
-
async run({ http, assert, state }) {
|
|
117
|
-
// Try to call user:sign-up again for the same user
|
|
118
|
-
// This should be blocked since signup has already been processed
|
|
119
|
-
const signupResponse = await http.as('referred').command('user:sign-up', {
|
|
120
|
-
attribution: {
|
|
121
|
-
affiliate: { code: state.referrerAffiliateCode },
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
assert.isError(signupResponse, 400, 'Duplicate signup should be blocked');
|
|
126
|
-
assert.ok(
|
|
127
|
-
signupResponse.error?.includes('already been processed'),
|
|
128
|
-
`Error should mention already processed: ${signupResponse.error}`
|
|
129
|
-
);
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
{
|
|
134
|
-
name: 'wait-for-referral-update',
|
|
135
|
-
async run({ firestore, assert, state, waitFor }) {
|
|
136
|
-
// Wait for the referral to be recorded
|
|
137
|
-
// The user:sign-up command calls updateReferral() which updates the referrer
|
|
138
|
-
|
|
139
|
-
const referralFound = await waitFor(async () => {
|
|
140
|
-
const referrerDoc = await firestore.get(`users/${state.referrerUid}`);
|
|
141
|
-
|
|
142
|
-
if (!referrerDoc) {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const referrals = referrerDoc?.affiliate?.referrals || [];
|
|
147
|
-
return referrals.some(r => r.uid === state.referredUid);
|
|
148
|
-
}, 30000, 1000); // Wait up to 30s, check every 1s
|
|
149
|
-
|
|
150
|
-
assert.ok(referralFound, 'Referrer should have referred user in referrals array');
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
|
|
154
|
-
{
|
|
155
|
-
name: 'verify-referrer-has-referral',
|
|
156
|
-
async run({ firestore, assert, state }) {
|
|
157
|
-
// Verify the referrer now has the referred user in their referrals
|
|
158
|
-
const referrerDoc = await firestore.get(`users/${state.referrerUid}`);
|
|
159
|
-
|
|
160
|
-
assert.ok(referrerDoc, 'Should read referrer doc');
|
|
161
|
-
|
|
162
|
-
const referrals = referrerDoc?.affiliate?.referrals || [];
|
|
163
|
-
|
|
164
|
-
assert.ok(referrals.length > 0, 'Referrer should have at least one referral');
|
|
165
|
-
|
|
166
|
-
const foundReferral = referrals.find(r => r.uid === state.referredUid);
|
|
167
|
-
|
|
168
|
-
assert.ok(foundReferral, `Referrer should have ${state.referredUid} in referrals`);
|
|
169
|
-
assert.ok(foundReferral.timestamp, 'Referral should have timestamp');
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
|
|
173
|
-
{
|
|
174
|
-
name: 'verify-attribution-data-saved',
|
|
175
|
-
async run({ firestore, assert, state }) {
|
|
176
|
-
// Verify the attribution data was saved correctly
|
|
177
|
-
const referredDoc = await firestore.get(`users/${state.referredUid}`);
|
|
178
|
-
|
|
179
|
-
assert.ok(referredDoc, 'Should read referred user doc');
|
|
180
|
-
|
|
181
|
-
// Check attribution object (single source of truth for referrer info)
|
|
182
|
-
const attribution = referredDoc?.attribution;
|
|
183
|
-
assert.ok(attribution, 'Attribution object should exist');
|
|
184
|
-
assert.ok(attribution?.affiliate?.code === state.referrerAffiliateCode, 'Attribution should have affiliate code');
|
|
185
|
-
assert.ok(attribution?.utm?.tags?.utm_source === 'test', 'Attribution should have UTM source');
|
|
186
|
-
assert.ok(attribution?.utm?.tags?.utm_campaign === 'signup-test', 'Attribution should have UTM campaign');
|
|
187
|
-
|
|
188
|
-
// Check activity context was merged
|
|
189
|
-
const activity = referredDoc?.activity;
|
|
190
|
-
assert.ok(activity, 'Activity object should exist');
|
|
191
|
-
assert.ok(activity?.referrer === 'https://google.com', 'Activity should have referrer from context');
|
|
192
|
-
assert.ok(activity?.landingPage === 'https://example.com/', 'Activity should have landingPage from context');
|
|
193
|
-
|
|
194
|
-
// Check flags
|
|
195
|
-
assert.ok(referredDoc?.flags?.signupProcessed === true, 'signupProcessed flag should be true');
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
|
|
199
|
-
// --- Disposable email referral test ---
|
|
200
|
-
{
|
|
201
|
-
name: 'disposable-email-referral-skipped',
|
|
202
|
-
async run({ http, firestore, assert, state, accounts }) {
|
|
203
|
-
// Record current referral count before disposable signup
|
|
204
|
-
const referrerBefore = await firestore.get(`users/${state.referrerUid}`);
|
|
205
|
-
const referralsBefore = referrerBefore?.affiliate?.referrals || [];
|
|
206
|
-
state.referralCountBefore = referralsBefore.length;
|
|
207
|
-
|
|
208
|
-
// Sign up a disposable email account with the referrer's affiliate code
|
|
209
|
-
// The signup itself should succeed (account was created via Admin SDK, bypassing beforeCreate)
|
|
210
|
-
// But the referral credit should be SKIPPED because the email is disposable
|
|
211
|
-
const signupResponse = await http.as('referred-disposable').command('user:sign-up', {
|
|
212
|
-
attribution: {
|
|
213
|
-
affiliate: { code: state.referrerAffiliateCode },
|
|
214
|
-
},
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
assert.isSuccess(signupResponse, 'Disposable email signup should succeed');
|
|
218
|
-
|
|
219
|
-
// Verify NO new referral was added to the referrer
|
|
220
|
-
// Small delay to ensure any async writes would have completed
|
|
221
|
-
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
222
|
-
|
|
223
|
-
const referrerAfter = await firestore.get(`users/${state.referrerUid}`);
|
|
224
|
-
const referralsAfter = referrerAfter?.affiliate?.referrals || [];
|
|
225
|
-
|
|
226
|
-
assert.equal(
|
|
227
|
-
referralsAfter.length,
|
|
228
|
-
state.referralCountBefore,
|
|
229
|
-
`Referrer should NOT get credit for disposable email referral (before=${state.referralCountBefore}, after=${referralsAfter.length})`
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const disposableReferral = referralsAfter.find(r => r.uid === accounts['referred-disposable'].uid);
|
|
233
|
-
assert.ok(!disposableReferral, 'Disposable account should NOT appear in referrals');
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
|
|
237
|
-
// --- Auth rejection test (at end per convention) ---
|
|
238
|
-
{
|
|
239
|
-
name: 'unauthenticated-rejected',
|
|
240
|
-
async run({ http, assert }) {
|
|
241
|
-
// Try to call user:sign-up without authentication
|
|
242
|
-
const signupResponse = await http.as('none').command('user:sign-up', {
|
|
243
|
-
attribution: {
|
|
244
|
-
affiliate: { code: REFERRER_AFFILIATE_CODE },
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
assert.isError(signupResponse, 401, 'Signup should fail without authentication');
|
|
249
|
-
},
|
|
250
|
-
},
|
|
251
|
-
],
|
|
252
|
-
};
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test: user:submit-feedback
|
|
3
|
-
* Tests the user submit feedback command
|
|
4
|
-
* Requires authentication, saves feedback to Firestore
|
|
5
|
-
* Note: Makes external call to ITW getApp endpoint
|
|
6
|
-
*/
|
|
7
|
-
module.exports = {
|
|
8
|
-
description: 'User submit feedback',
|
|
9
|
-
type: 'group',
|
|
10
|
-
tests: [
|
|
11
|
-
// Test 1: Authenticated user can submit feedback
|
|
12
|
-
{
|
|
13
|
-
name: 'authenticated-user-succeeds',
|
|
14
|
-
auth: 'basic',
|
|
15
|
-
timeout: 30000, // Longer timeout due to external API call
|
|
16
|
-
|
|
17
|
-
async run({ http, assert }) {
|
|
18
|
-
const response = await http.command('user:submit-feedback', {
|
|
19
|
-
rating: 'like',
|
|
20
|
-
like: 'Great app! Works well.',
|
|
21
|
-
dislike: '',
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
assert.isSuccess(response, 'Submit feedback should succeed for authenticated user');
|
|
25
|
-
assert.hasProperty(response, 'data.review', 'Response should contain review decision');
|
|
26
|
-
assert.hasProperty(response, 'data.originalRequest', 'Response should contain original request');
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
// Test 2: Feedback with love rating
|
|
31
|
-
{
|
|
32
|
-
name: 'love-rating-succeeds',
|
|
33
|
-
auth: 'basic',
|
|
34
|
-
timeout: 30000,
|
|
35
|
-
|
|
36
|
-
async run({ http, assert }) {
|
|
37
|
-
const response = await http.command('user:submit-feedback', {
|
|
38
|
-
rating: 'love',
|
|
39
|
-
like: 'Absolutely love this app! Best thing ever! Highly recommend!',
|
|
40
|
-
dislike: '',
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
assert.isSuccess(response, 'Submit feedback with love rating should succeed');
|
|
44
|
-
assert.hasProperty(response, 'data.review.promptReview', 'Response should have promptReview flag');
|
|
45
|
-
assert.ok(
|
|
46
|
-
typeof response.data.review.promptReview === 'boolean',
|
|
47
|
-
'promptReview should be a boolean'
|
|
48
|
-
);
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
// Test 3: Feedback with dislike
|
|
53
|
-
{
|
|
54
|
-
name: 'dislike-feedback-succeeds',
|
|
55
|
-
auth: 'basic',
|
|
56
|
-
timeout: 30000,
|
|
57
|
-
|
|
58
|
-
async run({ http, assert }) {
|
|
59
|
-
const response = await http.command('user:submit-feedback', {
|
|
60
|
-
rating: 'dislike',
|
|
61
|
-
like: '',
|
|
62
|
-
dislike: 'Could use some improvements in the UI',
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
assert.isSuccess(response, 'Submit negative feedback should succeed');
|
|
66
|
-
assert.hasProperty(response, 'data.review', 'Response should contain review decision');
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
// Test 4: Premium user can submit feedback
|
|
71
|
-
{
|
|
72
|
-
name: 'premium-user-succeeds',
|
|
73
|
-
auth: 'premium-active',
|
|
74
|
-
timeout: 30000,
|
|
75
|
-
|
|
76
|
-
async run({ http, assert }) {
|
|
77
|
-
const response = await http.command('user:submit-feedback', {
|
|
78
|
-
rating: 'like',
|
|
79
|
-
like: 'Premium features are great!',
|
|
80
|
-
dislike: '',
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
assert.isSuccess(response, 'Submit feedback should succeed for premium user');
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
// Test 5: Unauthenticated request fails
|
|
88
|
-
{
|
|
89
|
-
name: 'unauthenticated-rejected',
|
|
90
|
-
auth: 'none',
|
|
91
|
-
timeout: 15000,
|
|
92
|
-
|
|
93
|
-
async run({ http, assert }) {
|
|
94
|
-
const response = await http.command('user:submit-feedback', {
|
|
95
|
-
rating: 'like',
|
|
96
|
-
like: 'Test',
|
|
97
|
-
dislike: '',
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
assert.isError(response, 401, 'Submit feedback should fail without authentication');
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test: user:validate-settings
|
|
3
|
-
* Tests the user validate settings command
|
|
4
|
-
* Requires authentication and validates settings against schema
|
|
5
|
-
*
|
|
6
|
-
* SKIPPED: Requires project-specific defaults.js file which BEM test environment doesn't have
|
|
7
|
-
*/
|
|
8
|
-
module.exports = {
|
|
9
|
-
description: 'User validate settings',
|
|
10
|
-
skip: 'Requires project-specific defaults.js file',
|
|
11
|
-
type: 'group',
|
|
12
|
-
tests: [
|
|
13
|
-
// Test 1: Authenticated user can validate settings
|
|
14
|
-
{
|
|
15
|
-
name: 'authenticated-user-succeeds',
|
|
16
|
-
auth: 'basic',
|
|
17
|
-
timeout: 15000,
|
|
18
|
-
|
|
19
|
-
async run({ http, assert }) {
|
|
20
|
-
const response = await http.command('user:validate-settings', {
|
|
21
|
-
existingSettings: {},
|
|
22
|
-
newSettings: {},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
assert.isSuccess(response, 'Validate settings should succeed for authenticated user');
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
// Test 2: With existing settings
|
|
30
|
-
{
|
|
31
|
-
name: 'with-existing-settings',
|
|
32
|
-
auth: 'basic',
|
|
33
|
-
timeout: 15000,
|
|
34
|
-
|
|
35
|
-
async run({ http, assert }) {
|
|
36
|
-
const response = await http.command('user:validate-settings', {
|
|
37
|
-
existingSettings: {
|
|
38
|
-
theme: 'dark',
|
|
39
|
-
notifications: true,
|
|
40
|
-
},
|
|
41
|
-
newSettings: {
|
|
42
|
-
theme: 'light',
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
assert.isSuccess(response, 'Validate settings with data should succeed');
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
// Test 3: Premium user can validate settings
|
|
51
|
-
{
|
|
52
|
-
name: 'premium-user-succeeds',
|
|
53
|
-
auth: 'premium-active',
|
|
54
|
-
timeout: 15000,
|
|
55
|
-
|
|
56
|
-
async run({ http, assert }) {
|
|
57
|
-
const response = await http.command('user:validate-settings', {
|
|
58
|
-
existingSettings: {},
|
|
59
|
-
newSettings: {},
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
assert.isSuccess(response, 'Validate settings should succeed for premium user');
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
// Test 4: Unauthenticated request fails
|
|
67
|
-
{
|
|
68
|
-
name: 'unauthenticated-rejected',
|
|
69
|
-
auth: 'none',
|
|
70
|
-
timeout: 15000,
|
|
71
|
-
|
|
72
|
-
async run({ http, assert }) {
|
|
73
|
-
const response = await http.command('user:validate-settings', {
|
|
74
|
-
existingSettings: {},
|
|
75
|
-
newSettings: {},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
assert.isError(response, 401, 'Validate settings should fail without authentication');
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
};
|