From 64f2a16e3a970cca3be8d007869e98cb7e0e1ef1 Mon Sep 17 00:00:00 2001 From: Avinash K Singh Date: Thu, 12 Oct 2017 12:11:21 +0530 Subject: [PATCH 01/62] Added - Please Read First Added - Please Read First to the title. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43a660b25..ffa11ac27 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ We appreciate your continued support, thank you! * [About](#about) -# Introduction +# Introduction - Please Read First This library is broken up into several packages as a monorepo so that you only need to install the packages necessary for your use case. This README contains information pertaining to all packages. From 991fbddffaeaf6fa744298cf81d8bfd548ebcdf4 Mon Sep 17 00:00:00 2001 From: Shivam Agarwal Date: Sun, 15 Oct 2017 04:18:41 +0530 Subject: [PATCH 02/62] Update USE_CASES.md with Whitelabel and Email Statistics information --- packages/mail/USE_CASES.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/mail/USE_CASES.md b/packages/mail/USE_CASES.md index f1fdaf2a2..a663e942b 100644 --- a/packages/mail/USE_CASES.md +++ b/packages/mail/USE_CASES.md @@ -16,6 +16,8 @@ This documentation provides examples for specific email use cases. Please [open * [Specifying Custom Headers](#customheaders) * [Specifying Categories](#categories) * [Kitchen Sink - an example with all settings used](#kitchensink) +* [How to Setup a Domain Whitelabel](#domain_whitelabel) +* [How to View Email Statistics](#email_stats) # Send a Single Email to a Single Recipient @@ -456,3 +458,17 @@ sgMail .then(() => console.log('Mail sent successfully')) .catch(error => console.error(error.toString())); ``` + + +# How to Setup a Domain Whitelabel + +You can find documentation for how to setup a domain whitelabel via the UI [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/setup_domain_whitelabel.html) and via API [here](https://github.com/sendgrid/sendgrid-csharp/blob/master/USAGE.md#whitelabel). + +Find more information about all of SendGrid's whitelabeling related documentation [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/index.html). + + +# How to View Email Statistics + +You can find documentation for how to view your email statistics via the UI [here](https://app.sendgrid.com/statistics) and via API [here](https://github.com/sendgrid/sendgrid-csharp/blob/master/USAGE.md#stats). + +Alternatively, we can post events to a URL of your choice via our [Event Webhook](https://sendgrid.com/docs/API_Reference/Webhooks/event.html) about events that occur as SendGrid processes your email. From eb296332b77cd2585acc4b0cc8bd9791b35f2cf4 Mon Sep 17 00:00:00 2001 From: shreyas-a Date: Sun, 15 Oct 2017 11:33:54 +0530 Subject: [PATCH 03/62] moved logo on top & added MIT & Twitter badges --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 43a660b25..2d7e29407 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ +![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) + [![BuildStatus](https://travis-ci.org/sendgrid/sendgrid-nodejs.svg?branch=master)](https://travis-ci.org/sendgrid/sendgrid-nodejs) [![npm version](https://badge.fury.io/js/%40sendgrid%2Fclient.svg)](https://www.npmjs.com/org/sendgrid) [![Email Notifications Badge](https://dx.sendgrid.com/badge/nodejs)](https://dx.sendgrid.com/newsletter/nodejs) +[![npm](https://img.shields.io/npm/l/express.svg)]() +[![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid) **This library allows you to quickly and easily use the SendGrid Web API v3 via Node.js.** @@ -62,5 +66,3 @@ Please see our [troubleshooting guide](https://github.com/sendgrid/sendgrid-node sendgrid-nodejs is guided and supported by the SendGrid [Developer Experience Team](mailto:dx@sendgrid.com). sendgrid-nodejs is maintained and funded by SendGrid, Inc. The names and logos for sendgrid-nodejs are trademarks of SendGrid, Inc. - -![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) From 124debe2018e908560129cd810242e32c4eb0c78 Mon Sep 17 00:00:00 2001 From: Jaydeep Solanki Date: Sun, 15 Oct 2017 16:33:09 +0530 Subject: [PATCH 04/62] convert all vars to let or const --- packages/client/src/client.spec.js | 980 +++++++++--------- packages/contact-importer/src/importer.js | 32 +- .../contact-importer/src/importer.spec.js | 12 +- packages/inbound-mail-parser/src/parser.js | 20 +- .../inbound-mail-parser/src/parser.spec.js | 18 +- 5 files changed, 531 insertions(+), 531 deletions(-) diff --git a/packages/client/src/client.spec.js b/packages/client/src/client.spec.js index 7b3659d0b..3a2c1218b 100644 --- a/packages/client/src/client.spec.js +++ b/packages/client/src/client.spec.js @@ -5,7 +5,7 @@ const baseUrl = 'http://localhost:4010/'; * Tests */ describe('test_access_settings_activity_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1 }; @@ -13,7 +13,7 @@ describe('test_access_settings_activity_get', () => { request.method = 'GET'; request.url = '/v3/access_settings/activity'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -26,7 +26,7 @@ describe('test_access_settings_activity_get', () => { }); describe('test_access_settings_whitelist_post', () => { - var request = {}; + const request = {}; const data = { "ips": [ { @@ -44,7 +44,7 @@ describe('test_access_settings_whitelist_post', () => { request.method = 'POST'; request.url = '/v3/access_settings/whitelist'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -57,7 +57,7 @@ describe('test_access_settings_whitelist_post', () => { }); describe('test_access_settings_whitelist_delete', () => { - var request = {}; + const request = {}; const data = { "ids": [ 1, @@ -69,7 +69,7 @@ describe('test_access_settings_whitelist_delete', () => { request.method = 'DELETE'; request.url = '/v3/access_settings/whitelist'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -82,11 +82,11 @@ describe('test_access_settings_whitelist_delete', () => { }); describe('test_access_settings_whitelist_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/access_settings/whitelist'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -99,11 +99,11 @@ describe('test_access_settings_whitelist_get', () => { }); describe('test_access_settings_whitelist__rule_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/access_settings/whitelist/{rule_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -116,11 +116,11 @@ describe('test_access_settings_whitelist__rule_id__delete', () => { }); describe('test_access_settings_whitelist__rule_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/access_settings/whitelist/{rule_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -133,7 +133,7 @@ describe('test_access_settings_whitelist__rule_id__get', () => { }); describe('test_alerts_post', () => { - var request = {}; + const request = {}; const data = { "email_to": "example@example.com", "frequency": "daily", @@ -143,7 +143,7 @@ describe('test_alerts_post', () => { request.method = 'POST'; request.url = '/v3/alerts'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -156,11 +156,11 @@ describe('test_alerts_post', () => { }); describe('test_alerts_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/alerts'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -173,7 +173,7 @@ describe('test_alerts_get', () => { }); describe('test_alerts__alert_id__patch', () => { - var request = {}; + const request = {}; const data = { "email_to": "example@example.com" }; @@ -181,7 +181,7 @@ describe('test_alerts__alert_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/alerts/{alert_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -194,11 +194,11 @@ describe('test_alerts__alert_id__patch', () => { }); describe('test_alerts__alert_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/alerts/{alert_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -211,11 +211,11 @@ describe('test_alerts__alert_id__delete', () => { }); describe('test_alerts__alert_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/alerts/{alert_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -228,7 +228,7 @@ describe('test_alerts__alert_id__get', () => { }); describe('test_api_keys_post', () => { - var request = {}; + const request = {}; const data = { "name": "My API Key", "sample": "data", @@ -242,7 +242,7 @@ describe('test_api_keys_post', () => { request.method = 'POST'; request.url = '/v3/api_keys'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -255,7 +255,7 @@ describe('test_api_keys_post', () => { }); describe('test_api_keys_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1 }; @@ -263,7 +263,7 @@ describe('test_api_keys_get', () => { request.method = 'GET'; request.url = '/v3/api_keys'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -276,7 +276,7 @@ describe('test_api_keys_get', () => { }); describe('test_api_keys__api_key_id__put', () => { - var request = {}; + const request = {}; const data = { "name": "A New Hope", "scopes": [ @@ -288,7 +288,7 @@ describe('test_api_keys__api_key_id__put', () => { request.method = 'PUT'; request.url = '/v3/api_keys/{api_key_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -301,7 +301,7 @@ describe('test_api_keys__api_key_id__put', () => { }); describe('test_api_keys__api_key_id__patch', () => { - var request = {}; + const request = {}; const data = { "name": "A New Hope" }; @@ -309,7 +309,7 @@ describe('test_api_keys__api_key_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/api_keys/{api_key_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -322,11 +322,11 @@ describe('test_api_keys__api_key_id__patch', () => { }); describe('test_api_keys__api_key_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/api_keys/{api_key_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -339,11 +339,11 @@ describe('test_api_keys__api_key_id__delete', () => { }); describe('test_api_keys__api_key_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/api_keys/{api_key_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -356,7 +356,7 @@ describe('test_api_keys__api_key_id__get', () => { }); describe('test_asm_groups_post', () => { - var request = {}; + const request = {}; const data = { "description": "Suggestions for products our users might like.", "is_default": true, @@ -366,7 +366,7 @@ describe('test_asm_groups_post', () => { request.method = 'POST'; request.url = '/v3/asm/groups'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -379,7 +379,7 @@ describe('test_asm_groups_post', () => { }); describe('test_asm_groups_get', () => { - var request = {}; + const request = {}; const queryParams = { 'id': 1 }; @@ -387,7 +387,7 @@ describe('test_asm_groups_get', () => { request.method = 'GET'; request.url = '/v3/asm/groups'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -400,11 +400,11 @@ describe('test_asm_groups_get', () => { }); describe('test_asm_groups__group_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/asm/groups/{group_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -417,7 +417,7 @@ describe('test_asm_groups__group_id__delete', () => { }); describe('test_asm_groups__group_id__patch', () => { - var request = {}; + const request = {}; const data = { "description": "Suggestions for items our users might like.", "id": 103, @@ -427,7 +427,7 @@ describe('test_asm_groups__group_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/asm/groups/{group_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -440,11 +440,11 @@ describe('test_asm_groups__group_id__patch', () => { }); describe('test_asm_groups__group_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/asm/groups/{group_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -457,7 +457,7 @@ describe('test_asm_groups__group_id__get', () => { }); describe('test_asm_groups__group_id__suppressions_post', () => { - var request = {}; + const request = {}; const data = { "recipient_emails": [ "test1@example.com", @@ -468,7 +468,7 @@ describe('test_asm_groups__group_id__suppressions_post', () => { request.method = 'POST'; request.url = '/v3/asm/groups/{group_id}/suppressions'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -481,11 +481,11 @@ describe('test_asm_groups__group_id__suppressions_post', () => { }); describe('test_asm_groups__group_id__suppressions_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/asm/groups/{group_id}/suppressions'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -498,7 +498,7 @@ describe('test_asm_groups__group_id__suppressions_get', () => { }); describe('test_asm_groups__group_id__suppressions_search_post', () => { - var request = {}; + const request = {}; const data = { "recipient_emails": [ "exists1@example.com", @@ -510,7 +510,7 @@ describe('test_asm_groups__group_id__suppressions_search_post', () => { request.method = 'POST'; request.url = '/v3/asm/groups/{group_id}/suppressions/search'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -523,11 +523,11 @@ describe('test_asm_groups__group_id__suppressions_search_post', () => { }); describe('test_asm_groups__group_id__suppressions__email__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/asm/groups/{group_id}/suppressions/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -540,11 +540,11 @@ describe('test_asm_groups__group_id__suppressions__email__delete', () => { }); describe('test_asm_suppressions_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/asm/suppressions'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -557,7 +557,7 @@ describe('test_asm_suppressions_get', () => { }); describe('test_asm_suppressions_global_post', () => { - var request = {}; + const request = {}; const data = { "recipient_emails": [ "test1@example.com", @@ -568,7 +568,7 @@ describe('test_asm_suppressions_global_post', () => { request.method = 'POST'; request.url = '/v3/asm/suppressions/global'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -581,11 +581,11 @@ describe('test_asm_suppressions_global_post', () => { }); describe('test_asm_suppressions_global__email__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/asm/suppressions/global/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -598,11 +598,11 @@ describe('test_asm_suppressions_global__email__delete', () => { }); describe('test_asm_suppressions_global__email__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/asm/suppressions/global/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -615,11 +615,11 @@ describe('test_asm_suppressions_global__email__get', () => { }); describe('test_asm_suppressions__email__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/asm/suppressions/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -632,7 +632,7 @@ describe('test_asm_suppressions__email__get', () => { }); describe('test_browsers_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'browsers': 'test_string', @@ -645,7 +645,7 @@ describe('test_browsers_stats_get', () => { request.method = 'GET'; request.url = '/v3/browsers/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -658,7 +658,7 @@ describe('test_browsers_stats_get', () => { }); describe('test_campaigns_post', () => { - var request = {}; + const request = {}; const data = { "categories": [ "spring line" @@ -683,7 +683,7 @@ describe('test_campaigns_post', () => { request.method = 'POST'; request.url = '/v3/campaigns'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -696,7 +696,7 @@ describe('test_campaigns_post', () => { }); describe('test_campaigns_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1, 'offset': 1 @@ -705,7 +705,7 @@ describe('test_campaigns_get', () => { request.method = 'GET'; request.url = '/v3/campaigns'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -718,7 +718,7 @@ describe('test_campaigns_get', () => { }); describe('test_campaigns__campaign_id__patch', () => { - var request = {}; + const request = {}; const data = { "categories": [ "summer line" @@ -732,7 +732,7 @@ describe('test_campaigns__campaign_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/campaigns/{campaign_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -745,11 +745,11 @@ describe('test_campaigns__campaign_id__patch', () => { }); describe('test_campaigns__campaign_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/campaigns/{campaign_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -762,11 +762,11 @@ describe('test_campaigns__campaign_id__delete', () => { }); describe('test_campaigns__campaign_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/campaigns/{campaign_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -779,11 +779,11 @@ describe('test_campaigns__campaign_id__get', () => { }); describe('test_campaigns__campaign_id__schedules_delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/campaigns/{campaign_id}/schedules'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -796,7 +796,7 @@ describe('test_campaigns__campaign_id__schedules_delete', () => { }); describe('test_campaigns__campaign_id__schedules_post', () => { - var request = {}; + const request = {}; const data = { "send_at": 1489771528 }; @@ -804,7 +804,7 @@ describe('test_campaigns__campaign_id__schedules_post', () => { request.method = 'POST'; request.url = '/v3/campaigns/{campaign_id}/schedules'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -817,11 +817,11 @@ describe('test_campaigns__campaign_id__schedules_post', () => { }); describe('test_campaigns__campaign_id__schedules_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/campaigns/{campaign_id}/schedules'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -834,7 +834,7 @@ describe('test_campaigns__campaign_id__schedules_get', () => { }); describe('test_campaigns__campaign_id__schedules_patch', () => { - var request = {}; + const request = {}; const data = { "send_at": 1489451436 }; @@ -842,7 +842,7 @@ describe('test_campaigns__campaign_id__schedules_patch', () => { request.method = 'PATCH'; request.url = '/v3/campaigns/{campaign_id}/schedules'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -855,11 +855,11 @@ describe('test_campaigns__campaign_id__schedules_patch', () => { }); describe('test_campaigns__campaign_id__schedules_now_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/campaigns/{campaign_id}/schedules/now'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -872,7 +872,7 @@ describe('test_campaigns__campaign_id__schedules_now_post', () => { }); describe('test_campaigns__campaign_id__schedules_test_post', () => { - var request = {}; + const request = {}; const data = { "to": "your.email@example.com" }; @@ -880,7 +880,7 @@ describe('test_campaigns__campaign_id__schedules_test_post', () => { request.method = 'POST'; request.url = '/v3/campaigns/{campaign_id}/schedules/test'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -893,7 +893,7 @@ describe('test_campaigns__campaign_id__schedules_test_post', () => { }); describe('test_categories_get', () => { - var request = {}; + const request = {}; const queryParams = { 'category': 'test_string', 'limit': 1, @@ -903,7 +903,7 @@ describe('test_categories_get', () => { request.method = 'GET'; request.url = '/v3/categories'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -916,7 +916,7 @@ describe('test_categories_get', () => { }); describe('test_categories_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'categories': 'test_string', @@ -929,7 +929,7 @@ describe('test_categories_stats_get', () => { request.method = 'GET'; request.url = '/v3/categories/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -942,7 +942,7 @@ describe('test_categories_stats_get', () => { }); describe('test_categories_stats_sums_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -956,7 +956,7 @@ describe('test_categories_stats_sums_get', () => { request.method = 'GET'; request.url = '/v3/categories/stats/sums'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -969,7 +969,7 @@ describe('test_categories_stats_sums_get', () => { }); describe('test_clients_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -979,7 +979,7 @@ describe('test_clients_stats_get', () => { request.method = 'GET'; request.url = '/v3/clients/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -992,7 +992,7 @@ describe('test_clients_stats_get', () => { }); describe('test_clients__client_type__stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -1002,7 +1002,7 @@ describe('test_clients__client_type__stats_get', () => { request.method = 'GET'; request.url = '/v3/clients/{client_type}/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1015,7 +1015,7 @@ describe('test_clients__client_type__stats_get', () => { }); describe('test_contactdb_custom_fields_post', () => { - var request = {}; + const request = {}; const data = { "name": "pet", "type": "text" @@ -1024,7 +1024,7 @@ describe('test_contactdb_custom_fields_post', () => { request.method = 'POST'; request.url = '/v3/contactdb/custom_fields'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1037,11 +1037,11 @@ describe('test_contactdb_custom_fields_post', () => { }); describe('test_contactdb_custom_fields_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/custom_fields'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1054,11 +1054,11 @@ describe('test_contactdb_custom_fields_get', () => { }); describe('test_contactdb_custom_fields__custom_field_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/contactdb/custom_fields/{custom_field_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 202); @@ -1071,11 +1071,11 @@ describe('test_contactdb_custom_fields__custom_field_id__delete', () => { }); describe('test_contactdb_custom_fields__custom_field_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/custom_fields/{custom_field_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1088,7 +1088,7 @@ describe('test_contactdb_custom_fields__custom_field_id__get', () => { }); describe('test_contactdb_lists_post', () => { - var request = {}; + const request = {}; const data = { "name": "your list name" }; @@ -1096,7 +1096,7 @@ describe('test_contactdb_lists_post', () => { request.method = 'POST'; request.url = '/v3/contactdb/lists'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1109,7 +1109,7 @@ describe('test_contactdb_lists_post', () => { }); describe('test_contactdb_lists_delete', () => { - var request = {}; + const request = {}; const data = [ 1, 2, @@ -1120,7 +1120,7 @@ describe('test_contactdb_lists_delete', () => { request.method = 'DELETE'; request.url = '/v3/contactdb/lists'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -1133,11 +1133,11 @@ describe('test_contactdb_lists_delete', () => { }); describe('test_contactdb_lists_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/lists'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1150,7 +1150,7 @@ describe('test_contactdb_lists_get', () => { }); describe('test_contactdb_lists__list_id__delete', () => { - var request = {}; + const request = {}; const queryParams = { 'delete_contacts': 'true' }; @@ -1158,7 +1158,7 @@ describe('test_contactdb_lists__list_id__delete', () => { request.method = 'DELETE'; request.url = '/v3/contactdb/lists/{list_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 202); @@ -1171,7 +1171,7 @@ describe('test_contactdb_lists__list_id__delete', () => { }); describe('test_contactdb_lists__list_id__patch', () => { - var request = {}; + const request = {}; const data = { "name": "newlistname" }; @@ -1183,7 +1183,7 @@ describe('test_contactdb_lists__list_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/contactdb/lists/{list_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1196,7 +1196,7 @@ describe('test_contactdb_lists__list_id__patch', () => { }); describe('test_contactdb_lists__list_id__get', () => { - var request = {}; + const request = {}; const queryParams = { 'list_id': 1 }; @@ -1204,7 +1204,7 @@ describe('test_contactdb_lists__list_id__get', () => { request.method = 'GET'; request.url = '/v3/contactdb/lists/{list_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1217,7 +1217,7 @@ describe('test_contactdb_lists__list_id__get', () => { }); describe('test_contactdb_lists__list_id__recipients_post', () => { - var request = {}; + const request = {}; const data = [ "recipient_id1", "recipient_id2" @@ -1226,7 +1226,7 @@ describe('test_contactdb_lists__list_id__recipients_post', () => { request.method = 'POST'; request.url = '/v3/contactdb/lists/{list_id}/recipients'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1239,7 +1239,7 @@ describe('test_contactdb_lists__list_id__recipients_post', () => { }); describe('test_contactdb_lists__list_id__recipients_get', () => { - var request = {}; + const request = {}; const queryParams = { 'list_id': 1, 'page': 1, @@ -1249,7 +1249,7 @@ describe('test_contactdb_lists__list_id__recipients_get', () => { request.method = 'GET'; request.url = '/v3/contactdb/lists/{list_id}/recipients'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1262,11 +1262,11 @@ describe('test_contactdb_lists__list_id__recipients_get', () => { }); describe('test_contactdb_lists__list_id__recipients__recipient_id__post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/contactdb/lists/{list_id}/recipients/{recipient_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1279,7 +1279,7 @@ describe('test_contactdb_lists__list_id__recipients__recipient_id__post', () => }); describe('test_contactdb_lists__list_id__recipients__recipient_id__delete', () => { - var request = {}; + const request = {}; const queryParams = { 'list_id': 1, 'recipient_id': 1 @@ -1288,7 +1288,7 @@ describe('test_contactdb_lists__list_id__recipients__recipient_id__delete', () = request.method = 'DELETE'; request.url = '/v3/contactdb/lists/{list_id}/recipients/{recipient_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -1301,7 +1301,7 @@ describe('test_contactdb_lists__list_id__recipients__recipient_id__delete', () = }); describe('test_contactdb_recipients_post', () => { - var request = {}; + const request = {}; const data = [ { "age": 25, @@ -1320,7 +1320,7 @@ describe('test_contactdb_recipients_post', () => { request.method = 'POST'; request.url = '/v3/contactdb/recipients'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1333,7 +1333,7 @@ describe('test_contactdb_recipients_post', () => { }); describe('test_contactdb_recipients_delete', () => { - var request = {}; + const request = {}; const data = [ "recipient_id1", "recipient_id2" @@ -1342,7 +1342,7 @@ describe('test_contactdb_recipients_delete', () => { request.method = 'DELETE'; request.url = '/v3/contactdb/recipients'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1355,7 +1355,7 @@ describe('test_contactdb_recipients_delete', () => { }); describe('test_contactdb_recipients_get', () => { - var request = {}; + const request = {}; const queryParams = { 'page': 1, 'page_size': 1 @@ -1364,7 +1364,7 @@ describe('test_contactdb_recipients_get', () => { request.method = 'GET'; request.url = '/v3/contactdb/recipients'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1377,7 +1377,7 @@ describe('test_contactdb_recipients_get', () => { }); describe('test_contactdb_recipients_patch', () => { - var request = {}; + const request = {}; const data = [ { "email": "jones@example.com", @@ -1389,7 +1389,7 @@ describe('test_contactdb_recipients_patch', () => { request.method = 'PATCH'; request.url = '/v3/contactdb/recipients'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1402,11 +1402,11 @@ describe('test_contactdb_recipients_patch', () => { }); describe('test_contactdb_recipients_billable_count_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/recipients/billable_count'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1419,11 +1419,11 @@ describe('test_contactdb_recipients_billable_count_get', () => { }); describe('test_contactdb_recipients_count_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/recipients/count'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1436,7 +1436,7 @@ describe('test_contactdb_recipients_count_get', () => { }); describe('test_contactdb_recipients_search_get', () => { - var request = {}; + const request = {}; const queryParams = { '{field_name}': 'test_string' }; @@ -1444,7 +1444,7 @@ describe('test_contactdb_recipients_search_get', () => { request.method = 'GET'; request.url = '/v3/contactdb/recipients/search'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1457,11 +1457,11 @@ describe('test_contactdb_recipients_search_get', () => { }); describe('test_contactdb_recipients__recipient_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/contactdb/recipients/{recipient_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -1474,11 +1474,11 @@ describe('test_contactdb_recipients__recipient_id__delete', () => { }); describe('test_contactdb_recipients__recipient_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/recipients/{recipient_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1491,11 +1491,11 @@ describe('test_contactdb_recipients__recipient_id__get', () => { }); describe('test_contactdb_recipients__recipient_id__lists_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/recipients/{recipient_id}/lists'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1508,11 +1508,11 @@ describe('test_contactdb_recipients__recipient_id__lists_get', () => { }); describe('test_contactdb_reserved_fields_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/reserved_fields'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1525,7 +1525,7 @@ describe('test_contactdb_reserved_fields_get', () => { }); describe('test_contactdb_segments_post', () => { - var request = {}; + const request = {}; const data = { "conditions": [ { @@ -1554,7 +1554,7 @@ describe('test_contactdb_segments_post', () => { request.method = 'POST'; request.url = '/v3/contactdb/segments'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1567,11 +1567,11 @@ describe('test_contactdb_segments_post', () => { }); describe('test_contactdb_segments_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/segments'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1584,7 +1584,7 @@ describe('test_contactdb_segments_get', () => { }); describe('test_contactdb_segments__segment_id__delete', () => { - var request = {}; + const request = {}; const queryParams = { 'delete_contacts': 'true' }; @@ -1592,7 +1592,7 @@ describe('test_contactdb_segments__segment_id__delete', () => { request.method = 'DELETE'; request.url = '/v3/contactdb/segments/{segment_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -1605,7 +1605,7 @@ describe('test_contactdb_segments__segment_id__delete', () => { }); describe('test_contactdb_segments__segment_id__patch', () => { - var request = {}; + const request = {}; const data = { "conditions": [ { @@ -1626,7 +1626,7 @@ describe('test_contactdb_segments__segment_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/contactdb/segments/{segment_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1639,7 +1639,7 @@ describe('test_contactdb_segments__segment_id__patch', () => { }); describe('test_contactdb_segments__segment_id__get', () => { - var request = {}; + const request = {}; const queryParams = { 'segment_id': 1 }; @@ -1647,7 +1647,7 @@ describe('test_contactdb_segments__segment_id__get', () => { request.method = 'GET'; request.url = '/v3/contactdb/segments/{segment_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1660,7 +1660,7 @@ describe('test_contactdb_segments__segment_id__get', () => { }); describe('test_contactdb_segments__segment_id__recipients_get', () => { - var request = {}; + const request = {}; const queryParams = { 'page': 1, 'page_size': 1 @@ -1669,7 +1669,7 @@ describe('test_contactdb_segments__segment_id__recipients_get', () => { request.method = 'GET'; request.url = '/v3/contactdb/segments/{segment_id}/recipients'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1682,11 +1682,11 @@ describe('test_contactdb_segments__segment_id__recipients_get', () => { }); describe('test_contactdb_status_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/contactdb/status'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1699,7 +1699,7 @@ describe('test_contactdb_status_get', () => { }); describe('test_devices_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -1711,7 +1711,7 @@ describe('test_devices_stats_get', () => { request.method = 'GET'; request.url = '/v3/devices/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1724,7 +1724,7 @@ describe('test_devices_stats_get', () => { }); describe('test_geo_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'country': 'US', @@ -1737,7 +1737,7 @@ describe('test_geo_stats_get', () => { request.method = 'GET'; request.url = '/v3/geo/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1750,7 +1750,7 @@ describe('test_geo_stats_get', () => { }); describe('test_ips_post', () => { - var request = {}; + const request = {}; const data = { "count": 90323478, "subusers": [ @@ -1764,7 +1764,7 @@ describe('test_ips_post', () => { request.method = 'POST'; request.url = '/v3/ips'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1777,7 +1777,7 @@ describe('test_ips_post', () => { }); describe('test_ips_get', () => { - var request = {}; + const request = {}; const queryParams = { 'exclude_whitelabels': 'true', 'ip': 'test_string', @@ -1790,7 +1790,7 @@ describe('test_ips_get', () => { request.method = 'GET'; request.url = '/v3/ips'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1803,11 +1803,11 @@ describe('test_ips_get', () => { }); describe('test_ips_assigned_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/ips/assigned'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1820,7 +1820,7 @@ describe('test_ips_assigned_get', () => { }); describe('test_ips_pools_post', () => { - var request = {}; + const request = {}; const data = { "name": "marketing" }; @@ -1828,7 +1828,7 @@ describe('test_ips_pools_post', () => { request.method = 'POST'; request.url = '/v3/ips/pools'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1841,11 +1841,11 @@ describe('test_ips_pools_post', () => { }); describe('test_ips_pools_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/ips/pools'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1858,7 +1858,7 @@ describe('test_ips_pools_get', () => { }); describe('test_ips_pools__pool_name__put', () => { - var request = {}; + const request = {}; const data = { "name": "new_pool_name" }; @@ -1866,7 +1866,7 @@ describe('test_ips_pools__pool_name__put', () => { request.method = 'PUT'; request.url = '/v3/ips/pools/{pool_name}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1879,11 +1879,11 @@ describe('test_ips_pools__pool_name__put', () => { }); describe('test_ips_pools__pool_name__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/ips/pools/{pool_name}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -1896,11 +1896,11 @@ describe('test_ips_pools__pool_name__delete', () => { }); describe('test_ips_pools__pool_name__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/ips/pools/{pool_name}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1913,7 +1913,7 @@ describe('test_ips_pools__pool_name__get', () => { }); describe('test_ips_pools__pool_name__ips_post', () => { - var request = {}; + const request = {}; const data = { "ip": "0.0.0.0" }; @@ -1921,7 +1921,7 @@ describe('test_ips_pools__pool_name__ips_post', () => { request.method = 'POST'; request.url = '/v3/ips/pools/{pool_name}/ips'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -1934,11 +1934,11 @@ describe('test_ips_pools__pool_name__ips_post', () => { }); describe('test_ips_pools__pool_name__ips__ip__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/ips/pools/{pool_name}/ips/{ip}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -1951,11 +1951,11 @@ describe('test_ips_pools__pool_name__ips__ip__delete', () => { }); describe('test_ips_remaining_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/ips/remaining'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1968,7 +1968,7 @@ describe('test_ips_remaining_get', () => { }); describe('test_ips_warmup_post', () => { - var request = {}; + const request = {}; const data = { "ip": "0.0.0.0" }; @@ -1976,7 +1976,7 @@ describe('test_ips_warmup_post', () => { request.method = 'POST'; request.url = '/v3/ips/warmup'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -1989,11 +1989,11 @@ describe('test_ips_warmup_post', () => { }); describe('test_ips_warmup_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/ips/warmup'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2006,11 +2006,11 @@ describe('test_ips_warmup_get', () => { }); describe('test_ips_warmup__ip_address__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/ips/warmup/{ip_address}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -2023,11 +2023,11 @@ describe('test_ips_warmup__ip_address__delete', () => { }); describe('test_ips_warmup__ip_address__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/ips/warmup/{ip_address}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2040,11 +2040,11 @@ describe('test_ips_warmup__ip_address__get', () => { }); describe('test_ips__ip_address__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/ips/{ip_address}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2057,11 +2057,11 @@ describe('test_ips__ip_address__get', () => { }); describe('test_mail_batch_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/mail/batch'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -2074,11 +2074,11 @@ describe('test_mail_batch_post', () => { }); describe('test_mail_batch__batch_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail/batch/{batch_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2091,7 +2091,7 @@ describe('test_mail_batch__batch_id__get', () => { }); describe('test_mail_send_post', () => { - var request = {}; + const request = {}; const data = { "content": [ { @@ -2124,7 +2124,7 @@ describe('test_mail_send_post', () => { request.method = 'POST'; request.url = '/v3/mail/send'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 202); @@ -2137,7 +2137,7 @@ describe('test_mail_send_post', () => { }); describe('test_mail_settings_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1, 'offset': 1 @@ -2146,7 +2146,7 @@ describe('test_mail_settings_get', () => { request.method = 'GET'; request.url = '/v3/mail_settings'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2159,7 +2159,7 @@ describe('test_mail_settings_get', () => { }); describe('test_mail_settings_address_whitelist_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true, "list": [ @@ -2171,7 +2171,7 @@ describe('test_mail_settings_address_whitelist_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/address_whitelist'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2184,11 +2184,11 @@ describe('test_mail_settings_address_whitelist_patch', () => { }); describe('test_mail_settings_address_whitelist_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/address_whitelist'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2201,7 +2201,7 @@ describe('test_mail_settings_address_whitelist_get', () => { }); describe('test_mail_settings_bcc_patch', () => { - var request = {}; + const request = {}; const data = { "email": "email@example.com", "enabled": false @@ -2210,7 +2210,7 @@ describe('test_mail_settings_bcc_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/bcc'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2223,11 +2223,11 @@ describe('test_mail_settings_bcc_patch', () => { }); describe('test_mail_settings_bcc_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/bcc'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2240,7 +2240,7 @@ describe('test_mail_settings_bcc_get', () => { }); describe('test_mail_settings_bounce_purge_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true, "hard_bounces": 5, @@ -2250,7 +2250,7 @@ describe('test_mail_settings_bounce_purge_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/bounce_purge'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2263,11 +2263,11 @@ describe('test_mail_settings_bounce_purge_patch', () => { }); describe('test_mail_settings_bounce_purge_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/bounce_purge'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2280,7 +2280,7 @@ describe('test_mail_settings_bounce_purge_get', () => { }); describe('test_mail_settings_footer_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true, "html_content": "...", @@ -2290,7 +2290,7 @@ describe('test_mail_settings_footer_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/footer'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2303,11 +2303,11 @@ describe('test_mail_settings_footer_patch', () => { }); describe('test_mail_settings_footer_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/footer'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2320,7 +2320,7 @@ describe('test_mail_settings_footer_get', () => { }); describe('test_mail_settings_forward_bounce_patch', () => { - var request = {}; + const request = {}; const data = { "email": "example@example.com", "enabled": true @@ -2329,7 +2329,7 @@ describe('test_mail_settings_forward_bounce_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/forward_bounce'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2342,11 +2342,11 @@ describe('test_mail_settings_forward_bounce_patch', () => { }); describe('test_mail_settings_forward_bounce_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/forward_bounce'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2359,7 +2359,7 @@ describe('test_mail_settings_forward_bounce_get', () => { }); describe('test_mail_settings_forward_spam_patch', () => { - var request = {}; + const request = {}; const data = { "email": "", "enabled": false @@ -2368,7 +2368,7 @@ describe('test_mail_settings_forward_spam_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/forward_spam'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2381,11 +2381,11 @@ describe('test_mail_settings_forward_spam_patch', () => { }); describe('test_mail_settings_forward_spam_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/forward_spam'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2398,7 +2398,7 @@ describe('test_mail_settings_forward_spam_get', () => { }); describe('test_mail_settings_plain_content_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": false }; @@ -2406,7 +2406,7 @@ describe('test_mail_settings_plain_content_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/plain_content'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2419,11 +2419,11 @@ describe('test_mail_settings_plain_content_patch', () => { }); describe('test_mail_settings_plain_content_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/plain_content'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2436,7 +2436,7 @@ describe('test_mail_settings_plain_content_get', () => { }); describe('test_mail_settings_spam_check_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true, "max_score": 5, @@ -2446,7 +2446,7 @@ describe('test_mail_settings_spam_check_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/spam_check'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2459,11 +2459,11 @@ describe('test_mail_settings_spam_check_patch', () => { }); describe('test_mail_settings_spam_check_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/spam_check'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2476,7 +2476,7 @@ describe('test_mail_settings_spam_check_get', () => { }); describe('test_mail_settings_template_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true, "html_content": "<% body %>" @@ -2485,7 +2485,7 @@ describe('test_mail_settings_template_patch', () => { request.method = 'PATCH'; request.url = '/v3/mail_settings/template'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2498,11 +2498,11 @@ describe('test_mail_settings_template_patch', () => { }); describe('test_mail_settings_template_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/mail_settings/template'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2515,7 +2515,7 @@ describe('test_mail_settings_template_get', () => { }); describe('test_mailbox_providers_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -2528,7 +2528,7 @@ describe('test_mailbox_providers_stats_get', () => { request.method = 'GET'; request.url = '/v3/mailbox_providers/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2541,7 +2541,7 @@ describe('test_mailbox_providers_stats_get', () => { }); describe('test_partner_settings_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1, 'offset': 1 @@ -2550,7 +2550,7 @@ describe('test_partner_settings_get', () => { request.method = 'GET'; request.url = '/v3/partner_settings'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2563,7 +2563,7 @@ describe('test_partner_settings_get', () => { }); describe('test_partner_settings_new_relic_patch', () => { - var request = {}; + const request = {}; const data = { "enable_subuser_statistics": true, "enabled": true, @@ -2573,7 +2573,7 @@ describe('test_partner_settings_new_relic_patch', () => { request.method = 'PATCH'; request.url = '/v3/partner_settings/new_relic'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2586,11 +2586,11 @@ describe('test_partner_settings_new_relic_patch', () => { }); describe('test_partner_settings_new_relic_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/partner_settings/new_relic'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2603,11 +2603,11 @@ describe('test_partner_settings_new_relic_get', () => { }); describe('test_scopes_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/scopes'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2620,7 +2620,7 @@ describe('test_scopes_get', () => { }); describe('test_scopes_requests_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1, 'offset': 1 @@ -2629,7 +2629,7 @@ describe('test_scopes_requests_get', () => { request.method = 'GET'; request.url = '/v3/scopes/requests'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2642,11 +2642,11 @@ describe('test_scopes_requests_get', () => { }); describe('test_scopes_requests__request_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/scopes/requests/{request_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -2659,11 +2659,11 @@ describe('test_scopes_requests__request_id__delete', () => { }); describe('test_scopes_requests__request_id__approve_patch', () => { - var request = {}; + const request = {}; request.method = 'PATCH'; request.url = '/v3/scopes/requests/{request_id}/approve'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2676,7 +2676,7 @@ describe('test_scopes_requests__request_id__approve_patch', () => { }); describe('test_senders_post', () => { - var request = {}; + const request = {}; const data = { "address": "123 Elm St.", "address_2": "Apt. 456", @@ -2698,7 +2698,7 @@ describe('test_senders_post', () => { request.method = 'POST'; request.url = '/v3/senders'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -2711,11 +2711,11 @@ describe('test_senders_post', () => { }); describe('test_senders_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/senders'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2728,11 +2728,11 @@ describe('test_senders_get', () => { }); describe('test_senders__sender_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/senders/{sender_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2745,11 +2745,11 @@ describe('test_senders__sender_id__get', () => { }); describe('test_senders__sender_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/senders/{sender_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -2762,7 +2762,7 @@ describe('test_senders__sender_id__delete', () => { }); describe('test_senders__sender_id__patch', () => { - var request = {}; + const request = {}; const data = { "address": "123 Elm St.", "address_2": "Apt. 456", @@ -2784,7 +2784,7 @@ describe('test_senders__sender_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/senders/{sender_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2797,11 +2797,11 @@ describe('test_senders__sender_id__patch', () => { }); describe('test_senders__sender_id__resend_verification_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/senders/{sender_id}/resend_verification'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -2814,7 +2814,7 @@ describe('test_senders__sender_id__resend_verification_post', () => { }); describe('test_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -2826,7 +2826,7 @@ describe('test_stats_get', () => { request.method = 'GET'; request.url = '/v3/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2839,7 +2839,7 @@ describe('test_stats_get', () => { }); describe('test_subusers_post', () => { - var request = {}; + const request = {}; const data = { "email": "John@example.com", "ips": [ @@ -2853,7 +2853,7 @@ describe('test_subusers_post', () => { request.method = 'POST'; request.url = '/v3/subusers'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2866,7 +2866,7 @@ describe('test_subusers_post', () => { }); describe('test_subusers_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1, 'offset': 1, @@ -2876,7 +2876,7 @@ describe('test_subusers_get', () => { request.method = 'GET'; request.url = '/v3/subusers'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2889,7 +2889,7 @@ describe('test_subusers_get', () => { }); describe('test_subusers_reputations_get', () => { - var request = {}; + const request = {}; const queryParams = { 'usernames': 'test_string' }; @@ -2897,7 +2897,7 @@ describe('test_subusers_reputations_get', () => { request.method = 'GET'; request.url = '/v3/subusers/reputations'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2910,7 +2910,7 @@ describe('test_subusers_reputations_get', () => { }); describe('test_subusers_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -2923,7 +2923,7 @@ describe('test_subusers_stats_get', () => { request.method = 'GET'; request.url = '/v3/subusers/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2936,7 +2936,7 @@ describe('test_subusers_stats_get', () => { }); describe('test_subusers_stats_monthly_get', () => { - var request = {}; + const request = {}; const queryParams = { 'date': 'test_string', 'limit': 1, @@ -2949,7 +2949,7 @@ describe('test_subusers_stats_monthly_get', () => { request.method = 'GET'; request.url = '/v3/subusers/stats/monthly'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2962,7 +2962,7 @@ describe('test_subusers_stats_monthly_get', () => { }); describe('test_subusers_stats_sums_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -2976,7 +2976,7 @@ describe('test_subusers_stats_sums_get', () => { request.method = 'GET'; request.url = '/v3/subusers/stats/sums'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -2989,11 +2989,11 @@ describe('test_subusers_stats_sums_get', () => { }); describe('test_subusers__subuser_name__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/subusers/{subuser_name}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3006,7 +3006,7 @@ describe('test_subusers__subuser_name__delete', () => { }); describe('test_subusers__subuser_name__patch', () => { - var request = {}; + const request = {}; const data = { "disabled": false }; @@ -3014,7 +3014,7 @@ describe('test_subusers__subuser_name__patch', () => { request.method = 'PATCH'; request.url = '/v3/subusers/{subuser_name}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3027,7 +3027,7 @@ describe('test_subusers__subuser_name__patch', () => { }); describe('test_subusers__subuser_name__ips_put', () => { - var request = {}; + const request = {}; const data = [ "127.0.0.1" ]; @@ -3035,7 +3035,7 @@ describe('test_subusers__subuser_name__ips_put', () => { request.method = 'PUT'; request.url = '/v3/subusers/{subuser_name}/ips'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3048,7 +3048,7 @@ describe('test_subusers__subuser_name__ips_put', () => { }); describe('test_subusers__subuser_name__monitor_put', () => { - var request = {}; + const request = {}; const data = { "email": "example@example.com", "frequency": 500 @@ -3057,7 +3057,7 @@ describe('test_subusers__subuser_name__monitor_put', () => { request.method = 'PUT'; request.url = '/v3/subusers/{subuser_name}/monitor'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3070,7 +3070,7 @@ describe('test_subusers__subuser_name__monitor_put', () => { }); describe('test_subusers__subuser_name__monitor_post', () => { - var request = {}; + const request = {}; const data = { "email": "example@example.com", "frequency": 50000 @@ -3079,7 +3079,7 @@ describe('test_subusers__subuser_name__monitor_post', () => { request.method = 'POST'; request.url = '/v3/subusers/{subuser_name}/monitor'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3092,11 +3092,11 @@ describe('test_subusers__subuser_name__monitor_post', () => { }); describe('test_subusers__subuser_name__monitor_delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/subusers/{subuser_name}/monitor'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3109,11 +3109,11 @@ describe('test_subusers__subuser_name__monitor_delete', () => { }); describe('test_subusers__subuser_name__monitor_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/subusers/{subuser_name}/monitor'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3126,7 +3126,7 @@ describe('test_subusers__subuser_name__monitor_get', () => { }); describe('test_subusers__subuser_name__stats_monthly_get', () => { - var request = {}; + const request = {}; const queryParams = { 'date': 'test_string', 'limit': 1, @@ -3138,7 +3138,7 @@ describe('test_subusers__subuser_name__stats_monthly_get', () => { request.method = 'GET'; request.url = '/v3/subusers/{subuser_name}/stats/monthly'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3151,7 +3151,7 @@ describe('test_subusers__subuser_name__stats_monthly_get', () => { }); describe('test_suppression_blocks_delete', () => { - var request = {}; + const request = {}; const data = { "delete_all": false, "emails": [ @@ -3163,7 +3163,7 @@ describe('test_suppression_blocks_delete', () => { request.method = 'DELETE'; request.url = '/v3/suppression/blocks'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3176,7 +3176,7 @@ describe('test_suppression_blocks_delete', () => { }); describe('test_suppression_blocks_get', () => { - var request = {}; + const request = {}; const queryParams = { 'end_time': 1, 'limit': 1, @@ -3187,7 +3187,7 @@ describe('test_suppression_blocks_get', () => { request.method = 'GET'; request.url = '/v3/suppression/blocks'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3200,11 +3200,11 @@ describe('test_suppression_blocks_get', () => { }); describe('test_suppression_blocks__email__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/suppression/blocks/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3217,11 +3217,11 @@ describe('test_suppression_blocks__email__delete', () => { }); describe('test_suppression_blocks__email__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/suppression/blocks/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3234,7 +3234,7 @@ describe('test_suppression_blocks__email__get', () => { }); describe('test_suppression_bounces_delete', () => { - var request = {}; + const request = {}; const data = { "delete_all": true, "emails": [ @@ -3246,7 +3246,7 @@ describe('test_suppression_bounces_delete', () => { request.method = 'DELETE'; request.url = '/v3/suppression/bounces'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3259,7 +3259,7 @@ describe('test_suppression_bounces_delete', () => { }); describe('test_suppression_bounces_get', () => { - var request = {}; + const request = {}; const queryParams = { 'end_time': 1, 'start_time': 1 @@ -3268,7 +3268,7 @@ describe('test_suppression_bounces_get', () => { request.method = 'GET'; request.url = '/v3/suppression/bounces'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3281,7 +3281,7 @@ describe('test_suppression_bounces_get', () => { }); describe('test_suppression_bounces__email__delete', () => { - var request = {}; + const request = {}; const queryParams = { 'email_address': 'example@example.com' }; @@ -3289,7 +3289,7 @@ describe('test_suppression_bounces__email__delete', () => { request.method = 'DELETE'; request.url = '/v3/suppression/bounces/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3302,11 +3302,11 @@ describe('test_suppression_bounces__email__delete', () => { }); describe('test_suppression_bounces__email__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/suppression/bounces/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3319,7 +3319,7 @@ describe('test_suppression_bounces__email__get', () => { }); describe('test_suppression_invalid_emails_delete', () => { - var request = {}; + const request = {}; const data = { "delete_all": false, "emails": [ @@ -3331,7 +3331,7 @@ describe('test_suppression_invalid_emails_delete', () => { request.method = 'DELETE'; request.url = '/v3/suppression/invalid_emails'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3344,7 +3344,7 @@ describe('test_suppression_invalid_emails_delete', () => { }); describe('test_suppression_invalid_emails_get', () => { - var request = {}; + const request = {}; const queryParams = { 'end_time': 1, 'limit': 1, @@ -3355,7 +3355,7 @@ describe('test_suppression_invalid_emails_get', () => { request.method = 'GET'; request.url = '/v3/suppression/invalid_emails'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3368,11 +3368,11 @@ describe('test_suppression_invalid_emails_get', () => { }); describe('test_suppression_invalid_emails__email__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/suppression/invalid_emails/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3385,11 +3385,11 @@ describe('test_suppression_invalid_emails__email__delete', () => { }); describe('test_suppression_invalid_emails__email__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/suppression/invalid_emails/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3402,7 +3402,7 @@ describe('test_suppression_invalid_emails__email__get', () => { }); describe('test_suppression_spam_reports_delete', () => { - var request = {}; + const request = {}; const data = { "delete_all": false, "emails": [ @@ -3414,7 +3414,7 @@ describe('test_suppression_spam_reports_delete', () => { request.method = 'DELETE'; request.url = '/v3/suppression/spam_reports'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3427,7 +3427,7 @@ describe('test_suppression_spam_reports_delete', () => { }); describe('test_suppression_spam_reports_get', () => { - var request = {}; + const request = {}; const queryParams = { 'end_time': 1, 'limit': 1, @@ -3438,7 +3438,7 @@ describe('test_suppression_spam_reports_get', () => { request.method = 'GET'; request.url = '/v3/suppression/spam_reports'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3451,11 +3451,11 @@ describe('test_suppression_spam_reports_get', () => { }); describe('test_suppression_spam_reports__email__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/suppression/spam_reports/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3468,11 +3468,11 @@ describe('test_suppression_spam_reports__email__delete', () => { }); describe('test_suppression_spam_reports__email__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/suppression/spam_reports/{email}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3485,7 +3485,7 @@ describe('test_suppression_spam_reports__email__get', () => { }); describe('test_suppression_unsubscribes_get', () => { - var request = {}; + const request = {}; const queryParams = { 'end_time': 1, 'limit': 1, @@ -3496,7 +3496,7 @@ describe('test_suppression_unsubscribes_get', () => { request.method = 'GET'; request.url = '/v3/suppression/unsubscribes'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3509,7 +3509,7 @@ describe('test_suppression_unsubscribes_get', () => { }); describe('test_teammates_post', () => { - var request = {}; + const request = {}; const data = { "email": "teammate1@example.com", "is_admin": false, @@ -3522,7 +3522,7 @@ describe('test_teammates_post', () => { request.method = 'POST'; request.url = '/v3/teammates'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -3535,7 +3535,7 @@ describe('test_teammates_post', () => { }); describe('test_teammates_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1, 'offset': 1 @@ -3544,7 +3544,7 @@ describe('test_teammates_get', () => { request.method = 'GET'; request.url = '/v3/teammates'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3557,11 +3557,11 @@ describe('test_teammates_get', () => { }); describe('test_teammates_pending_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/teammates/pending'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3574,11 +3574,11 @@ describe('test_teammates_pending_get', () => { }); describe('test_teammates_pending__token__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/teammates/pending/{token}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3591,11 +3591,11 @@ describe('test_teammates_pending__token__delete', () => { }); describe('test_teammates_pending__token__resend_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/teammates/pending/{token}/resend'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3608,11 +3608,11 @@ describe('test_teammates_pending__token__resend_post', () => { }); describe('test_teammates__username__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/teammates/{username}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3625,7 +3625,7 @@ describe('test_teammates__username__delete', () => { }); describe('test_teammates__username__patch', () => { - var request = {}; + const request = {}; const data = { "is_admin": false, "scopes": [ @@ -3637,7 +3637,7 @@ describe('test_teammates__username__patch', () => { request.method = 'PATCH'; request.url = '/v3/teammates/{username}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3650,11 +3650,11 @@ describe('test_teammates__username__patch', () => { }); describe('test_teammates__username__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/teammates/{username}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3667,7 +3667,7 @@ describe('test_teammates__username__get', () => { }); describe('test_templates_post', () => { - var request = {}; + const request = {}; const data = { "name": "example_name" }; @@ -3675,7 +3675,7 @@ describe('test_templates_post', () => { request.method = 'POST'; request.url = '/v3/templates'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -3688,11 +3688,11 @@ describe('test_templates_post', () => { }); describe('test_templates_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/templates'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3705,11 +3705,11 @@ describe('test_templates_get', () => { }); describe('test_templates__template_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/templates/{template_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3722,7 +3722,7 @@ describe('test_templates__template_id__delete', () => { }); describe('test_templates__template_id__patch', () => { - var request = {}; + const request = {}; const data = { "name": "new_example_name" }; @@ -3730,7 +3730,7 @@ describe('test_templates__template_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/templates/{template_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3743,11 +3743,11 @@ describe('test_templates__template_id__patch', () => { }); describe('test_templates__template_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/templates/{template_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3760,7 +3760,7 @@ describe('test_templates__template_id__get', () => { }); describe('test_templates__template_id__versions_post', () => { - var request = {}; + const request = {}; const data = { "active": 1, "html_content": "<%body%>", @@ -3773,7 +3773,7 @@ describe('test_templates__template_id__versions_post', () => { request.method = 'POST'; request.url = '/v3/templates/{template_id}/versions'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -3786,11 +3786,11 @@ describe('test_templates__template_id__versions_post', () => { }); describe('test_templates__template_id__versions__version_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/templates/{template_id}/versions/{version_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -3803,7 +3803,7 @@ describe('test_templates__template_id__versions__version_id__delete', () => { }); describe('test_templates__template_id__versions__version_id__patch', () => { - var request = {}; + const request = {}; const data = { "active": 1, "html_content": "<%body%>", @@ -3815,7 +3815,7 @@ describe('test_templates__template_id__versions__version_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/templates/{template_id}/versions/{version_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3828,11 +3828,11 @@ describe('test_templates__template_id__versions__version_id__patch', () => { }); describe('test_templates__template_id__versions__version_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/templates/{template_id}/versions/{version_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3845,11 +3845,11 @@ describe('test_templates__template_id__versions__version_id__get', () => { }); describe('test_templates__template_id__versions__version_id__activate_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/templates/{template_id}/versions/{version_id}/activate'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3862,7 +3862,7 @@ describe('test_templates__template_id__versions__version_id__activate_post', () }); describe('test_tracking_settings_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1, 'offset': 1 @@ -3871,7 +3871,7 @@ describe('test_tracking_settings_get', () => { request.method = 'GET'; request.url = '/v3/tracking_settings'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3884,7 +3884,7 @@ describe('test_tracking_settings_get', () => { }); describe('test_tracking_settings_click_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true }; @@ -3892,7 +3892,7 @@ describe('test_tracking_settings_click_patch', () => { request.method = 'PATCH'; request.url = '/v3/tracking_settings/click'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3905,11 +3905,11 @@ describe('test_tracking_settings_click_patch', () => { }); describe('test_tracking_settings_click_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/tracking_settings/click'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3922,7 +3922,7 @@ describe('test_tracking_settings_click_get', () => { }); describe('test_tracking_settings_google_analytics_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true, "utm_campaign": "website", @@ -3935,7 +3935,7 @@ describe('test_tracking_settings_google_analytics_patch', () => { request.method = 'PATCH'; request.url = '/v3/tracking_settings/google_analytics'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3948,11 +3948,11 @@ describe('test_tracking_settings_google_analytics_patch', () => { }); describe('test_tracking_settings_google_analytics_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/tracking_settings/google_analytics'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3965,7 +3965,7 @@ describe('test_tracking_settings_google_analytics_get', () => { }); describe('test_tracking_settings_open_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true }; @@ -3973,7 +3973,7 @@ describe('test_tracking_settings_open_patch', () => { request.method = 'PATCH'; request.url = '/v3/tracking_settings/open'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -3986,11 +3986,11 @@ describe('test_tracking_settings_open_patch', () => { }); describe('test_tracking_settings_open_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/tracking_settings/open'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4003,7 +4003,7 @@ describe('test_tracking_settings_open_get', () => { }); describe('test_tracking_settings_subscription_patch', () => { - var request = {}; + const request = {}; const data = { "enabled": true, "html_content": "html content", @@ -4016,7 +4016,7 @@ describe('test_tracking_settings_subscription_patch', () => { request.method = 'PATCH'; request.url = '/v3/tracking_settings/subscription'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4029,11 +4029,11 @@ describe('test_tracking_settings_subscription_patch', () => { }); describe('test_tracking_settings_subscription_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/tracking_settings/subscription'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4046,11 +4046,11 @@ describe('test_tracking_settings_subscription_get', () => { }); describe('test_user_account_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/account'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4063,11 +4063,11 @@ describe('test_user_account_get', () => { }); describe('test_user_credits_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/credits'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4080,7 +4080,7 @@ describe('test_user_credits_get', () => { }); describe('test_user_email_put', () => { - var request = {}; + const request = {}; const data = { "email": "example@example.com" }; @@ -4088,7 +4088,7 @@ describe('test_user_email_put', () => { request.method = 'PUT'; request.url = '/v3/user/email'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4101,11 +4101,11 @@ describe('test_user_email_put', () => { }); describe('test_user_email_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/email'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4118,7 +4118,7 @@ describe('test_user_email_get', () => { }); describe('test_user_password_put', () => { - var request = {}; + const request = {}; const data = { "new_password": "new_password", "old_password": "old_password" @@ -4127,7 +4127,7 @@ describe('test_user_password_put', () => { request.method = 'PUT'; request.url = '/v3/user/password'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4140,7 +4140,7 @@ describe('test_user_password_put', () => { }); describe('test_user_profile_patch', () => { - var request = {}; + const request = {}; const data = { "city": "Orange", "first_name": "Example", @@ -4150,7 +4150,7 @@ describe('test_user_profile_patch', () => { request.method = 'PATCH'; request.url = '/v3/user/profile'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4163,11 +4163,11 @@ describe('test_user_profile_patch', () => { }); describe('test_user_profile_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/profile'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4180,7 +4180,7 @@ describe('test_user_profile_get', () => { }); describe('test_user_scheduled_sends_post', () => { - var request = {}; + const request = {}; const data = { "batch_id": "YOUR_BATCH_ID", "status": "pause" @@ -4189,7 +4189,7 @@ describe('test_user_scheduled_sends_post', () => { request.method = 'POST'; request.url = '/v3/user/scheduled_sends'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -4202,11 +4202,11 @@ describe('test_user_scheduled_sends_post', () => { }); describe('test_user_scheduled_sends_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/scheduled_sends'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4219,11 +4219,11 @@ describe('test_user_scheduled_sends_get', () => { }); describe('test_user_scheduled_sends__batch_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/user/scheduled_sends/{batch_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4236,7 +4236,7 @@ describe('test_user_scheduled_sends__batch_id__delete', () => { }); describe('test_user_scheduled_sends__batch_id__patch', () => { - var request = {}; + const request = {}; const data = { "status": "pause" }; @@ -4244,7 +4244,7 @@ describe('test_user_scheduled_sends__batch_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/user/scheduled_sends/{batch_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4257,11 +4257,11 @@ describe('test_user_scheduled_sends__batch_id__patch', () => { }); describe('test_user_scheduled_sends__batch_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/scheduled_sends/{batch_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4274,7 +4274,7 @@ describe('test_user_scheduled_sends__batch_id__get', () => { }); describe('test_user_settings_enforced_tls_patch', () => { - var request = {}; + const request = {}; const data = { "require_tls": true, "require_valid_cert": false @@ -4283,7 +4283,7 @@ describe('test_user_settings_enforced_tls_patch', () => { request.method = 'PATCH'; request.url = '/v3/user/settings/enforced_tls'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4296,11 +4296,11 @@ describe('test_user_settings_enforced_tls_patch', () => { }); describe('test_user_settings_enforced_tls_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/settings/enforced_tls'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4313,7 +4313,7 @@ describe('test_user_settings_enforced_tls_get', () => { }); describe('test_user_username_put', () => { - var request = {}; + const request = {}; const data = { "username": "test_username" }; @@ -4321,7 +4321,7 @@ describe('test_user_username_put', () => { request.method = 'PUT'; request.url = '/v3/user/username'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4334,11 +4334,11 @@ describe('test_user_username_put', () => { }); describe('test_user_username_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/username'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4351,7 +4351,7 @@ describe('test_user_username_get', () => { }); describe('test_user_webhooks_event_settings_patch', () => { - var request = {}; + const request = {}; const data = { "bounce": true, "click": true, @@ -4371,7 +4371,7 @@ describe('test_user_webhooks_event_settings_patch', () => { request.method = 'PATCH'; request.url = '/v3/user/webhooks/event/settings'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4384,11 +4384,11 @@ describe('test_user_webhooks_event_settings_patch', () => { }); describe('test_user_webhooks_event_settings_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/webhooks/event/settings'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4401,7 +4401,7 @@ describe('test_user_webhooks_event_settings_get', () => { }); describe('test_user_webhooks_event_test_post', () => { - var request = {}; + const request = {}; const data = { "url": "url" }; @@ -4409,7 +4409,7 @@ describe('test_user_webhooks_event_test_post', () => { request.method = 'POST'; request.url = '/v3/user/webhooks/event/test'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4422,7 +4422,7 @@ describe('test_user_webhooks_event_test_post', () => { }); describe('test_user_webhooks_parse_settings_post', () => { - var request = {}; + const request = {}; const data = { "hostname": "myhostname.com", "send_raw": false, @@ -4433,7 +4433,7 @@ describe('test_user_webhooks_parse_settings_post', () => { request.method = 'POST'; request.url = '/v3/user/webhooks/parse/settings'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -4446,11 +4446,11 @@ describe('test_user_webhooks_parse_settings_post', () => { }); describe('test_user_webhooks_parse_settings_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/webhooks/parse/settings'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4463,11 +4463,11 @@ describe('test_user_webhooks_parse_settings_get', () => { }); describe('test_user_webhooks_parse_settings__hostname__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/user/webhooks/parse/settings/{hostname}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4480,7 +4480,7 @@ describe('test_user_webhooks_parse_settings__hostname__delete', () => { }); describe('test_user_webhooks_parse_settings__hostname__patch', () => { - var request = {}; + const request = {}; const data = { "send_raw": true, "spam_check": false, @@ -4490,7 +4490,7 @@ describe('test_user_webhooks_parse_settings__hostname__patch', () => { request.method = 'PATCH'; request.url = '/v3/user/webhooks/parse/settings/{hostname}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4503,11 +4503,11 @@ describe('test_user_webhooks_parse_settings__hostname__patch', () => { }); describe('test_user_webhooks_parse_settings__hostname__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/user/webhooks/parse/settings/{hostname}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4520,7 +4520,7 @@ describe('test_user_webhooks_parse_settings__hostname__get', () => { }); describe('test_user_webhooks_parse_stats_get', () => { - var request = {}; + const request = {}; const queryParams = { 'aggregated_by': 'day', 'end_date': '2016-04-01', @@ -4532,7 +4532,7 @@ describe('test_user_webhooks_parse_stats_get', () => { request.method = 'GET'; request.url = '/v3/user/webhooks/parse/stats'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4545,7 +4545,7 @@ describe('test_user_webhooks_parse_stats_get', () => { }); describe('test_whitelabel_domains_post', () => { - var request = {}; + const request = {}; const data = { "automatic_security": false, "custom_spf": true, @@ -4562,7 +4562,7 @@ describe('test_whitelabel_domains_post', () => { request.method = 'POST'; request.url = '/v3/whitelabel/domains'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -4575,7 +4575,7 @@ describe('test_whitelabel_domains_post', () => { }); describe('test_whitelabel_domains_get', () => { - var request = {}; + const request = {}; const queryParams = { 'domain': 'test_string', 'exclude_subusers': 'true', @@ -4587,7 +4587,7 @@ describe('test_whitelabel_domains_get', () => { request.method = 'GET'; request.url = '/v3/whitelabel/domains'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4600,11 +4600,11 @@ describe('test_whitelabel_domains_get', () => { }); describe('test_whitelabel_domains_default_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/whitelabel/domains/default'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4617,11 +4617,11 @@ describe('test_whitelabel_domains_default_get', () => { }); describe('test_whitelabel_domains_subuser_delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/whitelabel/domains/subuser'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4634,11 +4634,11 @@ describe('test_whitelabel_domains_subuser_delete', () => { }); describe('test_whitelabel_domains_subuser_get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/whitelabel/domains/subuser'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4651,11 +4651,11 @@ describe('test_whitelabel_domains_subuser_get', () => { }); describe('test_whitelabel_domains__domain_id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/whitelabel/domains/{domain_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4668,7 +4668,7 @@ describe('test_whitelabel_domains__domain_id__delete', () => { }); describe('test_whitelabel_domains__domain_id__patch', () => { - var request = {}; + const request = {}; const data = { "custom_spf": true, "default": false @@ -4677,7 +4677,7 @@ describe('test_whitelabel_domains__domain_id__patch', () => { request.method = 'PATCH'; request.url = '/v3/whitelabel/domains/{domain_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4690,11 +4690,11 @@ describe('test_whitelabel_domains__domain_id__patch', () => { }); describe('test_whitelabel_domains__domain_id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/whitelabel/domains/{domain_id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4707,7 +4707,7 @@ describe('test_whitelabel_domains__domain_id__get', () => { }); describe('test_whitelabel_domains__domain_id__subuser_post', () => { - var request = {}; + const request = {}; const data = { "username": "jane@example.com" }; @@ -4715,7 +4715,7 @@ describe('test_whitelabel_domains__domain_id__subuser_post', () => { request.method = 'POST'; request.url = '/v3/whitelabel/domains/{domain_id}/subuser'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -4728,7 +4728,7 @@ describe('test_whitelabel_domains__domain_id__subuser_post', () => { }); describe('test_whitelabel_domains__id__ips_post', () => { - var request = {}; + const request = {}; const data = { "ip": "192.168.0.1" }; @@ -4736,7 +4736,7 @@ describe('test_whitelabel_domains__id__ips_post', () => { request.method = 'POST'; request.url = '/v3/whitelabel/domains/{id}/ips'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4749,11 +4749,11 @@ describe('test_whitelabel_domains__id__ips_post', () => { }); describe('test_whitelabel_domains__id__ips__ip__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/whitelabel/domains/{id}/ips/{ip}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4766,11 +4766,11 @@ describe('test_whitelabel_domains__id__ips__ip__delete', () => { }); describe('test_whitelabel_domains__id__validate_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/whitelabel/domains/{id}/validate'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4783,7 +4783,7 @@ describe('test_whitelabel_domains__id__validate_post', () => { }); describe('test_whitelabel_ips_post', () => { - var request = {}; + const request = {}; const data = { "domain": "example.com", "ip": "192.168.1.1", @@ -4793,7 +4793,7 @@ describe('test_whitelabel_ips_post', () => { request.method = 'POST'; request.url = '/v3/whitelabel/ips'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -4806,7 +4806,7 @@ describe('test_whitelabel_ips_post', () => { }); describe('test_whitelabel_ips_get', () => { - var request = {}; + const request = {}; const queryParams = { 'ip': 'test_string', 'limit': 1, @@ -4816,7 +4816,7 @@ describe('test_whitelabel_ips_get', () => { request.method = 'GET'; request.url = '/v3/whitelabel/ips'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4829,11 +4829,11 @@ describe('test_whitelabel_ips_get', () => { }); describe('test_whitelabel_ips__id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/whitelabel/ips/{id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4846,11 +4846,11 @@ describe('test_whitelabel_ips__id__delete', () => { }); describe('test_whitelabel_ips__id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/whitelabel/ips/{id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4863,11 +4863,11 @@ describe('test_whitelabel_ips__id__get', () => { }); describe('test_whitelabel_ips__id__validate_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/whitelabel/ips/{id}/validate'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4880,7 +4880,7 @@ describe('test_whitelabel_ips__id__validate_post', () => { }); describe('test_whitelabel_links_post', () => { - var request = {}; + const request = {}; const data = { "default": true, "domain": "example.com", @@ -4895,7 +4895,7 @@ describe('test_whitelabel_links_post', () => { request.method = 'POST'; request.url = '/v3/whitelabel/links'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 201); @@ -4908,7 +4908,7 @@ describe('test_whitelabel_links_post', () => { }); describe('test_whitelabel_links_get', () => { - var request = {}; + const request = {}; const queryParams = { 'limit': 1 }; @@ -4916,7 +4916,7 @@ describe('test_whitelabel_links_get', () => { request.method = 'GET'; request.url = '/v3/whitelabel/links'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4929,7 +4929,7 @@ describe('test_whitelabel_links_get', () => { }); describe('test_whitelabel_links_default_get', () => { - var request = {}; + const request = {}; const queryParams = { 'domain': 'test_string' }; @@ -4937,7 +4937,7 @@ describe('test_whitelabel_links_default_get', () => { request.method = 'GET'; request.url = '/v3/whitelabel/links/default'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4950,7 +4950,7 @@ describe('test_whitelabel_links_default_get', () => { }); describe('test_whitelabel_links_subuser_delete', () => { - var request = {}; + const request = {}; const queryParams = { 'username': 'test_string' }; @@ -4958,7 +4958,7 @@ describe('test_whitelabel_links_subuser_delete', () => { request.method = 'DELETE'; request.url = '/v3/whitelabel/links/subuser'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -4971,7 +4971,7 @@ describe('test_whitelabel_links_subuser_delete', () => { }); describe('test_whitelabel_links_subuser_get', () => { - var request = {}; + const request = {}; const queryParams = { 'username': 'test_string' }; @@ -4979,7 +4979,7 @@ describe('test_whitelabel_links_subuser_get', () => { request.method = 'GET'; request.url = '/v3/whitelabel/links/subuser'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -4992,11 +4992,11 @@ describe('test_whitelabel_links_subuser_get', () => { }); describe('test_whitelabel_links__id__delete', () => { - var request = {}; + const request = {}; request.method = 'DELETE'; request.url = '/v3/whitelabel/links/{id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 204); @@ -5009,7 +5009,7 @@ describe('test_whitelabel_links__id__delete', () => { }); describe('test_whitelabel_links__id__patch', () => { - var request = {}; + const request = {}; const data = { "default": true }; @@ -5017,7 +5017,7 @@ describe('test_whitelabel_links__id__patch', () => { request.method = 'PATCH'; request.url = '/v3/whitelabel/links/{id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -5030,11 +5030,11 @@ describe('test_whitelabel_links__id__patch', () => { }); describe('test_whitelabel_links__id__get', () => { - var request = {}; + const request = {}; request.method = 'GET'; request.url = '/v3/whitelabel/links/{id}'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -5047,11 +5047,11 @@ describe('test_whitelabel_links__id__get', () => { }); describe('test_whitelabel_links__id__validate_post', () => { - var request = {}; + const request = {}; request.method = 'POST'; request.url = '/v3/whitelabel/links/{id}/validate'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); @@ -5064,7 +5064,7 @@ describe('test_whitelabel_links__id__validate_post', () => { }); describe('test_whitelabel_links__link_id__subuser_post', () => { - var request = {}; + const request = {}; const data = { "username": "jane@example.com" }; @@ -5072,7 +5072,7 @@ describe('test_whitelabel_links__link_id__subuser_post', () => { request.method = 'POST'; request.url = '/v3/whitelabel/links/{link_id}/subuser'; it('should have the correct response code', () => { - var sgClient = require('./client'); + const sgClient = require('./client'); sgClient.setApiKey('SendGrid API Key'); sgClient.setDefaultRequest('baseUrl', baseUrl); sgClient.setDefaultHeader('X-Mock', 200); diff --git a/packages/contact-importer/src/importer.js b/packages/contact-importer/src/importer.js index eb5778b78..a03d78c54 100644 --- a/packages/contact-importer/src/importer.js +++ b/packages/contact-importer/src/importer.js @@ -1,17 +1,17 @@ /* eslint dot-notation: 'off' */ 'use strict'; -var Bottleneck = require('bottleneck'); -var EventEmitter = require('events').EventEmitter; -var chunk = require('lodash.chunk'); -var debug = require('debug')('sendgrid'); -var util = require('util'); -var queue = require('async.queue'); -var ensureAsync = require('async.ensureasync'); - -var ContactImporter = module.exports = function(sg, options) { +const Bottleneck = require('bottleneck'); +const EventEmitter = require('events').EventEmitter; +const chunk = require('lodash.chunk'); +const debug = require('debug')('sendgrid'); +const util = require('util'); +const queue = require('async.queue'); +const ensureAsync = require('async.ensureasync'); + +const ContactImporter = module.exports = function(sg, options) { options = options || {}; - var self = this; + const self = this; this.sg = sg; this.pendingItems = []; @@ -35,7 +35,7 @@ var ContactImporter = module.exports = function(sg, options) { this.queue.empty = function() { if (self.pendingItems.length) { debug('adding %s items from deferrd queue for processing', self.pendingItems.length); - var batch = self.pendingItems.splice(0); + const batch = self.pendingItems.splice(0); self.queue.push({ data: batch, owner: self, @@ -61,14 +61,14 @@ util.inherits(ContactImporter, EventEmitter); * @param {Array|Object} data A contact or array of contacts. */ ContactImporter.prototype.push = function(data) { - var self = this; + const self = this; data = Array.isArray(data) ? data : [data]; // Add the new items onto the pending items. - var itemsToProcess = this.pendingItems.concat(data); + const itemsToProcess = this.pendingItems.concat(data); // Chunk the pending items into batches and add onto the queue - var batches = chunk(itemsToProcess, this.batchSize); + const batches = chunk(itemsToProcess, this.batchSize); debug('generated batches %s from %s items', batches.length, data.length); batches.forEach(function(batch) { @@ -102,7 +102,7 @@ ContactImporter.prototype.push = function(data) { * @param {Function} callback Callback function. */ ContactImporter.prototype._worker = function(task, callback) { - var context = task.owner; + const context = task.owner; debug('processing batch (%s items)', task.data.length); context.throttle.submit(context._sendBatch, context, task.data, callback); }; @@ -110,7 +110,7 @@ ContactImporter.prototype._worker = function(task, callback) { ContactImporter.prototype._sendBatch = function(context, data, callback) { debug('sending batch (%s items)', data.length); - var request = context.sg.emptyRequest(); + const request = context.sg.emptyRequest(); request.method = 'POST'; request.path = '/v3/contactdb/recipients'; request.body = data; diff --git a/packages/contact-importer/src/importer.spec.js b/packages/contact-importer/src/importer.spec.js index 16b6687ca..2c885f8bd 100644 --- a/packages/contact-importer/src/importer.spec.js +++ b/packages/contact-importer/src/importer.spec.js @@ -1,10 +1,10 @@ -var ContactImporter = require('./importer'); +const ContactImporter = require('./importer'); describe.only('test_contact_importer', function() { beforeEach(function() { // Create a new SendGrid instance. - var API_KEY = process.env.API_KEY; - var sg = sendgrid(API_KEY); + const API_KEY = process.env.API_KEY; + const sg = sendgrid(API_KEY); // Create a new importer with a batch size of 2. this.contactImporter = new ContactImporter(sg, { @@ -14,9 +14,9 @@ describe.only('test_contact_importer', function() { this.sinon.spy(ContactImporter.prototype, '_sendBatch'); // Generate some test data. - var data = []; + const data = []; for (i = 0; i < 5; i++) { - var item = { + const item = { email: 'example' + i + '@example.com', first_name: 'Test', last_name: 'User', @@ -31,7 +31,7 @@ describe.only('test_contact_importer', function() { }); it('test_contact_importer sends items in batches', function(done) { - var self = this; + const self = this; this.timeout(30000); this.contactImporter.on('success', function(result, batch) { console.log('SUCCESS result', result); diff --git a/packages/inbound-mail-parser/src/parser.js b/packages/inbound-mail-parser/src/parser.js index c8ce29f57..fc1d23f24 100644 --- a/packages/inbound-mail-parser/src/parser.js +++ b/packages/inbound-mail-parser/src/parser.js @@ -15,7 +15,7 @@ const { * @return {Object} A SendGrid Attachment object with the file data */ function createAttachment(file) { - var attachment = new Attachment(); + const attachment = new Attachment(); attachment.setFilename(file.originalname || file.fileName); attachment.setType(file.mimetype || file.contentType); @@ -43,10 +43,10 @@ function Parse(config, request) { * @return {Object} Valid key/values in the webhook payload */ Parse.prototype.keyValues = function() { - var keyValues = {}; - var key; + const keyValues = {}; + let key; - for (var index in this.keys) { + for (const index in this.keys) { key = this.keys[index]; if (this.payload[key]) { @@ -70,8 +70,8 @@ Parse.prototype.hasRawEmail = function() { * @param {Function} callback Function which will receive the parsed email object as the sole argument */ Parse.prototype.getRawEmail = function(callback) { - var mailparser = new MailParser(); - var rawEmail = this.payload.email; + const mailparser = new MailParser(); + const rawEmail = this.payload.email; if (!rawEmail) { return callback(null); @@ -106,7 +106,7 @@ Parse.prototype._getAttachmentsRaw = function(callback) { return callback([]); } - var attachments = parsedEmail.attachments.map(function(file) { + const attachments = parsedEmail.attachments.map(function(file) { return createAttachment(file); }); @@ -120,10 +120,10 @@ Parse.prototype._getAttachmentsRaw = function(callback) { * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument */ Parse.prototype._getAttachments = function(callback) { - var file; - var attachments = []; + let file; + const attachments = []; - for (var index in this.files) { + for (const index in this.files) { file = this.files[index]; if (fs.existsSync(file.path)) { diff --git a/packages/inbound-mail-parser/src/parser.spec.js b/packages/inbound-mail-parser/src/parser.spec.js index 233255c5a..5b3cd0bb7 100644 --- a/packages/inbound-mail-parser/src/parser.spec.js +++ b/packages/inbound-mail-parser/src/parser.spec.js @@ -1,12 +1,12 @@ -var Parse = require('./parser'); +const Parse = require('./parser'); describe('test_parse', function() { describe('test_parse_key_values', function() { it('should return the key values specified in the config from the payload', function() { - var config = { + const config = { keys: ['to', 'from'], }; - var request = { + const request = { body: { to: 'inbound@inbound.example.com', from: 'Test User ', @@ -14,9 +14,9 @@ describe('test_parse', function() { }, }; - var parse = new Parse(config, request); - var keyValues = parse.keyValues(); - var expectedValues = { + const parse = new Parse(config, request); + const keyValues = parse.keyValues(); + const expectedValues = { to: 'inbound@inbound.example.com', from: 'Test User ', }; @@ -28,7 +28,7 @@ describe('test_parse', function() { describe('test_parse_get_raw_email', function() { it('should return null if no raw email property in payload', function(done) { - var parse = new Parse({}, {}); + const parse = new Parse({}, {}); function callback(email) { expect(email).to.be.null; @@ -39,13 +39,13 @@ describe('test_parse', function() { }); it('should parse raw email from payload and return a mail object', function(done) { - var request = { + const request = { body: { email: 'MIME-Version: 1.0\r\nReceived: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 14:44:21 -0700 (PDT)\r\nFrom: Example User \r\nDate: Wed, 10 Aug 2016 14:44:21 -0700\r\nSubject: Inbound Parse Test Raw Data\r\nTo: inbound@inbound.inbound.com\r\nContent-Type: multipart/alternative; boundary=001a113ee97c89842f0539be8e7a\r\n\r\n--001a113ee97c89842f0539be8e7a\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\nHello SendGrid!\r\n\r\n--001a113ee97c89842f0539be8e7a\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nHello SendGrid!\r\n\r\n--001a113ee97c89842f0539be8e7a--\r\n', }, }; - var parse = new Parse({}, request); + const parse = new Parse({}, request); function callback(email) { expect(email).to.be.an('object'); From e3be75bfc9d066abe7a3958315c33ba0d9224327 Mon Sep 17 00:00:00 2001 From: Saras Arya Date: Sun, 15 Oct 2017 23:42:47 +0530 Subject: [PATCH 05/62] Added examples sections --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ffa11ac27..267dbfdaa 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ We appreciate your continued support, thank you! # Introduction - Please Read First -This library is broken up into several packages as a monorepo so that you only need to install the packages necessary for your use case. This README contains information pertaining to all packages. +This library is broken up into several packages as a monorepo so that you only need to install the packages necessary for your use case. For examples on how to do get started quickly, head over to the README of individual package, which includes detailed examples. This README contains information pertaining to all packages. * [@sendgrid/mail](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/mail) - if you just want to send email * [@sendgrid/client](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/client) - to use all other [SendGrid v3 Web API endpoints](https://sendgrid.com/docs/API_Reference/api_v3.html) From edb3a933d86448c0f68b1570714c5bcbfbbeb366 Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 16 Oct 2017 10:23:53 -0700 Subject: [PATCH 06/62] Minor reformatting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 267dbfdaa..e0d11847a 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ We appreciate your continued support, thank you! # Introduction - Please Read First -This library is broken up into several packages as a monorepo so that you only need to install the packages necessary for your use case. For examples on how to do get started quickly, head over to the README of individual package, which includes detailed examples. This README contains information pertaining to all packages. +This library is broken up into several packages as a monorepo so that you only need to install the packages necessary for your use case. This README contains information pertaining to all packages. For examples on how to get started quickly, head over to the READMEs of each individual package (linked and described below), which includes detailed examples. * [@sendgrid/mail](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/mail) - if you just want to send email * [@sendgrid/client](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/client) - to use all other [SendGrid v3 Web API endpoints](https://sendgrid.com/docs/API_Reference/api_v3.html) From d98206c8502f57be420e9d539750932d06087c22 Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 16 Oct 2017 12:54:10 -0700 Subject: [PATCH 07/62] Update USE_CASES.md --- packages/mail/USE_CASES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mail/USE_CASES.md b/packages/mail/USE_CASES.md index a663e942b..b4b5ae3b4 100644 --- a/packages/mail/USE_CASES.md +++ b/packages/mail/USE_CASES.md @@ -462,13 +462,13 @@ sgMail # How to Setup a Domain Whitelabel -You can find documentation for how to setup a domain whitelabel via the UI [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/setup_domain_whitelabel.html) and via API [here](https://github.com/sendgrid/sendgrid-csharp/blob/master/USAGE.md#whitelabel). +You can find documentation for how to setup a domain whitelabel via the UI [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/setup_domain_whitelabel.html) and via API [here](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/client/USAGE.md#whitelabel). Find more information about all of SendGrid's whitelabeling related documentation [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/index.html). # How to View Email Statistics -You can find documentation for how to view your email statistics via the UI [here](https://app.sendgrid.com/statistics) and via API [here](https://github.com/sendgrid/sendgrid-csharp/blob/master/USAGE.md#stats). +You can find documentation for how to view your email statistics via the UI [here](https://app.sendgrid.com/statistics) and via API [here](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/client/USAGE.md#stats). Alternatively, we can post events to a URL of your choice via our [Event Webhook](https://sendgrid.com/docs/API_Reference/Webhooks/event.html) about events that occur as SendGrid processes your email. From cb074a998208d51bf0a09382cb912c8c608cc137 Mon Sep 17 00:00:00 2001 From: NitishPhanse Date: Tue, 17 Oct 2017 17:06:15 +0530 Subject: [PATCH 08/62] added condition to check if cb is a function, else return an error --- packages/client/src/client.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/client/src/client.js b/packages/client/src/client.js index 5961762ae..a9ff89a7a 100644 --- a/packages/client/src/client.js +++ b/packages/client/src/client.js @@ -106,7 +106,6 @@ class Client { * Do a request */ request(data, cb) { - //Create request const request = this.createRequest(data); @@ -129,6 +128,11 @@ class Client { }); }); + // Throw and error incase function not passed + if (cb && typeof(cb) !== 'function') { + return new Error('Callback passed is not a function.'); + } + //Execute callback if provided if (cb) { promise From ad828a7289efe346b4e9afc1d3856365cea1a8b8 Mon Sep 17 00:00:00 2001 From: NitishPhanse Date: Tue, 17 Oct 2017 17:06:57 +0530 Subject: [PATCH 09/62] test case for non function callback --- packages/mail/src/mail.spec.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/mail/src/mail.spec.js b/packages/mail/src/mail.spec.js index 5e66ab3e1..d46f78a43 100644 --- a/packages/mail/src/mail.spec.js +++ b/packages/mail/src/mail.spec.js @@ -36,6 +36,8 @@ describe('sgMail.send()', () => { html: '

Hello HTML world!

', }; + const cb = {}; + it('should throw an error when no data provided', () => { return expect(sgMail.send()).to.eventually.be.rejectedWith(Error); }); @@ -48,4 +50,10 @@ describe('sgMail.send()', () => { expect(response.statusCode).to.equal(201); }); }); + + + it('should throw an error if callback is not a function', () => { + return expect(sgMail.send(data, false, cb)).to.be.an('error'); + }); }); + From d8f6c0814ffa88b398c75c4a902d246913aa35eb Mon Sep 17 00:00:00 2001 From: NitishPhanse Date: Tue, 17 Oct 2017 17:09:04 +0530 Subject: [PATCH 10/62] empty line --- packages/client/src/client.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/client.js b/packages/client/src/client.js index a9ff89a7a..06ca501d8 100644 --- a/packages/client/src/client.js +++ b/packages/client/src/client.js @@ -106,6 +106,7 @@ class Client { * Do a request */ request(data, cb) { + //Create request const request = this.createRequest(data); From 0a1522cd4abc173ceb9a308adf3f07b1f165da45 Mon Sep 17 00:00:00 2001 From: Shreyas Agarkar Date: Wed, 18 Oct 2017 13:46:54 +0530 Subject: [PATCH 11/62] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e0d11847a..3d1bc544f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![BuildStatus](https://travis-ci.org/sendgrid/sendgrid-nodejs.svg?branch=master)](https://travis-ci.org/sendgrid/sendgrid-nodejs) [![npm version](https://badge.fury.io/js/%40sendgrid%2Fclient.svg)](https://www.npmjs.com/org/sendgrid) [![Email Notifications Badge](https://dx.sendgrid.com/badge/nodejs)](https://dx.sendgrid.com/newsletter/nodejs) +[![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/sendgrid-nodejs.svg)](https://github.com/sendgrid/sendgrid-nodejs/graphs/contributors) **This library allows you to quickly and easily use the SendGrid Web API v3 via Node.js.** From 400fa95a0fafe8cbb8b061ad8bd5a50fa7ea0d78 Mon Sep 17 00:00:00 2001 From: NitishPhanse Date: Fri, 20 Oct 2017 20:07:05 +0530 Subject: [PATCH 12/62] throwing error instead of return --- packages/client/src/client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/client.js b/packages/client/src/client.js index 06ca501d8..a0018ed83 100644 --- a/packages/client/src/client.js +++ b/packages/client/src/client.js @@ -130,8 +130,8 @@ class Client { }); // Throw and error incase function not passed - if (cb && typeof(cb) !== 'function') { - return new Error('Callback passed is not a function.'); + if (cb && typeof cb !== 'function') { + throw new Error('Callback passed is not a function.'); } //Execute callback if provided From 3c5ea6636d20941e94245d18cf53e3c33b0100c7 Mon Sep 17 00:00:00 2001 From: NitishPhanse Date: Fri, 20 Oct 2017 20:07:38 +0530 Subject: [PATCH 13/62] modified test to assert an error being thrown, removed un extra empty object --- packages/mail/src/mail.spec.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/mail/src/mail.spec.js b/packages/mail/src/mail.spec.js index d46f78a43..87e2472f6 100644 --- a/packages/mail/src/mail.spec.js +++ b/packages/mail/src/mail.spec.js @@ -36,8 +36,6 @@ describe('sgMail.send()', () => { html: '

Hello HTML world!

', }; - const cb = {}; - it('should throw an error when no data provided', () => { return expect(sgMail.send()).to.eventually.be.rejectedWith(Error); }); @@ -51,9 +49,10 @@ describe('sgMail.send()', () => { }); }); - it('should throw an error if callback is not a function', () => { - return expect(sgMail.send(data, false, cb)).to.be.an('error'); + return expect(function() { + sgMail.send(data, false, {}); + }).to.throw(Error); }); }); From 439ec6231d6b9c1d64f03b326416bacda4d7a6d6 Mon Sep 17 00:00:00 2001 From: eric horvat Date: Sat, 21 Oct 2017 09:47:36 +1100 Subject: [PATCH 14/62] Add/Update Badges on README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3d1bc544f..e1ad7ea7c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![npm version](https://badge.fury.io/js/%40sendgrid%2Fclient.svg)](https://www.npmjs.com/org/sendgrid) [![Email Notifications Badge](https://dx.sendgrid.com/badge/nodejs)](https://dx.sendgrid.com/newsletter/nodejs) [![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/sendgrid-nodejs.svg)](https://github.com/sendgrid/sendgrid-nodejs/graphs/contributors) +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.txt) **This library allows you to quickly and easily use the SendGrid Web API v3 via Node.js.** @@ -21,6 +22,7 @@ We appreciate your continued support, thank you! * [How to Contribute](#contribute) * [Troubleshooting](#troubleshooting) * [About](#about) +* [License](#license) # Introduction - Please Read First @@ -65,3 +67,7 @@ sendgrid-nodejs is guided and supported by the SendGrid [Developer Experience Te sendgrid-nodejs is maintained and funded by SendGrid, Inc. The names and logos for sendgrid-nodejs are trademarks of SendGrid, Inc. ![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) + + +# License +[The MIT License (MIT)](LICENSE.txt) From ff2c0c7d97cff879355bdc36bda07a9674dbc8fe Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Fri, 20 Oct 2017 16:29:47 -0700 Subject: [PATCH 15/62] SEO Friendly Section links --- CONTRIBUTING.md | 24 +++++++++--------- packages/client/USAGE.md | 24 +++++++++--------- packages/client/USE_CASES.md | 8 +++--- packages/mail/README.md | 2 +- packages/mail/USE_CASES.md | 48 ++++++++++++++++++------------------ 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1db46cc45..04a875835 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,13 +2,13 @@ Hello! Thank you for choosing to help contribute to one of the SendGrid open sou - [CLAs and CCLAs](#cla) - [Roadmap & Milestones](#roadmap) -- [Feature Request](#feature_request) -- [Submit a Bug Report](#submit_a_bug_report) -- [Improvements to the Codebase](#improvements_to_the_codebase) -- [Understanding the Code Base](#understanding_the_codebase) +- [Feature Request](#feature-request) +- [Submit a Bug Report](#submit-a-bug-report) +- [Improvements to the Codebase](#improvements-to-the-codebase) +- [Understanding the Code Base](#understanding-the-codebase) - [Testing](#testing) -- [Style Guidelines & Naming Conventions](#style_guidelines_and_naming_conventions) -- [Creating a Pull Request](#creating_a_pull_request) +- [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) +- [Creating a Pull Request](#creating-a-pull-request) We use [Milestones](https://github.com/sendgrid/sendgrid-nodejs/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions and additional PRs are welcomed and encouraged. @@ -26,7 +26,7 @@ When you create a Pull Request, after a few seconds, a comment will appear with There are a few ways to contribute, which we'll enumerate below: - + ## Feature Request If you'd like to make a feature request, please read this section. @@ -36,7 +36,7 @@ The GitHub issue tracker is the preferred channel for library feature requests, - Please **search for existing issues** in order to ensure we don't have duplicate bugs/feature requests. - Please be respectful and considerate of others when commenting on issues - + ## Submit a Bug Report Note: DO NOT include your credentials in ANY code examples, descriptions, or media you make public. @@ -53,7 +53,7 @@ Before you decide to create a new issue, please try the following: In order to make the process easier, we've included a [sample bug report template](https://github.com/sendgrid/sendgrid-nodejs/blob/master/.github/ISSUE_TEMPLATE) (borrowed from [Ghost](https://github.com/TryGhost/Ghost/)). The template uses [GitHub flavored markdown](https://help.github.com/articles/github-flavored-markdown/) for formatting. - + ## Improvements to the Codebase We welcome direct contributions to the sendgrid-nodejs code base. Thank you! @@ -103,7 +103,7 @@ Change the path to the Sendgrid library to the relative path, for example: `./pa node example.js ``` - + ## Understanding the Code Base This repo is organized as a monorepo with the packages residing in the `./packages` directory. Please see the root [README.md](https://github.com/sendgrid/sendgrid-nodejs/blob/master/README.md) for details. @@ -121,7 +121,7 @@ Open a new console window and run `lerna bootstrap`. And finally, run `yarn test`, or specific tests e.g. `yarn test:mail` or `yarn test:client`. - + ## Style Guidelines & Naming Conventions Generally, we follow the style guidelines as suggested by the official language. However, we ask that you conform to the styles that already exist in the library. If you wish to deviate, please explain your reasoning. @@ -132,7 +132,7 @@ Please run your code through: - [ESLint](http://eslint.org/) with the standard style guide. -## Creating a Pull Request +## Creating a Pull Request 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: diff --git a/packages/client/USAGE.md b/packages/client/USAGE.md index babef3e08..75b4147c5 100644 --- a/packages/client/USAGE.md +++ b/packages/client/USAGE.md @@ -9,9 +9,9 @@ client.setApiKey(process.env.SENDGRID_API_KEY); # Table of Contents -* [ACCESS SETTINGS](#access_settings) +* [ACCESS SETTINGS](#access-settings) * [ALERTS](#alerts) -* [API KEYS](#api_keys) +* [API KEYS](#api-keys) * [ASM](#asm) * [BROWSERS](#browsers) * [CAMPAIGNS](#campaigns) @@ -22,9 +22,9 @@ client.setApiKey(process.env.SENDGRID_API_KEY); * [GEO](#geo) * [IPS](#ips) * [MAIL](#mail) -* [MAIL SETTINGS](#mail_settings) -* [MAILBOX PROVIDERS](#mailbox_providers) -* [PARTNER SETTINGS](#partner_settings) +* [MAIL SETTINGS](#mail-settings) +* [MAILBOX PROVIDERS](#mailbox-providers) +* [PARTNER SETTINGS](#partner-settings) * [SCOPES](#scopes) * [SENDERS](#senders) * [STATS](#stats) @@ -32,12 +32,12 @@ client.setApiKey(process.env.SENDGRID_API_KEY); * [SUPPRESSION](#suppression) * [TEAMMATES](#teammates) * [TEMPLATES](#templates) -* [TRACKING SETTINGS](#tracking_settings) +* [TRACKING SETTINGS](#tracking-settings) * [USER](#user) * [WHITELABEL](#whitelabel) - + # ACCESS SETTINGS ## Retrieve all recent access attempts @@ -322,7 +322,7 @@ For more information about alerts, please see our [User Guide](https://sendgrid. console.log(response.body); }) ``` - + # API KEYS ## Create API keys @@ -2617,7 +2617,7 @@ For more detailed information about how to use the v3 Mail Send endpoint, please console.log(response.body); }) ``` - + # MAIL SETTINGS ## Retrieve all mail settings @@ -3057,7 +3057,7 @@ Mail settings allow you to tell SendGrid specific things to do to every email th console.log(response.body); }) ``` - + # MAILBOX PROVIDERS ## Retrieve email statistics by mailbox provider. @@ -3089,7 +3089,7 @@ Advanced Stats provide a more in-depth view of your email statistics and the act console.log(response.body); }) ``` - + # PARTNER SETTINGS ## Returns a list of all partner settings. @@ -4684,7 +4684,7 @@ For more information about transactional templates, please see our [User Guide]( console.log(response.body); }) ``` - + # TRACKING SETTINGS ## Retrieve Tracking Settings diff --git a/packages/client/USE_CASES.md b/packages/client/USE_CASES.md index fb1480054..bd47e07df 100644 --- a/packages/client/USE_CASES.md +++ b/packages/client/USE_CASES.md @@ -2,18 +2,18 @@ This documentation provides examples for specific SendGrid v3 API non mail/send # Table of Contents -* [How to Setup a Domain Whitelabel](#domain_whitelabel) -* [How to View Email Statistics](#email_stats) +* [How to Setup a Domain Whitelabel](#domain-white-label) +* [How to View Email Statistics](#email-stats) - + # How to Setup a Domain Whitelabel You can find documentation for how to setup a domain whitelabel via the UI [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/setup_domain_whitelabel.html) and via API [here](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/client/USAGE.md#whitelabel). Find more information about all of SendGrid's whitelabeling related documentation [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/index.html). - + # How to View Email Statistics You can find documentation for how to view your email statistics via the UI [here](https://app.sendgrid.com/statistics) and via API [here](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/client/USAGE.md#stats). diff --git a/packages/mail/README.md b/packages/mail/README.md index 438009b19..23d333890 100644 --- a/packages/mail/README.md +++ b/packages/mail/README.md @@ -46,7 +46,7 @@ You may also use [yarn](https://yarnpkg.com/en/) to install. yarn add @sendgrid/mail ``` - + # Quick Start, Hello Email The following is the minimum needed code to send an simple email. Use this example, and modify the `to` and `from` variables: diff --git a/packages/mail/USE_CASES.md b/packages/mail/USE_CASES.md index b4b5ae3b4..495c15616 100644 --- a/packages/mail/USE_CASES.md +++ b/packages/mail/USE_CASES.md @@ -2,24 +2,24 @@ This documentation provides examples for specific email use cases. Please [open # Table of Contents -* [Send a Single Email to a Single Recipient](#singleemailsinglerecipient) -* [Send a Single Email to Multiple Recipients](#singleemailmultiplerecipients) -* [Send Multiple Emails to Multiple Recipients](#multipleemailsmultiplerecipients) -* [CC, BCC and Reply To](#ccbccreplyto) -* [Handling Success/Failure/Errors](#successfailureerrors) +* [Send a Single Email to a Single Recipient](#single-email-single-recipient) +* [Send a Single Email to Multiple Recipients](#single-email-multiple-recipients) +* [Send Multiple Emails to Multiple Recipients](#multiple-emails-multiple-recipients) +* [CC, BCC and Reply To](#cc-bcc-reply-to) +* [Handling Success/Failure/Errors](#success-failure-errors) * [Advanced Usage](#advanced) - * [Transactional Templates](#transactional_templates) + * [Transactional Templates](#transactional-templates) * [Attachments](#attachments) * [Customization Per Recipient](#customization) - * [Manually Providing Content](#manualcontent) - * [Specifying Time to Send At](#timetosend) - * [Specifying Custom Headers](#customheaders) + * [Manually Providing Content](#manual-content) + * [Specifying Time to Send At](#time-to-send) + * [Specifying Custom Headers](#custom-headers) * [Specifying Categories](#categories) - * [Kitchen Sink - an example with all settings used](#kitchensink) -* [How to Setup a Domain Whitelabel](#domain_whitelabel) -* [How to View Email Statistics](#email_stats) + * [Kitchen Sink - an example with all settings used](#kitchen-sink) +* [How to Setup a Domain Whitelabel](#domain-white-label) +* [How to View Email Statistics](#email-stats) - + # Send a Single Email to a Single Recipient ```js @@ -35,7 +35,7 @@ const msg = { sgMail.send(msg); ``` - + # Send a Single Email to Multiple Recipients The `to` field can contain an array of recipients, which will send a single email with all of the recipients in the `to` field. The recipients will be able to see each other: @@ -70,7 +70,7 @@ sgMail.sendMultiple(msg); Note that `sendMultiple(msg)` is a convenience shortcut for `send(msg, true)`, and alternatively you can also set the `isMultiple` flag to `true` on your `msg` object. - + # Send Multiple Emails to Multiple Recipients The `send` method also accepts an array of email msg if you want to send multiple different single emails with for example different content and sender values. This will send multiple requests (in parallel), so be aware of any API rate restrictions: @@ -95,7 +95,7 @@ const emails = [ sgMail.send(emails); ``` - + # CC, BCC and Reply To You can specify the `cc`, `bcc` and `replyTo` fields for more control over who you send the email to and where people will reply to: @@ -143,7 +143,7 @@ const msg = { }; ``` - + # Handling Success/Failure/Errors The `send` and `sendMultiple` methods return a `Promise`, so you can handle success and capture errors: @@ -186,7 +186,7 @@ sgMail All other advanced settings are supported and can be passed in through the msg object according to the expected format as per the [API v3 documentation](https://sendgrid.com/docs/API_Reference/api_v3.html). Note that you can use either `camelCase` or `snake_case` for property names. - + ## Transactional Templates For this example, we assume you have created a [transactional template](https://sendgrid.com/docs/User_Guide/Transactional_Templates/index.html). Following is the template content we used for testing. @@ -323,7 +323,7 @@ const msg = { If the `substitutions` field is provided globally as well, these substitutions will be merged with any custom substitutions you provide in the `personalizations`. - + ## Manually Providing Content Instead of using the `text` and `html` shorthand properties, you can manually use the `content` property: @@ -346,7 +346,7 @@ const msg = { }; ``` - + ## Specifying Custom Headers Use the `headers` property to specify any custom headers (note that these can also be set globally per the [API specification](https://sendgrid.com/docs/API_Reference/api_v3.html): @@ -363,7 +363,7 @@ const msg = { }; ``` - + ## Specifying Time to Send At Use the `sendAt` property to specify when to send the emails (in [UNIX timestamp](https://en.wikipedia.org/wiki/Unix_time) seconds, not milliseconds): @@ -407,7 +407,7 @@ const msg = { }; ``` - + ## Kitchen Sink - an example with all settings used All other options from the [API definition](https://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/index.html) are supported (note that some settings can be used in multiple ways, see above for full details for each setting): @@ -459,14 +459,14 @@ sgMail .catch(error => console.error(error.toString())); ``` - + # How to Setup a Domain Whitelabel You can find documentation for how to setup a domain whitelabel via the UI [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/setup_domain_whitelabel.html) and via API [here](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/client/USAGE.md#whitelabel). Find more information about all of SendGrid's whitelabeling related documentation [here](https://sendgrid.com/docs/Classroom/Basics/Whitelabel/index.html). - + # How to View Email Statistics You can find documentation for how to view your email statistics via the UI [here](https://app.sendgrid.com/statistics) and via API [here](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/client/USAGE.md#stats). From fafb09600bd4b5ed96eacd70aa83fb6afb00ab58 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Fri, 20 Oct 2017 17:14:03 -0700 Subject: [PATCH 16/62] update hashtag in full links --- packages/mail/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mail/README.md b/packages/mail/README.md index 23d333890..a3633f366 100644 --- a/packages/mail/README.md +++ b/packages/mail/README.md @@ -88,9 +88,9 @@ If you are interested in the future direction of this project, please take a loo We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CONTRIBUTING.md) guide for details. -* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature_request) -* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit_a_bug_report) -* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements_to_the_codebase) +* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature-request) +* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit-a-bug-report) +* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements-to-the-codebase) # Troubleshooting From 4e2f1c1146b7b27c7d51d381a309e05d885b4da6 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Fri, 20 Oct 2017 17:31:08 -0700 Subject: [PATCH 17/62] more CONTRIBUTING.md links updates --- README.md | 6 +++--- packages/client/README.md | 6 +++--- packages/contact-importer/README.md | 6 +++--- packages/helpers/README.md | 6 +++--- packages/inbound-mail-parser/README.md | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 3d1bc544f..0a35f755e 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,9 @@ If you are interested in the future direction of this project, please take a loo We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CONTRIBUTING.md) guide for details. -* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature_request) -* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit_a_bug_report) -* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements_to_the_codebase) +* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature-request) +* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit-a-bug-report) +* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements-to-the-codebase) # Troubleshooting diff --git a/packages/client/README.md b/packages/client/README.md index 88470748e..d04e4583e 100644 --- a/packages/client/README.md +++ b/packages/client/README.md @@ -97,9 +97,9 @@ If you are interested in the future direction of this project, please take a loo We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CONTRIBUTING.md) guide for details. -* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature_request) -* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit_a_bug_report) -* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements_to_the_codebase) +* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature-request) +* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit-a-bug-report) +* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements-to-the-codebase) # Troubleshooting diff --git a/packages/contact-importer/README.md b/packages/contact-importer/README.md index a10768340..5d4f468c6 100644 --- a/packages/contact-importer/README.md +++ b/packages/contact-importer/README.md @@ -13,9 +13,9 @@ To be notified when this package is updated, please subscribe to email [notifica We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CONTRIBUTING.md) guide for details. -* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature_request) -* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit_a_bug_report) -* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements_to_the_codebase) +* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature-request) +* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit-a-bug-report) +* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements-to-the-codebase) # Troubleshooting diff --git a/packages/helpers/README.md b/packages/helpers/README.md index 55a00d051..e60eda13a 100644 --- a/packages/helpers/README.md +++ b/packages/helpers/README.md @@ -32,9 +32,9 @@ Internal helpers that mostly speak for themselves. We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CONTRIBUTING.md) guide for details. -* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature_request) -* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit_a_bug_report) -* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements_to_the_codebase) +* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature-request) +* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit-a-bug-report) +* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements-to-the-codebase) # About diff --git a/packages/inbound-mail-parser/README.md b/packages/inbound-mail-parser/README.md index 264270354..54135a189 100644 --- a/packages/inbound-mail-parser/README.md +++ b/packages/inbound-mail-parser/README.md @@ -37,9 +37,9 @@ yarn add @sendgrid/inbound-mail-parser We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CONTRIBUTING.md) guide for details. -* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature_request) -* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit_a_bug_report) -* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements_to_the_codebase) +* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature-request) +* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit-a-bug-report) +* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements-to-the-codebase) # Troubleshooting From f0aff0ca05337980a875fd2d607fc148b7af1594 Mon Sep 17 00:00:00 2001 From: ChatPion Date: Sat, 21 Oct 2017 23:30:28 +0200 Subject: [PATCH 18/62] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04a875835..6028cc68a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -141,7 +141,7 @@ Please run your code through: # Clone your fork of the repo into the current directory git clone https://github.com/sendgrid/sendgrid-nodejs # Navigate to the newly cloned directory - cd sendgrid-python + cd sendgrid-nodejs # Assign the original repo to a remote called "upstream" git remote add upstream https://github.com/sendgrid/sendgrid-nodejs ``` From b6ddd40567ca5e171831e31de91892307238ba86 Mon Sep 17 00:00:00 2001 From: Brandon Smith Date: Sat, 21 Oct 2017 18:11:36 -0400 Subject: [PATCH 19/62] Spelling corrections in CHANGELOG.md and client\USAGE.md --- CHANGELOG.md | 4 ++-- packages/client/USAGE.md | 46 ++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb3eea3cb..fa3fac636 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. ## [6.1.4] - 2017-09-11 ## ### Updated -- [Pull #445](https://github.com/sendgrid/sendgrid-nodejs/pull/445): Documenation Updates for better DX/UX +- [Pull #445](https://github.com/sendgrid/sendgrid-nodejs/pull/445): Documentation Updates for better DX/UX - Updates to README, TROUBLESHOOTING and USE_CASE documents to improve the developer experience. ## [6.1.3] - 2017-09-11 ## @@ -208,7 +208,7 @@ That is, in both cases, error.response is present ### Added - Extracted some logic into helpers - Using a getEmptyRequest helper to avoid code duplication -- emtpyRequest now accepts an object with data to extend the empty request with, this will allow simpler syntax for initializing requests. +- emptyRequest now accepts an object with data to extend the empty request with, this will allow simpler syntax for initializing requests. - Callback function now receives two parameters as per Node conventions (error, response) - If no callback provided, the method will return a promise instead. - Implemented promise API when not passing a callback function diff --git a/packages/client/USAGE.md b/packages/client/USAGE.md index 75b4147c5..51ad86294 100644 --- a/packages/client/USAGE.md +++ b/packages/client/USAGE.md @@ -176,7 +176,7 @@ For more information, please see our [User Guide](http://sendgrid.com/docs/User_ ``` ## Retrieve a specific whitelisted IP -**This endpoint allows you to retreive a specific IP address that has been whitelisted.** +**This endpoint allows you to retrieve a specific IP address that has been whitelisted.** You must include the ID for the specific IP address you want to retrieve in your call. @@ -230,7 +230,7 @@ For more information about alerts, please see our [User Guide](https://sendgrid. ``` ## Retrieve all alerts -**This endpoint allows you to retieve all of your alerts.** +**This endpoint allows you to retrieve all of your alerts.** Alerts allow you to specify an email address to receive notifications regarding your email usage or statistics. * Usage alerts allow you to set the threshold at which an alert will be sent. @@ -444,7 +444,7 @@ The API Keys feature allows customers to be able to generate an API Key credenti **This endpoint allows you to revoke an existing API Key** -Authentications using this API Key will fail after this request is made, with some small propogation delay.If the API Key ID does not exist an HTTP 404 will be returned. +Authentications using this API Key will fail after this request is made, with some small propagation delay.If the API Key ID does not exist an HTTP 404 will be returned. The API Keys feature allows customers to be able to generate an API Key credential which can be used for authentication with the SendGrid v3 Web API or the [Mail API Endpoint](https://sendgrid.com/docs/API_Reference/Web_API/mail.html). @@ -525,7 +525,7 @@ This endpoint will return information for each group ID that you include in your Suppressions are a list of email addresses that will not receive content sent under a given [group](https://sendgrid.com/docs/API_Reference/Web_API_v3/Suppression_Management/groups.html). -Suppression groups, or [unsubscribe groups](https://sendgrid.com/docs/API_Reference/Web_API_v3/Suppression_Management/groups.html), allow you to label a category of content that you regularly send. This gives your recipients the ability to opt out of a specific set of your email. For example, you might define a group for your transactional email, and one for your marketing email so that your users can continue recieving your transactional email witout having to receive your marketing content. +Suppression groups, or [unsubscribe groups](https://sendgrid.com/docs/API_Reference/Web_API_v3/Suppression_Management/groups.html), allow you to label a category of content that you regularly send. This gives your recipients the ability to opt out of a specific set of your email. For example, you might define a group for your transactional email, and one for your marketing email so that your users can continue receiving your transactional email without having to receive your marketing content. ### GET /asm/groups @@ -777,9 +777,9 @@ A global suppression (or global unsubscribe) is an email address of a recipient ``` ## Retrieve a Global Suppression -**This endpoint allows you to retrieve a global suppression. You can also use this endpoint to confirm if an email address is already globally suppresed.** +**This endpoint allows you to retrieve a global suppression. You can also use this endpoint to confirm if an email address is already globally suppressed.** -If the email address you include in the URL path parameter `{email}` is alreayd globally suppressed, the response will include that email address. If the address you enter for `{email}` is not globally suppressed, an empty JSON object `{}` will be returned. +If the email address you include in the URL path parameter `{email}` is already globally suppressed, the response will include that email address. If the address you enter for `{email}` is not globally suppressed, an empty JSON object `{}` will be returned. A global suppression (or global unsubscribe) is an email address of a recipient who does not want to receive any of your messages. A globally suppressed recipient will be removed from any email you send. For more information, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Suppressions/global_unsubscribes.html). @@ -1883,7 +1883,7 @@ Valid operators for create and update depend on the type of the field you are se Segment conditions using "eq" or "ne" for email clicks and opens should provide a "field" of either *clicks.campaign_identifier* or *opens.campaign_identifier*. The condition value should be a string containing the id of a completed campaign. -Segments may contain multiple condtions, joined by an "and" or "or" in the "and_or" field. The first condition in the conditions list must have an empty "and_or", and subsequent conditions must all specify an "and_or". +Segments may contain multiple conditions, joined by an "and" or "or" in the "and_or" field. The first condition in the conditions list must have an empty "and_or", and subsequent conditions must all specify an "and_or". The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. @@ -2254,7 +2254,7 @@ If an IP pool is NOT specified for an email, it will use any IP available, inclu ``` ## Retrieve all IP pools. -**This endpoint allows you to retreive all of your IP pools.** +**This endpoint allows you to retrieve all of your IP pools.** IP Pools allow you to group your dedicated SendGrid IP addresses together. For example, you could create separate pools for your transactional and marketing email. When sending marketing emails, specify that you want to use the marketing IP pool. This allows you to maintain separate reputations for your different email traffic. @@ -3168,7 +3168,7 @@ By integrating with New Relic, you can send your SendGrid email statistics to yo **This endpoint returns a list of all scopes that this user has access to.** -API Keys can be used to authenticate the use of [SendGrids v3 Web API](https://sendgrid.com/docs/API_Reference/Web_API_v3/index.html), or the [Mail API Endpoint](https://sendgrid.com/docs/API_Reference/Web_API/mail.html). API Keys may be assigned certain permissions, or scopes, that limit which API endpoints they are able to access. For a more detailed explanation of how you can use API Key permissios, please visit our [User Guide](https://sendgrid.com/docs/User_Guide/Settings/api_keys.html#-API-Key-Permissions) or [Classroom](https://sendgrid.com/docs/Classroom/Basics/API/api_key_permissions.html). +API Keys can be used to authenticate the use of [SendGrids v3 Web API](https://sendgrid.com/docs/API_Reference/Web_API_v3/index.html), or the [Mail API Endpoint](https://sendgrid.com/docs/API_Reference/Web_API/mail.html). API Keys may be assigned certain permissions, or scopes, that limit which API endpoints they are able to access. For a more detailed explanation of how you can use API Key permissions, please visit our [User Guide](https://sendgrid.com/docs/User_Guide/Settings/api_keys.html#-API-Key-Permissions) or [Classroom](https://sendgrid.com/docs/Classroom/Basics/API/api_key_permissions.html). ### GET /scopes @@ -3326,7 +3326,7 @@ Sender Identities are required to be verified before use. If your domain has bee ``` ## Delete a Sender Identity -**This endoint allows you to delete one of your sender identities.** +**This endpoint allows you to delete one of your sender identities.** Sender Identities are required to be verified before use. If your domain has been whitelabeled it will auto verify on creation. Otherwise an email will be sent to the `from.email`. @@ -3384,7 +3384,7 @@ Partial updates are allowed, but fields that are marked as "required" in the POS ``` ## Resend Sender Identity Verification -**This enpdoint allows you to resend a sender identity verification email.** +**This endpoint allows you to resend a sender identity verification email.** Sender Identities are required to be verified before use. If your domain has been whitelabeled it will auto verify on creation. Otherwise an email will be sent to the `from.email`. @@ -3759,7 +3759,7 @@ Subuser monitor settings allow you to receive a sample of an outgoing message by ``` ## Retrieve the monthly email statistics for a single subuser -**This endpoint allows you to retrive the monthly email statistics for a specific subuser.** +**This endpoint allows you to retrieve the monthly email statistics for a specific subuser.** While you can always view the statistics for all email activity on your account, subuser statistics enable you to view specific segments of your stats for your subusers. Emails sent, bounces, and spam reports are always tracked for subusers. Unsubscribes, clicks, and opens are tracked if you have enabled the required settings. @@ -4945,7 +4945,7 @@ For more information about your user profile: **This endpoint allows you to retrieve the current credit balance for your account.** -Your monthly credit allotment limits the number of emails you may send before incurring overage charges. For more information about credits and billing, please visit our [Clssroom](https://sendgrid.com/docs/Classroom/Basics/Billing/billing_info_and_faqs.html). +Your monthly credit allotment limits the number of emails you may send before incurring overage charges. For more information about credits and billing, please visit our [Classroom](https://sendgrid.com/docs/Classroom/Basics/Billing/billing_info_and_faqs.html). ### GET /user/credits @@ -5394,7 +5394,7 @@ The inbound parse webhook allows you to have incoming emails parsed, extracting **This endpoint allows you to retrieve all of your current inbound parse settings.** -The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the contnet, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). +The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the content, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). ### GET /user/webhooks/parse/settings @@ -5412,7 +5412,7 @@ The inbound parse webhook allows you to have incoming emails parsed, extracting **This endpoint allows you to delete a specific inbound parse setting.** -The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the contnet, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). +The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the content, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). ### DELETE /user/webhooks/parse/settings/{hostname} @@ -5432,7 +5432,7 @@ The inbound parse webhook allows you to have incoming emails parsed, extracting **This endpoint allows you to update a specific inbound parse setting.** -The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the contnet, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). +The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the content, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). ### PATCH /user/webhooks/parse/settings/{hostname} @@ -5456,7 +5456,7 @@ The inbound parse webhook allows you to have incoming emails parsed, extracting **This endpoint allows you to retrieve a specific inbound parse setting.** -The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the contnet, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). +The inbound parse webhook allows you to have incoming emails parsed, extracting some or all of the content, and then have that content POSTed by SendGrid to a URL of your choosing. For more information, please see our [User Guide](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). ### GET /user/webhooks/parse/settings/{hostname} @@ -5472,9 +5472,9 @@ The inbound parse webhook allows you to have incoming emails parsed, extracting ``` ## Retrieves Inbound Parse Webhook statistics. -**This endpoint allows you to retrieve the statistics for your Parse Webhook useage.** +**This endpoint allows you to retrieve the statistics for your Parse Webhook usage.** -SendGrid's Inbound Parse Webhook allows you to parse the contents and attachments of incomming emails. The Parse API can then POST the parsed emails to a URL that you specify. The Inbound Parse Webhook cannot parse messages greater than 20MB in size, including all attachments. +SendGrid's Inbound Parse Webhook allows you to parse the contents and attachments of incoming emails. The Parse API can then POST the parsed emails to a URL that you specify. The Inbound Parse Webhook cannot parse messages greater than 20MB in size, including all attachments. There are a number of pre-made integrations for the SendGrid Parse Webhook which make processing events easy. You can find these integrations in the [Library Index](https://sendgrid.com/docs/Integrate/libraries.html#-Webhook-Libraries). @@ -5859,7 +5859,7 @@ For more information, please see our [User Guide](https://sendgrid.com/docs/API_ ``` ## Retrieve all IP whitelabels -**This endpoint allows you to retrieve all of the IP whitelabels that have been createdy by this account.** +**This endpoint allows you to retrieve all of the IP whitelabels that have been created by this account.** You may include a search key by using the "ip" parameter. This enables you to perform a prefix search for a given IP segment (e.g. "192."). @@ -6040,7 +6040,7 @@ For more information, please see our [User Guide](https://sendgrid.com/docs/API_ **This endpoint allows you to disassociate a link whitelabel from a subuser.** Link whitelables can be associated with subusers from the parent account. This functionality allows -subusers to send mail using their parent's linke whitelabels. To associate a link whitelabel, the parent account +subusers to send mail using their parent's link whitelabels. To associate a link whitelabel, the parent account must first create a whitelabel and validate it. The parent may then associate that whitelabel with a subuser via the API or the Subuser Management page in the user interface. Email link whitelabels allow all of the click-tracked links you send in your emails to include the URL of your domain instead of sendgrid.net. @@ -6070,7 +6070,7 @@ For more information, please see our [User Guide](https://sendgrid.com/docs/API_ **This endpoint allows you to retrieve the associated link whitelabel for a subuser.** Link whitelables can be associated with subusers from the parent account. This functionality allows -subusers to send mail using their parent's linke whitelabels. To associate a link whitelabel, the parent account +subusers to send mail using their parent's link whitelabels. To associate a link whitelabel, the parent account must first create a whitelabel and validate it. The parent may then associate that whitelabel with a subuser via the API or the Subuser Management page in the user interface. Email link whitelabels allow all of the click-tracked links you send in your emails to include the URL of your domain instead of sendgrid.net. @@ -6186,7 +6186,7 @@ For more information, please see our [User Guide](https://sendgrid.com/docs/API_ **This endpoint allows you to associate a link whitelabel with a subuser account.** Link whitelables can be associated with subusers from the parent account. This functionality allows -subusers to send mail using their parent's linke whitelabels. To associate a link whitelabel, the parent account +subusers to send mail using their parent's link whitelabels. To associate a link whitelabel, the parent account must first create a whitelabel and validate it. The parent may then associate that whitelabel with a subuser via the API or the Subuser Management page in the user interface. Email link whitelabels allow all of the click-tracked links you send in your emails to include the URL of your domain instead of sendgrid.net. From 21531b1bcdca584769859bb14f032660253fb458 Mon Sep 17 00:00:00 2001 From: heroprotagonist Date: Sat, 21 Oct 2017 19:43:03 -0400 Subject: [PATCH 20/62] Fix markdown link --- packages/client/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/README.md b/packages/client/README.md index d04e4583e..e02a68625 100644 --- a/packages/client/README.md +++ b/packages/client/README.md @@ -14,7 +14,7 @@ To be notified when this package is updated, please subscribe to email [notifica ## Prerequisites - Node.js version 6, 7 or 8 -- A SendGrid account, [sign up for free](https://sendgrid.com/free?source=sendgrid-nodejs to send up to 40,000 emails for the first 30 days or check out [our pricing](https://sendgrid.com/pricing?source=sendgrid-nodejs). +- A SendGrid account, [sign up for free](https://sendgrid.com/free?source=sendgrid-nodejs) to send up to 40,000 emails for the first 30 days or check out [our pricing](https://sendgrid.com/pricing?source=sendgrid-nodejs). ## Obtain an API Key From 04cd1fb75f420a12dc77cde6e0fd96e358970b84 Mon Sep 17 00:00:00 2001 From: Rakshan Shetty Date: Sun, 22 Oct 2017 10:30:26 +0530 Subject: [PATCH 21/62] Added Badges on Redme --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a35f755e..e1ad7ea7c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![npm version](https://badge.fury.io/js/%40sendgrid%2Fclient.svg)](https://www.npmjs.com/org/sendgrid) [![Email Notifications Badge](https://dx.sendgrid.com/badge/nodejs)](https://dx.sendgrid.com/newsletter/nodejs) [![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/sendgrid-nodejs.svg)](https://github.com/sendgrid/sendgrid-nodejs/graphs/contributors) +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.txt) **This library allows you to quickly and easily use the SendGrid Web API v3 via Node.js.** @@ -21,6 +22,7 @@ We appreciate your continued support, thank you! * [How to Contribute](#contribute) * [Troubleshooting](#troubleshooting) * [About](#about) +* [License](#license) # Introduction - Please Read First @@ -48,9 +50,9 @@ If you are interested in the future direction of this project, please take a loo We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CONTRIBUTING.md) guide for details. -* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature-request) -* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit-a-bug-report) -* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements-to-the-codebase) +* [Feature Request](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#feature_request) +* [Bug Reports](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#submit_a_bug_report) +* [Improvements to the Codebase](https://github.com/sendgrid/sendgrid-nodejs/tree/master/CONTRIBUTING.md#improvements_to_the_codebase) # Troubleshooting @@ -65,3 +67,7 @@ sendgrid-nodejs is guided and supported by the SendGrid [Developer Experience Te sendgrid-nodejs is maintained and funded by SendGrid, Inc. The names and logos for sendgrid-nodejs are trademarks of SendGrid, Inc. ![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) + + +# License +[The MIT License (MIT)](LICENSE.txt) From 340bca124a863c3975956532ce77625e627775c8 Mon Sep 17 00:00:00 2001 From: thepriefy Date: Mon, 23 Oct 2017 17:27:53 +0700 Subject: [PATCH 22/62] update README.md - remove duplicate SendGrid logo - add license link --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 95c50b69c..34c5574e7 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,6 @@ sendgrid-nodejs is guided and supported by the SendGrid [Developer Experience Te sendgrid-nodejs is maintained and funded by SendGrid, Inc. The names and logos for sendgrid-nodejs are trademarks of SendGrid, Inc. -![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) - + # License -[The MIT License (MIT)](LICENSE.txt) \ No newline at end of file +[The MIT License (MIT)](LICENSE.txt) From fa97235d70b048b2439f9dd160aec95515c4dc8f Mon Sep 17 00:00:00 2001 From: Michael Poschacher Date: Mon, 23 Oct 2017 15:04:33 +0200 Subject: [PATCH 23/62] exclude headers from camel/snake case conversion fixes #527 added null check for setSubstitutionWrappers --- packages/helpers/classes/mail.js | 4 +- packages/helpers/classes/mail.spec.js | 43 +++++++++++++++++++ packages/helpers/classes/personalization.js | 7 +-- .../helpers/classes/personalization.spec.js | 16 +++++++ 4 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 packages/helpers/classes/mail.spec.js diff --git a/packages/helpers/classes/mail.js b/packages/helpers/classes/mail.js index 22c105055..97f7ed059 100644 --- a/packages/helpers/classes/mail.js +++ b/packages/helpers/classes/mail.js @@ -55,7 +55,7 @@ class Mail { //Convert to camel case to make it workable, making a copy to prevent //changes to the original objects data = deepClone(data); - data = toCamelCase(data, ['substitutions', 'customArgs']); + data = toCamelCase(data, ['substitutions', 'customArgs', 'headers']); //Extract properties from data const { @@ -539,7 +539,7 @@ class Mail { } //Return as snake cased object - return toSnakeCase(json, ['substitutions', 'customArgs']); + return toSnakeCase(json, ['substitutions', 'customArgs', 'headers']); } /************************************************************************** diff --git a/packages/helpers/classes/mail.spec.js b/packages/helpers/classes/mail.spec.js new file mode 100644 index 000000000..3ac3d710b --- /dev/null +++ b/packages/helpers/classes/mail.spec.js @@ -0,0 +1,43 @@ +'use strict'; + +/** + * Dependencies + */ +const Mail = require('./mail'); + +/** + * Tests + */ +describe('Mail', function() { + + describe('#527', function() { + it('shouldn\'t convert the headers to camel/snake case', function() { + const mail = new Mail({ + personalizations: [{ + to: 'test@example.com', + headers: { + 'test-header': 'test', + }, + }], + from: { + email: 'test@example.com', + }, + subject: 'test', + content: [{ + type: 'text/plain', + value: 'test', + }], + category: 'test', + headers: { + 'List-Unsubscribe': '', + }, + }); + + expect(mail.headers['List-Unsubscribe']).to + .equal(''); + + expect(mail.toJSON().headers['List-Unsubscribe']).to + .equal(''); + }); + }); +}); diff --git a/packages/helpers/classes/personalization.js b/packages/helpers/classes/personalization.js index 3e1a76c79..004036a0a 100644 --- a/packages/helpers/classes/personalization.js +++ b/packages/helpers/classes/personalization.js @@ -47,7 +47,7 @@ class Personalization { //Convert to camel case to make it workable, making a copy to prevent //changes to the original objects data = deepClone(data); - data = toCamelCase(data, ['substitutions', 'customArgs']); + data = toCamelCase(data, ['substitutions', 'customArgs', 'headers']); //Extract properties from data const { @@ -259,9 +259,10 @@ class Personalization { * Set substitution wrappers */ setSubstitutionWrappers(wrappers) { - if (typeof wrappers === 'undefined') { + if (typeof wrappers === 'undefined' || wrappers === null) { return; } + if (!Array.isArray(wrappers) || wrappers.length !== 2) { throw new Error( 'Array expected with two elements for `substitutionWrappers`' @@ -313,7 +314,7 @@ class Personalization { } //Return as snake cased object - return toSnakeCase(json, ['substitutions', 'customArgs']); + return toSnakeCase(json, ['substitutions', 'customArgs', 'headers']); } } diff --git a/packages/helpers/classes/personalization.spec.js b/packages/helpers/classes/personalization.spec.js index 42a34286d..a61cccc22 100644 --- a/packages/helpers/classes/personalization.spec.js +++ b/packages/helpers/classes/personalization.spec.js @@ -676,4 +676,20 @@ describe('Personalization', function() { expect(p.customArgs.snake_case).to.equal('Test'); }); }); + + describe('#527', function() { + it('shouldn\'t convert the headers to camel/snake case', function() { + const p = new Personalization({ + to: 'test@example.com', + headers: { + 'List-Unsubscribe': '', + }, + }); + + expect(p.headers['List-Unsubscribe']).to.equal(''); + + expect(p.toJSON().headers['List-Unsubscribe']).to + .equal(''); + }); + }); }); From 867161b166a4384db4ea013726536665594a9a97 Mon Sep 17 00:00:00 2001 From: pushkyn Date: Mon, 23 Oct 2017 20:21:57 +0300 Subject: [PATCH 24/62] update contributing.md - fix typo --- CONTRIBUTING.md | 2 +- README.md | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04a875835..6028cc68a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -141,7 +141,7 @@ Please run your code through: # Clone your fork of the repo into the current directory git clone https://github.com/sendgrid/sendgrid-nodejs # Navigate to the newly cloned directory - cd sendgrid-python + cd sendgrid-nodejs # Assign the original repo to a remote called "upstream" git remote add upstream https://github.com/sendgrid/sendgrid-nodejs ``` diff --git a/README.md b/README.md index 95c50b69c..e8d3259fd 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,6 @@ sendgrid-nodejs is guided and supported by the SendGrid [Developer Experience Te sendgrid-nodejs is maintained and funded by SendGrid, Inc. The names and logos for sendgrid-nodejs are trademarks of SendGrid, Inc. -![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) - + # License [The MIT License (MIT)](LICENSE.txt) \ No newline at end of file From ba400cd53b05a8b97486927a0543a3bbeb50b739 Mon Sep 17 00:00:00 2001 From: Ajitesh Rai Date: Mon, 23 Oct 2017 23:25:47 +0530 Subject: [PATCH 25/62] Fix typo Removed duplicate 'the'. --- packages/client/USAGE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/USAGE.md b/packages/client/USAGE.md index 51ad86294..2a92d6806 100644 --- a/packages/client/USAGE.md +++ b/packages/client/USAGE.md @@ -5597,7 +5597,7 @@ For more information on whitelabeling, please see our [User Guide](https://sendg A domain whitelabel allows you to remove the via or sent on behalf of message that your recipients see when they read your emails. Whitelabeling a domain allows you to replace sendgrid.net with your personal sending domain. You will be required to create a subdomain so that SendGrid can generate the DNS records which you must give to your host provider. If you choose to use Automated Security, SendGrid will provide you with 3 CNAME records. If you turn Automated Security off, you will be given 2 TXT records and 1 MX record. -Domain whitelabels can be associated with (i.e. assigned to) subusers from a parent account. This functionality allows subusers to send mail using their parent's whitelabels. To associate a whitelabel with a subuser, the parent account must first create the whitelabel and validate it. The the parent may then associate the whitelabel via the subuser management tools. +Domain whitelabels can be associated with (i.e. assigned to) subusers from a parent account. This functionality allows subusers to send mail using their parent's whitelabels. To associate a whitelabel with a subuser, the parent account must first create the whitelabel and validate it. The parent may then associate the whitelabel via the subuser management tools. For more information on whitelabeling, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Settings/Whitelabel/index.html) @@ -5626,7 +5626,7 @@ For more information on whitelabeling, please see our [User Guide](https://sendg A domain whitelabel allows you to remove the via or sent on behalf of message that your recipients see when they read your emails. Whitelabeling a domain allows you to replace sendgrid.net with your personal sending domain. You will be required to create a subdomain so that SendGrid can generate the DNS records which you must give to your host provider. If you choose to use Automated Security, SendGrid will provide you with 3 CNAME records. If you turn Automated Security off, you will be given 2 TXT records and 1 MX record. -Domain whitelabels can be associated with (i.e. assigned to) subusers from a parent account. This functionality allows subusers to send mail using their parent's whitelabels. To associate a whitelabel with a subuser, the parent account must first create the whitelabel and validate it. The the parent may then associate the whitelabel via the subuser management tools. +Domain whitelabels can be associated with (i.e. assigned to) subusers from a parent account. This functionality allows subusers to send mail using their parent's whitelabels. To associate a whitelabel with a subuser, the parent account must first create the whitelabel and validate it. The parent may then associate the whitelabel via the subuser management tools. For more information on whitelabeling, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Settings/Whitelabel/index.html) @@ -5720,7 +5720,7 @@ For more information on whitelabeling, please see our [User Guide](https://sendg A domain whitelabel allows you to remove the via or sent on behalf of message that your recipients see when they read your emails. Whitelabeling a domain allows you to replace sendgrid.net with your personal sending domain. You will be required to create a subdomain so that SendGrid can generate the DNS records which you must give to your host provider. If you choose to use Automated Security, SendGrid will provide you with 3 CNAME records. If you turn Automated Security off, you will be given 2 TXT records and 1 MX record. -Domain whitelabels can be associated with (i.e. assigned to) subusers from a parent account. This functionality allows subusers to send mail using their parent's whitelabels. To associate a whitelabel with a subuser, the parent account must first create the whitelabel and validate it. The the parent may then associate the whitelabel via the subuser management tools. +Domain whitelabels can be associated with (i.e. assigned to) subusers from a parent account. This functionality allows subusers to send mail using their parent's whitelabels. To associate a whitelabel with a subuser, the parent account must first create the whitelabel and validate it. The parent may then associate the whitelabel via the subuser management tools. For more information on whitelabeling, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Settings/Whitelabel/index.html) From eff846a74e5984465c0313102b1fab2fe645cdeb Mon Sep 17 00:00:00 2001 From: itaditya Date: Tue, 24 Oct 2017 13:07:41 +0530 Subject: [PATCH 26/62] object destructring & fat arrow --- packages/inbound-mail-parser/src/parser.js | 27 +++++++++++----------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/inbound-mail-parser/src/parser.js b/packages/inbound-mail-parser/src/parser.js index fc1d23f24..3b14a7653 100644 --- a/packages/inbound-mail-parser/src/parser.js +++ b/packages/inbound-mail-parser/src/parser.js @@ -1,7 +1,7 @@ 'use strict'; const fs = require('fs'); -const MailParser = require('mailparser').MailParser; +const { MailParser } = require('mailparser'); const { classes: { Attachment, @@ -14,12 +14,12 @@ const { * @param {Object} file The file object returned by file system or parsed email * @return {Object} A SendGrid Attachment object with the file data */ -function createAttachment(file) { +function createAttachment({originalname, fileName, mimetype, contentType, content}) { const attachment = new Attachment(); - attachment.setFilename(file.originalname || file.fileName); - attachment.setType(file.mimetype || file.contentType); - attachment.setContent(file.content.toString('base64')); + attachment.setFilename(originalname || fileName); + attachment.setType(mimetype || contentType); + attachment.setContent(content.toString('base64')); return attachment; } @@ -31,8 +31,8 @@ function createAttachment(file) { * @param {Object} config inbound configuration object * @param {Object} request request object of the parse webhook payload */ -function Parse(config, request) { - this.keys = config.keys; +function Parse({ keys }, request) { + this.keys = keys; this.request = request; this.payload = request.body || {}; this.files = request.files || []; @@ -71,7 +71,7 @@ Parse.prototype.hasRawEmail = function() { */ Parse.prototype.getRawEmail = function(callback) { const mailparser = new MailParser(); - const rawEmail = this.payload.email; + const { email:rawEmail } = this.payload; if (!rawEmail) { return callback(null); @@ -101,14 +101,12 @@ Parse.prototype.attachments = function(callback) { * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument */ Parse.prototype._getAttachmentsRaw = function(callback) { - this.getRawEmail(function(parsedEmail) { + this.getRawEmail(parsedEmail => { if (!parsedEmail || !parsedEmail.attachments) { return callback([]); } - const attachments = parsedEmail.attachments.map(function(file) { - return createAttachment(file); - }); + const attachments = parsedEmail.attachments.map(file => createAttachment(file)); callback(attachments); }); @@ -125,9 +123,10 @@ Parse.prototype._getAttachments = function(callback) { for (const index in this.files) { file = this.files[index]; + const { path } = file; - if (fs.existsSync(file.path)) { - file.content = fs.readFileSync(file.path); + if (fs.existsSync(path)) { + file.content = fs.readFileSync(path); attachments.push(createAttachment(file)); } } From 14bd54422c156c444e638034faf149966bb6d927 Mon Sep 17 00:00:00 2001 From: devchas Date: Tue, 24 Oct 2017 16:43:02 -0400 Subject: [PATCH 27/62] Add subscription widget to packages --- packages/subscription-widget/.gitignore | 1 + packages/subscription-widget/LICENSE.txt | 21 ++ packages/subscription-widget/Procfile | 1 + packages/subscription-widget/README.md | 128 +++++++++ packages/subscription-widget/app.json | 6 + packages/subscription-widget/index.js | 18 ++ packages/subscription-widget/package.json | 23 ++ .../controllers/contact_list_controller.js | 250 ++++++++++++++++++ packages/subscription-widget/server/router.js | 9 + .../server/static/check-inbox.html | 1 + .../server/static/error.html | 1 + .../server/static/index.html | 63 +++++ .../server/static/sample-form.png | Bin 0 -> 29927 bytes .../server/static/success.html | 1 + .../server/static/template.png | Bin 0 -> 73207 bytes packages/subscription-widget/settings.js | 17 ++ 16 files changed, 540 insertions(+) create mode 100644 packages/subscription-widget/.gitignore create mode 100644 packages/subscription-widget/LICENSE.txt create mode 100644 packages/subscription-widget/Procfile create mode 100644 packages/subscription-widget/README.md create mode 100644 packages/subscription-widget/app.json create mode 100644 packages/subscription-widget/index.js create mode 100644 packages/subscription-widget/package.json create mode 100644 packages/subscription-widget/server/controllers/contact_list_controller.js create mode 100644 packages/subscription-widget/server/router.js create mode 100644 packages/subscription-widget/server/static/check-inbox.html create mode 100644 packages/subscription-widget/server/static/error.html create mode 100644 packages/subscription-widget/server/static/index.html create mode 100644 packages/subscription-widget/server/static/sample-form.png create mode 100644 packages/subscription-widget/server/static/success.html create mode 100644 packages/subscription-widget/server/static/template.png create mode 100644 packages/subscription-widget/settings.js diff --git a/packages/subscription-widget/.gitignore b/packages/subscription-widget/.gitignore new file mode 100644 index 000000000..30bc16279 --- /dev/null +++ b/packages/subscription-widget/.gitignore @@ -0,0 +1 @@ +/node_modules \ No newline at end of file diff --git a/packages/subscription-widget/LICENSE.txt b/packages/subscription-widget/LICENSE.txt new file mode 100644 index 000000000..f7f6d4784 --- /dev/null +++ b/packages/subscription-widget/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 SendGrid, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/subscription-widget/Procfile b/packages/subscription-widget/Procfile new file mode 100644 index 000000000..5ec9cc2c5 --- /dev/null +++ b/packages/subscription-widget/Procfile @@ -0,0 +1 @@ +web: node index.js \ No newline at end of file diff --git a/packages/subscription-widget/README.md b/packages/subscription-widget/README.md new file mode 100644 index 000000000..7da406e62 --- /dev/null +++ b/packages/subscription-widget/README.md @@ -0,0 +1,128 @@ +# Email Subscription Widget with Double Opt-In + +Note: This is not an officially supported SendGrid library + +This is an open source repository to add a flexible email subscription widget, like the one shown below, to any website using [SendGrid](https://sendgrid.com/). After following these directions, you'll be able to add a snippet of HTML to any website that will collect email addresses for your app or business. This widget utilizes [double opt-in](https://sendgrid.com/docs/Glossary/opt_in_email.html) functionality, which means users must confirm their email addresses by clicking an email that is automatically sent to their provided email address. + +![alt text](https://github.com/devchas/sendgrid_subscription_widget/blob/master/server/static/sample-form.png "Sample Form") + +## Requirements + +Before following these instructions, you must: +* Have a SendGrid account - [sign up here](https://sendgrid.com/pricing/) +* Sign up for a [free Heroku account](https://signup.heroku.com/) + +## Instructions + +### Initial SendGrid Set-up - Create API Key & Contact List +To begin, you will first need to create an API key on SendGrid's website. Once logged in, go to Settings -> API Keys, and click the blue button in the top right corner of the website. You will be creating a General API key, which must have *Full Access* to *Mail Send* and *Marketing Campaigns*. Keep this API key in a *safe* and *private* location. You will need it later. + +### Fork this Repository to Create Your Own Copy +If you are unfamiliar with Github, simply click the button that reads *Fork* in the top right of this page. Doing this will provide you with your own copy. You'll need to change a few basic settings in your copy. + +### Deploy to Heroku + +**Make sure you Fork this repository before clicking the Deploy to Heroku button below** + +Click the button below to deploy this app to the Heroku account you created earlier. Once complete, locate the URL of your app. You will need this for the following step. + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) + +Once the app is deployed, you may want to connect your forked Github repository to your Heroku app for easy deployment. You can do this by navigating to the *Deploy* tab within your app on Heroku and following the instructions. + +### Update Your App Settings in Your Forked Repository on Github +Navigate to settings.js in your forked copy of the repository and change each of the four variables to the appropriate values. You can find your app's URL by opening your app or navigating to the *Activity* tab in Heroku and scrolling to the middle of the page to the domains section. See the example below. + +```javascript +exports.url = 'https://your_heroku_app_name.herokuapp.com'; +exports.senderEmail = "sender@example.com"; +exports.senderName = "Sender Name"; + +// set 'exports.listId = null' to add contact to all contacts, but no specific list +exports.listID = 651138; + +// set 'exports.templateId = null' to opt out of using a template +exports.templateId = "dbc810ec-b776-4345-b0c7-02e2bbcd2ab4" +``` + +#### Add Contact to a Custom Marketing List (Optional) +By default, the widget is configured to save a new contact to your master list of ALL CONTACTS. However, you may choose to save new contacts to a specified custom list as well. To do so, you must first create a new contact list by navigating to Marketing Campaigns -> Contacts, and then click the blue button in the top right corner of the page. Once the list is created, you will require the list ID. You can find this number by navigating to the list and looking at the URL. The list ID will be the numbers following the last forward slash. For example, the list ID of a list with URL of https://sendgrid.com/marketing_campaigns/lists/651138 would be 651138. Once you have created a new list, change the value of exports.listId to the ID of that marketing list. This value is null by default. + +#### Use a Transactional Template (Optional) +You may also send your confirmation email using [transactional email templates](https://sendgrid.com/solutions/transactional-email-templates/) to give your email a more professional look and feel. To do so, you must first create a template by following the steps provided in [this guide](https://sendgrid.com/docs/User_Guide/Transactional_Templates/index.html). Once you have created a custom transacitonal email template, change the value of the exports.templateId to the ID of the template you created. If you choose to use templates, **you must include a substitution tag named "link_insert"**. This will be substituted with the link that signs up a user in the double opt-in process. (Example template below) + +![alt text](https://github.com/devchas/sendgrid_subscription_widget/blob/master/server/static/template.png "Transactional Email Template") + +#### Edit the Form with Your Custom URL +Navigate to the index.html file (server -> static -> index.html) and change the action in the form to reflect your app's URL. Remember to leave "/confirmEmail" at the end. The text in this file is what you will be embedding in your website. See below for an example. + +```html +
+
+ Enter Your Information + +
+ +
+ +
+ +
+
+``` + +*Remember to always re-deploy your app after making any changes.* + +### Add API Key as Environmental Variable on Heroku +Next, configure your API key as an environmental variable, which can be done either through Heroku's user interface or the Heroku CLI as shown in [these directions](https://devcenter.heroku.com/articles/config-vars). Updating the environment variable in your Heroku account can be done by logging into your heroku account, navigating to your newly deployed app, and clicking settings. Inside the settings page you will see an option to "Reveal Config Vars". You must name your variable holding your API key *SG_API_KEY*. + +### Enable Event Webhook +The final step is to enable the event webhook on your SendGrid account. This will allow the opt-in component of the signup to function properly. In order to set up an event webhook, navigate to Settings -> Mail Settings, and then click on *Event Notification*. + +Make sure the toggle in the top left of that section is set to *ON*. Click edit. Enter the root URL of your Heroku app + '/signup'. The following is an example URL: https://your_heroku_app_name.herokuapp.com/signup. + +For the types of events to receive, make sure to select only *Clicked*. Then, click the blue check box in the top right corner of the section to save changes. + + +### Test Your Widget +In order to easily test that your subscription widget is working properly, you may navigate to the root URL of your Heroku app and enter an email that you have access to. If everything is working, you should receive an email with a link to confirm your subscription. Upon clicking this link, the email should be added to the SendGrid contact list you created earlier. + +## Usage and Customization + +### Usage + +In order to use this widget, once you've followed the setup steps above, drop all of text from the index.html file you altered earlier into any website. + +### Customization + +You may change the look and feel of the form or create a new one. The form will continue to work so long as the action is what you specified earlier, the method is post, and there is an input element with name *email*. The default widget comes with three fields: 1) email, 2) first name, 3) last name. You may remove first and/or last name if you so choose. In addition, you may change the form's styling by adjusting the CSS contained in index.html. + +#### Adding New Fields +You may also add [custom fields](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/custom_fields.html) to the form to save other information about your users during the sign up process. To do so, simply add an additional input field with the name(s) of your custom field(s). If you add a custom field to your form that does not already exist in your SendGrid account, one will automatically be created with the name specified in the form. The example below shows a form with the custom field "favorite_color". + +```html +
+
+ Enter Your Information + +
+ +
+ +
+ +
+ +
+
+``` + +You may also change the look of the check-inbox.html and success.html files, both of which are located in the static folder with index.html. These are the pages that users will be directed to upon entering their email and cliking the confirmation link, respectively. + +Finally, you may change the content of the confirmation email by changing the *mailText* variable in the contact_list_controller.js file, which is located in the controllers folder. However, be sure to keep the link intact. If you choose to use a transactional email template, the mail text will be produced by the template, and you may ignore this step. + +```javascript +mailText = "Thanks for signing up! Click this link \ + to sign up! This link will be active for 24 hours." +``` + diff --git a/packages/subscription-widget/app.json b/packages/subscription-widget/app.json new file mode 100644 index 000000000..4b46149da --- /dev/null +++ b/packages/subscription-widget/app.json @@ -0,0 +1,6 @@ +{ + "name": "Email Double Opt-In", + "description": "Double opt-in email automation", + "repository": "https://github.com/devchas/sendgrid_subscription_widget", + "keywords": ["email", "SendGrid"] +} \ No newline at end of file diff --git a/packages/subscription-widget/index.js b/packages/subscription-widget/index.js new file mode 100644 index 000000000..f92d3da0b --- /dev/null +++ b/packages/subscription-widget/index.js @@ -0,0 +1,18 @@ +const express = require('express'); +const http = require('http'); +const bodyParser = require('body-parser'); +const morgan = require('morgan'); +const app = express(); +const router = require('./server/router'); + +// App setup +app.use(morgan('combined')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); +router(app); + +// Server setup +const port = process.env.PORT || 3090; +const server = http.createServer(app); +server.listen(port); +console.log('Server listening on:', port); \ No newline at end of file diff --git a/packages/subscription-widget/package.json b/packages/subscription-widget/package.json new file mode 100644 index 000000000..5defb865d --- /dev/null +++ b/packages/subscription-widget/package.json @@ -0,0 +1,23 @@ +{ + "name": "signup", + "version": "1.0.0", + "description": "Double opt-in email automation", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "nodemon index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "body-parser": "^1.15.2", + "express": "^4.14.0", + "morgan": "^1.7.0", + "nodemon": "^1.9.2", + "sendgrid": "^4.0.2", + "sendgrid-rest": "^2.2.1" + }, + "engines": { + "node": "4.1.1" + } +} diff --git a/packages/subscription-widget/server/controllers/contact_list_controller.js b/packages/subscription-widget/server/controllers/contact_list_controller.js new file mode 100644 index 000000000..dd6a187f8 --- /dev/null +++ b/packages/subscription-widget/server/controllers/contact_list_controller.js @@ -0,0 +1,250 @@ +const sg = require('sendgrid')(process.env.SG_API_KEY); +sg.globalRequest.headers['User-Agent'] = 'subscription-widget/1.0.0'; + +const path = require('path'); +const Settings = require('../../settings'); +const optIn = 'opt-in'; + +function prepareConfirmationEmail(reqBody) { + const subject = "Please Confirm Your Email Address"; + const url = formatUrl(Settings.url) + '/success'; + const link = "this link" + const mailText = "Thanks for signing up! Click " + link + " to sign up! This link will be active for 24 hours."; + + var emailBody = { + personalizations: [ + { + to: [ + { + email: reqBody.email, + } + ], + subject: subject, + custom_args: { + type: optIn, + time_sent: String(Date.now()), + }, + substitutions: { + link_insert: link + } + }, + ], + from: { + email: Settings.senderEmail, + name: Settings.senderName, + }, + content: [ + { + type: "text/html", + value: mailText, + } + ] + } + + const templateId = Settings.templateId; + if (templateId) emailBody.template_id = templateId; + + for (key in reqBody) { + emailBody.personalizations[0].custom_args[key] = reqBody[key]; + } + + return emailBody; +} + +function prepareNotificationEmail(reqBody) { + const subject = "New email signup"; + const mailText = "A new person just confirmed they would look to receive your emails via your email subscription widget.
Name: " + reqBody.first_name + " " + reqBody.last_name + "
Email: " + reqBody.email; + + var emailBody = { + personalizations: [ + { + to: [ + { + email: Settings.notificationEmail, + } + ], + subject: subject + }, + ], + from: { + email: Settings.senderEmail, + name: Settings.senderName, + }, + content: [ + { + type: "text/html", + value: mailText, + } + ], + } + + return emailBody; +} + +// Send confirmation email to contact with link to confirm email +exports.sendConfirmation = (req, res, next) => { + var request = sg.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: prepareConfirmationEmail(req.body) + }); + + sg.API(request, function(error, response) { + if (error) { + console.log('Error response received'); + } + + if (response.statusCode >= 200 && response.statusCode < 300) { + res.sendFile(path.join(__dirname, '../static/check-inbox.html')); + } else { + res.sendFile(path.join(__dirname, '../static/error.html')); + } + }); +} + +// Create new contact and add contact to given list +exports.addUser = function(req, res, next) { + addUserToList(req.body[0], function() { + //send notification about the new signup + if (Settings.sendNotification) { + console.log("Sending notification"); + + var request = sg.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: prepareNotificationEmail(req.body[0]) + }); + + sg.API(request, function(error, response) { + if (error) { + console.log('Error sending notification'); + } + }); + } + + res.sendStatus(200); + }); +} + +function addUserToList(emailBody, callback) { + console.log(emailBody); + + var ignoreFields = ['ip', 'sg_event_id', 'sg_message_id', 'useragent', 'event', + 'url_offset', 'time_sent', 'timestamp', 'url', 'type', 'smtp-id']; + + var customFields = [{}]; + var customFieldArr = []; + + for (key in emailBody) { + if (!stringInArray(key, ignoreFields)) { + customFields[0][key] = emailBody[key]; + if (key != 'email' && key != 'first_name' && key != 'last_name') { + customFieldArr.push(key); + } + } + } + + checkAndAddCustomFields(customFieldArr, function() { + const emailType = emailBody.type; + const timestamp = parseInt(emailBody.time_sent); + const listId = Settings.listId; + const secondsInDay = 86400; + const timeElapsed = (Date.now() - timestamp) / 1000; + + // Confirm email type is opt in and link has been clicked within 1 day + if (emailType == optIn && timeElapsed < secondsInDay) { + var request = sg.emptyRequest({ + method: 'POST', + path: '/v3/contactdb/recipients', + body: customFields + }); + + sg.API(request, function(error, response) { + if (listId) { + var contactID = JSON.parse(response.body.toString()).persisted_recipients[0]; + var request = sg.emptyRequest({ + method: 'POST', + path: '/v3/contactdb/lists/' + listId + '/recipients/' + contactID, + body: customFields + }); + sg.API(request, function(error, response) { + console.log(response.statusCode) + console.log(response.body) + console.log(response.headers) + + callback(); + }); + } else { + callback(); + } + }); + } else { + callback(); + } + }); + +} + +function checkAndAddCustomFields(submittedFields, callback) { + var request = sg.emptyRequest({ + method: 'GET', + path: '/v3/contactdb/custom_fields', + }); + + sg.API(request, function(error, response) { + console.log(response.statusCode) + console.log(response.body) + console.log(response.headers) + + var existingCustomFields = JSON.parse(response.body); + var fieldsToCreate = []; + + submittedFields.map((submittedField) => { + var fieldExists = false; + existingCustomFields.custom_fields.map((field) => { + if (submittedField == field.name) { + fieldExists = true; + } + }); + if (!fieldExists) { + fieldsToCreate.push(submittedField) + } + }); + + if (fieldsToCreate.length == 0) { + callback(); + } else { + fieldsToCreate.map((fieldsToCreate) => { + var body = { name: fieldsToCreate, type: 'text' }; + + var request = sg.emptyRequest({ + method: 'POST', + path: '/v3/contactdb/custom_fields', + body: body + }); + + sg.API(request, function(error, response) { + callback(); + }); + }); + } + + }); +} + +function formatUrl(url) { + if (url.substr(-1) == '/') { + return url.substring(0, url.length - 1); + } + return url; +} + +function stringInArray(string, array) { + var isInArray = false; + array.map((item) => { + if (string == item) { + isInArray = true; + } + }); + return isInArray; +} diff --git a/packages/subscription-widget/server/router.js b/packages/subscription-widget/server/router.js new file mode 100644 index 000000000..a654e4af0 --- /dev/null +++ b/packages/subscription-widget/server/router.js @@ -0,0 +1,9 @@ +const path = require('path'); +const ContactList = require('./controllers/contact_list_controller'); + +module.exports = function(app) { + app.get('/', function(req, res) { res.sendFile(path.join(__dirname, '/static/index.html')) }); + app.get('/success', function(req, res) { res.sendFile(path.join(__dirname, '/static/success.html')) }); + app.post('/confirmEmail', ContactList.sendConfirmation); + app.post('/signup', ContactList.addUser); +} \ No newline at end of file diff --git a/packages/subscription-widget/server/static/check-inbox.html b/packages/subscription-widget/server/static/check-inbox.html new file mode 100644 index 000000000..010d97eb8 --- /dev/null +++ b/packages/subscription-widget/server/static/check-inbox.html @@ -0,0 +1 @@ +

Please check your inbox for an email containing a link to verify your email address.

\ No newline at end of file diff --git a/packages/subscription-widget/server/static/error.html b/packages/subscription-widget/server/static/error.html new file mode 100644 index 000000000..fe486a9d5 --- /dev/null +++ b/packages/subscription-widget/server/static/error.html @@ -0,0 +1 @@ +

Looks like something went wrong. Please try again. Please be sure to enter a valid email address.

\ No newline at end of file diff --git a/packages/subscription-widget/server/static/index.html b/packages/subscription-widget/server/static/index.html new file mode 100644 index 000000000..866700a0a --- /dev/null +++ b/packages/subscription-widget/server/static/index.html @@ -0,0 +1,63 @@ +
+
+ Enter Your Information + + +
+ + +
+ + +
+ + +
+
+ + + \ No newline at end of file diff --git a/packages/subscription-widget/server/static/sample-form.png b/packages/subscription-widget/server/static/sample-form.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf25c7f691a4887eca9acd45df1e97709fedb56 GIT binary patch literal 29927 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 literal 0 HcmV?d00001 diff --git a/packages/subscription-widget/server/static/success.html b/packages/subscription-widget/server/static/success.html new file mode 100644 index 000000000..bb51bfd17 --- /dev/null +++ b/packages/subscription-widget/server/static/success.html @@ -0,0 +1 @@ +

Thank you for confirming your email address. You've been added to our mailing list.

\ No newline at end of file diff --git a/packages/subscription-widget/server/static/template.png b/packages/subscription-widget/server/static/template.png new file mode 100644 index 0000000000000000000000000000000000000000..a39105430b00ce73b9728c5cfc3f39847f4b18b7 GIT binary patch literal 73207 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

IJ$KDmE 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�R5;+5UkK;QS&-&@D2W0^eN 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 Date: Wed, 25 Oct 2017 07:30:34 +0700 Subject: [PATCH 28/62] Update README.md remove duplicate MIT License badge (and seem like it doesn't link to any page) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 34c5574e7..615df8bf5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [![BuildStatus](https://travis-ci.org/sendgrid/sendgrid-nodejs.svg?branch=master)](https://travis-ci.org/sendgrid/sendgrid-nodejs) [![npm version](https://badge.fury.io/js/%40sendgrid%2Fclient.svg)](https://www.npmjs.com/org/sendgrid) [![Email Notifications Badge](https://dx.sendgrid.com/badge/nodejs)](https://dx.sendgrid.com/newsletter/nodejs) -[![npm](https://img.shields.io/npm/l/express.svg)]() [![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid) [![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/sendgrid-nodejs.svg)](https://github.com/sendgrid/sendgrid-nodejs/graphs/contributors) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.txt) From 8b91269b63179768cc7f37e0d760d65b1cfe6f0e Mon Sep 17 00:00:00 2001 From: Seth Etter Date: Wed, 25 Oct 2017 11:06:32 -0500 Subject: [PATCH 29/62] Turn ContactImporter into ES6 class Also add `sendgrid` as a dependency so the test will run and pass. Resolves #532 --- packages/contact-importer/package.json | 3 +- packages/contact-importer/src/importer.js | 266 +++++++++--------- .../contact-importer/src/importer.spec.js | 5 +- 3 files changed, 139 insertions(+), 135 deletions(-) diff --git a/packages/contact-importer/package.json b/packages/contact-importer/package.json index a2b71d63e..53b6a8448 100644 --- a/packages/contact-importer/package.json +++ b/packages/contact-importer/package.json @@ -30,7 +30,8 @@ "async.queue": "^0.5.2", "bottleneck": "^1.12.0", "debug": "^2.2.0", - "lodash.chunk": "^4.2.0" + "lodash.chunk": "^4.2.0", + "sendgrid": "^5.2.3" }, "tags": [ "sendgrid" diff --git a/packages/contact-importer/src/importer.js b/packages/contact-importer/src/importer.js index a03d78c54..36a5e8ebb 100644 --- a/packages/contact-importer/src/importer.js +++ b/packages/contact-importer/src/importer.js @@ -2,145 +2,147 @@ 'use strict'; const Bottleneck = require('bottleneck'); -const EventEmitter = require('events').EventEmitter; +const { EventEmitter } = require('events'); const chunk = require('lodash.chunk'); const debug = require('debug')('sendgrid'); const util = require('util'); const queue = require('async.queue'); const ensureAsync = require('async.ensureasync'); -const ContactImporter = module.exports = function(sg, options) { - options = options || {}; - const self = this; - this.sg = sg; - this.pendingItems = []; - - // Number of items to send per batch. - this.batchSize = options.batchSize || 1500; - - // Max number of requests per rate limit period. - this.rateLimitLimit = options.rateLimitLimit || 3; - - // Length of rate limit period (miliseconds). - this.rateLimitPeriod = options.rateLimitPeriod || 2000; - - // Create a throttler that will process no more than `rateLimitLimit` requests every `rateLimitPeriod` ms. - this.throttle = new Bottleneck(0, 0); - this.throttle.changeReservoir(this.rateLimitLimit); - - // Create a queue that wil be used to send batches to the throttler. - this.queue = queue(ensureAsync(this._worker)); - - // When the last batch is removed from the queue, add any incomplete batches. - this.queue.empty = function() { - if (self.pendingItems.length) { - debug('adding %s items from deferrd queue for processing', self.pendingItems.length); - const batch = self.pendingItems.splice(0); - self.queue.push({ - data: batch, - owner: self, - }, function(error, result) { - if (error) { - return self._notify(error, JSON.parse(error.response.body), batch); - } - return self._notify(null, JSON.parse(result.body), batch); +class ContactImporter extends EventEmitter { + constructor(sg, options = {}) { + super(); + + this.sg = sg; + this.pendingItems = []; + + // Number of items to send per batch. + this.batchSize = options.batchSize || 1500; + + // Max number of requests per rate limit period. + this.rateLimitLimit = options.rateLimitLimit || 3; + + // Length of rate limit period (miliseconds). + this.rateLimitPeriod = options.rateLimitPeriod || 2000; + + // Create a throttler that will process no more than `rateLimitLimit` requests every `rateLimitPeriod` ms. + this.throttle = new Bottleneck(0, 0); + this.throttle.changeReservoir(this.rateLimitLimit); + + // Create a queue that wil be used to send batches to the throttler. + this.queue = queue(ensureAsync(this._worker)); + + // When the last batch is removed from the queue, add any incomplete batches. + this.queue.empty = () => { + if (this.pendingItems.length) { + debug('adding %s items from deferrd queue for processing', this.pendingItems.length); + const batch = this.pendingItems.splice(0); + this.queue.push({ + data: batch, + owner: this, + }, (error, result) => { + if (error) { + return this._notify(error, error.response.body, batch); + } + return this._notify(null, result.body, batch); + }); + } + }; + + // Emit an event when the queue is drained. + this.queue.drain = () => { + this.emit('drain'); + }; + } + + /** + * Add a new contact, or an array of contacts, to the end of the queue. + * + * @param {Array|Object} data A contact or array of contacts. + */ + push(data) { + data = Array.isArray(data) ? data : [data]; + + // Add the new items onto the pending items. + const itemsToProcess = this.pendingItems.concat(data); + + // Chunk the pending items into batches and add onto the queue + const batches = chunk(itemsToProcess, this.batchSize); + debug('generated batches %s from %s items', batches.length, data.length); + + batches.forEach((batch) => { + // If this batch is full or the queue is empty queue it for processing. + if (batch.length === this.batchSize || !this.queue.length()) { + this.queue.push({ + data: batch, + owner: this, + }, (error, result) => { + if (error) { + return this._notify(error, error.response.body, batch); + } + return this._notify(null, result.body, batch); + }); + } + // Otherwise, it store it for later. + else { + debug('the last batch with only %s item is deferred (partial batch)', batch.length); + this.pendingItems = batch; + } + }); + + debug('batches in queue: %s', this.queue.length()); + debug('items in deferred queue: %s', this.pendingItems.length); + } + + /** + * Send a batch of contacts to Sendgrid. + * + * @param {Object} task Task to be processed (data in 'data' property) + * @param {Function} callback Callback function. + */ + _worker (task, callback) { + const context = task.owner; + debug('processing batch (%s items)', task.data.length); + context.throttle.submit(context._sendBatch, context, task.data, callback); + } + + _sendBatch (context, data, callback) { + debug('sending batch (%s items)', data.length); + + const request = context.sg.emptyRequest(); + request.method = 'POST'; + request.path = '/v3/contactdb/recipients'; + request.body = data; + + context.sg.API(request) + .then((response) => { + debug('got response: %o', response); + setTimeout(() => { + context.throttle.incrementReservoir(1); + }, context.rateLimitPeriod); + return callback(null, response); + }) + .catch((error) => { + debug('got error, %o', error); + setTimeout(() => { + context.throttle.incrementReservoir(1); + }, context.rateLimitPeriod); + return callback(error); }); + } + + /** + * Emit the result of processing a batch. + * + * @param {Object} error + * @param {Object} result + */ + _notify (error, result, batch) { + if (error) { + return this.emit('error', error, batch); } + return this.emit('success', result, batch); }; +} - // Emit an event when the queue is drained. - this.queue.drain = function() { - self.emit('drain'); - }; -}; -util.inherits(ContactImporter, EventEmitter); - -/** - * Add a new contact, or an array of contact, to the end of the queue. - * - * @param {Array|Object} data A contact or array of contacts. - */ -ContactImporter.prototype.push = function(data) { - const self = this; - data = Array.isArray(data) ? data : [data]; - - // Add the new items onto the pending items. - const itemsToProcess = this.pendingItems.concat(data); - - // Chunk the pending items into batches and add onto the queue - const batches = chunk(itemsToProcess, this.batchSize); - debug('generated batches %s from %s items', batches.length, data.length); - - batches.forEach(function(batch) { - // If this batch is full or the queue is empty queue it for processing. - if (batch.length === self.batchSize || !self.queue.length()) { - self.queue.push({ - data: batch, - owner: self, - }, function(error, result) { - if (error) { - return self._notify(error, JSON.parse(error.response.body), batch); - } - return self._notify(null, JSON.parse(result.body), batch); - }); - } - // Otherwise, it store it for later. - else { - debug('the last batch with only %s item is deferred (partial batch)', batch.length); - self.pendingItems = batch; - } - }); - - debug('batches in queue: %s', this.queue.length()); - debug('items in deferred queue: %s', this.pendingItems.length); -}; - -/** - * Send a batch of contacts to Sendgrid. - * - * @param {Object} task Task to be processed (data in 'data' property) - * @param {Function} callback Callback function. - */ -ContactImporter.prototype._worker = function(task, callback) { - const context = task.owner; - debug('processing batch (%s items)', task.data.length); - context.throttle.submit(context._sendBatch, context, task.data, callback); -}; - -ContactImporter.prototype._sendBatch = function(context, data, callback) { - debug('sending batch (%s items)', data.length); - - const request = context.sg.emptyRequest(); - request.method = 'POST'; - request.path = '/v3/contactdb/recipients'; - request.body = data; - - context.sg.API(request) - .then(function(response) { - debug('got response: %o', response); - setTimeout(function() { - context.throttle.incrementReservoir(1); - }, context.rateLimitPeriod); - return callback(null, response); - }) - .catch(function(error) { - debug('got error, %o', error); - setTimeout(function() { - context.throttle.incrementReservoir(1); - }, context.rateLimitPeriod); - return callback(error); - }); -}; - -/** - * Emit the result of processing a batch. - * - * @param {Object} error - * @param {Object} result - */ -ContactImporter.prototype._notify = function(error, result, batch) { - if (error) { - return this.emit('error', error, batch); - } - return this.emit('success', result, batch); -}; +module.exports = ContactImporter; diff --git a/packages/contact-importer/src/importer.spec.js b/packages/contact-importer/src/importer.spec.js index 2c885f8bd..0923a5be3 100644 --- a/packages/contact-importer/src/importer.spec.js +++ b/packages/contact-importer/src/importer.spec.js @@ -1,3 +1,4 @@ +const sendgrid = require('sendgrid'); const ContactImporter = require('./importer'); describe.only('test_contact_importer', function() { @@ -38,8 +39,8 @@ describe.only('test_contact_importer', function() { console.log('SUCCESS batch', batch); }); this.contactImporter.on('error', function(error, batch) { - console.log('SUCCESS error', error); - console.log('SUCCESS batch', batch); + console.log('ERROR error', error); + console.log('ERROR batch', batch); }); this.contactImporter.on('drain', function() { expect(self.contactImporter._sendBatch).to.have.callCount(3); From 0dd66e4fc54e76e61921a60472b4895a1e1cfe2d Mon Sep 17 00:00:00 2001 From: Rafael Nunes Verger Date: Thu, 26 Oct 2017 18:22:25 -0300 Subject: [PATCH 30/62] Add command shortcut to test inbound-mail-parser pkg --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index f38ee8886..dc3ae57c3 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "test:helpers": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/helpers/**/*.spec.js\"", "test:client": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/client/**/*.spec.js\"", "test:mail": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/mail/**/*.spec.js\"", + "test:inbound": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/inbound-mail-parser/**/*.spec.js\"", "test:typescript": "tsc", "test": "npm run test:all -s", "coverage": "open -a \"Google Chrome\" ./coverage/lcov-report/index.html" From 7574abbd3accf0d0cdc0eb70414da45afc82444f Mon Sep 17 00:00:00 2001 From: Rafael Nunes Verger Date: Thu, 26 Oct 2017 18:22:38 -0300 Subject: [PATCH 31/62] Update package-lock --- package-lock.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package-lock.json b/package-lock.json index 237f54620..cbfd1dd5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5546,6 +5546,12 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz", + "integrity": "sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=", + "dev": true + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", From 7b583704c908e51562ced068f08a2283f1f2d068 Mon Sep 17 00:00:00 2001 From: Rafael Nunes Verger Date: Thu, 26 Oct 2017 18:23:07 -0300 Subject: [PATCH 32/62] Refactor InboundMailParser class using ES6. Closes #533 --- packages/inbound-mail-parser/src/parser.js | 169 ++++++++---------- .../inbound-mail-parser/src/parser.spec.js | 12 +- 2 files changed, 81 insertions(+), 100 deletions(-) diff --git a/packages/inbound-mail-parser/src/parser.js b/packages/inbound-mail-parser/src/parser.js index fc1d23f24..423f4b7d4 100644 --- a/packages/inbound-mail-parser/src/parser.js +++ b/packages/inbound-mail-parser/src/parser.js @@ -14,7 +14,7 @@ const { * @param {Object} file The file object returned by file system or parsed email * @return {Object} A SendGrid Attachment object with the file data */ -function createAttachment(file) { +const createAttachment = (file) => { const attachment = new Attachment(); attachment.setFilename(file.originalname || file.fileName); @@ -27,112 +27,93 @@ function createAttachment(file) { /** * Simple class that parses data received from SendGrid Inbound Parse Webhook * - * @constructor - * @param {Object} config inbound configuration object - * @param {Object} request request object of the parse webhook payload */ -function Parse(config, request) { - this.keys = config.keys; - this.request = request; - this.payload = request.body || {}; - this.files = request.files || []; -} - -/** - * Return an object literal of key/values in the payload received from webhook - * @return {Object} Valid key/values in the webhook payload - */ -Parse.prototype.keyValues = function() { - const keyValues = {}; - let key; - - for (const index in this.keys) { - key = this.keys[index]; - - if (this.payload[key]) { - keyValues[key] = this.payload[key]; - } +class Parse { + + /** + * @constructor + * @param {Object} config inbound configuration object + * @param {Object} request request object of the parse webhook payload + */ + constructor(config, request) { + this.keys = config.keys; + this.request = request; + this.payload = request.body || {}; + this.files = request.files || []; } - return keyValues; -}; - -/** - * Whether the payload contains the raw email (Only applies to raw payloads) - * @return {Boolean} - */ -Parse.prototype.hasRawEmail = function() { - return Boolean(this.payload.email); -}; - -/** - * Parses the raw email and returns the mail object in a callback (Only applies to raw payloads) - * @param {Function} callback Function which will receive the parsed email object as the sole argument - */ -Parse.prototype.getRawEmail = function(callback) { - const mailparser = new MailParser(); - const rawEmail = this.payload.email; - - if (!rawEmail) { - return callback(null); + /** + * Return an object literal of key/values in the payload received from webhook + * @return {Object} Valid key/values in the webhook payload + */ + keyValues() { + return this.keys + .filter(key => this.payload[key]) + .map(key => ({ [key]: this.payload[key] })) + .reduce((keyValues, keyPayload) => Object.assign(keyValues, keyPayload)); } - mailparser.on('end', callback); - - mailparser.write(rawEmail); - mailparser.end(); -}; - -/** - * Retrieves all attachments received from the webhook payload - * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument - */ -Parse.prototype.attachments = function(callback) { - if (this.hasRawEmail()) { - return this._getAttachmentsRaw(callback); + /** + * Whether the payload contains the raw email (Only applies to raw payloads) + * @return {Boolean} + */ + hasRawEmail() { + return !!this.payload.email; } - this._getAttachments(callback); -}; + /** + * Parses the raw email and returns the mail object in a callback (Only applies to raw payloads) + * @param {Function} callback Function which will receive the parsed email object as the sole argument + */ + getRawEmail(callback) { + const mailparser = new MailParser(); + const { rawEmail } = this.payload; -/** - * Parses raw email to retrieve any encoded attachments (Only applies to raw payloads) - * @private - * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument - */ -Parse.prototype._getAttachmentsRaw = function(callback) { - this.getRawEmail(function(parsedEmail) { - if (!parsedEmail || !parsedEmail.attachments) { - return callback([]); + if (!this.hasRawEmail()) { + return callback(null); } - const attachments = parsedEmail.attachments.map(function(file) { - return createAttachment(file); - }); - - callback(attachments); - }); -}; - -/** - * Retrieves webhook payload files from the file system (Only applies to non raw payloads) - * @private - * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument - */ -Parse.prototype._getAttachments = function(callback) { - let file; - const attachments = []; + mailparser.on('end', callback); + mailparser.write(rawEmail); + mailparser.end(); + } - for (const index in this.files) { - file = this.files[index]; + /** + * Retrieves all attachments received from the webhook payload + * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument + */ + attachments(callback) { + return this[`_getAttachments${this.hasRawEmail() ? 'Raw' : ''}`](callback); + } - if (fs.existsSync(file.path)) { - file.content = fs.readFileSync(file.path); - attachments.push(createAttachment(file)); - } + /** + * Parses raw email to retrieve any encoded attachments (Only applies to raw payloads) + * @private + * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument + */ + _getAttachmentsRaw(callback) { + this.getRawEmail(parsedEmail => { + const attachments = (parsedEmail || {}).attachments || []; + callback(attachments.map(createAttachment)); + }); } - return callback(attachments); -}; + /** + * Retrieves webhook payload files from the file system (Only applies to non raw payloads) + * @private + * @param {Function} callback Function which will receive an array, of attachments found, as the sole argument + */ + _getAttachments(callback) { + return callback(this.files + .filter(file => fs.existsSync(file.path)) + .map((exists, idx) => [exists, this.files[idx]]) + .filter(([exists, _]) => exists) + .map(([_, file]) => { + file.content = fs.readFileSync(file.path); + return createAttachment(file); + }) + ); + } +} module.exports = Parse; diff --git a/packages/inbound-mail-parser/src/parser.spec.js b/packages/inbound-mail-parser/src/parser.spec.js index 5b3cd0bb7..293d41080 100644 --- a/packages/inbound-mail-parser/src/parser.spec.js +++ b/packages/inbound-mail-parser/src/parser.spec.js @@ -1,8 +1,8 @@ const Parse = require('./parser'); -describe('test_parse', function() { - describe('test_parse_key_values', function() { - it('should return the key values specified in the config from the payload', function() { +describe('test_parse', () => { + describe('test_parse_key_values', () => { + it('should return the key values specified in the config from the payload', () => { const config = { keys: ['to', 'from'], }; @@ -26,8 +26,8 @@ describe('test_parse', function() { }); }); - describe('test_parse_get_raw_email', function() { - it('should return null if no raw email property in payload', function(done) { + describe('test_parse_get_raw_email', () => { + it('should return null if no raw email property in payload', (done) => { const parse = new Parse({}, {}); function callback(email) { @@ -38,7 +38,7 @@ describe('test_parse', function() { parse.getRawEmail(callback); }); - it('should parse raw email from payload and return a mail object', function(done) { + it('should parse raw email from payload and return a mail object', (done) => { const request = { body: { email: 'MIME-Version: 1.0\r\nReceived: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 14:44:21 -0700 (PDT)\r\nFrom: Example User \r\nDate: Wed, 10 Aug 2016 14:44:21 -0700\r\nSubject: Inbound Parse Test Raw Data\r\nTo: inbound@inbound.inbound.com\r\nContent-Type: multipart/alternative; boundary=001a113ee97c89842f0539be8e7a\r\n\r\n--001a113ee97c89842f0539be8e7a\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\nHello SendGrid!\r\n\r\n--001a113ee97c89842f0539be8e7a\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nHello SendGrid!\r\n\r\n--001a113ee97c89842f0539be8e7a--\r\n', From b46942dd465d0f9808ba24dc425bb4210a30755d Mon Sep 17 00:00:00 2001 From: Seth Etter Date: Thu, 26 Oct 2017 16:59:26 -0500 Subject: [PATCH 33/62] Add test command for contact importer --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index f38ee8886..c8d1ee902 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "test:helpers": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/helpers/**/*.spec.js\"", "test:client": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/client/**/*.spec.js\"", "test:mail": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/mail/**/*.spec.js\"", + "test:contact": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/contact-importer/**/*.spec.js\"", "test:typescript": "tsc", "test": "npm run test:all -s", "coverage": "open -a \"Google Chrome\" ./coverage/lcov-report/index.html" From d6ecc4bef666ef80b082f7d1a61ead5fb5098d56 Mon Sep 17 00:00:00 2001 From: Seth Etter Date: Thu, 26 Oct 2017 18:40:12 -0500 Subject: [PATCH 34/62] A bit of refactoring on the ContactImporter --- packages/contact-importer/src/importer.js | 77 +++++++++++++---------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/packages/contact-importer/src/importer.js b/packages/contact-importer/src/importer.js index 36a5e8ebb..5266e1c4e 100644 --- a/packages/contact-importer/src/importer.js +++ b/packages/contact-importer/src/importer.js @@ -29,30 +29,7 @@ class ContactImporter extends EventEmitter { this.throttle = new Bottleneck(0, 0); this.throttle.changeReservoir(this.rateLimitLimit); - // Create a queue that wil be used to send batches to the throttler. - this.queue = queue(ensureAsync(this._worker)); - - // When the last batch is removed from the queue, add any incomplete batches. - this.queue.empty = () => { - if (this.pendingItems.length) { - debug('adding %s items from deferrd queue for processing', this.pendingItems.length); - const batch = this.pendingItems.splice(0); - this.queue.push({ - data: batch, - owner: this, - }, (error, result) => { - if (error) { - return this._notify(error, error.response.body, batch); - } - return this._notify(null, result.body, batch); - }); - } - }; - - // Emit an event when the queue is drained. - this.queue.drain = () => { - this.emit('drain'); - }; + this._setupQueue(); } /** @@ -60,7 +37,7 @@ class ContactImporter extends EventEmitter { * * @param {Array|Object} data A contact or array of contacts. */ - push(data) { + push(data = []) { data = Array.isArray(data) ? data : [data]; // Add the new items onto the pending items. @@ -73,15 +50,7 @@ class ContactImporter extends EventEmitter { batches.forEach((batch) => { // If this batch is full or the queue is empty queue it for processing. if (batch.length === this.batchSize || !this.queue.length()) { - this.queue.push({ - data: batch, - owner: this, - }, (error, result) => { - if (error) { - return this._notify(error, error.response.body, batch); - } - return this._notify(null, result.body, batch); - }); + this._pushToQueue(batch); } // Otherwise, it store it for later. else { @@ -143,6 +112,46 @@ class ContactImporter extends EventEmitter { } return this.emit('success', result, batch); }; + + /** + * Sets up the queue object on this instance of ContactImporter + */ + _setupQueue () { + // Create a queue that wil be used to send batches to the throttler. + this.queue = queue(ensureAsync(this._worker)); + + // When the last batch is removed from the queue, add any incomplete batches. + this.queue.empty = () => { + if (!this.pendingItems.length) return; + + debug('adding %s items from deferrd queue for processing', this.pendingItems.length); + + const batch = this.pendingItems.splice(0); + this._pushToQueue(batch); + }; + + // Emit an event when the queue is drained. + this.queue.drain = () => { + this.emit('drain'); + }; + } + + /** + * Takes a batch and pushes it to the queue, handling the result as well. + * + * @param {Array} batch A batch to send to the queue. + */ + _pushToQueue (batch) { + this.queue.push({ + data: batch, + owner: this, + }, (error, result) => { + if (error) { + return this._notify(error, error.response.body, batch); + } + return this._notify(null, result.body, batch); + }); + } } module.exports = ContactImporter; From ab9c51054bd82aa1376a4f9feb6f0f599faaed57 Mon Sep 17 00:00:00 2001 From: Shiva Kaushal Date: Thu, 26 Oct 2017 23:06:17 -0400 Subject: [PATCH 35/62] Create PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..bbb4b0033 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,37 @@ + + +**Description of the change**: + +**Reason for the change**: + +**Link to original source**: + +### Checklist + +Make sure all of these items are complete, or else the PR will be ineligible for a code review. + +- [ ] Code passes all existing [tests](https://github.com/sendgrid/open-source-library-data-collector/tree/master/test) +- [ ] Any new functionality added includes new unit tests in [`tests/test.py`](https://github.com/sendgrid/open-source-library-data-collector/blob/master/test/test.py) +- [ ] Create or update example code to show the new functionality in action. +- [ ] All code, branch, and git naming and style conventions are followed (see [`CONTRIBUTING.md`](https://github.com/sendgrid/open-source-library-data-collector/blob/master/CONTRIBUTING.md#style-guidelines--naming-conventions)) +- [ ] Feature branch has been rebased off of the latest `master` branch. ( see [`CONTRIBUTING.md`](https://github.com/sendgrid/open-source-library-data-collector/blob/master/CONTRIBUTING.md#creating-a-pull-request) ). + +If you have questions, please send an email [Sendgrid](mailto:dx@sendgrid.com), or file a Github Issue in this repository. + + From 81e98ac07bfc54a3c44d7e24af433cfc45df6d65 Mon Sep 17 00:00:00 2001 From: Shiva Kaushal Date: Thu, 26 Oct 2017 23:16:31 -0400 Subject: [PATCH 36/62] Create USAGE.md --- .github/USAGE.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/USAGE.md diff --git a/.github/USAGE.md b/.github/USAGE.md new file mode 100644 index 000000000..70cbcfb0e --- /dev/null +++ b/.github/USAGE.md @@ -0,0 +1,10 @@ +# Introduction + +This library is broken up into several packages as a monorepo so that you only need to install the packages necessary for your use case. +This USAGE.md contains information pertaining to all packages. For examples on how to get started quickly, head over to the READMEs of each individual package (linked and described below), which includes detailed examples. + +* [@sendgrid/mail](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/mail) - if you just want to send email +* [@sendgrid/client](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/client) - to use all other [SendGrid v3 Web API endpoints](https://sendgrid.com/docs/API_Reference/api_v3.html) +* [@sendgrid/inbound-mail-parser](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/inbound-mail-parser) - help with parsing the SendGrid Inbound Parse API +* [@sendgrid/contact-importer](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/contact-importer) - help with importing contacts into the ContactDB +* [@sendgrid/helpers](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/helpers) - a collection of classes and helpers used internally by the above packages From f8350f9361296a84399fa0206d14d3029f3cafae Mon Sep 17 00:00:00 2001 From: mbernier Date: Thu, 26 Oct 2017 21:39:22 -0600 Subject: [PATCH 37/62] adding esdoc support --- .esdoc.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .esdoc.json diff --git a/.esdoc.json b/.esdoc.json new file mode 100644 index 000000000..36b0371d6 --- /dev/null +++ b/.esdoc.json @@ -0,0 +1,13 @@ +{ + "source": "./packages", + "destination": "./docs", + "plugins": [ + { + "name": "esdoc-coverage-plugin", + "option": { + "enable": true, + "kind": ["class", "method", "member", "get", "set", "constructor", "function", "variable"] + } + } + ] + } \ No newline at end of file From 0cd89b9e142b163c1ef9711daf4ed882af9d7bd2 Mon Sep 17 00:00:00 2001 From: mbernier Date: Thu, 26 Oct 2017 21:43:14 -0600 Subject: [PATCH 38/62] updated json package for esdoc --- package.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f38ee8886..ca0150080 100644 --- a/package.json +++ b/package.json @@ -34,5 +34,22 @@ "test:typescript": "tsc", "test": "npm run test:all -s", "coverage": "open -a \"Google Chrome\" ./coverage/lcov-report/index.html" - } + }, + "description": "![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png)", + "bugs": { + "url": "https://github.com/sendgrid/sendgrid-nodejs/issues" + }, + "homepage": "https://github.com/sendgrid/sendgrid-nodejs#readme", + "main": "index.js", + "directories": { + "doc": "docs", + "test": "test" + }, + "dependencies": { + "chai": "^2.3.0", + "esdoc": "^1.0.3", + "esdoc-coverage-plugin": "^1.1.0", + "esdoc-type-inference-plugin": "^1.0.1" + }, + "author": "SendGrid" } From 73ba7acece98326694d1f0d209c77b9bafe9503e Mon Sep 17 00:00:00 2001 From: mbernier Date: Thu, 26 Oct 2017 21:50:13 -0600 Subject: [PATCH 39/62] added esdocs notes in CONTRIBUTING and USAGE --- .github/USAGE.md | 13 +++++++++++++ .gitignore | 1 + CONTRIBUTING.md | 1 + 3 files changed, 15 insertions(+) diff --git a/.github/USAGE.md b/.github/USAGE.md index 70cbcfb0e..b4e5cb335 100644 --- a/.github/USAGE.md +++ b/.github/USAGE.md @@ -8,3 +8,16 @@ This USAGE.md contains information pertaining to all packages. For examples on h * [@sendgrid/inbound-mail-parser](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/inbound-mail-parser) - help with parsing the SendGrid Inbound Parse API * [@sendgrid/contact-importer](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/contact-importer) - help with importing contacts into the ContactDB * [@sendgrid/helpers](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/helpers) - a collection of classes and helpers used internally by the above packages + + +# Documentation + +If you would like to auto-generate documentation of the packages, you can do so locally by running: +``` +./node_modules/.bin/esdoc +``` +Using the .esdoc.json file, esdoc will create documentation in the docs directory. + +## Checking docs coverage + +You will find a coverage.json file in the docs directory. This will contain information about the documentation coverage for each of the different files in this repo. \ No newline at end of file diff --git a/.gitignore b/.gitignore index cbdd97d02..b1baddc9b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ test/config.js *.log .vscode/ prism_darwin_amd64 +docs/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6028cc68a..90ed7cf94 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -131,6 +131,7 @@ Generally, we follow the style guidelines as suggested by the official language. Please run your code through: - [ESLint](http://eslint.org/) with the standard style guide. +- [esdoc](https://github.com/sendgrid/sendgrid-nodejs/blob/master/.github/USAGE.md) to check the documentation coverage of your added code. ## Creating a Pull Request From 6002c51d1956097df173c4e296559fe83cfbeb5d Mon Sep 17 00:00:00 2001 From: mbernier Date: Thu, 26 Oct 2017 21:50:44 -0600 Subject: [PATCH 40/62] moved USAGE to root dir --- .github/USAGE.md => USAGE.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/USAGE.md => USAGE.md (100%) diff --git a/.github/USAGE.md b/USAGE.md similarity index 100% rename from .github/USAGE.md rename to USAGE.md From 89522e5c976fe90dc434ec179473d613577c3e12 Mon Sep 17 00:00:00 2001 From: Ben Redden Date: Fri, 27 Oct 2017 16:57:02 -0400 Subject: [PATCH 41/62] updating readme.md with instructions on .env, adding .env_sample, updating .gitignore --- .env_sample | 1 + README.md | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 .env_sample diff --git a/.env_sample b/.env_sample new file mode 100644 index 000000000..2dd25759a --- /dev/null +++ b/.env_sample @@ -0,0 +1 @@ +export SENDGRID_API_KEY = '' diff --git a/README.md b/README.md index 615df8bf5..a386e04ea 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,10 @@ We appreciate your continued support, thank you! This library is broken up into several packages as a monorepo so that you only need to install the packages necessary for your use case. This README contains information pertaining to all packages. For examples on how to get started quickly, head over to the READMEs of each individual package (linked and described below), which includes detailed examples. +## .env file + +You will find a file in the root of the project called .env_sample. You can run `mv .env_sample .env` or manually rename the file to `.env`; be sure to add your [API key](https://sendgrid.com/docs/User_Guide/Settings/api_keys.html#-Creating-an-API-key). + * [@sendgrid/mail](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/mail) - if you just want to send email * [@sendgrid/client](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/client) - to use all other [SendGrid v3 Web API endpoints](https://sendgrid.com/docs/API_Reference/api_v3.html) * [@sendgrid/inbound-mail-parser](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/inbound-mail-parser) - help with parsing the SendGrid Inbound Parse API From 069d226952dfa21ff8c16778f669bfee9aa98fd5 Mon Sep 17 00:00:00 2001 From: t2013anurag Date: Sat, 28 Oct 2017 10:57:42 +0530 Subject: [PATCH 42/62] refactored specs fixes #552 --- .../helpers/classes/personalization.spec.js | 695 ------------------ .../527-camel-case-headers.spec.js | 36 + .../PERSONALIZATION-SPECS-README.md | 21 + .../personalization_specs/add-bcc.spec.js | 53 ++ .../personalization_specs/add-cc.spec.js | 53 ++ .../add-custom-args.spec.js | 48 ++ .../personalization_specs/add-headers.spec.js | 48 ++ .../add-substitutions.spec.js | 48 ++ .../personalization_specs/from-data.spec.js | 87 +++ .../reverse-merge-substitutions.spec.js | 54 ++ .../personalization_specs/set-add-to.spec.js | 53 ++ .../personalization_specs/set-bcc.spec.js | 56 ++ .../personalization_specs/set-cc.spec.js | 56 ++ .../set-custom-args.spec.js | 47 ++ .../personalization_specs/set-headers.spec.js | 47 ++ .../personalization_specs/set-send-at.spec.js | 45 ++ .../personalization_specs/set-subject.spec.js | 45 ++ .../set-substitutions.spec.js | 47 ++ .../personalization_specs/set-to.spec.js | 56 ++ .../substitutions-wrappers.spec.js | 58 ++ .../personalization_specs/to-json.spec.js | 117 +++ 21 files changed, 1075 insertions(+), 695 deletions(-) delete mode 100644 packages/helpers/classes/personalization.spec.js create mode 100644 packages/helpers/classes/personalization_specs/527-camel-case-headers.spec.js create mode 100644 packages/helpers/classes/personalization_specs/PERSONALIZATION-SPECS-README.md create mode 100644 packages/helpers/classes/personalization_specs/add-bcc.spec.js create mode 100644 packages/helpers/classes/personalization_specs/add-cc.spec.js create mode 100644 packages/helpers/classes/personalization_specs/add-custom-args.spec.js create mode 100644 packages/helpers/classes/personalization_specs/add-headers.spec.js create mode 100644 packages/helpers/classes/personalization_specs/add-substitutions.spec.js create mode 100644 packages/helpers/classes/personalization_specs/from-data.spec.js create mode 100644 packages/helpers/classes/personalization_specs/reverse-merge-substitutions.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-add-to.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-bcc.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-cc.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-custom-args.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-headers.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-send-at.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-subject.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-substitutions.spec.js create mode 100644 packages/helpers/classes/personalization_specs/set-to.spec.js create mode 100644 packages/helpers/classes/personalization_specs/substitutions-wrappers.spec.js create mode 100644 packages/helpers/classes/personalization_specs/to-json.spec.js diff --git a/packages/helpers/classes/personalization.spec.js b/packages/helpers/classes/personalization.spec.js deleted file mode 100644 index a61cccc22..000000000 --- a/packages/helpers/classes/personalization.spec.js +++ /dev/null @@ -1,695 +0,0 @@ -'use strict'; - -/** - * Dependencies - */ -const Personalization = require('./personalization'); -const EmailAddress = require('./email-address'); - -/** - * Tests - */ -describe('Personalization', function() { - - //Create new personalization before each test - let p; - beforeEach(function() { - p = new Personalization(); - }); - - //Set subject - describe('setSubject()', function() { - it('should set the given value', function() { - p.setSubject('Test'); - expect(p.subject).to.equal('Test'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.setSubject(5); - }).to.throw(Error); - expect(function() { - p.setSubject(null); - }).to.throw(Error); - }); - it('should accept no input', function() { - expect(function() { - p.setSubject(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setSubject('Test'); - p.setSubject(); - expect(p.subject).to.equal('Test'); - }); - }); - - //Set send at - describe('setSendAt()', function() { - it('should set the given value', function() { - p.setSendAt(1500077141); - expect(p.sendAt).to.equal(1500077141); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.setSendAt('Invalid'); - }).to.throw(Error); - expect(function() { - p.setSendAt(null); - }).to.throw(Error); - }); - it('should accept no input', function() { - expect(function() { - p.setSendAt(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setSendAt(1500077141); - p.setSendAt(); - expect(p.sendAt).to.equal(1500077141); - }); - }); - - //Set to - describe('setTo()', function() { - it('should handle array values', function() { - p.setTo(['test@example.org']); - expect(p.to).to.be.an.instanceof(Array); - expect(p.to).to.have.a.lengthOf(1); - expect(p.to[0]).to.be.an.instanceof(EmailAddress); - expect(p.to[0].email).to.equal('test@example.org'); - }); - it('should handle string values', function() { - p.setTo('test@example.org'); - expect(p.to).to.be.an.instanceof(Array); - expect(p.to).to.have.a.lengthOf(1); - expect(p.to[0]).to.be.an.instanceof(EmailAddress); - expect(p.to[0].email).to.equal('test@example.org'); - }); - it('should handle multiple values', function() { - p.setTo(['test1@example.org', 'test2@example.org']); - expect(p.to).to.be.an.instanceof(Array); - expect(p.to).to.have.a.lengthOf(2); - expect(p.to[0]).to.be.an.instanceof(EmailAddress); - expect(p.to[0].email).to.equal('test1@example.org'); - expect(p.to[1]).to.be.an.instanceof(EmailAddress); - expect(p.to[1].email).to.equal('test2@example.org'); - }); - it('should accept no input', function() { - expect(function() { - p.setTo(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setTo('test@example.org'); - p.setTo(); - expect(p.to[0].email).to.equal('test@example.org'); - }); - }); - - //Add to - describe('addTo()', function() { - it('should add the item', function() { - p.addTo('test@example.org'); - expect(p.to).to.be.an.instanceof(Array); - expect(p.to).to.have.a.lengthOf(1); - expect(p.to[0]).to.be.an.instanceof(EmailAddress); - expect(p.to[0].email).to.equal('test@example.org'); - }); - it('should handle multiple values', function() { - p.addTo('test1@example.org'); - p.addTo('test2@example.org'); - expect(p.to).to.be.an.instanceof(Array); - expect(p.to).to.have.a.lengthOf(2); - expect(p.to[0]).to.be.an.instanceof(EmailAddress); - expect(p.to[0].email).to.equal('test1@example.org'); - expect(p.to[1]).to.be.an.instanceof(EmailAddress); - expect(p.to[1].email).to.equal('test2@example.org'); - }); - it('should accept no input', function() { - expect(function() { - p.addTo(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.addTo('test@example.org'); - p.addTo(); - expect(p.to).to.be.an.instanceof(Array); - expect(p.to).to.have.a.lengthOf(1); - expect(p.to[0]).to.be.an.instanceof(EmailAddress); - expect(p.to[0].email).to.equal('test@example.org'); - }); - }); - - //Set cc - describe('setCc()', function() { - it('should handle array values', function() { - p.setCc(['test@example.org']); - expect(p.cc).to.be.an.instanceof(Array); - expect(p.cc).to.have.a.lengthOf(1); - expect(p.cc[0]).to.be.an.instanceof(EmailAddress); - expect(p.cc[0].email).to.equal('test@example.org'); - }); - it('should handle string values', function() { - p.setCc('test@example.org'); - expect(p.cc).to.be.an.instanceof(Array); - expect(p.cc).to.have.a.lengthOf(1); - expect(p.cc[0]).to.be.an.instanceof(EmailAddress); - expect(p.cc[0].email).to.equal('test@example.org'); - }); - it('should handle multiple values', function() { - p.setCc(['test1@example.org', 'test2@example.org']); - expect(p.cc).to.be.an.instanceof(Array); - expect(p.cc).to.have.a.lengthOf(2); - expect(p.cc[0]).to.be.an.instanceof(EmailAddress); - expect(p.cc[0].email).to.equal('test1@example.org'); - expect(p.cc[1]).to.be.an.instanceof(EmailAddress); - expect(p.cc[1].email).to.equal('test2@example.org'); - }); - it('should accept no input', function() { - expect(function() { - p.setCc(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setCc('test@example.org'); - p.setCc(); - expect(p.cc[0].email).to.equal('test@example.org'); - }); - }); - - //Add cc - describe('addCc()', function() { - it('should add the item', function() { - p.addCc('test@example.org'); - expect(p.cc).to.be.an.instanceof(Array); - expect(p.cc).to.have.a.lengthOf(1); - expect(p.cc[0]).to.be.an.instanceof(EmailAddress); - expect(p.cc[0].email).to.equal('test@example.org'); - }); - it('should handle multiple values', function() { - p.addCc('test1@example.org'); - p.addCc('test2@example.org'); - expect(p.cc).to.be.an.instanceof(Array); - expect(p.cc).to.have.a.lengthOf(2); - expect(p.cc[0]).to.be.an.instanceof(EmailAddress); - expect(p.cc[0].email).to.equal('test1@example.org'); - expect(p.cc[1]).to.be.an.instanceof(EmailAddress); - expect(p.cc[1].email).to.equal('test2@example.org'); - }); - it('should accept no input', function() { - expect(function() { - p.addCc(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.addCc('test@example.org'); - p.addCc(); - expect(p.cc).to.be.an.instanceof(Array); - expect(p.cc).to.have.a.lengthOf(1); - expect(p.cc[0]).to.be.an.instanceof(EmailAddress); - expect(p.cc[0].email).to.equal('test@example.org'); - }); - }); - - //Set bcc - describe('setBcc()', function() { - it('should handle array values', function() { - p.setBcc(['test@example.org']); - expect(p.bcc).to.be.an.instanceof(Array); - expect(p.bcc).to.have.a.lengthOf(1); - expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[0].email).to.equal('test@example.org'); - }); - it('should handle string values', function() { - p.setBcc('test@example.org'); - expect(p.bcc).to.be.an.instanceof(Array); - expect(p.bcc).to.have.a.lengthOf(1); - expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[0].email).to.equal('test@example.org'); - }); - it('should handle multiple values', function() { - p.setBcc(['test1@example.org', 'test2@example.org']); - expect(p.bcc).to.be.an.instanceof(Array); - expect(p.bcc).to.have.a.lengthOf(2); - expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[0].email).to.equal('test1@example.org'); - expect(p.bcc[1]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[1].email).to.equal('test2@example.org'); - }); - it('should accept no input', function() { - expect(function() { - p.setBcc(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setBcc('test@example.org'); - p.setBcc(); - expect(p.bcc[0].email).to.equal('test@example.org'); - }); - }); - - //Add bcc - describe('addBcc()', function() { - it('should add the item', function() { - p.addBcc('test@example.org'); - expect(p.bcc).to.be.an.instanceof(Array); - expect(p.bcc).to.have.a.lengthOf(1); - expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[0].email).to.equal('test@example.org'); - }); - it('should handle multiple values', function() { - p.addBcc('test1@example.org'); - p.addBcc('test2@example.org'); - expect(p.bcc).to.be.an.instanceof(Array); - expect(p.bcc).to.have.a.lengthOf(2); - expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[0].email).to.equal('test1@example.org'); - expect(p.bcc[1]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[1].email).to.equal('test2@example.org'); - }); - it('should accept no input', function() { - expect(function() { - p.addBcc(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.addBcc('test@example.org'); - p.addBcc(); - expect(p.bcc).to.be.an.instanceof(Array); - expect(p.bcc).to.have.a.lengthOf(1); - expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); - expect(p.bcc[0].email).to.equal('test@example.org'); - }); - }); - - //Set headers - describe('setHeaders()', function() { - it('should set the given value', function() { - p.setHeaders({test: 'Test'}); - expect(p.headers).to.be.an.instanceof(Object); - expect(p.headers).to.have.a.property('test'); - expect(p.headers.test).to.equal('Test'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.setHeaders('Invalid'); - }).to.throw(Error); - expect(function() { - p.setHeaders(null); - }).to.throw(Error); - }); - it('should accept no input', function() { - expect(function() { - p.setHeaders(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setHeaders({test: 'Test'}); - p.setHeaders(); - expect(p.headers.test).to.equal('Test'); - }); - }); - - //Add header - describe('addHeader()', function() { - it('should set the given value', function() { - p.addHeader('test', 'Test'); - expect(p.headers).to.be.an.instanceof(Object); - expect(p.headers).to.have.a.property('test'); - expect(p.headers.test).to.equal('Test'); - }); - it('should add multiple values', function() { - p.addHeader('test1', 'Test1'); - p.addHeader('test2', 'Test2'); - expect(p.headers).to.have.a.property('test1'); - expect(p.headers).to.have.a.property('test2'); - expect(p.headers.test1).to.equal('Test1'); - expect(p.headers.test2).to.equal('Test2'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.addHeader('test'); - }).to.throw(Error); - expect(function() { - p.addHeader(null, 'test'); - }).to.throw(Error); - expect(function() { - p.addHeader(3, 5); - }).to.throw(Error); - }); - }); - - //Set custom args - describe('setCustomArgs()', function() { - it('should set the given value', function() { - p.setCustomArgs({test: 'Test'}); - expect(p.customArgs).to.be.an.instanceof(Object); - expect(p.customArgs).to.have.a.property('test'); - expect(p.customArgs.test).to.equal('Test'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.setCustomArgs('Invalid'); - }).to.throw(Error); - expect(function() { - p.setCustomArgs(null); - }).to.throw(Error); - }); - it('should accept no input', function() { - expect(function() { - p.setCustomArgs(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setCustomArgs({test: 'Test'}); - p.setCustomArgs(); - expect(p.customArgs.test).to.equal('Test'); - }); - }); - - //Add custom arg - describe('addCustomArg()', function() { - it('should set the given value', function() { - p.addCustomArg('test', 'Test'); - expect(p.customArgs).to.be.an.instanceof(Object); - expect(p.customArgs).to.have.a.property('test'); - expect(p.customArgs.test).to.equal('Test'); - }); - it('should add multiple values', function() { - p.addCustomArg('test1', 'Test1'); - p.addCustomArg('test2', 'Test2'); - expect(p.customArgs).to.have.a.property('test1'); - expect(p.customArgs).to.have.a.property('test2'); - expect(p.customArgs.test1).to.equal('Test1'); - expect(p.customArgs.test2).to.equal('Test2'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.addCustomArg('test'); - }).to.throw(Error); - expect(function() { - p.addCustomArg(null, 'test'); - }).to.throw(Error); - expect(function() { - p.addCustomArg(3, 5); - }).to.throw(Error); - }); - }); - - //Set substitutions - describe('setSubstitutions()', function() { - it('should set the given value', function() { - p.setSubstitutions({test: 'Test'}); - expect(p.substitutions).to.be.an.instanceof(Object); - expect(p.substitutions).to.have.a.property('test'); - expect(p.substitutions.test).to.equal('Test'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.setSubstitutions('Invalid'); - }).to.throw(Error); - expect(function() { - p.setSubstitutions(3); - }).to.throw(Error); - }); - it('should accept no input', function() { - expect(function() { - p.setSubstitutions(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setSubstitutions({test: 'Test'}); - p.setSubstitutions(); - expect(p.substitutions.test).to.equal('Test'); - }); - }); - - //Add substitution - describe('addSubstitution()', function() { - it('should set the given value', function() { - p.addSubstitution('test', 'Test'); - expect(p.substitutions).to.be.an.instanceof(Object); - expect(p.substitutions).to.have.a.property('test'); - expect(p.substitutions.test).to.equal('Test'); - }); - it('should add multiple values', function() { - p.addSubstitution('test1', 'Test1'); - p.addSubstitution('test2', 2); - expect(p.substitutions).to.have.a.property('test1'); - expect(p.substitutions).to.have.a.property('test2'); - expect(p.substitutions.test1).to.equal('Test1'); - expect(p.substitutions.test2).to.equal(2); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.addSubstitution('test'); - }).to.throw(Error); - expect(function() { - p.addSubstitution(null, 'test'); - }).to.throw(Error); - expect(function() { - p.addSubstitution(3, false); - }).to.throw(Error); - }); - }); - - //Reverse merge substitutions - describe('reverseMergeSubstitutions()', function() { - it('should reverse merge substitutions', function() { - p.setSubstitutions({test1: 'Test1'}); - p.reverseMergeSubstitutions({test2: 'Test2'}); - expect(p.substitutions).to.have.a.property('test1'); - expect(p.substitutions).to.have.a.property('test2'); - expect(p.substitutions.test1).to.equal('Test1'); - expect(p.substitutions.test2).to.equal('Test2'); - }); - it('should not overwrite existing keys', function() { - p.setSubstitutions({test1: 'Test1'}); - p.reverseMergeSubstitutions({test1: 'Test3', test2: 'Test2'}); - expect(p.substitutions).to.have.a.property('test1'); - expect(p.substitutions).to.have.a.property('test2'); - expect(p.substitutions.test1).to.equal('Test1'); - expect(p.substitutions.test2).to.equal('Test2'); - }); - it('should work without prior substitutions', function() { - p.reverseMergeSubstitutions({test2: 'Test2'}); - expect(p.substitutions).to.have.a.property('test2'); - expect(p.substitutions.test2).to.equal('Test2'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.reverseMergeSubstitutions(3); - }).to.throw(Error); - }); - it('should accept no input', function() { - expect(function() { - p.reverseMergeSubstitutions(); - }).not.to.throw(Error); - }); - }); - - //Set substitutions - describe('setSubstitutionWrappers()', function() { - it('should have defaults', function() { - expect(p.substitutionWrappers).to.be.an.instanceof(Array); - expect(p.substitutionWrappers).to.have.a.lengthOf(2); - expect(p.substitutionWrappers[0]).to.equal('{{'); - expect(p.substitutionWrappers[1]).to.equal('}}'); - }); - it('should set the given value', function() { - p.setSubstitutionWrappers(['a', 'b']); - expect(p.substitutionWrappers).to.be.an.instanceof(Array); - expect(p.substitutionWrappers).to.have.a.lengthOf(2); - expect(p.substitutionWrappers[0]).to.equal('a'); - expect(p.substitutionWrappers[1]).to.equal('b'); - }); - it('should throw an error for invalid input', function() { - expect(function() { - p.setSubstitutionWrappers('Invalid'); - }).to.throw(Error); - expect(function() { - p.setSubstitutionWrappers(['a']); - }).to.throw(Error); - expect(function() { - p.setSubstitutionWrappers(['a', 'b', 'c']); - }).to.throw(Error); - }); - it('should accept no input', function() { - expect(function() { - p.setSubstitutionWrappers(); - }).not.to.throw(Error); - }); - it('should not overwrite with no input', function() { - p.setSubstitutionWrappers(['a', 'b']); - p.setSubstitutionWrappers(); - expect(p.substitutionWrappers[0]).to.equal('a'); - expect(p.substitutionWrappers[1]).to.equal('b'); - }); - }); - - //JSON conversion - describe('toJSON()', function() { - beforeEach(function() { - p.setTo('test@example.org'); - }); - - it('should always have the to field', function() { - const json = p.toJSON(); - expect(json).to.have.property('to'); - expect(json.to).to.be.an.instanceof(Array); - expect(json.to).to.have.a.lengthOf(1); - expect(json.to[0]).to.be.an.instanceof(EmailAddress); - expect(json.to[0].email).to.equal('test@example.org'); - }); - it('should set the cc field', function() { - p.setCc('testcc@example.org'); - const json = p.toJSON(); - expect(json).to.have.property('cc'); - expect(json.cc).to.be.an.instanceof(Array); - expect(json.cc).to.have.a.lengthOf(1); - expect(json.cc[0]).to.be.an.instanceof(EmailAddress); - expect(json.cc[0].email).to.equal('testcc@example.org'); - }); - it('should set the bcc field', function() { - p.setBcc('testbcc@example.org'); - const json = p.toJSON(); - expect(json).to.have.property('bcc'); - expect(json.bcc).to.be.an.instanceof(Array); - expect(json.bcc).to.have.a.lengthOf(1); - expect(json.bcc[0]).to.be.an.instanceof(EmailAddress); - expect(json.bcc[0].email).to.equal('testbcc@example.org'); - }); - it('should set the headers field', function() { - p.setHeaders({test: 'Test'}); - const json = p.toJSON(); - expect(json).to.have.property('headers'); - expect(json.headers).to.be.an.instanceof(Object); - expect(json.headers.test).to.equal('Test'); - }); - it('should set the custom_args field', function() { - p.setCustomArgs({test: 'Test'}); - const json = p.toJSON(); - expect(json).to.have.property('custom_args'); - expect(json.custom_args).to.be.an.instanceof(Object); - expect(json.custom_args.test).to.equal('Test'); - }); - it('should set the substitutions field', function() { - p.setSubstitutions({test: 'Test'}); - const json = p.toJSON(); - expect(json).to.have.property('substitutions'); - expect(json.substitutions).to.be.an.instanceof(Object); - }); - it('should apply wrappers to the substitutions', function() { - p.setSubstitutions({test: 'Test', otherTest2: 'Test2'}); - p.setSubstitutionWrappers(['{{', '}}']); - const json = p.toJSON(); - expect(json.substitutions).to.have.property('{{test}}'); - expect(json.substitutions).to.have.property('{{otherTest2}}'); - expect(json.substitutions['{{test}}']).to.equal('Test'); - expect(json.substitutions['{{otherTest2}}']).to.equal('Test2'); - expect(json.substitutions).not.to.have.property('test'); - expect(json.substitutions).not.to.have.property('otherTest2'); - }); - it('should set the subject field', function() { - p.setSubject('Test'); - const json = p.toJSON(); - expect(json).to.have.property('subject'); - expect(json.subject).to.equal('Test'); - }); - it('should set the send_at field', function() { - p.setSendAt(555); - const json = p.toJSON(); - expect(json).to.have.property('send_at'); - expect(json.send_at).to.equal(555); - }); - it('should not modify the keys of substitutions and custom args', () => { - const data = { - to: 'to@example.org', - customArgs: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, - substitutions: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, - }; - p.fromData(data); - const json = p.toJSON(); - expect(json.substitutions).to.have.property('{{T_EST}}'); - expect(json.substitutions).to.have.property('{{camelCase}}'); - expect(json.substitutions).to.have.property('{{snake_case}}'); - expect(json.substitutions['{{T_EST}}']).to.equal('Test'); - expect(json.substitutions['{{camelCase}}']).to.equal('Test'); - expect(json.substitutions['{{snake_case}}']).to.equal('Test'); - expect(json.custom_args).to.have.property('T_EST'); - expect(json.custom_args).to.have.property('camelCase'); - expect(json.custom_args).to.have.property('snake_case'); - expect(json.custom_args.T_EST).to.equal('Test'); - expect(json.custom_args.camelCase).to.equal('Test'); - expect(json.custom_args.snake_case).to.equal('Test'); - }); - }); - - //From data - describe('fromData()', function() { - - //Data - const data = { - to: 'to@example.org', - cc: ['cc1@example.org', 'cc2@example.org'], - bcc: ['bcc1@example.org', 'bcc2@example.org'], - subject: 'Test', - sendAt: 1000, - headers: {test: 'Test'}, - customArgs: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, - substitutions: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, - substitutionWrappers: ['[', ']'], - }; - - //Tests - it('should call fromData() from the constructor', () => { - p = new Personalization(data); - expect(p.to[0].email).to.equal('to@example.org'); - expect(p.subject).to.equal('Test'); - }); - it('should throw an error for invalid input', () => { - expect(function() { - p.fromData(5); - }).to.throw(Error); - }); - it('should have set all properties', () => { - p.fromData(data); - expect(p.to[0].email).to.equal('to@example.org'); - expect(p.cc[0].email).to.equal('cc1@example.org'); - expect(p.cc[1].email).to.equal('cc2@example.org'); - expect(p.bcc[0].email).to.equal('bcc1@example.org'); - expect(p.bcc[1].email).to.equal('bcc2@example.org'); - expect(p.subject).to.equal('Test'); - expect(p.sendAt).to.equal(1000); - expect(p.headers.test).to.equal('Test'); - expect(p.customArgs.snake_case).to.equal('Test'); - expect(p.substitutions.snake_case).to.equal('Test'); - expect(p.substitutionWrappers).to.have.members(['[', ']']); - }); - it('should not modify the keys of substitutions and custom args', () => { - p.fromData(data); - expect(p.substitutions.T_EST).to.equal('Test'); - expect(p.substitutions.camelCase).to.equal('Test'); - expect(p.substitutions.snake_case).to.equal('Test'); - expect(p.customArgs.T_EST).to.equal('Test'); - expect(p.customArgs.camelCase).to.equal('Test'); - expect(p.customArgs.snake_case).to.equal('Test'); - }); - }); - - describe('#527', function() { - it('shouldn\'t convert the headers to camel/snake case', function() { - const p = new Personalization({ - to: 'test@example.com', - headers: { - 'List-Unsubscribe': '', - }, - }); - - expect(p.headers['List-Unsubscribe']).to.equal(''); - - expect(p.toJSON().headers['List-Unsubscribe']).to - .equal(''); - }); - }); -}); diff --git a/packages/helpers/classes/personalization_specs/527-camel-case-headers.spec.js b/packages/helpers/classes/personalization_specs/527-camel-case-headers.spec.js new file mode 100644 index 000000000..e9fa1d746 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/527-camel-case-headers.spec.js @@ -0,0 +1,36 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + // camel case headers test + describe('#527', function() { + it('shouldn\'t convert the headers to camel/snake case', function() { + const p = new Personalization({ + to: 'test@example.com', + headers: { + 'List-Unsubscribe': '', + }, + }); + + expect(p.headers['List-Unsubscribe']).to.equal(''); + + expect(p.toJSON().headers['List-Unsubscribe']).to + .equal(''); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/PERSONALIZATION-SPECS-README.md b/packages/helpers/classes/personalization_specs/PERSONALIZATION-SPECS-README.md new file mode 100644 index 000000000..4f8aed983 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/PERSONALIZATION-SPECS-README.md @@ -0,0 +1,21 @@ +#### Personalization helper specs + +- setSubject() - set-subject.spec.js +- setSendAt() - set-send-at.spec.js +- setTo() - set-to.spec.js +- addTo() - add-to.spec.js +- setCc() - set-cc.spec.js +- addCc() - add-cc.spec.js +- setBcc() - set-bcc.spec.js +- addBcc() - add-bcc.spec.js +- setHeaders() - set-headers.spec.js +- addHeader() - add-headers.spec.js +- setCustomArgs() - set-custom-args.spec.js +- addCustomArg() - add-custom-args.spec.js +- setSubstitutions() - set-substitutions.spec.js +- addSubstitution() - add-substitutions.spec.js +- reverseMergeSubstitutions() - reverse-merge-substitutions.spec.js +- setSubstitutionWrappers() - set-substitutions-wrappers.spec.js +- toJSON() - to-json.spec.js +- fromData() - from-data.spec.js +- #527 - 527-camel-case-headers.spec.js \ No newline at end of file diff --git a/packages/helpers/classes/personalization_specs/add-bcc.spec.js b/packages/helpers/classes/personalization_specs/add-bcc.spec.js new file mode 100644 index 000000000..735ae3a5d --- /dev/null +++ b/packages/helpers/classes/personalization_specs/add-bcc.spec.js @@ -0,0 +1,53 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Add bcc + describe('addBcc()', function() { + it('should add the item', function() { + p.addBcc('test@example.org'); + expect(p.bcc).to.be.an.instanceof(Array); + expect(p.bcc).to.have.a.lengthOf(1); + expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[0].email).to.equal('test@example.org'); + }); + it('should handle multiple values', function() { + p.addBcc('test1@example.org'); + p.addBcc('test2@example.org'); + expect(p.bcc).to.be.an.instanceof(Array); + expect(p.bcc).to.have.a.lengthOf(2); + expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[0].email).to.equal('test1@example.org'); + expect(p.bcc[1]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[1].email).to.equal('test2@example.org'); + }); + it('should accept no input', function() { + expect(function() { + p.addBcc(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.addBcc('test@example.org'); + p.addBcc(); + expect(p.bcc).to.be.an.instanceof(Array); + expect(p.bcc).to.have.a.lengthOf(1); + expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[0].email).to.equal('test@example.org'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/add-cc.spec.js b/packages/helpers/classes/personalization_specs/add-cc.spec.js new file mode 100644 index 000000000..c280ee049 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/add-cc.spec.js @@ -0,0 +1,53 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Add cc + describe('addCc()', function() { + it('should add the item', function() { + p.addCc('test@example.org'); + expect(p.cc).to.be.an.instanceof(Array); + expect(p.cc).to.have.a.lengthOf(1); + expect(p.cc[0]).to.be.an.instanceof(EmailAddress); + expect(p.cc[0].email).to.equal('test@example.org'); + }); + it('should handle multiple values', function() { + p.addCc('test1@example.org'); + p.addCc('test2@example.org'); + expect(p.cc).to.be.an.instanceof(Array); + expect(p.cc).to.have.a.lengthOf(2); + expect(p.cc[0]).to.be.an.instanceof(EmailAddress); + expect(p.cc[0].email).to.equal('test1@example.org'); + expect(p.cc[1]).to.be.an.instanceof(EmailAddress); + expect(p.cc[1].email).to.equal('test2@example.org'); + }); + it('should accept no input', function() { + expect(function() { + p.addCc(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.addCc('test@example.org'); + p.addCc(); + expect(p.cc).to.be.an.instanceof(Array); + expect(p.cc).to.have.a.lengthOf(1); + expect(p.cc[0]).to.be.an.instanceof(EmailAddress); + expect(p.cc[0].email).to.equal('test@example.org'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/add-custom-args.spec.js b/packages/helpers/classes/personalization_specs/add-custom-args.spec.js new file mode 100644 index 000000000..a4cbde09b --- /dev/null +++ b/packages/helpers/classes/personalization_specs/add-custom-args.spec.js @@ -0,0 +1,48 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Add custom arg + describe('addCustomArg()', function() { + it('should set the given value', function() { + p.addCustomArg('test', 'Test'); + expect(p.customArgs).to.be.an.instanceof(Object); + expect(p.customArgs).to.have.a.property('test'); + expect(p.customArgs.test).to.equal('Test'); + }); + it('should add multiple values', function() { + p.addCustomArg('test1', 'Test1'); + p.addCustomArg('test2', 'Test2'); + expect(p.customArgs).to.have.a.property('test1'); + expect(p.customArgs).to.have.a.property('test2'); + expect(p.customArgs.test1).to.equal('Test1'); + expect(p.customArgs.test2).to.equal('Test2'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.addCustomArg('test'); + }).to.throw(Error); + expect(function() { + p.addCustomArg(null, 'test'); + }).to.throw(Error); + expect(function() { + p.addCustomArg(3, 5); + }).to.throw(Error); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/add-headers.spec.js b/packages/helpers/classes/personalization_specs/add-headers.spec.js new file mode 100644 index 000000000..2e22fb12e --- /dev/null +++ b/packages/helpers/classes/personalization_specs/add-headers.spec.js @@ -0,0 +1,48 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Add header + describe('addHeader()', function() { + it('should set the given value', function() { + p.addHeader('test', 'Test'); + expect(p.headers).to.be.an.instanceof(Object); + expect(p.headers).to.have.a.property('test'); + expect(p.headers.test).to.equal('Test'); + }); + it('should add multiple values', function() { + p.addHeader('test1', 'Test1'); + p.addHeader('test2', 'Test2'); + expect(p.headers).to.have.a.property('test1'); + expect(p.headers).to.have.a.property('test2'); + expect(p.headers.test1).to.equal('Test1'); + expect(p.headers.test2).to.equal('Test2'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.addHeader('test'); + }).to.throw(Error); + expect(function() { + p.addHeader(null, 'test'); + }).to.throw(Error); + expect(function() { + p.addHeader(3, 5); + }).to.throw(Error); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/add-substitutions.spec.js b/packages/helpers/classes/personalization_specs/add-substitutions.spec.js new file mode 100644 index 000000000..9650a164a --- /dev/null +++ b/packages/helpers/classes/personalization_specs/add-substitutions.spec.js @@ -0,0 +1,48 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Add substitution + describe('addSubstitution()', function() { + it('should set the given value', function() { + p.addSubstitution('test', 'Test'); + expect(p.substitutions).to.be.an.instanceof(Object); + expect(p.substitutions).to.have.a.property('test'); + expect(p.substitutions.test).to.equal('Test'); + }); + it('should add multiple values', function() { + p.addSubstitution('test1', 'Test1'); + p.addSubstitution('test2', 2); + expect(p.substitutions).to.have.a.property('test1'); + expect(p.substitutions).to.have.a.property('test2'); + expect(p.substitutions.test1).to.equal('Test1'); + expect(p.substitutions.test2).to.equal(2); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.addSubstitution('test'); + }).to.throw(Error); + expect(function() { + p.addSubstitution(null, 'test'); + }).to.throw(Error); + expect(function() { + p.addSubstitution(3, false); + }).to.throw(Error); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/from-data.spec.js b/packages/helpers/classes/personalization_specs/from-data.spec.js new file mode 100644 index 000000000..6d1a500f6 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/from-data.spec.js @@ -0,0 +1,87 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //From data + describe('fromData()', function() { + + //Data + const data = { + to: 'to@example.org', + cc: ['cc1@example.org', 'cc2@example.org'], + bcc: ['bcc1@example.org', 'bcc2@example.org'], + subject: 'Test', + sendAt: 1000, + headers: {test: 'Test'}, + customArgs: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, + substitutions: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, + substitutionWrappers: ['[', ']'], + }; + + //Tests + it('should call fromData() from the constructor', () => { + p = new Personalization(data); + expect(p.to[0].email).to.equal('to@example.org'); + expect(p.subject).to.equal('Test'); + }); + it('should throw an error for invalid input', () => { + expect(function() { + p.fromData(5); + }).to.throw(Error); + }); + it('should have set all properties', () => { + p.fromData(data); + expect(p.to[0].email).to.equal('to@example.org'); + expect(p.cc[0].email).to.equal('cc1@example.org'); + expect(p.cc[1].email).to.equal('cc2@example.org'); + expect(p.bcc[0].email).to.equal('bcc1@example.org'); + expect(p.bcc[1].email).to.equal('bcc2@example.org'); + expect(p.subject).to.equal('Test'); + expect(p.sendAt).to.equal(1000); + expect(p.headers.test).to.equal('Test'); + expect(p.customArgs.snake_case).to.equal('Test'); + expect(p.substitutions.snake_case).to.equal('Test'); + expect(p.substitutionWrappers).to.have.members(['[', ']']); + }); + it('should not modify the keys of substitutions and custom args', () => { + p.fromData(data); + expect(p.substitutions.T_EST).to.equal('Test'); + expect(p.substitutions.camelCase).to.equal('Test'); + expect(p.substitutions.snake_case).to.equal('Test'); + expect(p.customArgs.T_EST).to.equal('Test'); + expect(p.customArgs.camelCase).to.equal('Test'); + expect(p.customArgs.snake_case).to.equal('Test'); + }); + }); + + describe('#527', function() { + it('shouldn\'t convert the headers to camel/snake case', function() { + const p = new Personalization({ + to: 'test@example.com', + headers: { + 'List-Unsubscribe': '', + }, + }); + + expect(p.headers['List-Unsubscribe']).to.equal(''); + + expect(p.toJSON().headers['List-Unsubscribe']).to + .equal(''); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/reverse-merge-substitutions.spec.js b/packages/helpers/classes/personalization_specs/reverse-merge-substitutions.spec.js new file mode 100644 index 000000000..ab6144348 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/reverse-merge-substitutions.spec.js @@ -0,0 +1,54 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Reverse merge substitutions + describe('reverseMergeSubstitutions()', function() { + it('should reverse merge substitutions', function() { + p.setSubstitutions({test1: 'Test1'}); + p.reverseMergeSubstitutions({test2: 'Test2'}); + expect(p.substitutions).to.have.a.property('test1'); + expect(p.substitutions).to.have.a.property('test2'); + expect(p.substitutions.test1).to.equal('Test1'); + expect(p.substitutions.test2).to.equal('Test2'); + }); + it('should not overwrite existing keys', function() { + p.setSubstitutions({test1: 'Test1'}); + p.reverseMergeSubstitutions({test1: 'Test3', test2: 'Test2'}); + expect(p.substitutions).to.have.a.property('test1'); + expect(p.substitutions).to.have.a.property('test2'); + expect(p.substitutions.test1).to.equal('Test1'); + expect(p.substitutions.test2).to.equal('Test2'); + }); + it('should work without prior substitutions', function() { + p.reverseMergeSubstitutions({test2: 'Test2'}); + expect(p.substitutions).to.have.a.property('test2'); + expect(p.substitutions.test2).to.equal('Test2'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.reverseMergeSubstitutions(3); + }).to.throw(Error); + }); + it('should accept no input', function() { + expect(function() { + p.reverseMergeSubstitutions(); + }).not.to.throw(Error); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-add-to.spec.js b/packages/helpers/classes/personalization_specs/set-add-to.spec.js new file mode 100644 index 000000000..9e82f29a8 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-add-to.spec.js @@ -0,0 +1,53 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Add to + describe('addTo()', function() { + it('should add the item', function() { + p.addTo('test@example.org'); + expect(p.to).to.be.an.instanceof(Array); + expect(p.to).to.have.a.lengthOf(1); + expect(p.to[0]).to.be.an.instanceof(EmailAddress); + expect(p.to[0].email).to.equal('test@example.org'); + }); + it('should handle multiple values', function() { + p.addTo('test1@example.org'); + p.addTo('test2@example.org'); + expect(p.to).to.be.an.instanceof(Array); + expect(p.to).to.have.a.lengthOf(2); + expect(p.to[0]).to.be.an.instanceof(EmailAddress); + expect(p.to[0].email).to.equal('test1@example.org'); + expect(p.to[1]).to.be.an.instanceof(EmailAddress); + expect(p.to[1].email).to.equal('test2@example.org'); + }); + it('should accept no input', function() { + expect(function() { + p.addTo(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.addTo('test@example.org'); + p.addTo(); + expect(p.to).to.be.an.instanceof(Array); + expect(p.to).to.have.a.lengthOf(1); + expect(p.to[0]).to.be.an.instanceof(EmailAddress); + expect(p.to[0].email).to.equal('test@example.org'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-bcc.spec.js b/packages/helpers/classes/personalization_specs/set-bcc.spec.js new file mode 100644 index 000000000..85e699941 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-bcc.spec.js @@ -0,0 +1,56 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set bcc + describe('setBcc()', function() { + it('should handle array values', function() { + p.setBcc(['test@example.org']); + expect(p.bcc).to.be.an.instanceof(Array); + expect(p.bcc).to.have.a.lengthOf(1); + expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[0].email).to.equal('test@example.org'); + }); + it('should handle string values', function() { + p.setBcc('test@example.org'); + expect(p.bcc).to.be.an.instanceof(Array); + expect(p.bcc).to.have.a.lengthOf(1); + expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[0].email).to.equal('test@example.org'); + }); + it('should handle multiple values', function() { + p.setBcc(['test1@example.org', 'test2@example.org']); + expect(p.bcc).to.be.an.instanceof(Array); + expect(p.bcc).to.have.a.lengthOf(2); + expect(p.bcc[0]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[0].email).to.equal('test1@example.org'); + expect(p.bcc[1]).to.be.an.instanceof(EmailAddress); + expect(p.bcc[1].email).to.equal('test2@example.org'); + }); + it('should accept no input', function() { + expect(function() { + p.setBcc(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setBcc('test@example.org'); + p.setBcc(); + expect(p.bcc[0].email).to.equal('test@example.org'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-cc.spec.js b/packages/helpers/classes/personalization_specs/set-cc.spec.js new file mode 100644 index 000000000..359dc110e --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-cc.spec.js @@ -0,0 +1,56 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set cc + describe('setCc()', function() { + it('should handle array values', function() { + p.setCc(['test@example.org']); + expect(p.cc).to.be.an.instanceof(Array); + expect(p.cc).to.have.a.lengthOf(1); + expect(p.cc[0]).to.be.an.instanceof(EmailAddress); + expect(p.cc[0].email).to.equal('test@example.org'); + }); + it('should handle string values', function() { + p.setCc('test@example.org'); + expect(p.cc).to.be.an.instanceof(Array); + expect(p.cc).to.have.a.lengthOf(1); + expect(p.cc[0]).to.be.an.instanceof(EmailAddress); + expect(p.cc[0].email).to.equal('test@example.org'); + }); + it('should handle multiple values', function() { + p.setCc(['test1@example.org', 'test2@example.org']); + expect(p.cc).to.be.an.instanceof(Array); + expect(p.cc).to.have.a.lengthOf(2); + expect(p.cc[0]).to.be.an.instanceof(EmailAddress); + expect(p.cc[0].email).to.equal('test1@example.org'); + expect(p.cc[1]).to.be.an.instanceof(EmailAddress); + expect(p.cc[1].email).to.equal('test2@example.org'); + }); + it('should accept no input', function() { + expect(function() { + p.setCc(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setCc('test@example.org'); + p.setCc(); + expect(p.cc[0].email).to.equal('test@example.org'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-custom-args.spec.js b/packages/helpers/classes/personalization_specs/set-custom-args.spec.js new file mode 100644 index 000000000..61c6554e0 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-custom-args.spec.js @@ -0,0 +1,47 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set custom args + describe('setCustomArgs()', function() { + it('should set the given value', function() { + p.setCustomArgs({test: 'Test'}); + expect(p.customArgs).to.be.an.instanceof(Object); + expect(p.customArgs).to.have.a.property('test'); + expect(p.customArgs.test).to.equal('Test'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.setCustomArgs('Invalid'); + }).to.throw(Error); + expect(function() { + p.setCustomArgs(null); + }).to.throw(Error); + }); + it('should accept no input', function() { + expect(function() { + p.setCustomArgs(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setCustomArgs({test: 'Test'}); + p.setCustomArgs(); + expect(p.customArgs.test).to.equal('Test'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-headers.spec.js b/packages/helpers/classes/personalization_specs/set-headers.spec.js new file mode 100644 index 000000000..3cc1cb485 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-headers.spec.js @@ -0,0 +1,47 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set headers + describe('setHeaders()', function() { + it('should set the given value', function() { + p.setHeaders({test: 'Test'}); + expect(p.headers).to.be.an.instanceof(Object); + expect(p.headers).to.have.a.property('test'); + expect(p.headers.test).to.equal('Test'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.setHeaders('Invalid'); + }).to.throw(Error); + expect(function() { + p.setHeaders(null); + }).to.throw(Error); + }); + it('should accept no input', function() { + expect(function() { + p.setHeaders(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setHeaders({test: 'Test'}); + p.setHeaders(); + expect(p.headers.test).to.equal('Test'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-send-at.spec.js b/packages/helpers/classes/personalization_specs/set-send-at.spec.js new file mode 100644 index 000000000..664d69cb5 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-send-at.spec.js @@ -0,0 +1,45 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set send at + describe('setSendAt()', function() { + it('should set the given value', function() { + p.setSendAt(1500077141); + expect(p.sendAt).to.equal(1500077141); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.setSendAt('Invalid'); + }).to.throw(Error); + expect(function() { + p.setSendAt(null); + }).to.throw(Error); + }); + it('should accept no input', function() { + expect(function() { + p.setSendAt(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setSendAt(1500077141); + p.setSendAt(); + expect(p.sendAt).to.equal(1500077141); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-subject.spec.js b/packages/helpers/classes/personalization_specs/set-subject.spec.js new file mode 100644 index 000000000..e65ef9101 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-subject.spec.js @@ -0,0 +1,45 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ + describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set subject + describe('setSubject()', function() { + it('should set the given value', function() { + p.setSubject('Test'); + expect(p.subject).to.equal('Test'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.setSubject(5); + }).to.throw(Error); + expect(function() { + p.setSubject(null); + }).to.throw(Error); + }); + it('should accept no input', function() { + expect(function() { + p.setSubject(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setSubject('Test'); + p.setSubject(); + expect(p.subject).to.equal('Test'); + }); + }); +}); \ No newline at end of file diff --git a/packages/helpers/classes/personalization_specs/set-substitutions.spec.js b/packages/helpers/classes/personalization_specs/set-substitutions.spec.js new file mode 100644 index 000000000..fa50604eb --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-substitutions.spec.js @@ -0,0 +1,47 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set substitutions + describe('setSubstitutions()', function() { + it('should set the given value', function() { + p.setSubstitutions({test: 'Test'}); + expect(p.substitutions).to.be.an.instanceof(Object); + expect(p.substitutions).to.have.a.property('test'); + expect(p.substitutions.test).to.equal('Test'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.setSubstitutions('Invalid'); + }).to.throw(Error); + expect(function() { + p.setSubstitutions(3); + }).to.throw(Error); + }); + it('should accept no input', function() { + expect(function() { + p.setSubstitutions(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setSubstitutions({test: 'Test'}); + p.setSubstitutions(); + expect(p.substitutions.test).to.equal('Test'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/set-to.spec.js b/packages/helpers/classes/personalization_specs/set-to.spec.js new file mode 100644 index 000000000..657f5784d --- /dev/null +++ b/packages/helpers/classes/personalization_specs/set-to.spec.js @@ -0,0 +1,56 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set to + describe('setTo()', function() { + it('should handle array values', function() { + p.setTo(['test@example.org']); + expect(p.to).to.be.an.instanceof(Array); + expect(p.to).to.have.a.lengthOf(1); + expect(p.to[0]).to.be.an.instanceof(EmailAddress); + expect(p.to[0].email).to.equal('test@example.org'); + }); + it('should handle string values', function() { + p.setTo('test@example.org'); + expect(p.to).to.be.an.instanceof(Array); + expect(p.to).to.have.a.lengthOf(1); + expect(p.to[0]).to.be.an.instanceof(EmailAddress); + expect(p.to[0].email).to.equal('test@example.org'); + }); + it('should handle multiple values', function() { + p.setTo(['test1@example.org', 'test2@example.org']); + expect(p.to).to.be.an.instanceof(Array); + expect(p.to).to.have.a.lengthOf(2); + expect(p.to[0]).to.be.an.instanceof(EmailAddress); + expect(p.to[0].email).to.equal('test1@example.org'); + expect(p.to[1]).to.be.an.instanceof(EmailAddress); + expect(p.to[1].email).to.equal('test2@example.org'); + }); + it('should accept no input', function() { + expect(function() { + p.setTo(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setTo('test@example.org'); + p.setTo(); + expect(p.to[0].email).to.equal('test@example.org'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/substitutions-wrappers.spec.js b/packages/helpers/classes/personalization_specs/substitutions-wrappers.spec.js new file mode 100644 index 000000000..e3c25b8e3 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/substitutions-wrappers.spec.js @@ -0,0 +1,58 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //Set substitutions wrappers + describe('setSubstitutionWrappers()', function() { + it('should have defaults', function() { + expect(p.substitutionWrappers).to.be.an.instanceof(Array); + expect(p.substitutionWrappers).to.have.a.lengthOf(2); + expect(p.substitutionWrappers[0]).to.equal('{{'); + expect(p.substitutionWrappers[1]).to.equal('}}'); + }); + it('should set the given value', function() { + p.setSubstitutionWrappers(['a', 'b']); + expect(p.substitutionWrappers).to.be.an.instanceof(Array); + expect(p.substitutionWrappers).to.have.a.lengthOf(2); + expect(p.substitutionWrappers[0]).to.equal('a'); + expect(p.substitutionWrappers[1]).to.equal('b'); + }); + it('should throw an error for invalid input', function() { + expect(function() { + p.setSubstitutionWrappers('Invalid'); + }).to.throw(Error); + expect(function() { + p.setSubstitutionWrappers(['a']); + }).to.throw(Error); + expect(function() { + p.setSubstitutionWrappers(['a', 'b', 'c']); + }).to.throw(Error); + }); + it('should accept no input', function() { + expect(function() { + p.setSubstitutionWrappers(); + }).not.to.throw(Error); + }); + it('should not overwrite with no input', function() { + p.setSubstitutionWrappers(['a', 'b']); + p.setSubstitutionWrappers(); + expect(p.substitutionWrappers[0]).to.equal('a'); + expect(p.substitutionWrappers[1]).to.equal('b'); + }); + }); +}); diff --git a/packages/helpers/classes/personalization_specs/to-json.spec.js b/packages/helpers/classes/personalization_specs/to-json.spec.js new file mode 100644 index 000000000..7ff318d98 --- /dev/null +++ b/packages/helpers/classes/personalization_specs/to-json.spec.js @@ -0,0 +1,117 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + //JSON conversion + describe('toJSON()', function() { + beforeEach(function() { + p.setTo('test@example.org'); + }); + + it('should always have the to field', function() { + const json = p.toJSON(); + expect(json).to.have.property('to'); + expect(json.to).to.be.an.instanceof(Array); + expect(json.to).to.have.a.lengthOf(1); + expect(json.to[0]).to.be.an.instanceof(EmailAddress); + expect(json.to[0].email).to.equal('test@example.org'); + }); + it('should set the cc field', function() { + p.setCc('testcc@example.org'); + const json = p.toJSON(); + expect(json).to.have.property('cc'); + expect(json.cc).to.be.an.instanceof(Array); + expect(json.cc).to.have.a.lengthOf(1); + expect(json.cc[0]).to.be.an.instanceof(EmailAddress); + expect(json.cc[0].email).to.equal('testcc@example.org'); + }); + it('should set the bcc field', function() { + p.setBcc('testbcc@example.org'); + const json = p.toJSON(); + expect(json).to.have.property('bcc'); + expect(json.bcc).to.be.an.instanceof(Array); + expect(json.bcc).to.have.a.lengthOf(1); + expect(json.bcc[0]).to.be.an.instanceof(EmailAddress); + expect(json.bcc[0].email).to.equal('testbcc@example.org'); + }); + it('should set the headers field', function() { + p.setHeaders({test: 'Test'}); + const json = p.toJSON(); + expect(json).to.have.property('headers'); + expect(json.headers).to.be.an.instanceof(Object); + expect(json.headers.test).to.equal('Test'); + }); + it('should set the custom_args field', function() { + p.setCustomArgs({test: 'Test'}); + const json = p.toJSON(); + expect(json).to.have.property('custom_args'); + expect(json.custom_args).to.be.an.instanceof(Object); + expect(json.custom_args.test).to.equal('Test'); + }); + it('should set the substitutions field', function() { + p.setSubstitutions({test: 'Test'}); + const json = p.toJSON(); + expect(json).to.have.property('substitutions'); + expect(json.substitutions).to.be.an.instanceof(Object); + }); + it('should apply wrappers to the substitutions', function() { + p.setSubstitutions({test: 'Test', otherTest2: 'Test2'}); + p.setSubstitutionWrappers(['{{', '}}']); + const json = p.toJSON(); + expect(json.substitutions).to.have.property('{{test}}'); + expect(json.substitutions).to.have.property('{{otherTest2}}'); + expect(json.substitutions['{{test}}']).to.equal('Test'); + expect(json.substitutions['{{otherTest2}}']).to.equal('Test2'); + expect(json.substitutions).not.to.have.property('test'); + expect(json.substitutions).not.to.have.property('otherTest2'); + }); + it('should set the subject field', function() { + p.setSubject('Test'); + const json = p.toJSON(); + expect(json).to.have.property('subject'); + expect(json.subject).to.equal('Test'); + }); + it('should set the send_at field', function() { + p.setSendAt(555); + const json = p.toJSON(); + expect(json).to.have.property('send_at'); + expect(json.send_at).to.equal(555); + }); + it('should not modify the keys of substitutions and custom args', () => { + const data = { + to: 'to@example.org', + customArgs: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, + substitutions: {snake_case: 'Test', T_EST: 'Test', camelCase: 'Test'}, + }; + p.fromData(data); + const json = p.toJSON(); + expect(json.substitutions).to.have.property('{{T_EST}}'); + expect(json.substitutions).to.have.property('{{camelCase}}'); + expect(json.substitutions).to.have.property('{{snake_case}}'); + expect(json.substitutions['{{T_EST}}']).to.equal('Test'); + expect(json.substitutions['{{camelCase}}']).to.equal('Test'); + expect(json.substitutions['{{snake_case}}']).to.equal('Test'); + expect(json.custom_args).to.have.property('T_EST'); + expect(json.custom_args).to.have.property('camelCase'); + expect(json.custom_args).to.have.property('snake_case'); + expect(json.custom_args.T_EST).to.equal('Test'); + expect(json.custom_args.camelCase).to.equal('Test'); + expect(json.custom_args.snake_case).to.equal('Test'); + }); + }); +}); From d945b876e38a1d5cb2d4307e4f9cc7d1b237dd55 Mon Sep 17 00:00:00 2001 From: Divyanshu Maithani Date: Sat, 28 Oct 2017 17:10:15 +0530 Subject: [PATCH 43/62] Add .codeclimate.yml for #557 --- .codeclimate.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .codeclimate.yml diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 000000000..a1b1d52bd --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,15 @@ +--- +engines: + duplication: + enabled: true + config: + languages: + - javascript + eslint: + enabled: true +ratings: + paths: + - "**.js" +exclude_paths: +- node_modules/ +- test/ From 9b37f05ad5b566b5d57d0eeb7836305dfeb83380 Mon Sep 17 00:00:00 2001 From: Divyanshu Maithani Date: Sat, 28 Oct 2017 19:46:50 +0530 Subject: [PATCH 44/62] Update .eslintrc.yaml for #557 --- .eslintrc.yaml | 213 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index a789d98ae..0712935c5 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -134,3 +134,216 @@ rules: no-whitespace-before-property: error no-lonely-if: error no-console: off + + # Possible Errors + no-await-in-loop: off + no-cond-assign: error + no-constant-condition: error + no-control-regex: error + no-debugger: error + no-dupe-args: error + no-dupe-keys: error + no-duplicate-case: error + no-empty-character-class: error + no-empty: error + no-ex-assign: error + no-extra-boolean-cast: error + no-extra-parens: off + no-extra-semi: error + no-func-assign: error + no-inner-declarations: + - error + - functions + no-invalid-regexp: error + no-irregular-whitespace: error + no-negated-in-lhs: error + no-obj-calls: error + no-prototype-builtins: off + no-regex-spaces: error + no-sparse-arrays: error + no-unsafe-finally: off + no-unsafe-negation: off + use-isnan: error + valid-jsdoc: off + valid-typeof: error + + # Best Practices + accessor-pairs: error + array-callback-return: off + block-scoped-var: off + class-methods-use-this: off + complexity: + - error + - 6 + consistent-return: off + default-case: off + dot-location: off + guard-for-in: error + no-alert: error + no-caller: error + no-case-declarations: error + no-div-regex: error + no-else-return: off + no-empty-function: off + no-empty-pattern: error + no-eq-null: error + no-eval: error + no-extend-native: error + no-extra-bind: error + no-extra-label: off + no-fallthrough: error + no-floating-decimal: off + no-global-assign: off + no-implied-eval: error + no-invalid-this: off + no-iterator: error + no-labels: + - error + - allowLoop: true + allowSwitch: true + no-lone-blocks: error + no-loop-func: error + no-magic-number: off + no-native-reassign: error + no-new-func: error + no-new-wrappers: error + no-new: error + no-octal-escape: error + no-octal: error + no-param-reassign: off + no-proto: error + no-restricted-properties: off + no-return-assign: error + no-return-await: off + no-script-url: error + no-self-assign: off + no-self-compare: error + no-sequences: off + no-throw-literal: off + no-unmodified-loop-condition: off + no-unused-expressions: error + no-unused-labels: off + no-useless-call: error + no-useless-concat: error + no-useless-escape: off + no-useless-return: off + no-void: error + no-warning-comments: off + prefer-promise-reject-errors: off + radix: error + require-await: off + vars-on-top: off + + # Strict + strict: off + + # Variables + init-declarations: off + no-catch-shadow: error + no-delete-var: error + no-label-var: error + no-restricted-globals: off + no-shadow-restricted-names: error + no-shadow: off + no-undef-init: error + no-undef: off + no-undefined: off + no-unused-vars: off + no-use-before-define: off + + # Node.js and CommonJS + callback-return: error + global-require: error + handle-callback-err: error + no-mixed-requires: off + no-new-require: off + no-path-concat: error + no-process-env: off + no-process-exit: error + no-restricted-modules: off + no-sync: off + + # Stylistic Issues + camelcase: off + capitalized-comments: off + comma-style: off + func-call-spacing: off + func-name-matching: off + func-names: off + func-style: off + id-length: off + id-match: off + jsx-quotes: off + line-comment-position: off + lines-around-comment: off + lines-around-directive: off + max-depth: off + max-nested-callbacks: off + max-params: off + max-statements-per-line: off + max-statements: + - error + - 30 + multiline-ternary: off + new-parens: off + newline-after-var: off + newline-before-return: off + no-array-constructor: off + no-bitwise: off + no-continue: off + no-inline-comments: off + no-mixed-operators: off + no-multi-assign: off + no-negated-condition: off + no-nested-ternary: off + no-new-object: off + no-plusplus: off + no-restricted-syntax: off + no-tabs: off + no-ternary: off + no-underscore-dangle: off + no-unneeded-ternary: off + object-property-newline: off + one-var: off + operator-assignment: off + operator-linebreak: off + padded-blocks: off + quote-props: off + require-jsdoc: off + sort-keys: off + sort-vars: off + spaced-comment: off + template-tag-spacing: off + unicode-bom: off + wrap-regex: off + + # ECMAScript 6 + arrow-body-style: off + arrow-parens: off + constructor-super: off + no-class-assign: off + no-confusing-arrow: off + no-const-assign: off + no-dupe-class-members: off + no-duplicate-imports: off + no-new-symbol: off + no-restricted-imports: off + no-this-before-super: off + no-useless-computed-key: off + no-useless-constructor: off + no-useless-rename: off + no-var: off + object-shorthand: off + prefer-arrow-callback: off + prefer-const: off + prefer-destructuring: off + prefer-numeric-literals: off + prefer-rest-params: off + prefer-reflect: off + prefer-spread: off + prefer-template: off + require-yield: off + rest-spread-spacing: off + sort-imports: off + symbol-description: off + yield-star-spacing: off From 4f73c88cd2800072835c63826a32aff898d9d444 Mon Sep 17 00:00:00 2001 From: Varayut Lerdkanlayanawat Date: Sat, 28 Oct 2017 17:29:40 +0200 Subject: [PATCH 45/62] Update the license file to have the correct date range --- packages/subscription-widget/LICENSE.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/subscription-widget/LICENSE.txt b/packages/subscription-widget/LICENSE.txt index f7f6d4784..f3cd0ef82 100644 --- a/packages/subscription-widget/LICENSE.txt +++ b/packages/subscription-widget/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 SendGrid, Inc. +Copyright (c) 2012-2017 SendGrid, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. From 02125c9b4d1ef44d869fe5fa029d9a36cfa4be56 Mon Sep 17 00:00:00 2001 From: Varayut Lerdkanlayanawat Date: Sat, 28 Oct 2017 18:28:55 +0200 Subject: [PATCH 46/62] Add a unittest to check the license.md file date range --- license.spec.js | 18 ++++++++++++++++++ package.json | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 license.spec.js diff --git a/license.spec.js b/license.spec.js new file mode 100644 index 000000000..8a5e3c4a6 --- /dev/null +++ b/license.spec.js @@ -0,0 +1,18 @@ +'use strict'; + +/** + * Dependencies + */ +const fs = require("fs"); + +/** + * Tests + */ +describe('LICENSE', () => { + it('should contain the current year as the end year of the license', () => { + const license = fs.readFileSync(`${process.cwd()}/LICENSE.md`, 'utf8'); + const currentYear= (new Date()).getFullYear(); + return expect(license.indexOf(`-${currentYear}`)).to.not.equal(-1); + }); +}); + diff --git a/package.json b/package.json index ba9092b57..48b6517ad 100644 --- a/package.json +++ b/package.json @@ -27,11 +27,12 @@ "lint": "eslint . --fix", "prism:install": "curl https://raw.githubusercontent.com/stoplightio/prism/master/install.sh | sh", "prism": "prism run --mock --list --spec https://raw.githubusercontent.com/sendgrid/sendgrid-oai/master/oai_stoplight.json", - "test:all": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/**/*.spec.js\"", + "test:all": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"**/*.spec.js\"", "test:helpers": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/helpers/**/*.spec.js\"", "test:client": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/client/**/*.spec.js\"", "test:mail": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/mail/**/*.spec.js\"", "test:contact": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha \"packages/contact-importer/**/*.spec.js\"", + "test:license": "babel-node ./node_modules/istanbul/lib/cli cover ./node_modules/mocha/bin/_mocha license.spec.js", "test:typescript": "tsc", "test": "npm run test:all -s", "coverage": "open -a \"Google Chrome\" ./coverage/lcov-report/index.html" From 8b74906a429e8bf76994330005cb8372a6318c14 Mon Sep 17 00:00:00 2001 From: Varayut Lerdkanlayanawat Date: Sat, 28 Oct 2017 19:02:24 +0200 Subject: [PATCH 47/62] Set up travis to run test:license --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9429150c8..fce3fbed3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ script: - yarn test:client - yarn test:helpers - yarn test:typescript +- yarn test:license notifications: hipchat: rooms: From be5e4c9290391c1ab9b41f5f98c472d0099be7be Mon Sep 17 00:00:00 2001 From: mptap Date: Sat, 28 Oct 2017 11:43:06 -0700 Subject: [PATCH 48/62] Added unittest to check for specific repo files --- test/test.js | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 test/test.js diff --git a/test/test.js b/test/test.js new file mode 100644 index 000000000..eb0dc44a2 --- /dev/null +++ b/test/test.js @@ -0,0 +1,81 @@ +var assert = require('assert'); +var should = require('should'); +var fs = require('fs'); + +describe('sendgrid-nodejs repo', function() { + it('should have ./Docker or docker/Docker file', function() { + assert(fileExists('Docker') || fileExists('docker/Docker')); + }); + + it('should have ./docker-compose.yml or ./docker/docker-compose.yml file', function() { + assert(fileExists('docker-compose.yml') || fileExists('docker/docker-compose.yml')); + }); + + it('should have ./.env_sample file', function() { + assert(fileExists('.env_sample')); + }); + + it('should have ./.gitignore file', function() { + assert(fileExists('.gitignore')); + }); + + it('should have ./.travis.yml file', function() { + assert(fileExists('.travis.yml')); + }); + + it('should have ./.codeclimate.yml file', function() { + assert(fileExists('.codeclimate.yml')); + }); + + it('should have ./CHANGELOG.md file', function() { + assert(fileExists('CHANGELOG.md')); + }); + + it('should have ./CODE_OF_CONDUCT.md file', function() { + assert(fileExists('CODE_OF_CONDUCT.md')); + }); + + it('should have ./CONTRIBUTING.md file', function() { + assert(fileExists('CONTRIBUTING.md')); + }); + + it('should have ./.github/ISSUE_TEMPLATE file', function() { + assert(fileExists('.github/ISSUE_TEMPLATE')); + }); + + it('should have ./LICENSE.md file', function() { + assert(fileExists('LICENSE.md')); + }); + + it('should have ./.github/PULL_REQUEST_TEMPLATE file', function() { + assert(fileExists('.github/PULL_REQUEST_TEMPLATE')); + }); + + it('should have ./README.md file', function() { + assert(fileExists('README.md')); + }); + + it('should have ./TROUBLESHOOTING.md file', function() { + assert(fileExists('TROUBLESHOOTING.md')); + }); + + it('should have ./USAGE.md file', function() { + assert(fileExists('USAGE.md')); + }); + + it('should have ./USE_CASES.md file', function() { + assert(fileExists('USE_CASES.md')); + }); + + function fileExists(filepath) { + try { + return fs.statSync(filepath).isFile(); + } catch(e) { + if (e.code === 'ENOENT') { + console.log('' + filepath + ' doesn\'t exist.'); + return false; + } + throw e; + } + } +}); From 43dba0a76ef19f85525e815ad9ee25d4d633b021 Mon Sep 17 00:00:00 2001 From: mptap Date: Sat, 28 Oct 2017 12:29:38 -0700 Subject: [PATCH 49/62] Addressed comments --- .travis.yml | 1 + test/{test.js => files.spec.js} | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename test/{test.js => files.spec.js} (97%) diff --git a/.travis.yml b/.travis.yml index 9429150c8..a2cdda216 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ script: - yarn test:client - yarn test:helpers - yarn test:typescript +- yarn test:files.spec notifications: hipchat: rooms: diff --git a/test/test.js b/test/files.spec.js similarity index 97% rename from test/test.js rename to test/files.spec.js index eb0dc44a2..5b8744341 100644 --- a/test/test.js +++ b/test/files.spec.js @@ -2,7 +2,7 @@ var assert = require('assert'); var should = require('should'); var fs = require('fs'); -describe('sendgrid-nodejs repo', function() { +describe('nodemailer-sendgrid-transport repo', function() { it('should have ./Docker or docker/Docker file', function() { assert(fileExists('Docker') || fileExists('docker/Docker')); }); From 84eadb9d53ade916b8013d66ac94444c3be97f85 Mon Sep 17 00:00:00 2001 From: mptap Date: Sat, 28 Oct 2017 12:36:01 -0700 Subject: [PATCH 50/62] Resolve merge conflicts --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a2cdda216..219a91a38 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ script: - yarn test:helpers - yarn test:typescript - yarn test:files.spec +- yarn test:license notifications: hipchat: rooms: From 5d3bacb0c98c3186dade6edfc5023ef5fb898215 Mon Sep 17 00:00:00 2001 From: Ben Redden Date: Sat, 28 Oct 2017 16:16:50 -0400 Subject: [PATCH 51/62] updating readme from using mv to cp --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a386e04ea..346c793ee 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ This library is broken up into several packages as a monorepo so that you only n ## .env file -You will find a file in the root of the project called .env_sample. You can run `mv .env_sample .env` or manually rename the file to `.env`; be sure to add your [API key](https://sendgrid.com/docs/User_Guide/Settings/api_keys.html#-Creating-an-API-key). +You will find a file in the root of the project called .env_sample. You can run `cp .env_sample .env` or manually rename the file to `.env`; be sure to add your [API key](https://sendgrid.com/docs/User_Guide/Settings/api_keys.html#-Creating-an-API-key). * [@sendgrid/mail](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/mail) - if you just want to send email * [@sendgrid/client](https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages/client) - to use all other [SendGrid v3 Web API endpoints](https://sendgrid.com/docs/API_Reference/api_v3.html) From cb0eea752869a531396ff86c89c6b6a555a3dcd2 Mon Sep 17 00:00:00 2001 From: duncanleung Date: Sat, 28 Oct 2017 17:34:04 -0700 Subject: [PATCH 52/62] Create PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..ba377ae70 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,24 @@ + +# Fixes # + +### Checklist +- [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) +- [ ] I have read the [Contribution Guide] and my PR follows them. +- [ ] I updated my branch with the master branch. +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have added necessary documentation about the functionality in the appropriate .md file +- [ ] I have added in line documentation to the code I modified + +### Short description of what this PR does: +- +- + +If you have questions, please send an email to [Sendgrid](mailto:dx@sendgrid.com), or file a Github Issue in this repository. \ No newline at end of file From d43fde69bf9c6745b815ef6ddf99c1f229412dd0 Mon Sep 17 00:00:00 2001 From: thepriefy Date: Sun, 29 Oct 2017 09:57:55 +0700 Subject: [PATCH 53/62] create PULL_REQUEST_TEMPLATE --- .github/PULL_REQUEST_TEMPLATE | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE new file mode 100644 index 000000000..7ad590b42 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE @@ -0,0 +1,24 @@ + +# Fixes # + +### Checklist +- [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) +- [ ] I have read the [Contribution Guide] and my PR follows them. +- [ ] I updated my branch with the master branch. +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have added necessary documentation about the functionality in the appropriate .md file +- [ ] I have added in line documentation to the code I modified + +### Short description of what this PR does: +- +- + +If you have questions, please send an email to [Sendgrid](mailto:dx@sendgrid.com), or file a Github Issue in this repository. From e9b0e49aed71c3f6da5875dee259ec57cb105de7 Mon Sep 17 00:00:00 2001 From: thepriefy Date: Sun, 29 Oct 2017 22:44:30 +0700 Subject: [PATCH 54/62] update README.md fix invalid license url --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 615df8bf5..0176fec7d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Email Notifications Badge](https://dx.sendgrid.com/badge/nodejs)](https://dx.sendgrid.com/newsletter/nodejs) [![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid) [![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/sendgrid-nodejs.svg)](https://github.com/sendgrid/sendgrid-nodejs/graphs/contributors) -[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.txt) +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/sendgrid/sendgrid-nodejs/blob/master/LICENSE.md) **This library allows you to quickly and easily use the SendGrid Web API v3 via Node.js.** @@ -71,4 +71,4 @@ sendgrid-nodejs is maintained and funded by SendGrid, Inc. The names and logos f # License -[The MIT License (MIT)](LICENSE.txt) +[The MIT License (MIT)](https://github.com/sendgrid/sendgrid-nodejs/blob/master/LICENSE.md) From a6df6dc00ddd7dd46460f658da230de690f4414f Mon Sep 17 00:00:00 2001 From: Shiva Kaushal Date: Sun, 29 Oct 2017 14:25:49 -0400 Subject: [PATCH 55/62] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 51 ++++++++++++-------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bbb4b0033..7ad590b42 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,37 +1,24 @@ - - -**Description of the change**: - -**Reason for the change**: - -**Link to original source**: +# Fixes # ### Checklist - -Make sure all of these items are complete, or else the PR will be ineligible for a code review. - -- [ ] Code passes all existing [tests](https://github.com/sendgrid/open-source-library-data-collector/tree/master/test) -- [ ] Any new functionality added includes new unit tests in [`tests/test.py`](https://github.com/sendgrid/open-source-library-data-collector/blob/master/test/test.py) -- [ ] Create or update example code to show the new functionality in action. -- [ ] All code, branch, and git naming and style conventions are followed (see [`CONTRIBUTING.md`](https://github.com/sendgrid/open-source-library-data-collector/blob/master/CONTRIBUTING.md#style-guidelines--naming-conventions)) -- [ ] Feature branch has been rebased off of the latest `master` branch. ( see [`CONTRIBUTING.md`](https://github.com/sendgrid/open-source-library-data-collector/blob/master/CONTRIBUTING.md#creating-a-pull-request) ). - -If you have questions, please send an email [Sendgrid](mailto:dx@sendgrid.com), or file a Github Issue in this repository. - - +- [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) +- [ ] I have read the [Contribution Guide] and my PR follows them. +- [ ] I updated my branch with the master branch. +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have added necessary documentation about the functionality in the appropriate .md file +- [ ] I have added in line documentation to the code I modified + +### Short description of what this PR does: +- +- + +If you have questions, please send an email to [Sendgrid](mailto:dx@sendgrid.com), or file a Github Issue in this repository. From 5f9a6a75878cdb43fe3056088ea2ae2942302ff4 Mon Sep 17 00:00:00 2001 From: Shubham Padia Date: Mon, 30 Oct 2017 01:49:55 +0530 Subject: [PATCH 56/62] Fix broken link in handling errors sections --- TROUBLESHOOTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index df7a258fa..aacd7a914 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -64,7 +64,7 @@ Click the "Clone or download" green button in [GitHub](https://github.com/sendgr ## Error Messages -To read the error message returned by SendGrid's API, please see [this example](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/mail/USE_CASES.md#successfailureerrors). +To read the error message returned by SendGrid's API, please see [this example](https://github.com/sendgrid/sendgrid-nodejs/blob/master/packages/mail/USE_CASES.md#success-failure-errors). ## Versions From 034441e2795c5aed68996270de796cd365292aed Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 30 Oct 2017 22:10:03 -0700 Subject: [PATCH 57/62] v6.1.4 --- lerna.json | 2 +- packages/client/package.json | 4 ++-- packages/contact-importer/package.json | 2 +- packages/helpers/package.json | 2 +- packages/inbound-mail-parser/package.json | 4 ++-- packages/mail/package.json | 6 +++--- packages/subscription-widget/package.json | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lerna.json b/lerna.json index 5b8943215..e37353779 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ "packages": [ "packages/*" ], - "version": "6.1.3" + "version": "6.1.4" } diff --git a/packages/client/package.json b/packages/client/package.json index b326e982e..2e302878a 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/client", "description": "SendGrid NodeJS API client", - "version": "6.1.3", + "version": "6.1.4", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", @@ -27,7 +27,7 @@ "node": ">=6.0.0" }, "dependencies": { - "@sendgrid/helpers": "^6.1.3", + "@sendgrid/helpers": "^6.1.4", "@types/request": "^2.0.3", "request": "^2.81.0" }, diff --git a/packages/contact-importer/package.json b/packages/contact-importer/package.json index 53b6a8448..5e40baff1 100644 --- a/packages/contact-importer/package.json +++ b/packages/contact-importer/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/contact-importer", "description": "SendGrid NodeJS contact importer", - "version": "6.1.0", + "version": "6.1.4", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", diff --git a/packages/helpers/package.json b/packages/helpers/package.json index 1e0ecc3a3..bc0468203 100644 --- a/packages/helpers/package.json +++ b/packages/helpers/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/helpers", "description": "SendGrid NodeJS internal helpers", - "version": "6.1.3", + "version": "6.1.4", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", diff --git a/packages/inbound-mail-parser/package.json b/packages/inbound-mail-parser/package.json index 379f784c6..567f9c8e5 100644 --- a/packages/inbound-mail-parser/package.json +++ b/packages/inbound-mail-parser/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/inbound-mail-parser", "description": "SendGrid NodeJS inbound mail parser", - "version": "6.1.3", + "version": "6.1.4", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", @@ -26,7 +26,7 @@ "node": ">=6.0.0" }, "dependencies": { - "@sendgrid/helpers": "^6.1.3", + "@sendgrid/helpers": "^6.1.4", "mailparser": "^0.6.1" }, "tags": [ diff --git a/packages/mail/package.json b/packages/mail/package.json index dc7091db4..c571fb793 100644 --- a/packages/mail/package.json +++ b/packages/mail/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/mail", "description": "SendGrid NodeJS mail service", - "version": "6.1.3", + "version": "6.1.4", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", @@ -27,8 +27,8 @@ "access": "public" }, "dependencies": { - "@sendgrid/client": "^6.1.3", - "@sendgrid/helpers": "^6.1.3" + "@sendgrid/client": "^6.1.4", + "@sendgrid/helpers": "^6.1.4" }, "tags": [ "http", diff --git a/packages/subscription-widget/package.json b/packages/subscription-widget/package.json index 5defb865d..d4ce8f668 100644 --- a/packages/subscription-widget/package.json +++ b/packages/subscription-widget/package.json @@ -1,6 +1,6 @@ { - "name": "signup", - "version": "1.0.0", + "name": "@sendgrid/subscription-widget", + "version": "6.1.4", "description": "Double opt-in email automation", "main": "index.js", "scripts": { From 8eccf2bec0b56d8102042002106d738b2ad775dd Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 30 Oct 2017 22:10:41 -0700 Subject: [PATCH 58/62] v6.1.5 --- lerna.json | 2 +- packages/client/package.json | 4 ++-- packages/contact-importer/package.json | 2 +- packages/helpers/package.json | 2 +- packages/inbound-mail-parser/package.json | 4 ++-- packages/mail/package.json | 6 +++--- packages/subscription-widget/package.json | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lerna.json b/lerna.json index e37353779..1bebe92c5 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ "packages": [ "packages/*" ], - "version": "6.1.4" + "version": "6.1.5" } diff --git a/packages/client/package.json b/packages/client/package.json index 2e302878a..a7c5f61a3 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/client", "description": "SendGrid NodeJS API client", - "version": "6.1.4", + "version": "6.1.5", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", @@ -27,7 +27,7 @@ "node": ">=6.0.0" }, "dependencies": { - "@sendgrid/helpers": "^6.1.4", + "@sendgrid/helpers": "^6.1.5", "@types/request": "^2.0.3", "request": "^2.81.0" }, diff --git a/packages/contact-importer/package.json b/packages/contact-importer/package.json index 5e40baff1..119329eb5 100644 --- a/packages/contact-importer/package.json +++ b/packages/contact-importer/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/contact-importer", "description": "SendGrid NodeJS contact importer", - "version": "6.1.4", + "version": "6.1.5", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", diff --git a/packages/helpers/package.json b/packages/helpers/package.json index bc0468203..f8728c3f0 100644 --- a/packages/helpers/package.json +++ b/packages/helpers/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/helpers", "description": "SendGrid NodeJS internal helpers", - "version": "6.1.4", + "version": "6.1.5", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", diff --git a/packages/inbound-mail-parser/package.json b/packages/inbound-mail-parser/package.json index 567f9c8e5..ef445ce0e 100644 --- a/packages/inbound-mail-parser/package.json +++ b/packages/inbound-mail-parser/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/inbound-mail-parser", "description": "SendGrid NodeJS inbound mail parser", - "version": "6.1.4", + "version": "6.1.5", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", @@ -26,7 +26,7 @@ "node": ">=6.0.0" }, "dependencies": { - "@sendgrid/helpers": "^6.1.4", + "@sendgrid/helpers": "^6.1.5", "mailparser": "^0.6.1" }, "tags": [ diff --git a/packages/mail/package.json b/packages/mail/package.json index c571fb793..496f5615d 100644 --- a/packages/mail/package.json +++ b/packages/mail/package.json @@ -1,7 +1,7 @@ { "name": "@sendgrid/mail", "description": "SendGrid NodeJS mail service", - "version": "6.1.4", + "version": "6.1.5", "author": "SendGrid (sendgrid.com)", "contributors": [ "Kyle Partridge ", @@ -27,8 +27,8 @@ "access": "public" }, "dependencies": { - "@sendgrid/client": "^6.1.4", - "@sendgrid/helpers": "^6.1.4" + "@sendgrid/client": "^6.1.5", + "@sendgrid/helpers": "^6.1.5" }, "tags": [ "http", diff --git a/packages/subscription-widget/package.json b/packages/subscription-widget/package.json index d4ce8f668..8f4ca4a9c 100644 --- a/packages/subscription-widget/package.json +++ b/packages/subscription-widget/package.json @@ -1,6 +1,6 @@ { "name": "@sendgrid/subscription-widget", - "version": "6.1.4", + "version": "6.1.5", "description": "Double opt-in email automation", "main": "index.js", "scripts": { From 0203bf5daf0d47865a49dc4c93293c77bd088617 Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 30 Oct 2017 22:11:56 -0700 Subject: [PATCH 59/62] v6.1.5 --- packages/subscription-widget/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/subscription-widget/package.json b/packages/subscription-widget/package.json index 8f4ca4a9c..1389de7a0 100644 --- a/packages/subscription-widget/package.json +++ b/packages/subscription-widget/package.json @@ -17,6 +17,9 @@ "sendgrid": "^4.0.2", "sendgrid-rest": "^2.2.1" }, + "publishConfig": { + "access": "public" + }, "engines": { "node": "4.1.1" } From e38eb8f4987a0f5128c72ec43761051bc18f8574 Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 30 Oct 2017 22:16:36 -0700 Subject: [PATCH 60/62] v6.1.5 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa3fac636..0304e2244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log All notable changes to this project will be documented in this file. +## [6.1.5] - 2017-10-30 ## +### Updated +- [Pull #542](https://github.com/sendgrid/sendgrid-nodejs/pull/542): Turn ContactImporter into ES6 class +- Thanks to [Seth Etter](https://github.com/sethetter) for the PR! + ## [6.1.4] - 2017-09-11 ## ### Updated - [Pull #445](https://github.com/sendgrid/sendgrid-nodejs/pull/445): Documentation Updates for better DX/UX From a017038a6a0d4959e0705a9a4f72ed37231278fe Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 30 Oct 2017 22:22:28 -0700 Subject: [PATCH 61/62] v6.1.6 --- lerna.json | 2 +- packages/subscription-widget/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 1bebe92c5..5eaf3575a 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ "packages": [ "packages/*" ], - "version": "6.1.5" + "version": "6.1.6" } diff --git a/packages/subscription-widget/package.json b/packages/subscription-widget/package.json index 1389de7a0..4b58757ec 100644 --- a/packages/subscription-widget/package.json +++ b/packages/subscription-widget/package.json @@ -1,6 +1,6 @@ { "name": "@sendgrid/subscription-widget", - "version": "6.1.5", + "version": "6.1.6", "description": "Double opt-in email automation", "main": "index.js", "scripts": { From 1128d3efe91a148e8ba5a50b9c07e8fdbe4d3b28 Mon Sep 17 00:00:00 2001 From: Marghodk Date: Tue, 31 Oct 2017 13:16:19 -0600 Subject: [PATCH 62/62] Sr. Front End Engineer job posting in Announcements --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 46a83d6fb..3429afa7a 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ You will find a file in the root of the project called .env_sample. You can run All updates to this library are documented in our [CHANGELOG](https://github.com/sendgrid/sendgrid-nodejs/blob/master/CHANGELOG.md) and [releases](https://github.com/sendgrid/sendgrid-nodejs/releases). You may also subscribe to email [release notifications](https://dx.sendgrid.com/newsletter/nodejs) for releases and breaking changes. +Join an experienced and passionate team that focuses on making an impact. Opportunities abound to grow the product - and grow your career! [Sr. Front End Engineer- MC](http://grnh.se/thy5pa1) + # Roadmap