Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add integration tests #374

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Integration Tests

on:
push:
branches:
- master
- main
pull_request:
branches:
- master
- main

jobs:
on-pull-request:
name: test
strategy:
matrix:
node-version: [14.x, 16.x, 18.x, 20.x]
runs-on: 'ubuntu-latest'
steps:
- name: Checkout
uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}

- name: Print node version
run: node -v

- name: Install dependencies
run: npm ci

- name: Run build
run: npm run build

- if: ((matrix.node-version != '14.x') && (matrix.node-version != '16.x')) # starting from v18 there is FormData implementation in Node.js
name: Run Node.js integration tests with builtin FormData
run: export LAUNCH_TYPE=native && npm run test:node

- name: Run Node.js integration tests with form-data package
run: export LAUNCH_TYPE=package && npm run test:node

- name: Copy dist for test server
run: cp ${{ github.workspace}}/dist/mailgun.web.js ${{ github.workspace}}/integration_tests/server/dist/mailgun.web.js

- name: Serve Files
uses: Eun/http-server-action@v1
with:
directory: ${{ github.workspace}}/integration_tests/server/
port: 3000
no-cache: false
allowed-methods: |
["GET", "HEAD", "POST"]
log: "log.txt"
logTime: "false"

- run: curl -vvvv http://localhost:3000/pages/AMD.html && cat log.txt

- name: Run Browser integration tests
run: export LAUNCH_TYPE=amd && npm run test:browser

- name: Show expected changes in the changelog file
run: npm run release:test
4 changes: 2 additions & 2 deletions .github/workflows/on-pull-request.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI
name: Build and test

on:
push:
Expand Down Expand Up @@ -37,7 +37,7 @@ jobs:
- name: Run build
run: npm run build

- name: Run tests
- name: Run TS tests
run: npm test

- name: Show expected changes in the changelog file
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ build

./test.js
.coverage/
.DS_Store
.nvmrc
2 changes: 1 addition & 1 deletion dist/Classes/common/FormDataBuilder.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ declare class FormDataBuilder {
private FormDataConstructor;
constructor(FormDataConstructor: InputFormData);
createFormData(data: any): NodeFormData | FormData;
private isNodeFormData;
private isFormDataPackage;
private getAttachmentOptions;
private addMimeDataToFD;
private addFilesToFD;
Expand Down
14,292 changes: 14,289 additions & 3 deletions dist/mailgun.node.js

Large diffs are not rendered by default.

9,601 changes: 9,598 additions & 3 deletions dist/mailgun.web.js

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions integration_tests/configs/globalSetup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const { setup: setupDevServer } = require('jest-dev-server');
const setup = require('jest-environment-puppeteer/setup');
const fs = require('fs');
const path = require('path');

module.exports = async function globalSetup(globalConfig) {
if (process.env.CI !== true) { // local machine
fs.copyFileSync(path.join(__dirname, '../../dist/mailgun.web.js'), path.join(__dirname, '../server/dist/mailgun.web.js'));

// set up a web server to server pages
globalThis.servers = await setupDevServer({
command: 'http-server ./integration_tests/server -p 3000', // this goes to background
launchTimeout: 20000,
port: 3000
});
}

await setup(globalConfig);
console.log('globalSetup.js was invoked');
};
12 changes: 12 additions & 0 deletions integration_tests/configs/globalTeardown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { teardown: teardownDevServer } = require('jest-dev-server');
const teardownPuppeteer = require('jest-environment-puppeteer/teardown');

module.exports = async function globalTeardown(globalConfig) {
// shut down the testing http server.
if (process.env.CI !== true) { // local machine
await teardownDevServer(globalThis.servers);
}

await teardownPuppeteer(globalConfig);
console.log('globalTeardown.js was invoked');
};
33 changes: 33 additions & 0 deletions integration_tests/configs/setupMailgunClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable no-console */
/* global page, beforeAll */
const { default: mockServer } = require('pptr-mock-server');
const BrowserClient = require('../helpers/BrowserClient');
const NodeClient = require('../helpers/NodeClient');

const launchType = process.env.LAUNCH_TYPE;
beforeAll(async function () {
global.MailgunClient = null;
if (typeof page !== 'undefined') { // browser environment
// add page listeners
page.on('console', (message) => console.debug(`Browser console -> ${message.type()} ${message.text()}`))
.on('pageerror', ({ message }) => console.error(`Browser page error -> ${message}`))
.on('response', (response) => console.log(`Browser got response -> ${response.status()} ${response.url()}`))
.on('requestfailed', (request) => console.log(`Browser request failed ->${request.failure().errorText} ${request.url()}`));

global.server_url = 'http://localhost:3000';
const mockRequest = await mockServer.init(page, {
// By default all requests matching baseAppUrl are continued.
baseAppUrl: global.server_url,
});
const browserClient = new BrowserClient(mockRequest);
browserClient.setLaunchType(launchType);
await browserClient.initiateClient();
global.MailgunClient = browserClient;
} else {
const nodeClient = new NodeClient();
nodeClient.setLaunchType(launchType);
await nodeClient.initiateClient();
global.MailgunClient = nodeClient;
}
return global.MailgunClient;
});
6 changes: 6 additions & 0 deletions integration_tests/data/messageResponses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports.successResponse = {
body: {
message: 'Queued. Thank you.',
id: '<20111114174239.25659.5817@samples.mailgun.org>'
}
};
71 changes: 71 additions & 0 deletions integration_tests/helpers/BrowserClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* global page */
const { successResponse } = require('../data/messageResponses');

let client;

class BrowserClient {
constructor(mockRequest) {
this.launchType = 'amd';
/*
can be used only for checking object structure.
Doesn't contain the methods.
Client created in browser and came to node.js without methods implementations
*/
this.client = null;
this.mockRequest = mockRequest;
}

setLaunchType(launchType) {
const availableTypes = new Set(['amd']);
if (availableTypes.has(launchType)) {
this.launchType = launchType;
} else {
throw new Error(`Unknown launch type '${launchType}' available types are ${[...availableTypes]}`);
}
}

async initiateClient() {
if (this.launchType === 'amd') {
if (this.client) {
return this.client;
}

await page.goto(`${global.server_url}/pages/AMD.html`);
await page.waitForFunction(function () { return typeof window.mailgunClient !== 'undefined'; });
client = await page.evaluate(() => window.mailgunClient);
this.client = client;
}
return this.client;
}

async sendMessage(domain, messageData) {
if ('message' in messageData) {
this.mockRequest.post(`${global.server_url}/v3/test.domain.com/messages.mime`, 200, successResponse);
} else {
this.mockRequest.post(`${global.server_url}/v3/test.domain.com/messages`, 200, successResponse);
}
return page.evaluate(
(domain, messageData) => window.mailgunClient.messages.create(domain, messageData),
domain, messageData
);
}

async sendMessageWithAttachment(domain, messageData) {
await page.waitForSelector('input[type=file]');
const input = await page.$('input[type=file]');
await input.uploadFile('../../img/mailgun.png');
this.mockRequest.post(`${global.server_url}/v3/test.domain.com/messages`, 200, successResponse);
return page.evaluate(
async (domain, messageData) => {
const messageDataCopy = { ...messageData };
const inputFile = document.getElementById('fileUpload');
const mailgunLogo = inputFile.files[0];
messageDataCopy.attachment = [{ filename: mailgunLogo.name, data: mailgunLogo }];
return window.mailgunClient.messages.create(domain, messageDataCopy);
},
domain, messageData
);
}
}

module.exports = BrowserClient;
75 changes: 75 additions & 0 deletions integration_tests/helpers/NodeClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const formData = require('form-data');
const fs = require('fs');
const nock = require('nock');
const path = require('path');
const { successResponse } = require('../data/messageResponses');
const Mailgun = require('../../dist/mailgun.node');

class NodeClient {
constructor() {
this.launchType = 'native';
this.client = null;
this.url = 'https://api.mailgun.net';
}

setLaunchType(launchType) {
const availableTypes = new Set(['native', 'package']);
if (availableTypes.has(launchType)) {
this.launchType = launchType;
} else {
throw new Error(`Unknown launch type '${launchType}' available types are ${[...availableTypes]}`);
}
}

async initiateClient() {
let mailgun;

if (this.launchType === 'native') {
if (typeof global.FormData !== 'undefined') {
mailgun = new Mailgun(global.FormData);
} else {
throw new Error('global.FormData is undefined');
}
} else {
mailgun = new Mailgun(formData);
}

const client = mailgun.client({
username: 'js_test_username',
key: 'js_test_key',
public_key: 'js_test_key',
timeout: 10000,
});
this.client = client;
return this.client;
}

async sendMessage(domain, messageData) {
const api = nock(this.url);

if ('message' in messageData) {
api.post('/v3/test.domain.com/messages.mime').reply(200, successResponse.body);
} else {
api.post('/v3/test.domain.com/messages').reply(200, successResponse.body);
}
const result = await this.client.messages.create(domain, messageData);
api.done();
return result;
}

async sendMessageWithAttachment(domain, messageData) {
const messageDataClone = { ...messageData };
const img = await fs.readFileSync(path.resolve(__dirname, '../img/mailgun.png'));

const api = nock(this.url);
api.post('/v3/test.domain.com/messages').reply(200, successResponse.body);

messageDataClone.attachment = [{ filename: 'test_file', data: img }];
const result = await this.client.messages.create(domain, messageDataClone);

api.done();
return result;
}
}

module.exports = NodeClient;
Binary file added integration_tests/img/mailgun.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions integration_tests/jest-puppeteer.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = {
launch: {
headless: 'new',
slowMo: process.env.SLOWMO ? parseInt(process.env.SLOWMO, 10) : 0,
devtools: true,
product: 'chrome',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920,1080',
],
},
};
13 changes: 13 additions & 0 deletions integration_tests/jest.config.browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const path = require('path');

module.exports = {
preset: 'jest-puppeteer',
globalSetup: './configs/globalSetup.js',
globalTeardown: './configs/globalTeardown.js',
testEnvironment: 'jest-environment-puppeteer',
testMatch: ['**/tests/*.test.js'],
setupFilesAfterEnv: ['./configs/setupMailgunClient.js'],
testTimeout: 20000,
// maxConcurrency: 0,
maxWorkers: 9 // to avoid MaxListenersExceededWarning
};
5 changes: 5 additions & 0 deletions integration_tests/jest.config.node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
testEnvironment: 'node',
testMatch: ['**/tests/*.test.js'],
setupFilesAfterEnv: ['./configs/setupMailgunClient.js'],
};
Loading
Loading