Skip to content

Commit

Permalink
Finish unsubscribe tests
Browse files Browse the repository at this point in the history
Add support for fetching more contacts

Add support for fetching contacts by status

Add utility function to set boolean settings
  • Loading branch information
MaxwellGarceau committed Jan 10, 2025
1 parent 07e1ec6 commit 1673755
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 69 deletions.
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "WP Env",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/wp-content/plugins/wordpress": "${workspaceFolder}/"
}
}
]
}
140 changes: 79 additions & 61 deletions tests/cypress/e2e/submission/unsubscribe.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,29 @@ describe('Unsubscribe form', () => {

cy.selectList('10up'); // Ensure list is selected, refreshes Mailchimp data with WP

// Single Opt-in
cy.setDoubleOptInOption(false);

// Check unsubscription link
cy.visit('/wp-admin/admin.php?page=mailchimp_sf_options');
cy.get('#mc_use_unsub_link').check();
cy.get('input[value="Update Subscribe Form Settings"]').first().click();
cy.setSettingsOption('#mc_use_unsub_link', true);
});

after(() => {
// I don't know why we have to login again, but we do
cy.login(); // WP

// Uncheck unsubscription link
cy.visit('/wp-admin/admin.php?page=mailchimp_sf_options');
cy.get('#mc_use_unsub_link').uncheck();
cy.get('input[value="Update Subscribe Form Settings"]').first().click();
cy.setSettingsOption('#mc_use_unsub_link', false);
});

it('unsubscribe link appears on both shortcode and block pages', () => {
[shortcodePostURL, blockPostPostURL].forEach((url) => {
// Visit the mailchimp block page
cy.visit(url);

// Assert unsubscribe link exists
cy.get('a[href*="/unsubscribe"]').should('exist');
});
})

