Giter Club home page Giter Club logo

nodemailer-mock's Introduction

nodemailer-mock

nodemailer-mock Code Coverage Badge Downloads

Easy as pie nodemailer mock for unit testing your Node.js applications.

From SecretParty.io with ❤️.

install

npm install nodemailer-mock --save-dev
yarn add -D nodemailer-mock

module loading

Depending on your mock configuration nodemailer-mock may, or may not, have access to nodemailer when it is loaded. For example, using mockery you can replace nodemailer with require('nodemailer-mock'), however in jest you will need to inject nodemailer using module.exports = require('nodemailer-mock').getMockFor(require('nodemailer'));

mock api

Use with test suites like jest and mocha. There are some special methods available on the mocked module to help with testing. They are under the .mock key of the mocked nodemailer.

NodemailerMock.mock functions

  • reset: () => void
    • resets the mock class to default values
  • getSentMail: () => Mail.Options[]
    • returns an array of sent emails during your tests, since the last reset
  • getCloseCallCount: () => number
    • get the number of times the transporter.close() was called across all instances
  • setShouldFailOnce: (isSet?: boolean) => void
    • should the mock return an error on the next call to transporter.sendMail() or transport.send()
  • isShouldFailOnce: () => boolean
    • returns status of setShouldFailOnce(?)
  • setShouldFail: (isFail?: boolean) => void
    • indicate if errors should be returned for subsequent calls to transporter.sendMail() or transport.send()
      • if true, return error
      • if false, return success
  • isShouldFail: () => boolean
    • returns status of setShouldFail()
  • setShouldFailCheck: (check: CheckMailMessageOrNull) => void
    • indicate if the specific email passed to the function should fail the call to transporter.sendMail() or transport.send()
      • if function returns true, return error
      • if function returns false, return success
    • use type CheckMailMessageOrNull = ((email: MailMessage) => boolean) | null
  • getShouldFailCheck: () => CheckMailMessageOrNull
    • returns the function used to check the MailMessage or null if it is not set
  • setMockedVerify: (isMocked: boolean) => void
    • determine if a call to transport.verify() should be mocked or passed through to nodemailer, defaults to true.
      • if true, use a mocked callback
      • if false, pass through to a real nodemailer transport
  • isMockedVerify: () => boolean
    • returns status of setMockedVerify(?)
  • setMockedClose: (isMocked: boolean) => void
    • determine if calls to transporter.close() should be passed through to the underlying transport, defaults to true.
  • isMockedClose: () => boolean
    • when the result is true the underlying transport is not used, when false the call is passed through.
  • setSuccessResponse: (response: string) => void
    • set the success message that is returned in the callback for transporter.sendMail() or transport.send()
  • getSuccessResponse: () => string
    • returns the success message value
  • setFailResponse: (error: Error) => void
    • set the Error that is returned in the callback for transporter.sendMail() or transport.send()
  • getFailResponse: () => Error
    • returns the fail Error value
  • scheduleIsIdle: (isIdle: boolean, timeout: number) => void
    • schedule a status change for calls to transporter.isIdle() instances
  • setIsIdle: (isIdle: boolean) => void
    • set the status that is returned by calls to all transporter.isIdle() instances
  • setUnmockedUsePlugins: (isUnmockUsePlugins: boolean) => void default false
    • should the plugins added via transporter.use() be run outside the mock?
  • isUnmockedUsePlugins: () => boolean
    • returns the status of setUnmockedUsePlugins(?)

NodemailerMockTransporter.mock functions

  • getPlugins: () => { [key: string]: Mail.PluginFunction<Mail.Options>[] }
    • returns the plugins that have been added via transporter.use() as arrays, keyed by step
  • getCloseCallCount: () => number
    • get the number of times close() has been called on this transporter. this number is not reset with the mock.
  • setIdle(isIdle: boolean): void
    • sets the idle state of transporter.isIdle() and emits an idle event when the isIdle argument is true.

usage

The mocked module behaves in a similar fashion to other transports provided by nodemailer.

setup test

const nodemailermock = require('nodemailer-mock');
const transport = nodemailermock.createTransport();

// the email you want to send
const email = ... // <-- your email here

use nodestyle callbacks

