From 3e62764a64ad21e83b0dac2b99ad21d8e4b1e92e Mon Sep 17 00:00:00 2001 From: Ronald Langeveld Date: Thu, 8 Dec 2022 16:30:32 +0700 Subject: [PATCH] Added csv validation, members export Playwright test ref https://github.com/TryGhost/Team/issues/2371 - updated Member exports with csv validation - added member fixtures to be loaded into Ghost to ensure filtering works correctly when downloading / exporting members csv. --- .../test/e2e-browser/admin/members.spec.js | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/ghost/core/test/e2e-browser/admin/members.spec.js b/ghost/core/test/e2e-browser/admin/members.spec.js index 9cde2a7130..b2761cb43c 100644 --- a/ghost/core/test/e2e-browser/admin/members.spec.js +++ b/ghost/core/test/e2e-browser/admin/members.spec.js @@ -1,5 +1,6 @@ const {expect, test} = require('@playwright/test'); const {createMember} = require('../utils/e2e-browser-utils'); +const fs = require('fs'); test.describe('Admin', () => { test.describe('Members', () => { @@ -104,13 +105,33 @@ test.describe('Admin', () => { email: 'test@member3.com', note: 'This is a test member', label: 'Test Label' + }, + { + name: 'Sashi', + email: 'test@member4.com', + note: 'This is a test member', + label: 'dog' + }, + { + name: 'Mia', + email: 'test@member5.com', + note: 'This is a test member', + label: 'dog' + }, + { + name: 'Minki', + email: 'test@member6.com', + note: 'This is a test member', + label: 'dog' } ]; test('All members can be exported', async ({page}) => { + // adds 6 members, 3 with the same label for (let member of membersFixture) { await createMember(page, member); } + await page.goto('/ghost'); await page.locator('.gh-nav a[href="#/members/"]').click(); await page.waitForSelector('button[data-test-button="members-actions"]'); await page.locator('button[data-test-button="members-actions"]').click(); @@ -121,6 +142,24 @@ test.describe('Admin', () => { ]); const filename = await download.suggestedFilename(); expect(filename).toContain('.csv'); + const csv = await download.path(); + let csvContents = await fs.readFileSync(csv).toString(); + expect(csvContents).toMatch(/id,email,name,note,subscribed_to_emails,complimentary_plan,stripe_customer_id,created_at,deleted_at,labels,tiers/); + membersFixture.forEach((member) => { + expect(csvContents).toMatch(member.name); + expect(csvContents).toMatch(member.email); + expect(csvContents).toMatch(member.note); + expect(csvContents).toMatch(member.label); + }); + // expect(csvContents).toMatch('Test Label'); we deleted the label in a previous test so it's not in this the export + const countIds = csvContents.match(/[a-z0-9]{24}/gm).length; + expect(countIds).toEqual(6); + const countTimestamps = csvContents.match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/gm).length; + expect(countTimestamps).toEqual(6); + const countRows = csvContents.match(/(?:"(?:[^"]|"")*"|[^,\n]*)(?:,(?:"(?:[^"]|"")*"|[^,\n]*))*\n/g).length; + expect(countRows).toEqual(6); + const csvRegex = /^[^",]+((?<=[,\n])|(?=[,\n]))|[^",]+/gm; + expect(csvContents).toMatch(csvRegex); }); test('A filtered list of members can be exported', async ({page}) => { @@ -131,7 +170,10 @@ test.describe('Admin', () => { await page.waitForSelector('div[data-test-button="members-filter-actions"]'); await page.locator('div[data-test-button="members-filter-actions"]').click(); await page.locator('select[data-test-select="members-filter"]').click(); - await page.locator('select[data-test-select="members-filter"]').selectOption('subscribed'); + await page.locator('select[data-test-select="members-filter"]').selectOption('label'); + await page.locator('div[data-test-members-filter="0"] > div > div').click(); + await page.locator('span[data-test-label-filter="dog"]').click(); + await page.keyboard.press('Tab'); await page.locator('button[data-test-button="members-apply-filter"]').click(); await page.locator('button[data-test-button="members-actions"]').click(); const exportButton = await page.locator('button[data-test-button="export-members"] > span').innerText(); @@ -143,6 +185,27 @@ test.describe('Admin', () => { ]); const filename = await download.suggestedFilename(); expect(filename).toContain('.csv'); + const csv = await download.path(); + let csvContents = await fs.readFileSync(csv).toString(); + expect(csvContents).toMatch(/id,email,name,note,subscribed_to_emails,complimentary_plan,stripe_customer_id,created_at,deleted_at,labels,tiers/); + // filter memberFixtures to only include members with the label 'dog' + const filteredMembersFixture = membersFixture.filter((member) => { + return member.label === 'dog'; + }); + filteredMembersFixture.forEach((member) => { + expect(csvContents).toMatch(member.name); + expect(csvContents).toMatch(member.email); + expect(csvContents).toMatch(member.note); + expect(csvContents).toMatch('dog'); + }); + const countIds = csvContents.match(/[a-z0-9]{24}/gm).length; + expect(countIds).toEqual(3); + const countTimestamps = csvContents.match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/gm).length; + expect(countTimestamps).toEqual(3); + const countRows = csvContents.match(/(?:"(?:[^"]|"")*"|[^,\n]*)(?:,(?:"(?:[^"]|"")*"|[^,\n]*))*\n/g).length; + expect(countRows).toEqual(3); + const csvRegex = /^[^",]+((?<=[,\n])|(?=[,\n]))|[^",]+/gm; + expect(csvContents).toMatch(csvRegex); }); }); });