Code Monkey home page Code Monkey logo

gmail-tester's Introduction

gmail-tester

gmail-tester

npm version NPM downloads License: MIT GitHub stars

A simple Node.js Gmail client which checks/returns email message(s) straight from any Gmail-powered account (both private and company).
There are two main functionalities this library provides:

  1. check_inbox(): Polls a mailbox for a given amount of time. At the end of the operation, the desired message is returned (if found).
  2. get_messages(): Can be used to perform various assertions on the email objects (see example below).

P.S, I have written a story on medium, how using Cypress, we are testing our user registration process at Tastewise.

Usage

  1. Install using npm:
npm install --save-dev gmail-tester
  1. Save the Google Cloud Platform OAuth2 Authentication file named credentials.json inside an accessible directory (see instructions below).
  2. In terminal, run the following command:
node <node_modules>/gmail-tester/init.js <path-to-credentials.json> <path-to-token.json> <target-email>

<path-to-credentials.json> Is the path to OAuth2 Authentication file.
<path-to-token.json> Is the path to OAuth2 token. If it doesn't exist, the script will create it.
The script will prompt you to go to google.com to activate a token. Go to the given link, and select the account for <target-email>. Grant permission to view your email messages and settings. At the end of the process you should see the token:

copy-token

Hit the copy button and paste it to init.js script. The process should look like this:

Run script

How to get credentials.json?

  1. Follow the instructions to Create a client ID and client secret. Make sure to select Desktop app for the application type.

  2. Once done, go to https://console.cloud.google.com/apis/credentials?project=(project-name)&folder&organizationId and download the OAuth2 credentials file, as shown in the image below. Make sure to replace (project-name) with your project name.

    Get credentials.json

    The credentials.json file should look like this:

    Credentials file

  3. Make sure the Gmail API is activated for your account.

If everything is done right, the last output from the script should be:

[gmail] Found!

Congratulations! gmail-tester is ready to use.

⛔️ Never share or commit credentials.json nor token.json!!! Whoever has it will have full access to your inbox!

API

get_messages(credentials, token, options)

credentials: Path to credentials JSON file or JSON Object.
token: Path to OAuth2 token file or JSON Object.
options:

  • from: String. Filter on the email address of the receiver.
  • to: String. Filter on the email address of the sender.
  • subject: String. Filter on the subject of the email.
  • include_body: boolean. Set to true to fetch decoded email bodies.
  • include_attachments: boolean. Set to true to fetch the base64-encoded email attachments.
  • before: Date. Filter messages received before the specified date.
  • after: Date. Filter messages received after the specified date.
  • label: String. The default label is 'INBOX', but can be changed to 'SPAM', 'TRASH' or a custom label. For a full list of built-in labels, see https://developers.google.com/gmail/api/guides/labels?hl=en

Returns: An array of email objects with the following fields:

[
  {
    from: "Human Friendly Name <sender@email-address>",
    receiver: "your@email-address",
    subject: "string",
    body: {
      html: "string",
      text: "string"
    }
  }
  // ...
];

Some senders will send you text/html content, the others will send you plain/text, and some will send you both. Make sure you are looking for the content in the right body field.

check_inbox(credentials, token, options = {})

credentials: Path to credentials JSON file or JSON Object.
token: Path to OAuth2 token file or JSON Object.
options:

  • from: String. Filter on the email address of the receiver.
  • to: String. Filter on the email address of the sender.
  • subject: String. Filter on the subject of the email.
  • include_body: boolean. Set to true to fetch decoded email bodies.
  • include_attachments: boolean. Set to true to fetch the base64-encoded email attachments.
  • before: Date. Filter messages received before the specified date.
  • after: Date. Filter messages received after the specified date.
  • wait_time_sec: Integer. Interval between inbox checks (in seconds). Default: 30 seconds.
  • max_wait_time_sec: Integer. Maximum wait time (in seconds). When reached and the email was not found, the script exits. Default: 60 seconds.
  • label: String. The default label is 'INBOX', but can be changed to 'SPAM', 'TRASH' or a custom label. For a full list of built-in labels, see https://developers.google.com/gmail/api/guides/labels?hl=en

Returns: An array of email objects with the following fields:

[
  {
    from: "Human Friendly Name <sender@email-address>",
    receiver: "your@email-address",
    subject: "string",
    body: {
      html: "string",
      text: "string"
    }
  }
  // ...
];

In addition, verbose messages will be written to console.

refresh_access_token(credentials, token)

credentials: Path to credentials JSON file or JSON Object.
token: Path to OAuth2 token file or JSON Object.

Refresh the access token. A new file will overwrite the existing one in token_path.

Example

Using check_inbox() to look for a specific message:

const path = require("path");
const gmail = require("gmail-tester");
const email = await gmail.check_inbox(
  path.resolve(__dirname, "credentials.json"), // Assuming credentials.json is in the current directory.
  path.resolve(__dirname, "gmail_token.json"), // Look for gmail_token.json in the current directory (if it doesn't exists, it will be created by the script).
  {
    subject: "Activate Your Account", // We are looking for 'Activate Your Account' in the subject of the message.
    from: "[email protected]", // We are looking for a sender header which is '[email protected]'.
    to: "<target-email>", // Which inbox to poll. credentials.json should contain the credentials to it.
    wait_time_sec: 10, // Poll interval (in seconds).
    max_wait_time_sec: 30, // Maximum poll time (in seconds), after which we'll giveup.
    include_body: true
  }
);
if (email) {
  console.log("Email was found!");
} else {
  console.log("Email was not found!");
}

Using get_messages() to assert email body using Cypress

cypress.config.js:

const { defineConfig } = require("cypress");
const gmailTester = require("gmail-tester");
const path = require("path");

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on("task", {
        "gmail:get-messages": async (args) => {
          const messages = await gmailTester.get_messages(
            path.resolve(__dirname, "credentials.json"),
            path.resolve(__dirname, "token.json"),
            args.options
          );
          return messages;
        },
      });
    },
  },
});

spec.cy.js:

/// <reference types="Cypress" />

describe("Email assertion:", () => {
  it("Using gmail_tester.get_messages(), look for an email with specific subject and link in email body", function () {
    // debugger; //Uncomment for debugger to work...
    cy.task("gmail:get-messages", {
      options: {
        from: "[email protected]",
        subject: "Ubisoft Password Change Request",
        include_body: true,
        before: new Date(2019, 8, 24, 12, 31, 13), // Before September 24rd, 2019 12:31:13
        after: new Date(2019, 7, 23), // After August 23, 2019
      },
    }).then((emails) => {
      assert.isAtLeast(
        emails.length,
        1,
        "Expected to find at least one email, but none were found!"
      );
      const body = emails[0].body.html;
      assert.isTrue(
        body.indexOf(
          "https://account-uplay.ubi.com/en-GB/action/change-password?genomeid="
        ) >= 0,
        "Found reset link!"
      );
    });
  });
});

