diff --git a/ghost/core/test/integration/services/email-service/__snapshots__/batch-sending.test.js.snap b/ghost/core/test/integration/services/email-service/__snapshots__/batch-sending.test.js.snap index 3f7004a8cc..86adacd2b3 100644 --- a/ghost/core/test/integration/services/email-service/__snapshots__/batch-sending.test.js.snap +++ b/ghost/core/test/integration/services/email-service/__snapshots__/batch-sending.test.js.snap @@ -6809,14 +6809,13 @@ table.body figcaption a {

Subscription details

- You are receiving this because you are a free subscriber to Ghost. - + You are receiving this because you are a free subscriber to Ghost.

-

Name: Simon Tester

-

Email: replacements-test-2@example.com

+

Name: not provided

+

Email: subscription-box-1@example.com

Member since: date

@@ -6958,7 +6957,27 @@ Subscription details -You are receiving this because you are a free subscriber to Ghost. +You are receiving this because you are a free subscriber to Ghost. + + + + + + + + +Name: not provided + + +Email: subscription-box-1@example.com + + +Member since: date + + + + +Manage subscription → [http://127.0.0.1:2369/#/portal/account] @@ -6968,10 +6987,3805 @@ You are receiving this because you are a free subscriber to Ghost. -Name: Simon Tester -Email: replacements-test-2@example.com + +Ghost © 2023 – Unsubscribe [unsubscribe_url] + + + +https://ghost.org/ + + + + + + + + + + + +  + + + + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for canceled paid member 1 1`] = ` +Object { + "html": " + + + + + + This is a test post title + + + + Hello world + + + + + + + + + + +
  +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ This is a test post title +
+ + + + + +
+ By Joe Bloggs • 1 Jan 2023 + + View in browser +
+
+ +

Hello world

+ + +
+
+

Subscription details

+

+ You are receiving this because you are a paid subscriber to Ghost. Your subscription has been canceled and will expire on date. You can resume your subscription via your account settings. +

+ + + + + +
+

Name: not provided

+

Email: canceled-paid@example.com

+

Member since: date

+
+ Manage subscription → +
+
+ + + + + + + + +
Ghost © 2023 – Unsubscribe
\\"Powered
+
+ +
+
 
+ + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for canceled paid member 2 1`] = ` +Object { + "html": " +Hello world + + + + + + +  + + + + + + + + + + + + + + + + + + + + + + + + + +Ghost [http://127.0.0.1:2369/] + + +Daily newsletter [http://127.0.0.1:2369/] + + + + + + + + + + +This is a test post title [http://127.0.0.1:2369/this-is-a-test-post-title-12/] + + + + + + + + + +By Joe Bloggs • 1 Jan 2023 + + +View in browser [http://127.0.0.1:2369/this-is-a-test-post-title-12/] + + + + + + + + + + + +Hello world + + + + + + + + + + + + + + + + + +Subscription details + + + +You are receiving this because you are a paid subscriber to Ghost. Your subscription has been canceled and will expire on date. You can resume your subscription via your account settings. + + + + + + + + +Name: not provided + + +Email: canceled-paid@example.com + + +Member since: date + + + + +Manage subscription → [http://127.0.0.1:2369/#/portal/account] + + + + + + + + + + + + +Ghost © 2023 – Unsubscribe [unsubscribe_url] + + + +https://ghost.org/ + + + + + + + + + + + +  + + + + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for comped members 1 1`] = ` +Object { + "html": " + + + + + + This is a test post title + + + + Hello world + + + + + + + + + + +
  +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ This is a test post title +
+ + + + + +
+ By Joe Bloggs • 1 Jan 2023 + + View in browser +
+
+ +

Hello world

+ + +
+
+

Subscription details

+

+ You are receiving this because you are a complimentary subscriber to Ghost. +

+ + + + + +
+

Name: not provided

+

Email: subscription-box-comped@example.com

+

Member since: date

+
+ Manage subscription → +
+
+ + + + + + + + +
Ghost © 2023 – Unsubscribe
\\"Powered
+
+ +
+
 
+ + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for comped members 2 1`] = ` +Object { + "html": " +Hello world + + + + + + +  + + + + + + + + + + + + + + + + + + + + + + + + + +Ghost [http://127.0.0.1:2369/] + + +Daily newsletter [http://127.0.0.1:2369/] + + + + + + + + + + +This is a test post title [http://127.0.0.1:2369/this-is-a-test-post-title-9/] + + + + + + + + + +By Joe Bloggs • 1 Jan 2023 + + +View in browser [http://127.0.0.1:2369/this-is-a-test-post-title-9/] + + + + + + + + + + + +Hello world + + + + + + + + + + + + + + + + + +Subscription details + + + +You are receiving this because you are a complimentary subscriber to Ghost. + + + + + + + + +Name: not provided + + +Email: subscription-box-comped@example.com + + +Member since: date + + + + +Manage subscription → [http://127.0.0.1:2369/#/portal/account] + + + + + + + + + + + + +Ghost © 2023 – Unsubscribe [unsubscribe_url] + + + +https://ghost.org/ + + + + + + + + + + + +  + + + + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for free members 1 1`] = ` +Object { + "html": " + + + + + + This is a test post title + + + + Hello world + + + + + + + + + + +
  +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ This is a test post title +
+ + + + + +
+ By Joe Bloggs • 1 Jan 2023 + + View in browser +
+
+ +

Hello world

+ + +
+
+

Subscription details

+

+ You are receiving this because you are a free subscriber to Ghost. +

+ + + + + +
+

Name: not provided

+

Email: subscription-box-1@example.com

+

Member since: date

+
+ Manage subscription → +
+
+ + + + + + + + +
Ghost © 2023 – Unsubscribe
\\"Powered
+
+ +
+
 
+ + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for free members 2 1`] = ` +Object { + "html": " +Hello world + + + + + + +  + + + + + + + + + + + + + + + + + + + + + + + + + +Ghost [http://127.0.0.1:2369/] + + +Daily newsletter [http://127.0.0.1:2369/] + + + + + + + + + + +This is a test post title [http://127.0.0.1:2369/this-is-a-test-post-title-8/] + + + + + + + + + +By Joe Bloggs • 1 Jan 2023 + + +View in browser [http://127.0.0.1:2369/this-is-a-test-post-title-8/] + + + + + + + + + + + +Hello world + + + + + + + + + + + + + + + + + +Subscription details + + + +You are receiving this because you are a free subscriber to Ghost. + + + + + + + + +Name: not provided + + +Email: subscription-box-1@example.com + + +Member since: date + + + + +Manage subscription → [http://127.0.0.1:2369/#/portal/account] + + + + + + + + + + + + +Ghost © 2023 – Unsubscribe [unsubscribe_url] + + + +https://ghost.org/ + + + + + + + + + + + +  + + + + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for paid member 1 1`] = ` +Object { + "html": " + + + + + + This is a test post title + + + + Hello world + + + + + + + + + + +
  +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ This is a test post title +
+ + + + + +
+ By Joe Bloggs • 1 Jan 2023 + + View in browser +
+
+ +

Hello world

+ + +
+
+

Subscription details

+

+ You are receiving this because you are a paid subscriber to Ghost. Your subscription will renew on date. +

+ + + + + +
+

Name: not provided

+

Email: paid@example.com

+

Member since: date

+
+ Manage subscription → +
+
+ + + + + + + + +
Ghost © 2023 – Unsubscribe
\\"Powered
+
+ +
+
 
+ + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for paid member 2 1`] = ` +Object { + "html": " +Hello world + + + + + + +  + + + + + + + + + + + + + + + + + + + + + + + + + +Ghost [http://127.0.0.1:2369/] + + +Daily newsletter [http://127.0.0.1:2369/] + + + + + + + + + + +This is a test post title [http://127.0.0.1:2369/this-is-a-test-post-title-11/] + + + + + + + + + +By Joe Bloggs • 1 Jan 2023 + + +View in browser [http://127.0.0.1:2369/this-is-a-test-post-title-11/] + + + + + + + + + + + +Hello world + + + + + + + + + + + + + + + + + +Subscription details + + + +You are receiving this because you are a paid subscriber to Ghost. Your subscription will renew on date. + + + + + + + + +Name: not provided + + +Email: paid@example.com + + +Member since: date + + + + +Manage subscription → [http://127.0.0.1:2369/#/portal/account] + + + + + + + + + + + + +Ghost © 2023 – Unsubscribe [unsubscribe_url] + + + +https://ghost.org/ + + + + + + + + + + + +  + + + + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for trialing member 1 1`] = ` +Object { + "html": " + + + + + + This is a test post title + + + + Hello world + + + + + + + + + + +
  +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ This is a test post title +
+ + + + + +
+ By Joe Bloggs • 1 Jan 2023 + + View in browser +
+
+ +

Hello world

+ + +
+
+

Subscription details

+

+ You are receiving this because you are a trialing subscriber to Ghost. Your free trial ends on date, at which time you will be charged the regular price. You can always cancel before then. +

+ + + + + +
+

Name: not provided

+

Email: trialing-paid@example.com

+

Member since: date

+
+ Manage subscription → +
+
+ + + + + + + + +
Ghost © 2023 – Unsubscribe
\\"Powered
+
+ +
+
 
+ + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for trialing member 2 1`] = ` +Object { + "html": " +Hello world + + + + + + +  + + + + + + + + + + + + + + + + + + + + + + + + + +Ghost [http://127.0.0.1:2369/] + + +Daily newsletter [http://127.0.0.1:2369/] + + + + + + + + + + +This is a test post title [http://127.0.0.1:2369/this-is-a-test-post-title-10/] + + + + + + + + + +By Joe Bloggs • 1 Jan 2023 + + +View in browser [http://127.0.0.1:2369/this-is-a-test-post-title-10/] + + + + + + + + + + + +Hello world + + + + + + + + + + + + + + + + + +Subscription details + + + +You are receiving this because you are a trialing subscriber to Ghost. Your free trial ends on date, at which time you will be charged the regular price. You can always cancel before then. + + + + + + + + +Name: not provided + + +Email: trialing-paid@example.com + + +Member since: date + + + + +Manage subscription → [http://127.0.0.1:2369/#/portal/account] + + + + + + + + + + + + +Ghost © 2023 – Unsubscribe [unsubscribe_url] + + + +https://ghost.org/ + + + + + + + + + + + +  + + + + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for trialing member 3 1`] = ` +Object { + "html": " + + + + + + This is a test post title + + + + Hello world + + + + + + + + + + +
  +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ This is a test post title +
+ + + + + +
+ By Joe Bloggs • 1 Jan 2023 + + View in browser +
+
+ +

Hello world

+ + +
+
+

Subscription details

+

+ You are receiving this because you are a paid subscriber to Ghost. Your subscription will renew on date. +

+ + + + + +
+

Name: not provided

+

Email: cus_c4f7911df8ef447a@example.com

+

Member since: date

+
+ Manage subscription → +
+
+ + + + + + + + +
Ghost © 2023 – Unsubscribe
\\"Powered
+
+ +
+
 
+ + +", +} +`; + +exports[`Batch sending tests Newsletter settings Shows subscription details box for trialing member 4 1`] = ` +Object { + "html": " +Hello world + + + + + + +  + + + + + + + + + + + + + + + + + + + + + + + + + +Ghost [http://127.0.0.1:2369/] + + +Daily newsletter [http://127.0.0.1:2369/] + + + + + + + + + + +This is a test post title [http://127.0.0.1:2369/this-is-a-test-post-title-10/] + + + + + + + + + +By Joe Bloggs • 1 Jan 2023 + + +View in browser [http://127.0.0.1:2369/this-is-a-test-post-title-10/] + + + + + + + + + + + +Hello world + + + + + + + + + + + + + + + + + +Subscription details + + + +You are receiving this because you are a paid subscriber to Ghost. Your subscription will renew on date. + + + + + + + + +Name: not provided + + +Email: cus_c4f7911df8ef447a@example.com Member since: date diff --git a/ghost/core/test/integration/services/email-service/batch-sending.test.js b/ghost/core/test/integration/services/email-service/batch-sending.test.js index d553df568b..10cf336bc7 100644 --- a/ghost/core/test/integration/services/email-service/batch-sending.test.js +++ b/ghost/core/test/integration/services/email-service/batch-sending.test.js @@ -13,7 +13,7 @@ const {settingsCache} = require('../../../../core/server/services/settings-helpe const DomainEvents = require('@tryghost/domain-events'); const emailService = require('../../../../core/server/services/email-service'); const should = require('should'); -const {mockSetting} = require('../../../utils/e2e-framework-mock-manager'); +const {mockSetting, stripeMocker} = require('../../../utils/e2e-framework-mock-manager'); const mobileDocExample = '{"version":"0.3.1","atoms":[],"cards":[],"markups":[],"sections":[[1,"p",[[0,[],0,"Hello world"]]]],"ghostVersion":"4.0"}'; const mobileDocWithPaywall = '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["paywall",{}]],"sections":[[1,"p",[[0,[],0,"Free content"]]],[10,0],[1,"p",[[0,[],0,"Members content"]]]]}'; @@ -263,6 +263,7 @@ describe('Batch sending tests', function () { // Allows for setting stubbedSend during tests return stubbedSend.call(this, ...arguments); }); + mockManager.mockStripe(); }); afterEach(async function () { @@ -1039,19 +1040,189 @@ describe('Batch sending tests', function () { await models.Newsletter.edit({show_comment_cta: true}, {id: defaultNewsletter.id}); }); - it('Shows subscription details box', async function () { + it('Shows subscription details box for free members', async function () { + // Create a new member without a first_name + await models.Member.add({ + email: 'subscription-box-1@example.com', + labels: [{name: 'subscription-box-tests'}], + newsletters: [{ + id: fixtureManager.get('newsletters', 0).id + }] + }); + mockSetting('email_track_clicks', false); // Disable link replacement for this test const defaultNewsletter = await getDefaultNewsletter(); await models.Newsletter.edit({show_subscription_details: true}, {id: defaultNewsletter.id}); - const {html} = await sendEmail({ + const {html, plaintext} = await sendEmail({ title: 'This is a test post title', mobiledoc: mobileDocExample - }); + }, 'label:subscription-box-tests'); // Currently the link is not present in plaintext version (because no text) assert.equal(html.match(/#\/portal\/account/g).length, 1, 'Subscription details box should contain a link to the account page'); + + // Check text matches + assert.match(plaintext, /You are receiving this because you are a free subscriber to Ghost\./); + + await lastEmailMatchSnapshot(); + + // undo + await models.Newsletter.edit({show_subscription_details: false}, {id: defaultNewsletter.id}); + }); + + it('Shows subscription details box for comped members', async function () { + // Create a new member without a first_name + await models.Member.add({ + email: 'subscription-box-comped@example.com', + labels: [{name: 'subscription-box-comped-tests'}], + newsletters: [{ + id: fixtureManager.get('newsletters', 0).id + }], + status: 'comped' + }); + + mockSetting('email_track_clicks', false); // Disable link replacement for this test + + const defaultNewsletter = await getDefaultNewsletter(); + await models.Newsletter.edit({show_subscription_details: true}, {id: defaultNewsletter.id}); + + const {html, plaintext} = await sendEmail({ + title: 'This is a test post title', + mobiledoc: mobileDocExample + }, 'label:subscription-box-comped-tests'); + + // Currently the link is not present in plaintext version (because no text) + assert.equal(html.match(/#\/portal\/account/g).length, 1, 'Subscription details box should contain a link to the account page'); + + // Check text matches + assert.match(plaintext, /You are receiving this because you are a complimentary subscriber to Ghost\./); + + await lastEmailMatchSnapshot(); + + // undo + await models.Newsletter.edit({show_subscription_details: false}, {id: defaultNewsletter.id}); + }); + + it('Shows subscription details box for trialing member', async function () { + mockSetting('email_track_clicks', false); // Disable link replacement for this test + + // Create a new member without a first_name + const customer = stripeMocker.createCustomer({ + email: 'trialing-paid@example.com' + }); + const price = await stripeMocker.getPriceForTier('default-product', 'month'); + await stripeMocker.createTrialSubscription({ + customer, + price + }); + + const member = await models.Member.findOne({email: customer.email}, {require: true}); + await models.Member.edit({ + labels: [{name: 'subscription-box-trialing-tests'}], + newsletters: [{ + id: fixtureManager.get('newsletters', 0).id + }] + }, {id: member.id}); + + const defaultNewsletter = await getDefaultNewsletter(); + await models.Newsletter.edit({show_subscription_details: true}, {id: defaultNewsletter.id}); + + const {html, plaintext} = await sendEmail({ + title: 'This is a test post title', + mobiledoc: mobileDocExample + }, 'label:subscription-box-trialing-tests'); + + // Currently the link is not present in plaintext version (because no text) + assert.equal(html.match(/#\/portal\/account/g).length, 1, 'Subscription details box should contain a link to the account page'); + + // Check text matches + assert.match(plaintext, /You are receiving this because you are a trialing subscriber to Ghost\. Your free trial ends on \d+ \w+ \d+, at which time you will be charged the regular price\. You can always cancel before then\./); + + await lastEmailMatchSnapshot(); + + // undo + await models.Newsletter.edit({show_subscription_details: false}, {id: defaultNewsletter.id}); + }); + + it('Shows subscription details box for paid member', async function () { + mockSetting('email_track_clicks', false); // Disable link replacement for this test + + // Create a new member without a first_name + const customer = stripeMocker.createCustomer({ + email: 'paid@example.com' + }); + const price = await stripeMocker.getPriceForTier('default-product', 'month'); + await stripeMocker.createSubscription({ + customer, + price + }); + + const member = await models.Member.findOne({email: customer.email}, {require: true}); + await models.Member.edit({ + labels: [{name: 'subscription-box-paid-tests'}], + newsletters: [{ + id: fixtureManager.get('newsletters', 0).id + }] + }, {id: member.id}); + + const defaultNewsletter = await getDefaultNewsletter(); + await models.Newsletter.edit({show_subscription_details: true}, {id: defaultNewsletter.id}); + + const {html, plaintext} = await sendEmail({ + title: 'This is a test post title', + mobiledoc: mobileDocExample + }, 'label:subscription-box-paid-tests'); + + // Currently the link is not present in plaintext version (because no text) + assert.equal(html.match(/#\/portal\/account/g).length, 1, 'Subscription details box should contain a link to the account page'); + + // Check text matches + assert.match(plaintext, /You are receiving this because you are a paid subscriber to Ghost\. Your subscription will renew on \d+ \w+ \d+\./); + + await lastEmailMatchSnapshot(); + + // undo + await models.Newsletter.edit({show_subscription_details: false}, {id: defaultNewsletter.id}); + }); + + it('Shows subscription details box for canceled paid member', async function () { + mockSetting('email_track_clicks', false); // Disable link replacement for this test + + // Create a new member without a first_name + const customer = stripeMocker.createCustomer({ + email: 'canceled-paid@example.com' + }); + const price = await stripeMocker.getPriceForTier('default-product', 'month'); + await stripeMocker.createSubscription({ + customer, + price, + cancel_at_period_end: true + }); + + const member = await models.Member.findOne({email: customer.email}, {require: true}); + await models.Member.edit({ + labels: [{name: 'subscription-box-canceled-tests'}], + newsletters: [{ + id: fixtureManager.get('newsletters', 0).id + }] + }, {id: member.id}); + + const defaultNewsletter = await getDefaultNewsletter(); + await models.Newsletter.edit({show_subscription_details: true}, {id: defaultNewsletter.id}); + + const {html, plaintext} = await sendEmail({ + title: 'This is a test post title', + mobiledoc: mobileDocExample + }, 'label:subscription-box-canceled-tests'); + + // Currently the link is not present in plaintext version (because no text) + assert.equal(html.match(/#\/portal\/account/g).length, 1, 'Subscription details box should contain a link to the account page'); + + // Check text matches + assert.match(plaintext, /You are receiving this because you are a paid subscriber to Ghost\. Your subscription has been canceled and will expire on \d+ \w+ \d+\. You can resume your subscription via your account settings\./); + await lastEmailMatchSnapshot(); // undo diff --git a/ghost/core/test/utils/stripe-mocker.js b/ghost/core/test/utils/stripe-mocker.js index 083a7d5dc7..a7d2e4fb8b 100644 --- a/ghost/core/test/utils/stripe-mocker.js +++ b/ghost/core/test/utils/stripe-mocker.js @@ -85,7 +85,8 @@ class StripeMocker { customer, price, status: 'trialing', - trial_end_at: (Date.now() + 1000 * 60 * 60 * 24 * 7) / 1000, + trial_start: Date.now() / 1000, + trial_end: (Date.now() + 1000 * 60 * 60 * 24 * 7) / 1000, ...overrides }); } diff --git a/ghost/email-service/lib/email-renderer.js b/ghost/email-service/lib/email-renderer.js index af6239309e..c58522344a 100644 --- a/ghost/email-service/lib/email-renderer.js +++ b/ghost/email-service/lib/email-renderer.js @@ -11,7 +11,7 @@ const tpl = require('@tryghost/tpl'); const messages = { subscriptionStatus: { - free: 'You are currently subscribed to the free plan.', + free: '', expired: 'Your subscription has expired.', canceled: 'Your subscription has been canceled and will expire on {date}. You can resume your subscription via your account settings.', active: 'Your subscription will renew on {date}.', @@ -405,6 +405,29 @@ class EmailRenderer { return url.href; } + /** + * Returns whether a paid member is trialing a subscription + */ + isMemberTrialing(member) { + // Do we have an active subscription? + if (member.status === 'paid') { + let activeSubscription = member.subscriptions.find((subscription) => { + return subscription.status === 'trialing'; + }); + + if (!activeSubscription) { + return false; + } + + // Translate to a human readable string + if (activeSubscription.trial_end_at && activeSubscription.trial_end_at > new Date() && activeSubscription.status === 'trialing') { + return true; + } + } + + return false; + } + /** * @param {MemberLike} member * @returns {string} @@ -528,6 +551,9 @@ class EmailRenderer { if (member.status === 'comped') { return 'complimentary'; } + if (this.isMemberTrialing(member)) { + return 'trialing'; + } return member.status; } }, diff --git a/ghost/email-service/lib/email-templates/template.hbs b/ghost/email-service/lib/email-templates/template.hbs index b686785fb2..aeacc39c0e 100644 --- a/ghost/email-service/lib/email-templates/template.hbs +++ b/ghost/email-service/lib/email-templates/template.hbs @@ -180,8 +180,7 @@

Subscription details

- You are receiving this because you are a %%{status}%% subscriber to {{site.title}}. - %%{status_text}%% + You are receiving this because you are a %%{status}%% subscriber to {{site.title}}. %%{status_text}%%

diff --git a/ghost/email-service/test/email-renderer.test.js b/ghost/email-service/test/email-renderer.test.js index 1ee4c34a41..2b5403120e 100644 --- a/ghost/email-service/test/email-renderer.test.js +++ b/ghost/email-service/test/email-renderer.test.js @@ -203,6 +203,24 @@ describe('Email renderer', function () { assert.equal(replacements[0].getValue(member), 'complimentary'); }); + it('returns mapped trialing status', function () { + member.status = 'paid'; + member.subscriptions = [ + { + status: 'trialing', + trial_end_at: new Date(2050, 2, 13, 12, 0), + current_period_end: new Date(2023, 2, 13, 12, 0), + cancel_at_period_end: false + } + ]; + const html = 'Hello %%{status}%%,'; + const replacements = emailRenderer.buildReplacementDefinitions({html, newsletterUuid: newsletter.get('uuid')}); + assert.equal(replacements.length, 1); + assert.equal(replacements[0].token.toString(), '/%%\\{status\\}%%/g'); + assert.equal(replacements[0].id, 'status'); + assert.equal(replacements[0].getValue(member), 'trialing'); + }); + it('returns manage_account_url', function () { const html = 'Hello %%{manage_account_url}%%,'; const replacements = emailRenderer.buildReplacementDefinitions({html, newsletterUuid: newsletter.get('uuid')}); @@ -214,11 +232,21 @@ describe('Email renderer', function () { it('returns status_text', function () { const html = 'Hello %%{status_text}%%,'; + member.status = 'paid'; + member.subscriptions = [ + { + status: 'trialing', + trial_end_at: new Date(2050, 2, 13, 12, 0), + current_period_end: new Date(2023, 2, 13, 12, 0), + cancel_at_period_end: false + } + ]; + const replacements = emailRenderer.buildReplacementDefinitions({html, newsletterUuid: newsletter.get('uuid')}); assert.equal(replacements.length, 1); assert.equal(replacements[0].token.toString(), '/%%\\{status_text\\}%%/g'); assert.equal(replacements[0].id, 'status_text'); - assert.equal(replacements[0].getValue(member), 'You are currently subscribed to the free plan.'); + assert.equal(replacements[0].getValue(member), 'Your free trial ends on 13 March 2050, at which time you will be charged the regular price. You can always cancel before then.'); }); it('returns correct createdAt', function () { @@ -279,6 +307,109 @@ describe('Email renderer', function () { }); }); + describe('isMemberTrialing', function () { + let emailRenderer; + + beforeEach(function () { + emailRenderer = new EmailRenderer({ + urlUtils: { + urlFor: () => 'http://example.com/subdirectory/' + }, + labs: { + isSet: () => true + }, + settingsCache: { + get: (key) => { + if (key === 'timezone') { + return 'UTC'; + } + } + } + }); + }); + + it('Returns false for free member', function () { + const member = { + id: '456', + uuid: 'myuuid', + name: 'Test User', + email: 'test@example.com', + createdAt: new Date(2023, 2, 13, 12, 0), + status: 'free' + }; + + const result = emailRenderer.isMemberTrialing(member); + assert.equal(result, false); + }); + + it('Returns false for paid member without trial', function () { + const member = { + id: '456', + uuid: 'myuuid', + name: 'Test User', + email: 'test@example.com', + createdAt: new Date(2023, 2, 13, 12, 0), + status: 'paid', + subscriptions: [ + { + status: 'active', + current_period_end: new Date(2023, 2, 13, 12, 0), + cancel_at_period_end: false + } + ] + }; + + const result = emailRenderer.isMemberTrialing(member); + assert.equal(result, false); + }); + + it('Returns true for trialing paid member', function () { + const member = { + id: '456', + uuid: 'myuuid', + name: 'Test User', + email: 'test@example.com', + createdAt: new Date(2023, 2, 13, 12, 0), + status: 'paid', + subscriptions: [ + { + status: 'trialing', + trial_end_at: new Date(2050, 2, 13, 12, 0), + current_period_end: new Date(2023, 2, 13, 12, 0), + cancel_at_period_end: false + } + ], + tiers: [] + }; + + const result = emailRenderer.isMemberTrialing(member); + assert.equal(result, true); + }); + + it('Returns false for expired trialing paid member', function () { + const member = { + id: '456', + uuid: 'myuuid', + name: 'Test User', + email: 'test@example.com', + createdAt: new Date(2023, 2, 13, 12, 0), + status: 'paid', + subscriptions: [ + { + status: 'trialing', + trial_end_at: new Date(2000, 2, 13, 12, 0), + current_period_end: new Date(2023, 2, 13, 12, 0), + cancel_at_period_end: false + } + ], + tiers: [] + }; + + const result = emailRenderer.isMemberTrialing(member); + assert.equal(result, false); + }); + }); + describe('getMemberStatusText', function () { let emailRenderer; @@ -311,7 +442,7 @@ describe('Email renderer', function () { }; const result = emailRenderer.getMemberStatusText(member); - assert.equal(result, 'You are currently subscribed to the free plan.'); + assert.equal(result, ''); }); it('Returns for active paid member', function () {