// send with nodestyle callback
transport.sendMail(email, function(err, info) {
  if (err) {
    return console.log('Error!', err, info);
  }
  return console.log('Success!', info);
}

// verify with nodestyle callback
transport.verify(function(err, success) {
  if (err) {
    return console.log('Error!', err);
  }
  return console.log('Success!', success);
});

use promises

// send with promises
transport.sendMail(email)
  .then(function(info) {
    console.log('Success!', info);
  })
  .catch(function(err) {
    console.log('Error!', err);
  });

// verify with promises
transport.verify()
  .then(function(success) {
    console.log('Success!', success);
  });
  .catch(function(err) {
    console.log('Error!', err);
  });

use async/await

// send an email with async / wait
try {
  const info = await transport.sendMail(email);
} catch (err) {
  console.log('Error!', err);
}

// verify with async / wait
try {
  const info = await transport.verify();
} catch (err) {
  console.log('Error!', err);
}

example tests using mocked module

To use nodemailer-mock in your tests you will need to mock nodemailer with it. There are working examples using jest and mocha in the ./examples/ folder of the project. The jest code is in ./examples/__mocks__ and ./examples/__tests__, and the mocha tests are in ./examples/test. Run the examples with npm run example:jest and npm run example:mocha. Both JavaScript and TypeScript example tests are provided.

example using jest

To mock nodemailer using jest create a file called ./__mocks__/nodemailer.js that exports the mocked module:

/**
 * Jest Mock
 * ./__mocks__/nodemailer.js
 **/
// load the real nodemailer
const nodemailer = require('nodemailer');
// pass it in when creating the mock using getMockFor()
const nodemailermock = require('nodemailer-mock').getMockFor(nodemailer);
// export the mocked module
module.exports = nodemailermock;

Once the mock file is created all calls to nodemailer from your tests will return the mocked module. To access to mock functions, just load it in your test file.

/**
 * Jest Test
 * ./__tests__/my-test.js
 **/
const { mock } = require('nodemailer');

test('Send an email using the mocked nodemailer', async () => {
  /* ... run your tests that send emails here */

  // check the mock for our sent emails
  const sentEmails = mock.getSentMail();
  // there should be one
  expect(sentEmails.length).toBe(1);
  // and it should match the to address
  expect(sentEmails[0].to).toBe('[email protected]');
});

Using typescript you can coerce the NodemailerMock type.

/**
 * Jest Test
 * ./__tests__/my-test.js
 **/
import { expect, test } from '@jest/globals';
// 'nodemailer' is automatically mocked in ./__mocks__/nodemailer.js
import * as nodemailer from 'nodemailer';
import { NodemailerMock } from 'nodemailer-mock';
const { mock } = nodemailer as unknown as NodemailerMock;

test('Send an email using the mocked nodemailer + typescript', async () => {
  /* ... run your tests that send emails here */

  // check the mock for our sent emails
  const sentEmails = mock.getSentMail();
  // there should be one
  expect(sentEmails.length).toBe(1);
  // and it should match the to address
  expect(sentEmails[0].to).toBe('[email protected]');
});

example using mocha and mockery

Here is an example of using a mocked nodemailer class in a mocha test using mockery. Make sure that any modules that require()'s a mocked module must be called AFTER the module is mocked or node will use the unmocked version from the module cache. Note that this example uses async/await. See the module tests for additional example code.

/**
 * Mocha Test / Mockery Mock
 * ./test/my-test.js
 **/
const { expect } = require('chai');
const mockery = require('mockery');
const nodemailermock = require('nodemailer-mock');

describe('Tests that send email',  async () {

  /* This could be an app, Express, etc. It should be
  instantiated *after* nodemailer is mocked. */
  let app = null;

  before(async () {
    // Enable mockery to mock objects
    mockery.enable({
      warnOnUnregistered: false,
    });

    /* Once mocked, any code that calls require('nodemailer')
    will get our nodemailermock */
    mockery.registerMock('nodemailer', nodemailermock)

    /*
    ##################
    ### IMPORTANT! ###
    ##################
    */
    /* Make sure anything that uses nodemailer is loaded here,
    after it is mocked just above... */
    const moduleThatRequiresNodemailer = require('module-that-requires-nodemailer');

  });

  afterEach(async () {
    // Reset the mock back to the defaults after each test
    nodemailermock.mock.reset();
  });

  after(async () {
    // Remove our mocked nodemailer and disable mockery
    mockery.deregisterAll();
    mockery.disable();
  });

  it('should send an email using nodemailer-mock', async () {
    // call a service that uses nodemailer
    const response = ... // <-- your email code here

    // a fake test for something on our response
    expect(response.value).to.equal('value');

    // get the array of emails we sent
    const sentMail = nodemailermock.mock.getSentMail();

    // we should have sent one email
    expect(sentMail.length).to.equal(1);

    // check the email for something
    expect(sentMail[0].property).to.equal('foobar');
  });

  it('should fail to send an email using nodemailer-mock', async () {
    // tell the mock class to return an error
    const err = new Error('My custom error');
    nodemailermock.mock.setShouldFailOnce();
    nodemailermock.mock.setFailResponse(err);

    // call a service that uses nodemailer
    var response = ... // <-- your code here

    // a fake test for something on our response
    expect(response.error).to.equal(err);
  });

  /* this will not work with jest as all nodemailers are mocked */
  it('should verify using the real nodemailer transport', async () {
    // tell the mock class to pass verify requests to nodemailer
    nodemailermock.mock.setMockedVerify(false);

    // call a service that uses nodemailer
    var response = ... // <-- your code here

    /* calls to transport.verify() will be passed through,
       transporter.send() is still mocked */
  });
});

nodemailer-mock's People

Contributors

axosoft-dans avatar doublesharp avatar floedelmann avatar lgaticaq avatar marcusicaro avatar okjake 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

Watchers

 avatar  avatar  avatar

nodemailer-mock's Issues

Cannot set property 'mailer' of undefined

When trying to use nodemailer-mock, I get this error:

Cannot set property 'mailer' of undefined

Repro:

npm init -y
yarn add nodemailer
yarn add nodemailer-mock --dev

index.js:

const nodemailerMock = require('nodemailer-mock');
const transport = nodemailerMock.createTransport();
node index.js

Result:

/Users/alexzeitler/src/spikes/nodemailer-mock-spike/node_modules/nodemailer-mock/node_modules/nodemailer/lib/mailer/index.js:45
        this.transporter.mailer = this;
                                ^

TypeError: Cannot set property 'mailer' of undefined
    at new Mail (/Users/alexzeitler/src/spikes/nodemailer-mock-spike/node_modules/nodemailer-mock/node_modules/nodemailer/lib/mailer/index.js:45:33)
    at Object.module.exports.createTransport (/Users/alexzeitler/src/spikes/nodemailer-mock-spike/node_modules/nodemailer-mock/node_modules/nodemailer/lib/nodemailer.js:58:14)
    at Object.createTransport (/Users/alexzeitler/src/spikes/nodemailer-mock-spike/node_modules/nodemailer-mock/nodemailer-mock.js:48:28)
    at Object.<anonymous> (/Users/alexzeitler/src/spikes/nodemailer-mock-spike/index.js:2:34)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)

Node.js version : 10.15.1

Add support for sendMail()'s Promise return value

Nodemailer conveniently provides a Promise wrapper for sendMail() (see the note at the bottom of https://nodemailer.com/usage/, If callback argument is not set then the method returns a Promise object.

The mock sendMail() only provides the callback-based interface, without the Promise wrapper.

Would you accept a PR to add the Promise wrapper, to have the same semantics as nodemailer's?

Unwanted developer tools install

I installed and used this package. It works great but since it has developer-tools as a dependency, it wound up installing git hooks, and npm scripts as well as some .eslintrc, and other files. I didn't want the developer-tools package to install these files and settings. I imagine other's wouldn't want it either.

Is the developer-tools package needed? If so, can a note be added to the README to mention that it uses the package and to expect some files and settings to be installed? Or even an option to add/remove the package?

Thanks

The presence of npm-shrinkwrap.json making shrink wrapping fail at the root module

Hi.
Thanks for providing this module.
Problem:
I am maintaining npm-shrinkwrap.json in my application. Now if I try install nodemailer-mock, my application's shrink wrapping is failing by giving many extraneous errors.
Example error:
npm WARN saveError extraneous: [email protected] /Users/sravankumarrekandar/workarea/nodemailer-test/node_modules/nodemailer-mock/node_modules/lodash.keys
..
The issue was fixed when I deleted both my-app/node_modules/nodemailer-mock/node_modules and my-app/node_modules/nodemailer-mock/npm-shrinkwrap.json
Then reinstalled my-app dependencies.
And everything is working fine.

However, we cannot maintain the hack. Please make sure the module is compatible with other apps.

Thanks.

Mock rejected emails

Is there the possibility to mock the array returned by SMTP transports that includes recipient addresses that were rejected by the server?

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.