From 6e92229a0759e4d9ff60353158dacd10f8be2d4b Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Mon, 25 Apr 2022 20:11:27 +0100 Subject: [PATCH] Remapped `member.subscribed` value using newsletter subscriptions (#14563) refs https://github.com/TryGhost/Team/issues/1545 - Remapped `member.subscribed` value based on newsletter subscriptions in API output - Enabled filtering by subscribed status for multiple newsletters Co-authored-by: Matt Hanley --- .c8rc.json | 2 +- .../canary/utils/serializers/input/members.js | 18 + .../utils/serializers/output/members.js | 18 +- .../members-newsletters.test.js.snap | 671 ++++++++++++++++++ .../admin/__snapshots__/members.test.js.snap | 85 ++- .../__snapshots__/newsletters.test.js.snap | 4 +- .../e2e-api/admin/members-newsletters.test.js | 184 +++++ test/e2e-api/admin/members.test.js | 4 +- test/utils/fixtures/data-generator.js | 2 +- 9 files changed, 966 insertions(+), 22 deletions(-) create mode 100644 test/e2e-api/admin/__snapshots__/members-newsletters.test.js.snap create mode 100644 test/e2e-api/admin/members-newsletters.test.js diff --git a/.c8rc.json b/.c8rc.json index 0f4dd54fbd..57546f8bd8 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -7,7 +7,7 @@ "cobertura" ], "statements": 57, - "branches": 86, + "branches": 85, "functions": 53, "lines": 57, "include": [ diff --git a/core/server/api/canary/utils/serializers/input/members.js b/core/server/api/canary/utils/serializers/input/members.js index e886c4f171..e1a5195a44 100644 --- a/core/server/api/canary/utils/serializers/input/members.js +++ b/core/server/api/canary/utils/serializers/input/members.js @@ -1,5 +1,7 @@ const _ = require('lodash'); const debug = require('@tryghost/debug')('api:canary:utils:serializers:input:members'); +const mapNQLKeyValues = require('@tryghost/nql').utils.mapKeyValues; +const labsService = require('../../../../../../shared/labs'); function defaultRelations(frame) { if (frame.options.withRelated) { @@ -17,6 +19,22 @@ module.exports = { browse(apiConfig, frame) { debug('browse'); defaultRelations(frame); + + if (labsService.isSet('multipleNewsletters')) { + frame.options.mongoTransformer = mapNQLKeyValues({ + key: { + from: 'subscribed', + to: 'newsletters.status' + }, + values: [{ + from: true, + to: 'active' + }, { + from: false, + to: {$ne: 'active'} + }] + }); + } }, read() { diff --git a/core/server/api/canary/utils/serializers/output/members.js b/core/server/api/canary/utils/serializers/output/members.js index 071d039f19..c8726a7b0d 100644 --- a/core/server/api/canary/utils/serializers/output/members.js +++ b/core/server/api/canary/utils/serializers/output/members.js @@ -132,11 +132,19 @@ function serializeMember(member, options) { serialized.products = json.products; } - if (json.newsletters && labsService.isSet('multipleNewsletters')) { - json.newsletters.sort((a, b) => { - return a.sort_order - b.sort_order; - }); - serialized.newsletters = json.newsletters; + if (labsService.isSet('multipleNewsletters')) { + if (json.newsletters) { + serialized.newsletters = json.newsletters + .filter(newsletter => newsletter.status === 'active') + .sort((a, b) => { + return a.sort_order - b.sort_order; + }); + } + // override the `subscribed` param to mean "subscribed to any active newsletter" + serialized.subscribed = false; + if (serialized.newsletters.length > 0) { + serialized.subscribed = true; + } } return serialized; diff --git a/test/e2e-api/admin/__snapshots__/members-newsletters.test.js.snap b/test/e2e-api/admin/__snapshots__/members-newsletters.test.js.snap new file mode 100644 index 0000000000..c7f22e5366 --- /dev/null +++ b/test/e2e-api/admin/__snapshots__/members-newsletters.test.js.snap @@ -0,0 +1,671 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Members API - No Newsletters Can fetch members who are NOT subscribed 1: [body] 1`] = ` +Object { + "members": Array [ + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "vip-paid@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Peter Venkman", + "note": null, + "status": "paid", + "subscribed": false, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "with-product@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Dana Barrett", + "note": null, + "status": "paid", + "subscribed": false, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + ], + "meta": Object { + "pagination": Object { + "limit": 15, + "next": null, + "page": 1, + "pages": 1, + "prev": null, + "total": 2, + }, + }, +} +`; + +exports[`Members API - No Newsletters Can fetch members who are NOT subscribed 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "2028", + "content-type": "application/json; charset=utf-8", + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + +exports[`Members API - No Newsletters Can fetch members who are subscribed 1: [body] 1`] = ` +Object { + "members": Array [ + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "member1@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Mr Egg", + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "member2@test.com", + "email_count": 0, + "email_open_rate": 50, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": null, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "paid@test.com", + "email_count": 0, + "email_open_rate": 80, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Egon Spengler", + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "trialing@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Ray Stantz", + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "comped@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Vinz Clortho", + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "vip@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Winston Zeddemore", + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + ], + "meta": Object { + "pagination": Object { + "limit": 15, + "next": null, + "page": 1, + "pages": 1, + "prev": null, + "total": 6, + }, + }, +} +`; + +exports[`Members API - No Newsletters Can fetch members who are subscribed 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "6501", + "content-type": "application/json; charset=utf-8", + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + +exports[`Members API - With Newsletters - compat mode Can fetch members who are NOT subscribed 1: [body] 1`] = ` +Object { + "members": Array [ + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "vip-paid@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Peter Venkman", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": false, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "with-product@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Dana Barrett", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": false, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + ], + "meta": Object { + "pagination": Object { + "limit": 15, + "next": null, + "page": 1, + "pages": 1, + "prev": null, + "total": 2, + }, + }, +} +`; + +exports[`Members API - With Newsletters - compat mode Can fetch members who are NOT subscribed 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "2062", + "content-type": "application/json; charset=utf-8", + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + +exports[`Members API - With Newsletters - compat mode Can fetch members who are subscribed 1: [body] 1`] = ` +Object { + "members": Array [ + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "member1@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Mr Egg", + "newsletters": Any, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "member2@test.com", + "email_count": 0, + "email_open_rate": 50, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": null, + "newsletters": Any, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "paid@test.com", + "email_count": 0, + "email_open_rate": 80, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Egon Spengler", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "trialing@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Ray Stantz", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "comped@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Vinz Clortho", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "vip@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Winston Zeddemore", + "newsletters": Any, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + ], + "meta": Object { + "pagination": Object { + "limit": 15, + "next": null, + "page": 1, + "pages": 1, + "prev": null, + "total": 6, + }, + }, +} +`; + +exports[`Members API - With Newsletters - compat mode Can fetch members who are subscribed 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "10814", + "content-type": "application/json; charset=utf-8", + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + +exports[`Members API - With Newsletters Can fetch members who are NOT subscribed 1: [body] 1`] = ` +Object { + "members": Array [ + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "vip-paid@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Peter Venkman", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": false, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "with-product@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Dana Barrett", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": false, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + ], + "meta": Object { + "pagination": Object { + "limit": 15, + "next": null, + "page": 1, + "pages": 1, + "prev": null, + "total": 2, + }, + }, +} +`; + +exports[`Members API - With Newsletters Can fetch members who are NOT subscribed 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "2062", + "content-type": "application/json; charset=utf-8", + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + +exports[`Members API - With Newsletters Can fetch members who are subscribed 1: [body] 1`] = ` +Object { + "members": Array [ + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "member1@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Mr Egg", + "newsletters": Any, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "member2@test.com", + "email_count": 0, + "email_open_rate": 50, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": null, + "newsletters": Any, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "paid@test.com", + "email_count": 0, + "email_open_rate": 80, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Egon Spengler", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "trialing@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Ray Stantz", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "comped@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Vinz Clortho", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "vip@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Winston Zeddemore", + "newsletters": Any, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + ], + "meta": Object { + "pagination": Object { + "limit": 15, + "next": null, + "page": 1, + "pages": 1, + "prev": null, + "total": 6, + }, + }, +} +`; + +exports[`Members API - With Newsletters Can fetch members who are subscribed 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "10814", + "content-type": "application/json; charset=utf-8", + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; diff --git a/test/e2e-api/admin/__snapshots__/members.test.js.snap b/test/e2e-api/admin/__snapshots__/members.test.js.snap index 56ddb89ffd..413f2ccb56 100644 --- a/test/e2e-api/admin/__snapshots__/members.test.js.snap +++ b/test/e2e-api/admin/__snapshots__/members.test.js.snap @@ -2050,7 +2050,7 @@ Object { "note": "test note", "products": Array [], "status": "free", - "subscribed": false, + "subscribed": true, "subscriptions": Any, "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, @@ -2063,7 +2063,7 @@ exports[`Members API: with multiple newsletters Can add and edit with custom new Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1249", + "content-length": "1248", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -2118,7 +2118,7 @@ Object { "note": "test note", "products": Array [], "status": "free", - "subscribed": false, + "subscribed": true, "subscriptions": Any, "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, @@ -2131,7 +2131,7 @@ exports[`Members API: with multiple newsletters Can add and edit with custom new Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1248", + "content-length": "1247", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -2210,7 +2210,7 @@ Object { "note": "test note", "products": Array [], "status": "free", - "subscribed": false, + "subscribed": true, "subscriptions": Any, "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, @@ -2223,7 +2223,7 @@ exports[`Members API: with multiple newsletters Can add with default newsletters Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1834", + "content-length": "1833", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -2421,7 +2421,7 @@ exports[`Members API: with multiple newsletters Can browse 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "8564", + "content-length": "12775", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -2432,6 +2432,69 @@ Object { exports[`Members API: with multiple newsletters Can filter on newsletter slug 1: [body] 1`] = ` Object { "members": Array [ + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "trialing@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Ray Stantz", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "comped@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Vinz Clortho", + "newsletters": Any, + "note": null, + "status": "paid", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, + Object { + "avatar_image": null, + "comped": false, + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "email": "vip@test.com", + "email_count": 0, + "email_open_rate": null, + "email_opened_count": 0, + "geolocation": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "labels": Any, + "last_seen_at": null, + "name": "Winston Zeddemore", + "newsletters": Any, + "note": null, + "status": "free", + "subscribed": true, + "subscriptions": Any, + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + }, Object { "avatar_image": null, "comped": false, @@ -2448,7 +2511,7 @@ Object { "newsletters": Any, "note": "test note", "status": "free", - "subscribed": false, + "subscribed": true, "subscriptions": Any, "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, @@ -2461,7 +2524,7 @@ Object { "page": 1, "pages": 1, "prev": null, - "total": 1, + "total": 4, }, }, } @@ -2471,7 +2534,7 @@ exports[`Members API: with multiple newsletters Can filter on newsletter slug 2: Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1908", + "content-length": "8174", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -2512,7 +2575,7 @@ exports[`Members API: with multiple newsletters Can read 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "607", + "content-length": "1208", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", diff --git a/test/e2e-api/admin/__snapshots__/newsletters.test.js.snap b/test/e2e-api/admin/__snapshots__/newsletters.test.js.snap index afbe8053cd..eab24acd06 100644 --- a/test/e2e-api/admin/__snapshots__/newsletters.test.js.snap +++ b/test/e2e-api/admin/__snapshots__/newsletters.test.js.snap @@ -201,7 +201,7 @@ Object { "show_header_title": true, "slug": "old-newsletter", "sort_order": 2, - "status": "inactive", + "status": "archived", "subscribe_on_signup": true, "title_alignment": "center", "title_font_category": "serif", @@ -439,7 +439,7 @@ Object { "show_header_title": true, "slug": "old-newsletter", "sort_order": 2, - "status": "inactive", + "status": "archived", "subscribe_on_signup": true, "title_alignment": "center", "title_font_category": "serif", diff --git a/test/e2e-api/admin/members-newsletters.test.js b/test/e2e-api/admin/members-newsletters.test.js new file mode 100644 index 0000000000..e425d1ef46 --- /dev/null +++ b/test/e2e-api/admin/members-newsletters.test.js @@ -0,0 +1,184 @@ +const {agentProvider, mockManager, fixtureManager, matchers} = require('../../utils/e2e-framework'); +const {anyEtag, anyObjectId, anyUuid, anyISODateTime, anyISODate, anyString, anyArray, anyLocationFor, anyErrorId} = matchers; + +const assert = require('assert'); +const nock = require('nock'); +const should = require('should'); +const sinon = require('sinon'); +const testUtils = require('../../utils'); +const Papa = require('papaparse'); + +const models = require('../../../core/server/models'); +const {Product} = require('../../../core/server/models/product'); + +async function assertMemberEvents({eventType, memberId, asserts}) { + const events = await models[eventType].where('member_id', memberId).fetchAll(); + events.map(e => e.toJSON()).should.match(asserts); + assert.equal(events.length, asserts.length, `Only ${asserts.length} ${eventType} should have been added.`); +} + +async function assertSubscription(subscriptionId, asserts) { + // eslint-disable-next-line dot-notation + const subscription = await models['StripeCustomerSubscription'].where('subscription_id', subscriptionId).fetch({require: true}); + + // We use the native toJSON to prevent calling the overriden serialize method + models.Base.Model.prototype.serialize.call(subscription).should.match(asserts); +} + +async function getPaidProduct() { + return await Product.findOne({type: 'paid'}); +} + +const memberMatcherNoIncludes = { + id: anyObjectId, + uuid: anyUuid, + created_at: anyISODateTime, + updated_at: anyISODateTime +}; + +const memberMatcherShallowIncludes = { + id: anyObjectId, + uuid: anyUuid, + created_at: anyISODateTime, + updated_at: anyISODateTime, + subscriptions: anyArray, + labels: anyArray +}; + +const memberMatcherShallowIncludesForNewsletters = { + id: anyObjectId, + uuid: anyUuid, + created_at: anyISODateTime, + updated_at: anyISODateTime, + subscriptions: anyArray, + labels: anyArray, + newsletters: anyArray +}; + +let agent; + +describe('Members API - No Newsletters', function () { + before(async function () { + agent = await agentProvider.getAdminAPIAgent(); + await fixtureManager.init('members'); + await agent.loginAsOwner(); + }); + + beforeEach(function () { + mockManager.mockLabsDisabled('multipleNewsletters'); + }); + + afterEach(function () { + mockManager.restore(); + }); + + // List Members + + it('Can fetch members who are subscribed', async function () { + await agent + .get('/members/?filter=subscribed:true') + .expectStatus(200) + .matchBodySnapshot({ + members: new Array(6).fill(memberMatcherShallowIncludes) + }) + .matchHeaderSnapshot({ + etag: anyEtag + }); + }); + + it('Can fetch members who are NOT subscribed', async function () { + await agent + .get('/members/?filter=subscribed:false') + .expectStatus(200) + .matchBodySnapshot({ + members: new Array(2).fill(memberMatcherShallowIncludes) + }) + .matchHeaderSnapshot({ + etag: anyEtag + }); + }); +}); + +describe('Members API - With Newsletters', function () { + before(async function () { + agent = await agentProvider.getAdminAPIAgent(); + await fixtureManager.init('newsletters', 'members:newsletters'); + await agent.loginAsOwner(); + }); + + beforeEach(function () { + mockManager.mockLabsEnabled('multipleNewsletters'); + }); + + afterEach(function () { + mockManager.restore(); + }); + + // List Members + + it('Can fetch members who are subscribed', async function () { + await agent + .get('/members/?filter=newsletters.status:active') + .expectStatus(200) + .matchBodySnapshot({ + members: new Array(6).fill(memberMatcherShallowIncludesForNewsletters) + }) + .matchHeaderSnapshot({ + etag: anyEtag + }); + }); + + it('Can fetch members who are NOT subscribed', async function () { + await agent + .get('/members/?filter=newsletters.status:-active') + .expectStatus(200) + .matchBodySnapshot({ + members: new Array(2).fill(memberMatcherShallowIncludesForNewsletters) + }) + .matchHeaderSnapshot({ + etag: anyEtag + }); + }); +}); + +describe('Members API - With Newsletters - compat mode', function () { + before(async function () { + agent = await agentProvider.getAdminAPIAgent(); + await fixtureManager.init('newsletters', 'members:newsletters'); + await agent.loginAsOwner(); + }); + + beforeEach(function () { + mockManager.mockLabsEnabled('multipleNewsletters'); + }); + + afterEach(function () { + mockManager.restore(); + }); + + // List Members + + it('Can fetch members who are subscribed', async function () { + await agent + .get('/members/?filter=subscribed:true') + .expectStatus(200) + .matchBodySnapshot({ + members: new Array(6).fill(memberMatcherShallowIncludesForNewsletters) + }) + .matchHeaderSnapshot({ + etag: anyEtag + }); + }); + + it('Can fetch members who are NOT subscribed', async function () { + await agent + .get('/members/?filter=subscribed:false') + .expectStatus(200) + .matchBodySnapshot({ + members: new Array(2).fill(memberMatcherShallowIncludesForNewsletters) + }) + .matchHeaderSnapshot({ + etag: anyEtag + }); + }); +}); diff --git a/test/e2e-api/admin/members.test.js b/test/e2e-api/admin/members.test.js index b588b3e494..30207e843f 100644 --- a/test/e2e-api/admin/members.test.js +++ b/test/e2e-api/admin/members.test.js @@ -1344,7 +1344,7 @@ describe('Members API', function () { describe('Members API: with multiple newsletters', function () { before(async function () { agent = await agentProvider.getAdminAPIAgent(); - await fixtureManager.init('members', 'newsletters'); + await fixtureManager.init('newsletters', 'members:newsletters'); await agent.loginAsOwner(); }); @@ -1422,7 +1422,7 @@ describe('Members API: with multiple newsletters', function () { .get('/members/?filter=newsletters:weekly-newsletter') .expectStatus(200) .matchBodySnapshot({ - members: new Array(1).fill(memberMatcherShallowIncludesForNewsletters) + members: new Array(4).fill(memberMatcherShallowIncludesForNewsletters) }) .matchHeaderSnapshot({ etag: anyEtag diff --git a/test/utils/fixtures/data-generator.js b/test/utils/fixtures/data-generator.js index ec206d5db2..841d7a14d2 100644 --- a/test/utils/fixtures/data-generator.js +++ b/test/utils/fixtures/data-generator.js @@ -410,7 +410,7 @@ DataGenerator.Content = { sender_name: 'Jamie', sender_email: 'jamie@example.com', sender_reply_to: 'newsletter', - status: 'inactive', + status: 'archived', subscribe_on_signup: true, title_font_category: 'serif', body_font_category: 'serif',