Contributors

 

Please feel free to contribute to this project.

Credits

gmail-tester's People

Contributors

ash0080 avatar borhan10 avatar chris-catignani avatar danielvdbos avatar dependabot[bot] avatar kdepp avatar kshmidt avatar larabr avatar levz0r avatar matteomolinari93 avatar nigelzor avatar paulmwhite avatar templth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

gmail-tester's Issues

Can't start server

Hello,

I apply gmail-tester for my example but I got an issue about start server

I run OS; Mac: 10.15.2 and chrome: 79 and cypress: 3.8.0
My log:
Can't start server

Cypress failed to make a connection to the Chrome DevTools Protocol after retrying for 20 seconds.

This usually indicates there was a problem opening the Chrome browser.

The CDP port requested was 53784.

Error details:

Error: connect ECONNREFUSED 127.0.0.1:53784 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1056:14)

=====================
Failed to connect to Chrome, retrying in 1 second (attempt 18/32)
Failed to connect to Chrome, retrying in 1 second (attempt 19/32)
Failed to connect to Chrome, retrying in 1 second (attempt 20/32)
Failed to connect to Chrome, retrying in 1 second (attempt 21/32)
HEAD / - - ms - -
HEAD / - - ms - -
HEAD / - - ms - -
Failed to connect to Chrome, retrying in 1 second (attempt 22/32)
Failed to connect to Chrome, retrying in 1 second (attempt 23/32)
Failed to connect to Chrome, retrying in 1 second (attempt 24/32)
Failed to connect to Chrome, retrying in 1 second (attempt 25/32)
Failed to connect to Chrome, retrying in 1 second (attempt 26/32)
Failed to connect to Chrome, retrying in 1 second (attempt 27/32)
Failed to connect to Chrome, retrying in 1 second (attempt 28/32)
Failed to connect to Chrome, retrying in 1 second (attempt 29/32)
Failed to connect to Chrome, retrying in 1 second (attempt 30/32)
Failed to connect to Chrome, retrying in 1 second (attempt 31/32)
Failed to connect to Chrome, retrying in 1 second (attempt 32/32)

Getting 403 access_denied when running init.js

I'm sure this is an error with what I am doing, but I seem to be following the instructions exactly.
My steps:

  1. Create credentials.json with google account [email protected]
  2. Download credentials and place into cypress/plugins
  3. Run command: node ../node_modules/gmail-tester/init.js ./credentials.json gmail_token.json [email protected]

After clicking on the link and trying to sign into [email protected], I get the following error:

The developer hasn’t given you access to this app. It’s currently being tested and it hasn’t been verified by Google. If you think you should have access, contact the developer

Have you ran into this before?

Error [gmail] Error: TypeError: gmail_emails is not iterable when checking email

Hi, first of all, thanks for your plugin, it's being very useful.

I wonder if you could provide me with some advice or support on this topic I've seen in other issues as closed. Find attached a screenshot with the console output I am getting when checking for an email I positively now has reach the inbox:

bug

If there is anything else I can add to understand the issue just say it and I'll do my best.

Thanks in advance!

Unexpected end of JSON input

I have followed all the directions and my credentials.json looks exactly like the one provided in the README. Anyone know of a fix for this?

node node_modules/gmail-tester/init.js ./cypress/plugins/credentials.json ./cypress/plugins/gmail_token.json MY_EMAIL

[gmail] Checking for message from '', to: MY_EMAIL, contains '' in subject...
[gmail] Error: SyntaxError: Unexpected end of JSON input
at JSON.parse ()
at _get_recent_email (/Users/stephenphillips/Desktop/webApp/webapp/node_modules/gmail-tester/gmail-tester.js:41:51)
at Object.check_inbox (/Users/stephenphillips/Desktop/webApp/webapp/node_modules/gmail-tester/gmail-tester.js:111:28)
at /Users/stephenphillips/Desktop/webApp/webapp/node_modules/gmail-tester/init.js:4:15
at Object. (/Users/stephenphillips/Desktop/webApp/webapp/node_modules/gmail-tester/init.js:5:3)
at Module._compile (internal/modules/cjs/loader.js:936:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:947:10)
at Module.load (internal/modules/cjs/loader.js:790:32)
at Function.Module._load (internal/modules/cjs/loader.js:703:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:999:10)

[gmail] Error: TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type undefined

this is my code


        const email = await gmail.check_inbox(
            path.resolve(__dirname, "gmail-credentials.json"), // Assuming credentials.json is in the current directory.
            path.resolve(__dirname, "gmail-token.json"), // Look for gmail_token.json in the current directory (if it doesn't exists, it will be created by the script).
            "alert", // We are looking for 'Activate Your Account' in the subject of the message.
            "google", // We are looking for a sender header which has '[email protected]' in it.
            "[email protected]", // Which inbox to poll. credentials.json should contain the credentials to it.
            10, // Poll interval (in seconds).
            30, // Maximum poll time (in seconds), after which we'll giveup.
            {include_body: true} // If we want to include the body of messages (optional)
            )
        ;

        if(email){
            console.log(email)
        }

gmail-credentials.json and gmail-token.json are in the same directory,

and this works

image

but in node, this is the output

console.log node_modules/gmail-tester/gmail-tester.js:108
    [gmail] Checking for message from 'google', to: [email protected], contains 'alert' in subject...

  console.log node_modules/gmail-tester/gmail-tester.js:145
    [gmail] Error: TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type undefined
        at Function.from (buffer.js:293:9)
        at _get_recent_email (C:\src\e2e\node_modules\gmail-tester\gmail-tester.js:84:36)
        at processTicksAndRejections (internal/process/task_queues.js:93:5)
        at Object.check_inbox (C:\src\e2e\node_modules\gmail-tester\gmail-tester.js:115:22)
        at Object.<anonymous> (C:\src\e2e\test\gmailTest.test.js:8:23) {
      code: 'ERR_INVALID_ARG_TYPE'
    }

any suggestion please?
thanks

issues on check_inbox example

the check_inbox example here https://github.com/levz0r/gmail-tester

const path = require("path");
const gmail = require("gmail-tester");
const email = await gmail.check_inbox(
  path.resolve(__dirname, "credentials.json"), // Assuming credentials.json is in the current directory.
  path.resolve(__dirname, "gmail_token.json"), // Look for gmail_token.json in the current directory (if it doesn't exists, it will be created by the script).
  "Activate Your Account", // We are looking for 'Activate Your Account' in the subject of the message.
  "[email protected]", // We are looking for a sender header which has '[email protected]' in it.
  "<target-email>", // Which inbox to poll. credentials.json should contain the credentials to it.
  10, // Poll interval (in seconds).
  30 // Maximum poll time (in seconds), after which we'll giveup.
  { include_body: true } // If we want to include the body of messages (optional)
  ]
);
if (email) {
  console.log("Email was found!");
} else {
  console.log("Email was not found!");
}

this code wont works, a comma is missing after 30 and the square brackets should to be a brackets after { include_body: true }

const path = require("path");
const gmail = require("gmail-tester");
const email = await gmail.check_inbox(
  path.resolve(__dirname, "credentials.json"), // Assuming credentials.json is in the current directory.
  path.resolve(__dirname, "gmail_token.json"), // Look for gmail_token.json in the current directory (if it doesn't exists, it will be created by the script).
  "Activate Your Account", // We are looking for 'Activate Your Account' in the subject of the message.
  "[email protected]", // We are looking for a sender header which has '[email protected]' in it.
  "<target-email>", // Which inbox to poll. credentials.json should contain the credentials to it.
  10, // Poll interval (in seconds).
  30, // Maximum poll time (in seconds), after which we'll giveup.
  { include_body: true } // If we want to include the body of messages (optional)
  )
);
if (email) {
  console.log("Email was found!");
} else {
  console.log("Email was not found!");
}

also,

in the documentation of check_inbox
https://github.com/levz0r/gmail-tester#check_inboxcredentials_json-token_path-subject-from-to-wait_time_sec--30-max_wait_time_sec--60-options--
subject , from and to are exact match but in the example they aren't, because comments says "IN IT"

check-inbox not returning an array

According to the documentation on check-inbox, it should return an array of email objects. When running the task, I only get the most recent email returned as an object.

plugins/index.js

on("task", 
{
    "gmail:check-inbox": async args => {
      const email = await gmail_tester.check_inbox(
        path.resolve(__dirname, "credentials.json"),
        path.resolve(__dirname, "token.json"),
        args.options
      );
      return email;
    }
  });

testcase.js:

cy.task("gmail:check-inbox", {
            options: {
                from: emailfrom,
                subject: emailsubject,
                wait_time_sec: 10, // Poll interval (in seconds).
                max_wait_time_sec: 30, // Maximum poll time (in seconds), after which we'll giveup.
                include_body: true
            }
        }).then(emails => {
            cy.log(emails)
        });

Not able to get response from get_messages

Hi,

I am starting with gmail-tester and so far I've managed to get the token when authenticating the app and allowing access to it but now the issue I'm facing is get-messages task not returning anything:

here's the example code I grabbed from the example:

task

const debug = require("debug");
const path = require("path");
const gmail_tester = require("../../node_modules/gmail-tester");

module.exports = (on, config) => {
  on("task", {
    "gmail:get-messages": async args => {
      const messages = await gmail_tester.get_messages(
        path.resolve("../", "credentials.json"),
        path.resolve("../", "token.json"),
        args.options
      );
      return messages;
    }
  });
};

and then in my test

describe("Email assertion:", () => {
  it("Look for an email with specific subject and link in email body", function() {
    // debugger; //Uncomment for debugger to work...
         cy.task("gmail:get-messages", {
      options: {
        include_body: true
      }
    }).then(emails => {
      // debugger;
      console.log('emails', emails);
      assert.isTrue(emails, "tesstss");
    });

  });
});

but the error I can see is

CypressError: cy.task('gmail:get-messages') failed with the following error:

The task 'gmail:get-messages' returned undefined. You must return a promise, a value, or null to indicate that the task was handled.

The task handler was:

async args => {
      const messages = await gmail_tester.get_messages(
        path.resolve("../", "credentials.json"),
        path.resolve("../", "token.json"),
        args.options
      );
      return messages;
    }

If I try to use the gmail.check_inbox method I have timeouts 😕

The API returned an error: Error: User-rate limit exceeded.

Hello!

Can someone please have a look at possible issue? Sorry if this is not enough of information - please let me know and I'll reply with more details.

The API returned an error: FetchError: request to https://oauth2.googleapis.com/token failed, reason: connect ETIMEDOUT 172.217.21.138:443
[gmail] Error: TypeError: gmail_emails is not iterable
at _get_recent_email (C:\projects\cypress-test\node_modules\gmail-tester\gmail-tester.js:37:29)
at
at process._tickCallback (internal/process/next_tick.js:188:7)

TypeScript support (types)

Firstly, congrats on this amazing lib!

It would be nice to have the definition of the types so it could be integrated into a TS project.

Always have to provide to, from and subject when checking for mail

Hi,

thanks for the great work, this module came in very handy!

When trying it out, I was wondering, why this part in the __check_inbox function might be necessary because the emails that you loop over here have already been filtered according to "to", "subject" and "from" in _get_recent_email (this loop won't find anything if we didin't provide all three filters):

     for (let email of emails) {
        if (
          email.receiver === to &&
          email.subject.indexOf(subject) >= 0 &&
          email.from.indexOf(from) >= 0
        ) {
          console.log(`[gmail] Found!`);
          found_email = email;
          break;
        }
      }

This additional filtering has the effect, that we cannot check for combinations of e.g. just "to" and "from" because this loop always checks against all three of them. I was able to make this work by replacing the for loop with just this:

if(emails) {
  console.log(`[gmail] Found!`);
  found_email = emails[0];
}

Is there any good reason for the loop that I did not see?

Regards.

Question: What to put for redirect_uris?

I am getting the expected instructions from CLI during setup. However, if I click the link provided, I get:
image

Authorize this app by visiting this url: https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&response_type=code&client_id=clientId&redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground

This is how my credentials.json looks currently:

{
  "installed": {
    "client_id": "YOUR_CLIENT_ID",
    "project_id": "PROJECT_ID",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "CLIENT_SECRET",
    "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"]
  }
}

Issue - script times out when connecting

Does anyone have any idea why my script init.js could be timing out when connecting to gmail?
I have the credentials file, I followed all of the instructions. And after a few tries I am now getting the connection refused.
Any ideas what could be missing?
However after running the script it looks like this:

[gmail] Checking for message from '', to: jacektestingacc@gmail.com, contains '' in subject...
Authorize this app by visiting this url: https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&response_type=code&client_id=551825224117-b6jdrtk3e6bnin4rja7ca2luk70ar6ua.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob
Enter the code from that page here: 4/wQHsvgRmZNLmhgVb82egfVucO3cxNTnaTxZw1s9gpBH9Ol7xCvG2C7A
[gmail] Error: TypeError: gmail_emails is not iterable
    at _get_recent_email (/Users/jacek/Desktop/Cypress/node_modules/gmail-tester/gmail-tester.js:48:29)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async __check_inbox (/Users/jacek/Desktop/Cypress/node_modules/gmail-tester/gmail-tester.js:107:22)
    at async /Users/jacek/Desktop/Cypress/node_modules/gmail-tester/init.js:4:3
(node:80110) UnhandledPromiseRejectionWarning: TypeError: gmail_emails is not iterable
    at _get_recent_email (/Users/jacek/Desktop/Cypress/node_modules/gmail-tester/gmail-tester.js:48:29)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async __check_inbox (/Users/jacek/Desktop/Cypress/node_modules/gmail-tester/gmail-tester.js:107:22)
    at async /Users/jacek/Desktop/Cypress/node_modules/gmail-tester/init.js:4:3
(node:80110) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:80110) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.```

After/before options not working

When I try to use the before or after options in the get_messages, I get an exception:
[gmail] Error: TypeError: after.getFullYear is not a function

I pass a "new Date" as value. But it seems that it's passed s string iso Date.

When I patch the module to parse it back to a Date() in the init-query, it seems to work.

function _init_query(options) {
const { before, after } = options;
let query = "";
if (before) {
let beforeDate = new Date(before);
query += before:${beforeDate.getFullYear()}/${beforeDate.getMonth()}/${beforeDate.getDate()} ;
}
if (after) {
let afterDate = new Date(after);
query += after:${afterDate.getFullYear()}/${afterDate.getMonth()}/${afterDate.getDate()} ;
}
query = query.trim();
return query;
}

Can't get check-inbox to work.

Hi, here's my issue
I have an app in which you fill out the form and the email arrives after 10-15 seconds with confirmation.

I tried get-messages, and since it can't wait for email I used hard-coded wait, and it was finding the mail just fine, as well as doing assertions.

So I tried adding check-message before that, and it seems like it never waits for the message. It's just... there.
So the test goes through and fails on the get-messages, because the email didn't arrive yet.

I'm guessing the check-message fails, because I am providing only "TO" parameter (and trying assertion on the body, since I think we can do that). The FROM and Subject are every time a bit different, and I tried adding regexp, which won't work
from: "noreply.",
to: myEmail,
subject: FormName.
;

Long story short - if I don't do assertion, it just finishes the wait in 5 seconds, instead of waiting the 30. If I do assertion it fails on function(){} TypeError: Cannot read property 'length' of null

cy.task("gmail:check-inbox", {
            options: {
                to: emailAnswer
            }
        }).then(emails => {
            assert.isAtLeast(
                emails.length,
                1,
                "Expected to find at least one email, but none were found!"
            );
            const body = emails[0].body.html;
            assert.isTrue(
                body.indexOf(
                    emailAnswer
                ) >= 0,
                "Found Email field answer!"
            );
            assert.isTrue(
                body.indexOf(
                    shortAnswer
                ) >= 0,
                "Found short answer field answer!"
            );
        });

instructions unclear when creating credentials

Was running into issues when trying to create a token because I selected "web-application" when creating 0Auth creds.

Threw error when trying to run init.js

[gmail] Error: TypeError: Cannot destructure property `client_secret` of 'undefined' or 'null'.
    at Object.authorize

FIX:

credentials.json MUST be in the format (generate OAuth as Other type

{
  "installed": {
     ...
  }
}

The API returned an error: Error: User-rate limit exceeded.

Hi

First of all, thank you so much for creating this package... it is quite handy... I am facing below written issues and I am using version 1.1.5. I have checked the Google Mail metrics/usage and we are nowhere near the limit but after each run, we are getting this error and we have to wait 24 hours for Google to unblock my email... This email is only used in automation in a simplistic way to check the inbox email...

[0-0] [gmail] Checking for message from 'xxxxxx', to: [email protected], contains 'Your app verification link' in subject...
[0-0] The API returned an error: Error: User-rate limit exceeded.  Retry after 2020-01-21T12:57:51.196Z
[0-0] [gmail] Error: TypeError: gmail_emails is not iterable
at _get_recent_email (/Users/yyyy/node_modules/gmail-tester/gmail-tester.js:48:29)
at process._tickCallback (internal/process/next_tick.js:68:7)

Cannot read property 'body' of undefined

Any help appreciated ...

gmail:get-messages task failing

I am trying to use cy.task("gmail:get-messages") -- but am having some errors doing so.

ApplicationFrameHost_2020-09-22_15-39-55

My configuration seems ok, as it is giving the [gmail] Found! message

Though, when I run this bit of code below, I get an error for the task returning undefined.

    it('gmail:get-messages', function () {
        cy.task("gmail:get-messages", {
            options: {
                include_body: true,
                before: new Date(2020, 9, 20, 12, 31, 13), // Before September 20th, 2020 12:31:13
                after: new Date(2019, 7, 23) // After August 23, 2020
            }
        }).then(emails => {
            assert.isAtLeast(
                emails.length,
                1,
                "Expected to find at least one email, but none were found!"
            );
        });
    });

Error:

cy.task('gmail:get-messages') failed with the following error:

The task 'gmail:get-messages' returned undefined. You must return a value, null, or a promise that resolves to a value or null to indicate that the task was handled.

The task handler was:

async args => {
            const messages = await gmail_tester.get_messages(
                path.resolve(__dirname, "credentials.json"),
                path.resolve(__dirname, "token.json"),
                args.options
            );
            return messages;
        }

This is in my index.js file:

const path = require("path");
const gmail_tester = require("gmail-tester");

module.exports = (on, config) => {
    on("task", {
        "gmail:get-messages": async args => {
            const messages = await gmail_tester.get_messages(
                path.resolve(__dirname, "credentials.json"),
                path.resolve(__dirname, "token.json"),
                args.options
            );
            return messages;
        }
    });
};

Let me know if any more info would help.

No 'Other' option for application type.

Screen Shot 2020-08-17 at 5 43 31 PM
Follow the instructions to Create a client ID and client secret. Make sure to select Other for the application type.

What are you guys selecting for application type?

Unexpected token T in JSON at position 0

I have error for using gmail tester in CI. What is the correct way how to use it in CI ?

I run it locally (node <node_modules>/gmail-tester/init.js <path-to-credentials.json> <path-to-token.json> ) and the generated token, I put credensials.json and token in plugin folder in cypress docker , but got the error:

[gmail] Error: SyntaxError: Unexpected token T in JSON at position 0

at JSON.parse (<anonymous>)

at _get_recent_email (/e2e/node_modules/gmail-tester/gmail-tester.js:15:51)

at Object.get_messages (/e2e/node_modules/gmail-tester/gmail-tester.js:120:26)

at gmail:get-messages (/e2e/cypress/plugins/index.js:49:36)

at invoke (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/lib/plugins/child/task.js:37:14)

at /root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/lib/plugins/util.js:48:16

at tryCatcher (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/util.js:16:23)

at Function.Promise.attempt.Promise.try (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/method.js:39:29)

at Object.wrapChildPromise (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/lib/plugins/util.js:47:28)

at Object.wrap (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/lib/plugins/child/task.js:43:8)

at execute (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/lib/plugins/child/run_plugins.js:86:12)

at EventEmitter.ipc.on (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/lib/plugins/child/run_plugins.js:136:5)

at emitThree (events.js:136:13)

at EventEmitter.emit (events.js:217:7)

at process.<anonymous> (/root/.cache/Cypress/3.4.0/Cypress/resources/app/packages/server/lib/plugins/util.js:25:29)

at emitTwo (events.js:126:13)

check_inbox allows passing duplicated options

Hi Lev!

Thank you for creating this library! 👍
I wanted to leave some feedback regarding check_inbox.

There's an opportunity for passing from, to, subject as arguments and as a part of options, which is a bit confusing. This creates a situation where it is possible to poll for emails with one filter, while the actual messages received from the API are filtered using different options.

Maybe it would make sense to stick to the options and remove the extra arguments?

gmail:check from within a cypress test timesout Error [ERR_IPC_CHANNEL_CLOSED] [ERR_IPC_CHANNEL_CLOSED]: Channel closed

Using this within cypress trying to check an email, eventually want to extract and click the verify link. When it hits the check mail step it just falls over, error not overly helpful, wonder if you can advise what I might have got wrong. I followed this post: https://levz0r.medium.com/how-to-poll-a-gmail-inbox-in-cypress-io-a4286cfdb888

Oh, in that post the test says "email not found" but I think its suppose to say email found?? Anyways....

Here is my index.js file

const path = require("path");
const gmail = require("gmail-tester");

module.exports = (on, config) => {

  on("task", {
    "gmail:check": async args => {
      const { from, to, subject } = args;
      const email = await gmail.check_inbox(
        path.resolve(__dirname, "credentials.json"), // credentials.json is inside plugins/ directory.
        path.resolve(__dirname, "gmail_token.json"), // gmail_token.json is inside plugins/ directory.
        subject,
        from,
        to,
        30,                                          // Poll interval (in seconds)
        60                                           // Maximum poll interval (in seconds). If reached, return null, indicating the completion of the task().
      );
      console.log('gmail check is working');
      return email;
    }
  });

};

here is my test.js file:

it('link is no longer valid, we can request and new one and the new link works', () => {

  cy.visit('/urlforresetform');

  // Check we get the email and its content is correct.
  const test_id = new Date().getTime();
  const incoming_mailbox = `myemail+${test_id}@gmail.com`;
  const password = 'somepassword';

  cy.get("#edit-name").type(incoming_mailbox);
  cy.get("#edit-submit").click();

  cy
    .task("gmail:check", {
      from: "mysitesemailaddress",
      to: incoming_mailbox,
      subject: "emailtitle"
    })
    .then(email => {

      console.log('we have an email??');
      assert.isNotNull(email, `Email was found!`);
    });

})

"gmail:check-inbox" timing out after 60 seconds despite "max_wait_time_sec" being set to 180

I am using gmail:check-inbox with the following task definition:

    on('task', {
        'gmail:check-inbox': async args => {
            return await gmail_tester.check_inbox(
                path.resolve('src/support/credentials/google', 'googleCredentials.json'),
                path.resolve('src/support/credentials/google', 'googleToken.json'),
                args.options
            );
        },
    });

And am calling with these args:

   cy.task("gmail:check-inbox", {
       options: {
           to: user,
           from: sender,
           include_body: true,
           wait_time_sec: 5,
           max_wait_time_sec: 180
       }
   }

I am seeing some intermittent failures with the following logged:

CypressError: cy.task('gmail:check-inbox')timed out after waiting60000ms.

I would expect the timeout to occur after 180000ms , not 60000ms. Am I missing something?

Error with Cypress when check_inbox doesn't return mail

Hi,

When I use gmail-tester with cypress and I receive an email, test is OK.

But when I don't receive email, cypress throw an error :

Message: The plugins file is missing or invalid.

Your pluginsFile is set to /home/pierre/Documents/core/cypress/plugins/index.js, but either the file is missing, it contains a syntax error, or threw an error when required. The pluginsFile must be a .js or .coffee file.

Or you might have renamed the extension of your pluginsFile to .ts. If that's the case, restart the test runner.

Please fix this, or set pluginsFile to false if a plugins file is not necessary for your project.

Details: /home/pierre/Documents/core/cypress/plugins/index.js:28
return await gmail.check_inbox(
^^^^^^

SyntaxError: Unexpected token 'return'
at Module._compile (internal/modules/cjs/loader.js:896:18)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:986:10)
at Module.load (internal/modules/cjs/loader.js:816:32)
at Module._load (internal/modules/cjs/loader.js:728:14)
at Module._load (electron/js2c/asar.js:717:26)
at Function.Module._load (electron/js2c/asar.js:717:26)
at Module.require (internal/modules/cjs/loader.js:853:19)
at require (internal/modules/cjs/helpers.js:74:18)
at module.exports (/home/pierre/.cache/Cypress/4.9.0/Cypress/resources/app/packages/server/lib/plugins/child/run_plugins.js:208:15)
at Object. (/home/pierre/.cache/Cypress/4.9.0/Cypress/resources/app/packages/server/lib/plugins/child/index.js:6:25)
at Module._compile (internal/modules/cjs/loader.js:968:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:986:10)
at Module.load (internal/modules/cjs/loader.js:816:32)
at Module._load (internal/modules/cjs/loader.js:728:14)
at Module._load (electron/js2c/asar.js:717:26)
at Function.Module._load (electron/js2c/asar.js:717:26)

Stack trace:

Error: The plugins file is missing or invalid.

Your `pluginsFile` is set to `/home/pierre/Documents/core/cypress/plugins/index.js`, but either the file is missing, it contains a syntax error, or threw an error when required. The `pluginsFile` must be a `.js` or `.coffee` file.

Or you might have renamed the extension of your `pluginsFile` to `.ts`. If that's the case, restart the test runner.

Please fix this, or set `pluginsFile` to `false` if a plugins file is not necessary for your project.
    at Object.get (/home/pierre/.cache/Cypress/4.9.0/Cypress/resources/app/packages/server/lib/errors.js:946:15)
    at EventEmitter.<anonymous> (/home/pierre/.cache/Cypress/4.9.0/Cypress/resources/app/packages/server/lib/plugins/index.js:121:21)
    at EventEmitter.emit (events.js:210:5)
    at ChildProcess.<anonymous> (/home/pierre/.cache/Cypress/4.9.0/Cypress/resources/app/packages/server/lib/plugins/util.js:19:22)
    at ChildProcess.emit (events.js:210:5)
    at emit (internal/child_process.js:876:12)
    at processTicksAndRejections (internal/process/task_queues.js:81:21)

My code is :

plugins/index.js

module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
  on('task', {
    'gmail:check': async args => {
      const { from, to, subject } = args;
      return await gmail.check_inbox(
        path.resolve(__dirname, 'credentials.json'), // credentials.json is inside plugins/ directory.
        path.resolve(__dirname, 'gmail_token.json'), // gmail_token.json is inside plugins/ directory.
        subject,
        from,
        to,
        10,                                          // Poll interval (in seconds)
        30                                           // Maximum poll interval (in seconds). If reached, return null, indicating the completion of the task().
      )
    }
  })
}

spec.js

 it.only('should send an orderlight by mail', () => {
    cy.getOrderId(nameClientStorage).then(
      (orderId) => {
        cy.visit('backoffice/orderlights/'+ orderId +'/sendOrderLight')
        cy.get('[data-cy="button-send-mail"]').click({force: true})
        cy
          .task('gmail:check', {
            from: '[email protected]',
            to: nameClientStorage,
          })
          .then(email => {
            assert.isNotNull(email, 'Email was not found')
          });
      }
    )
  })

token.json

Maybe a missing documentation part,
how to auto-update die token.json regular? The token comes with an expire date:
... "scope":"https://www.googleapis.com/auth/gmail.readonly","token_type":"Bearer","expiry_date":1614682765030}

So howto setup gmail-tester in an CI environment?

Is it any way to poll 'Sent' messages

Hi! Thanks for your great library. I managed to add it to my puppeteer tests, and it works just fine :)
And now new test problem raised.
I need to verify, that smtp is configured correctly in the tested application and messages are sent within gmail account.
Is it any way I can use gmail-tester for polling 'Sent' gmail box?
Thanks in advance!

cy.task('gmail:get-messages') timed out after waiting 60000ms.

I have been able to get the check_inbox to work properly. I have now tried to get the get-messages() to work, but I keep getting the following error message:

cy.task('gmail:get-messages') timed out after waiting 60000ms.

None of the messages are retrieved.

This is my index.js file:

const path = require("path");
const gmail = require("gmail-tester");

module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
  
  on("task", {
    "gmail:check": async args => {
      const { from, to, subject } = args;
      const email = await gmail.check_inbox(
        path.resolve(__dirname, "credentials.json"), // credentials.json is inside plugins/ directory.
        path.resolve(__dirname, "gmail_token.json"), // gmail_token.json is inside plugins/ directory.
        subject,
        from,
        to,
        10,                                          // Poll interval (in seconds)
        30                                           // Maximum poll interval (in seconds). If reached, return null, indicating the completion of the task().
      );
      return email;
    }
  });
  

 on("task", {
    "gmail:get-messages": async args => {
      const messages = await gmail.get_messages(
        path.resolve(__dirname, "credentials.json"),
        path.resolve(__dirname, "token.json"),
        args.options
      );
      return messages;
    }
  });
  
}

This is my sample_spec.js file;

describe("Email assertion:", () => {
  it("Look for an email with specific subject and link in email body", function () {
    // debugger; //Uncomment for debugger to work...
    cy.task("gmail:get-messages", {
      options: {
       from: "[email protected]",
        subject: "Some Topic",
        include_body: true
      }
    }).then(emails => {
      // debugger;
      console.log('emails', emails);
      assert.isTrue(emails, "tesstss");
    });
	  });
});

This is my init.js file:

const gmail = require("./gmail-tester");

(async () => {
  await gmail.check_inbox(process.argv[2], process.argv[3], "", "", process.argv[4]);
})();

every time I got "Expected to find at least one email, but none were found!: expected 0 to be at least 1"

Even I provide true vales for
from: "", subject: "", include_body: true, before: new Date(2020, 6, 24, 12, 31, 13), // Before September 24rd, 2019 12:31:13 after: new Date(2019, 7, 23) // After August 23, 2019
I am getting
Expected to find at least one email, but none were found!: expected 0 to be at least 1

gmail.spec.js
`///

describe("Email assertion:", () => {
it("Look for an email with specific subject and link in email body", function() {
// debugger; //Uncomment for debugger to work...
cy
.task("gmail:get-messages", {
options: {
from: "",
subject: "",
include_body: true,
before: new Date(2020, 6, 24, 12, 31, 13), // Before September 24rd, 2019 12:31:13
after: new Date(2019, 7, 23) // After August 23, 2019
}
})
.then(emails => {
assert.isAtLeast(
emails.length,
1,
"Expected to find at least one email, but none were found!"
);
const body = emails[0].body.html;
assert.isTrue(
body.indexOf(
"https://account-uplay.ubi.com/en-GB/action/change-password?genomeid="
) >= 0,
"Found reset link!"
);
});
});
});`

index.js
`const debug = require("debug");
const path = require("path");
const gmail_tester = require("gmail-tester");

module.exports = (on, config) => {
on("before:browser:launch", (browser = {}, args) => {
if (browser.name === "chrome") {
args.push("--remote-debugging-port=9221");
return args;
}
});
on("task", {
"gmail:get-messages": async args => {
const messages = await gmail_tester.get_messages(
path.resolve(__dirname, "credentials.json"),
path.resolve(__dirname, "gmail_token.json"),
args.options
);
return messages;
}
});
};`

Please help me to slove this issue

To delete a mail

Hi,

Do you plan to add function to delete an email ?
It could be great.
Thanks.

No Refresh Token is Set

Hi, I'm currently running into an issue with my tokens using this library. This may in fact be a limitation but just wanted to confirm that I'm not doing anything unexpected here.

When I generate a token (gmail-token.json) it is only good for one hour. Is this expected? I was assuming it would use a refresh token to make requests beyond that time limit. Right now when I hit the hour limit it will return:

[gmail] Checking for message from '_', to: _, contains '_' in subject...
The API returned an error: Error: No refresh token is set.
Error when getting recent emails: Error: No refresh token is set.
[gmail] Error: Error: No refresh token is set.

Any thoughts?

Thanks in advance.

check_inbox error when Message is not found

Most probably user error but i'd appreciate the help if it is :)

I'm using this great library with TestCafe and when I use the check_inbox function and the message is not found, it prints Message not found. Waiting 15 seconds..., but then throws the following error:

[gmail] Message not found. Waiting 15 seconds...
[gmail] Error: TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received 15000
    at setTimeout (node:timers:135:3)
    at ~/node_modules/testcafe/src/api/test-run-tracker.ts:34:35
    at node:internal/util:325:7
    at new Promise (<anonymous>)
    at node:internal/util:311:12
    at __check_inbox (~/node_modules/gmail-tester/gmail-tester.js:126:39)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:94:5) {
  code: 'ERR_INVALID_CALLBACK'
}

I'm using it like this:

export async function waitForAndGetEmailMessage(t, emailType, targetEmailAddress) {
    const email = await check_inbox(resolve(__dirname, '../credentials.json'), resolve(__dirname, '../token.json'), {
        subject: EMAILS[emailType].SUBJECT,
        from: EMAILS.SENDER,
        to: targetEmailAddress,
        wait_time_sec: 15, // in seconds.
        max_wait_time_sec: 60, // in seconds.
    });
    await t.expect(email).ok('Email was not found!');
...other code
}

Any idea what I'm doing wrong?

:new request: Delete messages function required

Sorry for posting this in Issues, however, i am a noob and trying to understand how to use GitHub for now!
Gmail tester is a great addition to my cypress test suites. However, I was looking for a function to delete messages form inbox.
Any plans to build this in future releases?

Get email body with the check_inbox function

Hello,

Thanks very much for this very useful lib!

I wonder if it's possible to get the email content when using the check_inbox function. I had a look at the code and this doesn't seem to be supported.

Thanks for your help!
Thierry

Issue when selecting "Web application" as Type

Per documentation Step 1,

Follow the instructions to Create a client ID and client secret. Make sure to select Other for the application type.

But I do not see "Other" as an option. I tried as "Web application" instead per #40 solution, and changed my json file to contain installed, but still got the following error when running setup command:

[gmail] Error: TypeError: Cannot read property '0' of undefined
    at Object.authorize 

Is there a way to wait for new E-mail?

Currently, when I call gmail_tester.check_inbox(), from my cy.task(), it seems like the gmail-tester library just scans my inbox and returns the most recent emails from that inbox. Does the library contain a way to asynchronously wait for a new email to arrive before moving onto the next step? This issue also arises when I want to run the test again, but the task continues to take an old link rather than wait for a new one.

Supporting different languages

Hello,

Apparently, gmail-tester can validate English only subject/content which is not the case when you test for multinational product

Any plans for supporting this in the near future? (fingerscrossed)

Util.promisify is not a function in Cypress when require("gmail-tester")

Cypress tests that require("gmail-tester") in support/index.js fail when executing a test, with the browser showing the following error

util.promisify is not a function

This error originated from your test code, not from Cypress.

When Cypress detects uncaught errors originating from your test code it will automatically fail the current test.

Cypress could not associate this error to any specific test.

We dynamically generated a new test to display this failure.

Check your console for the stack trace or click this message to see where it originated from.
View stack trace
Uncaught TypeError: util.promisify is not a function

This error originated from your test code, not from Cypress.

When Cypress detects uncaught errors originating from your test code it will automatically fail the current test.

Cypress could not associate this error to any specific test.

We dynamically generated a new test to display this failure.

Check your console for the stack trace or click this message to see where it originated from.
    at Object.53../apirequest (http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:9871:23)
    at o (http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:1:265)
    at http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:1:316
    at Object.55../apiIndex (http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:10147:19)
    at o (http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:1:265)
    at http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:1:316
    at Object.73../v1 (http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:11812:29)
    at o (http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:1:265)
    at http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:1:316
    at Object.318../abusiveexperiencereport (http://localhost:4201/__cypress/tests?p=cypress/support/index.js-776:200070:33)

If require("gmail-tester") is not added to the file, the issue is not present.

Investigating potential causes:
Opening chrome dev tools and following the error code link brings me to the following
image

That led me down a rabbit hole to find that this issue may be related?
googleapis/google-api-nodejs-client#1775

System Information
npm -v
6.14.4

node -v
v10.20.1

OSX Catalina & Mojave

Cypress Version 4.5.0
Happens both when cypress set to use 'system' (10.20.1) and builtin (12.13.0) nodejs versions (cypress.conf setting)

I'd really love some direction as to how to progress forward with this - I've tried different node versions, etc but nothing seems to get me any further!

Can't successfully connect

Hi there,

I have made a client ID and secret and downloaded the credentials.json file. The file is in my cypress/plugins folder. I don't have the token file, but I understand that is created by the script.

Whenever I run the init.js file, I get this error log:

response:
   { config:
      { method: 'POST',
        url: 'https://oauth2.googleapis.com/token',
        data: 'code=&client_id=463521082580-h8ai8v0h2cdbupfqv1afk79o0huqvkcb.apps.googleusercontent.com&client_secret=T2JUqUQBE6_-1koxlGVFZHTB&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=authorization_code&code_verifier=',
        headers: [Object],
        params: {},
        paramsSerializer: [Function: paramsSerializer],
        body: 'code=&client_id=463521082580-h8ai8v0h2cdbupfqv1afk79o0huqvkcb.apps.googleusercontent.com&client_secret=T2JUqUQBE6_-1koxlGVFZHTB&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=authorization_code&code_verifier=',
        validateStatus: [Function: validateStatus],
        responseType: 'json' },
     data:
      { error: 'invalid_request',
        error_description: 'Missing required parameter: code' },
     headers:
      { 'alt-svc': 'quic=":443"; ma=2592000; v="46,43,39"',
        'cache-control': 'private',
        connection: 'close',
        'content-encoding': 'gzip',
        'content-type': 'application/json; charset=utf-8',
        date: 'Wed, 25 Sep 2019 11:08:52 GMT',
        server: 'scaffolding on HTTPServer2',
        'transfer-encoding': 'chunked',
        vary: 'Origin, X-Origin, Referer',
        'x-content-type-options': 'nosniff',
        'x-frame-options': 'SAMEORIGIN',
        'x-xss-protection': '0' },
     status: 400,
     statusText: 'Bad Request' },
  config:
   { method: 'POST',
     url: 'https://oauth2.googleapis.com/token',
     data: 'code=&client_id=463521082580-h8ai8v0h2cdbupfqv1afk79o0huqvkcb.apps.googleusercontent.com&client_secret=T2JUqUQBE6_-1koxlGVFZHTB&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=authorization_code&code_verifier=',
     headers:
      { 'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'google-api-nodejs-client/5.2.2',
        'x-goog-api-client': 'gl-node/8.11.3 auth/5.2.2',
        Accept: 'application/json' },
     params: {},
     paramsSerializer: [Function: paramsSerializer],
     body: 'code=&client_id=463521082580-h8ai8v0h2cdbupfqv1afk79o0huqvkcb.apps.googleusercontent.com&client_secret=T2JUqUQBE6_-1koxlGVFZHTB&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=authorization_code&code_verifier=',
     validateStatus: [Function: validateStatus],
     responseType: 'json' },
  code: '400' }

Do I have to enable the Gmail API inside cloud console? I am not sure what i'm doing wrong here, do you have any idea? Thank you!

GaxiosError: Mail service not enabled

Hi,

I'm fairly confident that this is something that I'm doing wrong (rather than an issue with the package) but I haven't been able to fix it.

I get a 'Mail service not enabled' error when running this command:

node ../../../node_modules/gmail-tester/init.js ./credentials.json gmail_token.json [email protected]

This is part of the JSON output:

errors: [
    {
      message: 'Mail service not enabled',
      domain: 'global',
      reason: 'failedPrecondition'
    }
]

The JSON output also mentions the gmail.readonly scope. So, I thought I needed to enable that OAuth consent screen (which I have done) but that has not fixed it.

Does it matter what Google account has registered the OAuth consent screen and been added as a user, etc?

My Google account that hosts the project is just my personal email (not my company domain). I also added my personal email as a test user so that I could click the link and follow the process through to get a token.

Is that right? Or should I have created a Gmail account for my '[email protected]' email address and added that?

Plugin does not wait the total time 'the max_wait_time_sec' and fails after the first try

Testing framework is Cypress.
Sorry maybe for some coding style or misusing the JS. I learned it like only two weeks ago. :) On my way of mastering.

This is me PageObject that contains method to check emails.
cy.wait(10000); is added cause wait_time_sec and max_wait_time_sec does do its job :(

export const THANK_YOU_TEXT = '[class^="content"]';

export default class ConfirmationEmailSentPage {
  assertEmailPresentInThePageText(email) {
    cy.get(THANK_YOU_TEXT).should('include.text', email);
  }

  async confirmRegistrationForMerchantViaEmail(emailTo) {
    cy.wait(10000);
    cy.task('gmail:get-messages', {
      options: {
        from: '[email protected]',
        to: emailTo,
        subject: 'Підтвердження e-mail при реєстраціїї',
        include_body: true,
        wait_time_sec: 1,
        max_wait_time_sec: 60,
      },
    }).then((emails) => {
      assert.isAtLeast(
        emails.length,
        1,
        'Expected to find at least one email, but none were found!'
      );
      const emailBody = emails[0].body.html;
      const confirmationLink = substringConfirmationLinkFromTheEmail(emailBody);
      assert.isTrue(
        emailBody.indexOf(confirmationLink) >= 0,
        `Found confirmation link! Here it is ${confirmationLink}`
      );
      cy.visit(confirmationLink);
    });
  }

  async assertMerchantIsConfirmedAndReceivedWelcomeEmail(
    merchantFirstName,
    merchantLastName,
    emailTo
  ) {
    cy.wait(10000);
    cy.task('gmail:get-messages', {
      options: {
        from: '[email protected]',
        to: emailTo,
        subject: `${merchantFirstName} ${merchantLastName}, ласкаво просимо на маркетплейс Епіцентр!`,
        include_body: true,
        wait_time_sec: 1,
        max_wait_time_sec: 60,
      },
    }).then((emails) => {
      assert.isAtLeast(
        emails.length,
        1,
        'Expected to find at least one email, but none were found!'
      );
      const emailBody = emails[0].body.html;
      assert.isTrue(
        emailBody.toString().indexOf(merchantFirstName) > 0,
        'Expected the merchant to receive the Welcome Email.'
      );
    });
  }
}

function substringConfirmationLinkFromTheEmail(emailText) {
  const cutLinkGross = emailText.substring(
    emailText.indexOf('finish-registration') - 40,
    emailText.indexOf('finish-registration') + 300
  );
  const cutLinkPolishedStart = cutLinkGross.substring(
    cutLinkGross.indexOf('href="') + 6
  );
  return cutLinkPolishedStart.substring(0, cutLinkPolishedStart.indexOf('"'));
}

Here is the usage of the function from the test body. confirmRegistrationForMerchantViaEmail(merchant.email)`

it('C22261 Register new Merchant and confirm the account via link in the email', () => {
      merchantCabinetLoginPage.openLoginPage();
      merchantCabinetLoginPage.openRegistrationPage();

      const merchant = registrationPage.generateRandomMerchant();
      registrationPage.registerNewMerchant(merchant.email, merchant.password);

      confirmEmailPage.confirmRegistrationForMerchantViaEmail(merchant.email`);
}

The plugin is AWESOME and finds emails less that in 1 second! That's beautiful! Thank you!
But one great feature of the plugin seem to fails. We need it. Please help, sir levz0r :D

image

It generates token with life duration = 1 hour

I've created "Credentials.json" file as per instructions.
Then I am running the command to generate Token:
node ..\..\node_modules\gmail-tester\init.js .\credentials.json gmail_token.json [email protected]
It successfully creates Token, BUT it's life time is just 1 hour.

{
  "access_token": "ya29.a0AfH6SMDwy2 ... xMze5YfDMru-CYaM",
  "refresh_token": "1//09boFIYyEL0w3Cg ... UKq7eNZHeSKxIv3MyZqI",
  "scope": "https://www.googleapis.com/auth/gmail.readonly",
  "token_type": "Bearer",
  "expiry_date": 1610372897000
}

How extend token life time (to at least half of the year)?

Usage in CI environment

Hi,
A bunch of thanks for this great repo.
I was able to move forward with instruction and inbox reading works perfectly in the local machine

As mentioned in documents we shouldn't push credentials JSON files into the git repository. so, I'm wondering how we should set up the package in the CI environment? is there any advice?

Thanks.

Issue: run init.js command in terminal doesn't work?

Every time I try to run node ....\node_modules\gmail-tester\init.js .\credentials.json gmail_token.json [email protected] in terminal, I get an Error message "This functionality is absolete! Please pass all params in options object!". Does any one know whats the problem?
Maybe Google made some changes with the API?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.