it('unsubscribes valid emails that were previously subscribed to a list', () => {
Expand All @@ -41,81 +50,90 @@ describe('Unsubscribe form', () => {
cy.subscribeToList(listId, email);
});

[shortcodePostURL, blockPostPostURL].forEach((url) => {
let baseUrl;
let baseUrl;

// Visit the mailchimp block page
cy.visit(url);
// Visit the mailchimp block page
cy.visit(blockPostPostURL);

// Get baseUrl to use for later assertion
cy.url().then((url) => {
// Extract the base URL
const urlObject = new URL(url);
baseUrl = `${urlObject.protocol}//${urlObject.host}`;
});

// Get baseUrl to use for later assertion
cy.url().then((url) => {
// Extract the base URL
const urlObject = new URL(url);
baseUrl = `${urlObject.protocol}//${urlObject.host}`;
});

// Assert unsubscribe link exists
cy.get('a[href*="/unsubscribe"]').should('exist');

// Visit unsubscribe link
cy.get('a[href*="/unsubscribe"]')
.invoke('removeAttr', 'target') // Prevent opening in new window so that Cypress can test
.click();
// Assert unsubscribe link exists
cy.get('a[href*="/unsubscribe"]').should('exist');

// Unsubscribe
cy.get('#email-address').type(email);
cy.get('input[type="submit"]').click();
cy.get('body').should('contain', 'Unsubscribe Successful');
// Visit unsubscribe link
cy.get('a[href*="/unsubscribe"]')
.invoke('removeAttr', 'target') // Prevent opening in new window so that Cypress can test
.click();

// Navigate back to the website button exists
cy.contains('a', 'return to our website')
.should('exist');
// Unsubscribe
cy.get('#email-address').type(email);
cy.get('input[type="submit"]').click();
cy.get('body').should('contain', 'Unsubscribe Successful');

// Navigate back to the website button exists
cy.contains('a', 'return to our website')
.should('exist');

// Verify contact exists in Mailchimp with status 'unsubscribed'
cy.verifyContactInMailchimp(email, '10up', 'unsubscribed').then((contact) => {
cy.verifyContactStatus(contact, 'unsubscribed');

// Delete contact to clean up
cy.deleteContactFromList(email);

// Navigate to website
// NOTE: The website URL is site in Mailchimp and it won't accept localhost or our test URL
// TODO: Assert that we're back on our website (we currently have no way to set this)
// cy.contains('a', 'return to our website').click();
// cy.url().should('include', baseUrl); // TODO: Do we want to assert a specific landing page?

});

// Navigate to back website
// NOTE: The website URL is site in Mailchimp and it won't accept localhost or our test URL
// TODO: Assert that we're back on our website (we currently have no way to set this)
// cy.contains('a', 'return to our website').click();
// cy.url().should('include', baseUrl); // TODO: Do we want to assert a specific landing page?
});

it('throws an error when unsubscribing an email that was never subscribed to a list', () => {
const email = generateRandomEmail('never-subscribed-user');

[shortcodePostURL, blockPostPostURL].forEach((url) => {
// Visit the mailchimp block page
cy.visit(url);
// Visit the mailchimp block page
cy.visit(blockPostPostURL);

// Assert unsubscribe link exists
cy.get('a[href*="/unsubscribe"]').should('exist');
// Assert unsubscribe link exists
cy.get('a[href*="/unsubscribe"]').should('exist');

// Visit unsubscribe link
cy.get('a[href*="/unsubscribe"]')
.invoke('removeAttr', 'target') // Prevent opening in new window so that Cypress can test
.click();
// Visit unsubscribe link
cy.get('a[href*="/unsubscribe"]')
.invoke('removeAttr', 'target') // Prevent opening in new window so that Cypress can test
.click();

// Unsubscribe
cy.get('#email-address').type(email);
cy.get('input[type="submit"]').click();
// Unsubscribe
cy.get('#email-address').type(email);
cy.get('input[type="submit"]').click();

// Assert that the unsubscribe didn't work because the email isn't subscribed
cy.get('.errorText').should('contain', 'this email is not subscribed');

});
// Assert that the unsubscribe didn't work because the email isn't subscribed
cy.get('.errorText').should('contain', 'this email is not subscribed');
});

// TODO: Test not written yet
it.skip('does not display an unsubscribe link when the unsubscribe option is disabled', () => {
// Test here...
});
it('does not display an unsubscribe link when the unsubscribe option is disabled', () => {
// Not sure why we have to login for this test, but we do
cy.login(); // WP

// TODO: Test not written yet
it.skip('redirects the user back to the website when the user is finished unsubscribing and clicks the back link', () => {
// Test here...
// Uncheck unsubscription link
cy.setSettingsOption('#mc_use_unsub_link', false);

[shortcodePostURL, blockPostPostURL].forEach((url) => {
// Visit the mailchimp block page
cy.visit(url);

// Assert unsubscribe link exists
cy.get('a[href*="/unsubscribe"]').should('not.exist');
});
});

// NOTE: We can not set the "return to website" URL from the Mailchimp plugin or through the API.
// Alternative proposals on issue #91 and #92 to add a user tutorial
// it.skip('redirects the user back to the website when the user is finished unsubscribing and clicks the back link', () => {});
});
35 changes: 31 additions & 4 deletions tests/cypress/support/commands/mailchimpApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,36 @@ async function getListId(listName) {
* Gets lists from the account of the API token set in the mailchimp config
*/
Cypress.Commands.add('getContactsFromAList', getContactsFromAList);
async function getContactsFromAList(listId) {
const response = await mailchimp.lists.getListMembersInfo(listId);
return response.members;
async function getContactsFromAList(listId, status = null) {
let members = [];
let offset = 0;
const count = 100; // Number of members to fetch per request (Mailchimp's limit is usually 1000 per page)

while (true) {
const options = {
count,
offset,
};

// Add status filter if provided
if (status) {
options.status = status;
}

const response = await mailchimp.lists.getListMembersInfo(listId, options);

members = members.concat(response.members);

// Break the loop if we've fetched all members
if (members.length >= response.total_items) {
break;
}

// Increment the offset for the next page
offset += count;
}

return members;
}

/**
Expand Down Expand Up @@ -125,7 +152,7 @@ async function updateMergeFieldByTag(listId, tag, data) {
async function getMergeFields(listId) {
let mergeFields = [];
let offset = 0;
const count = 25; // Number of fields to fetch per request
const count = 100; // Number of fields to fetch per request

while (true) {
const response = await mailchimp.lists.getListMergeFields(listId, {
Expand Down
11 changes: 11 additions & 0 deletions tests/cypress/support/commands/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ function setDoubleOptInOption(enabled) {
cy.get('input[value="Update Subscribe Form Settings"]').first().click();
}

Cypress.Commands.add('setSettingsOption', setSettingsOption);
function setSettingsOption(selector, enabled) {
cy.visit('/wp-admin/admin.php?page=mailchimp_sf_options');
if (enabled) {
cy.get(selector).check();
} else {
cy.get(selector).uncheck();
}
cy.get('input[value="Update Subscribe Form Settings"]').first().click();
}

/**
* Custom Cypress command to enable or disable Mailchimp merge fields in the WordPress admin settings.
*
Expand Down
9 changes: 5 additions & 4 deletions tests/cypress/support/commands/submission.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@ Cypress.Commands.add('submitFormAndVerifyError', () => {
/**
* Custom command to verify that a contact was added to a specified list in Mailchimp
*/
Cypress.Commands.add('verifyContactInMailchimp', (email, listName = '10up') => {
Cypress.Commands.add('verifyContactInMailchimp', (email, listName = '10up', status = null) => {
// Step 1: Get the list ID for the specified list name
cy.getListId(listName).then((listId) => {
// Step 2: Retrieve the contacts from the specified list
cy.getContactsFromAList(listId).then((contacts) => {
cy.log('Contacts retrieved:', contacts); // Log the contacts for debugging
cy.getContactsFromAList(listId, status).then((contacts) => {
// Log the contacts for debugging
console.log(contacts)

// Step 3: Verify that the contact with the provided email exists in the list
const contact = contacts.find((c) => c.email_address === email);
expect(contact).to.exist;
return contact;
cy.wrap(contact); // Wrap the contact to allow further chaining
});
});
});
Expand Down

0 comments on commit 1673755

Please sign in to comment.