Skip to content

Instantly share code, notes, and snippets.

@pittgoose
Created January 17, 2017 10:51
Show Gist options
  • Save pittgoose/f29a653b8cac18fe794169ef40c2a24b to your computer and use it in GitHub Desktop.
Save pittgoose/f29a653b8cac18fe794169ef40c2a24b to your computer and use it in GitHub Desktop.
Typescript class for using Node Gmail API and Protractor
// Required packages:
// google-auth-library
// googleapis
// @types/lodash
// @types/node (for 'fs')
// protractor
// retry
// First step is to follow the instructions here and get your client ID, client secret, and redirect uris:
// https://developers.google.com/gmail/api/quickstart/nodejs
import * as fs from 'fs';
import * as _ from 'lodash';
import {browser} from "protractor";
let retry = require('retry'),
googleAuth = require('google-auth-library'),
google = require('googleapis'),
gmail = google.gmail('v1');
export class GmailHelper {
// Getting an auth object
static getAuth() {
let auth = new googleAuth(),
oauth2Client = new auth.OAuth2(
myCreds.client_id,
myCreds.client_secret,
myCreds.redirect_uris[0]
),
oauth2Client.credentials = {however a cred json looks like};
return oauth2Client;
}
// Converts the query passed as an object into a string
private static convertQuery(query): string {
return _.map(query, (operator, item) => `${item}:${operator}`).join(' ');
}
// Retrieve a list of emails, matching the specified query, from the authenticated inbox. The query is an object like: {from: ''}
searchForEmails(query): Promise<Array<any>> {
return this.googleCallWrapper(cb => {
gmail.users.messages.list({
auth: GmailHelper.getAuth(),
userId: 'me',
q: GmailHelper.convertQuery(query)
}, cb)
}, (err, res) => {
return err ? err : res.messages == undefined;
}).then((res) => res.messages);
}
// Retrieve the full data of a specific email from the authenticated inbox
getEmailContent(id): Promise<any> {
return this.googleCallWrapper(cb => {
gmail.users.messages.get({
auth: GmailHelper.getAuth(),
userId: 'me',
id: id
}, cb)
}, (err, res) => {
return err;
}).then((res) => res);
}
// Wraps all types of gmail calls into promise notation and retries the call x number of times with a scaling up timeout
// Also performs `browser.waitForAngular()` before the call in order to allow the operation on the page to finish before
// checking for the email
/**
* @param googleCall {Function(googleCallback: Function) : Void} a function which performs a GoogleAPI call. When called, it is passed a GoogleAPI callback function which needs to be passed to the GoogleAPI
* @param shouldRetry {Function(error: string, response: Object) : boolean} a function which decides whether we should retry the GoogleAPI call. When called, it is passed the same arguments as the GoogleAPI callback function. It should return true if an error occurred or if the response is not satisfactory
**/
googleCallWrapper(googleCall, shouldRetry): Promise<any> {
return new Promise((resolve, reject) => {
let operation = retry.operation({
retries: 4,
minTimeout: 1000,
maxTimeout: 3000,
factor: 1.5,
});
return browser.waitForAngular().then(() =>
operation.attempt(function (currentAttempt) {
googleCall((err, res) => {
if (operation.retry(shouldRetry(err, res))) {
console.log('Retrying the email check');
return;
}
if (err) {
console.log('Email not found!');
reject(err)
} else {
console.log('Email found!');
resolve(res)
}
});
})
).catch((err) => {
reject(err)
});
})
}
}
import {GmailHelper} from "gmail-helper";
let gmailHelper = new GmailHelper,
userEmail = [email protected];
describe('Users receive emails', ()=> {
it('and it arrives', (done)=> {
// protractor steps here which send the user an email
gmailHelper.searchForEmails({to: userEmail}).then((emails) => { // see example-emails.json for example
gmailHelper.getEmailContent(emails[0].id).then((emailData) => { // see example-emailData.json for example
expect(emailData.snippet).toBe('expected snippet');
}).then(() => done());
});
};
};
[
{
"id": "159ab9cfa0b5f30e",
"threadId": "159a0d35184ee9be"
},
{
"id": "159ab9cfa0b5f30e",
"threadId": "159a0d35184ee9be"
},
{
"id": "159ab9cfa0b5f30e",
"threadId": "159a0d35184ee9be"
},
]
{
"id": "159ab9cfa0b5f30e",
"threadId": "159a0d35184ee9be",
"labelIds": [
"UNREAD",
"CATEGORY_PERSONAL",
"INBOX"
],
"snippet": "Example snippet",
"historyId": "46433",
"internalDate": "1484642908000",
"payload": {
"partId": "",
"mimeType": "text/html",
"filename": "",
"headers": [
{
"name": "Delivered-To",
"value": "<redacted>@gmail.com"
},
{
"name": "Received",
"value": "<redacted>"
},
{
"name": "X-Received",
"value": "<redacted>"
},
{
"name": "Return-Path",
"value": "<redacted>"
},
{
"name": "Received",
"value": "<redacted>"
},
{
"name": "Received-SPF",
"value": "<redacted>"
},
{
"name": "Authentication-Results",
"value": "<redacted>"
},
{
"name": "DKIM-Signature",
"value": "<redacted>"
},
{
"name": "Received",
"value": "<redacted>"
},
{
"name": "DKIM-Signature",
"value": "<redacted>"
},
{
"name": "From",
"value": "[email protected]"
},
{
"name": "Sender",
"value": "Example <[email protected]>"
},
{
"name": "Subject",
"value": "Example email subject"
},
{
"name": "Return-Path",
"value": "<redacted>"
},
{
"name": "Received",
"value": "<redacted>"
},
{
"name": "To",
"value": "[email protected]"
},
{
"name": "X-Report-Abuse",
"value": "Please forward a copy of this message, including all headers, to [email protected]"
},
{
"name": "X-Report-Abuse",
"value": "<redacted>"
},
{
"name": "X-Mandrill-User",
"value": "<redacted>"
},
{
"name": "Message-Id",
"value": "<redacted>"
},
{
"name": "Date",
"value": "Tue, 17 Jan 2017 08:48:28 +0000"
},
{
"name": "MIME-Version",
"value": "1.0"
},
{
"name": "Content-Type",
"value": "text/html; charset=utf-8"
},
{
"name": "Content-Transfer-Encoding",
"value": "7bit"
}
],
"body": {
"size": 1068,
"data": "<redacted email body in base64 encoding>"
}
},
"sizeEstimate": 4801
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment