cypress-mailosaur
Version:
Extends Cypress' cy commands that let you integrate email and SMS testing into your continuous integration process.
478 lines (477 loc) • 20.5 kB
JavaScript
;
/* eslint-disable class-methods-use-this */
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResultEnum = void 0;
const request_1 = __importDefault(require("./request"));
/**
* The result of a deliverability check
*/
var ResultEnum;
(function (ResultEnum) {
/**
* The check had a positive result
*/
ResultEnum[ResultEnum["Pass"] = 0] = "Pass";
/**
* The check was acceptable but could be improved
*/
ResultEnum[ResultEnum["Warning"] = 1] = "Warning";
/**
* The check had a negative result
*/
ResultEnum[ResultEnum["Fail"] = 2] = "Fail";
/**
* The check was inconclusive due to a timeout
*/
ResultEnum[ResultEnum["Timeout"] = 3] = "Timeout";
})(ResultEnum || (exports.ResultEnum = ResultEnum = {}));
class MailosaurCommands {
static get cypressCommands() {
return [
'mailosaurSetApiKey',
'mailosaurListServers',
'mailosaurCreateServer',
'mailosaurGetServer',
'mailosaurGetServerPassword',
'mailosaurUpdateServer',
'mailosaurDeleteServer',
'mailosaurListMessages',
'mailosaurCreateMessage',
'mailosaurForwardMessage',
'mailosaurReplyToMessage',
'mailosaurGetMessage',
'mailosaurGetMessageById',
'mailosaurSearchMessages',
'mailosaurGetMessagesBySubject',
'mailosaurGetMessagesByBody',
'mailosaurGetMessagesBySentFrom',
'mailosaurGetMessagesBySentTo',
'mailosaurDeleteMessage',
'mailosaurDeleteAllMessages',
'mailosaurDownloadAttachment',
'mailosaurDownloadMessage',
'mailosaurGetSpamAnalysis',
'mailosaurGetDeliverabilityReport',
'mailosaurGenerateEmailAddress',
'mailosaurGetUsageLimits',
'mailosaurGetUsageTransactions',
'mailosaurListDevices',
'mailosaurCreateDevice',
'mailosaurGetDeviceOtp',
'mailosaurDeleteDevice',
'mailosaurListPreviewEmailClients',
'mailosaurGenerateEmailPreviews',
'mailosaurDownloadPreview',
];
}
constructor() {
this._request = null;
}
init() {
if (this._request) {
return cy.wrap(this._request);
}
return cy
.env(['MAILOSAUR_API_KEY', 'MAILOSAUR_BASE_URL'])
.then(({ MAILOSAUR_API_KEY: apiKey, MAILOSAUR_BASE_URL: baseUrl, }) => {
this._request = new request_1.default({ apiKey, baseUrl });
return this._request;
});
}
mailosaurSetApiKey(apiKey) {
return cy
.env(['MAILOSAUR_BASE_URL'])
.then(({ MAILOSAUR_BASE_URL: baseUrl }) => {
this._request = new request_1.default({ apiKey, baseUrl });
});
}
/**
* Returns a list of your virtual servers. Servers are returned sorted in alphabetical order.
*/
mailosaurListServers() {
return this.init().then((req) => req.get('api/servers'));
}
/**
* Creates a new virtual server.
* @param options Options used to create a new Mailosaur server.
*/
mailosaurCreateServer(options) {
return this.init().then((req) => req.post('api/servers', options));
}
/**
* Retrieves the detail for a single server.
* @param serverId The unique identifier of the server.
*/
mailosaurGetServer(serverId) {
return this.init().then((req) => req.get(`api/servers/${serverId}`));
}
/**
* Retrieves the password for a server. This password can be used for SMTP, POP3, and IMAP connectivity.
* @param serverId The unique identifier of the server.
*/
mailosaurGetServerPassword(serverId) {
return this.init().then((req) => req
.get(`api/servers/${serverId}/password`)
.then((result) => result.value));
}
/**
* Updates the attributes of a server.
* @param server The updated server.
*/
mailosaurUpdateServer(server = {}) {
return this.init().then((req) => req.put(`api/servers/${server.id}`, server));
}
/**
* Permanently delete a server. This will also delete all messages, associated attachments, etc. within the server. This operation cannot be undone.
* @param serverId The unique identifier of the server.
*/
mailosaurDeleteServer(serverId) {
return this.init().then((req) => req.del(`api/servers/${serverId}`));
}
/**
* Permenantly delete all messages within a server.
* @param serverId The unique identifier of the server.
*/
mailosaurDeleteAllMessages(serverId) {
return this.init().then((req) => req.del(`api/messages?server=${serverId}`));
}
/**
* Returns a list of your messages in summary form. The summaries are returned sorted by received date, with the most recently-received messages appearing first.
* @param serverId The unique identifier of the required server.
* @param options Message listing options.
*/
mailosaurListMessages(serverId, options = {}) {
return this.init().then((req) => {
const qs = {
server: serverId,
page: options.page,
itemsPerPage: options.itemsPerPage,
receivedAfter: options.receivedAfter,
dir: options.dir,
};
return req.get('api/messages', { qs });
});
}
/**
* Creates a new message that can be sent to a verified email address. This is useful
* in scenarios where you want an email to trigger a workflow in your product.
* @param serverId The unique identifier of the required server.
* @param options Options to use when creating a new message.
*/
mailosaurCreateMessage(serverId, options) {
return this.init().then((req) => req.post(`api/messages?server=${serverId}`, options));
}
/**
* Forwards the specified email to a verified email address.
* @param messageId The unique identifier of the message to be forwarded.
* @param options Options to use when forwarding a message.
*/
mailosaurForwardMessage(messageId, options) {
return this.init().then((req) => req.post(`api/messages/${messageId}/forward`, options));
}
/**
* Sends a reply to the specified message. This is useful for when simulating a user replying to one of your email or SMS messages.
* @param messageId The unique identifier of the message to be forwarded.
* @param options Options to use when replying to a message.
*/
mailosaurReplyToMessage(messageId, options) {
return this.init().then((req) => req.post(`api/messages/${messageId}/reply`, options));
}
/**
* Waits for a message to be found. Returns as soon as a message matching the specified search criteria is found.
* **Recommended:** This is the most efficient method of looking up a message, therefore we recommend using it wherever possible.
* @param serverId The unique identifier of the containing server.
* @param criteria The criteria with which to find messages during a search.
* @param options Search options.
*/
mailosaurGetMessage(serverId, criteria = {}, options = {}) {
// Only return 1 result
options.page = 0;
options.itemsPerPage = 1;
// Default timeout to 10s
options.timeout = options.timeout || 10000;
// Default receivedAfter to 1h
options.receivedAfter =
options.receivedAfter || new Date(Date.now() - 3600000);
return cy
.mailosaurSearchMessages(serverId, criteria, options)
.then((result) => { var _a; return cy.mailosaurGetMessageById((_a = result.items) === null || _a === void 0 ? void 0 : _a[0].id); });
}
/**
* Retrieves the detail for a single message. Must be used in conjunction with either list or
* search in order to get the unique identifier for the required message.
* @param messageId The unique identifier of the message to be retrieved.
*/
mailosaurGetMessageById(messageId) {
return this.init().then((req) => req.get(`api/messages/${messageId}`));
}
/**
* Returns a list of messages matching the specified search criteria, in summary form.
* The messages are returned sorted by received date, with the most recently-received messages appearing first.
* @param serverId The unique identifier of the server to search.
* @param searchCriteria The criteria with which to find messages during a search.
* @param options Search options.
*/
mailosaurSearchMessages(serverId, searchCriteria = {}, options = {}) {
return this.init().then((req) => {
let pollCount = 0;
const startTime = Date.now();
const qs = {
server: serverId,
page: options.page,
itemsPerPage: options.itemsPerPage,
receivedAfter: options.receivedAfter,
dir: options.dir,
};
if (!Number.isInteger(options.timeout)) {
options.timeout = 0;
}
if (typeof options.errorOnTimeout !== 'boolean') {
options.errorOnTimeout = true;
}
const fn = (resolve, reject) => () => {
const reqOptions = req.buildOptions('POST', 'api/messages/search');
reqOptions.qs = qs;
reqOptions.json = searchCriteria;
return Cypress.backend('http:request', reqOptions)
.timeout(10000)
.then(req.getResponseHandler(true))
.then((result) => {
var _a;
const { body, headers } = result;
if (options.timeout && !((_a = body.items) === null || _a === void 0 ? void 0 : _a.length)) {
const delayPattern = (headers['x-ms-delay'] || '1000')
.split(',')
.map((x) => parseInt(x, 10));
const delay = pollCount >= delayPattern.length
? delayPattern[delayPattern.length - 1]
: delayPattern[pollCount];
pollCount += 1;
// Stop if timeout will be exceeded
if (Date.now() - startTime + delay > (options.timeout || 0)) {
return options.errorOnTimeout === false
? resolve(body)
: reject(new Error('No matching messages found in time. By default, only messages received in the last hour are checked ' +
`(use receivedAfter to override this). The search criteria used for this query was ` +
`[${JSON.stringify(searchCriteria)}] which timed out after ${options.timeout}ms`));
}
return setTimeout(fn(resolve, reject), delay);
}
return resolve(body);
});
};
return cy.wrap(new Cypress.Promise((resolve, reject) => {
fn(resolve, reject)();
}), {
log: false,
timeout: (options.timeout || 0) + 10000,
});
});
}
/**
* Returns a list of messages matching the specified subject, in summary form.
* The messages are returned sorted by received date, with the most recently-received messages appearing first.
* @param serverId The unique identifier of the server to search.
* @param subject The value to seek within the subject line of a target email.
*/
mailosaurGetMessagesBySubject(serverId, subject) {
return cy.mailosaurSearchMessages(serverId, {
subject,
});
}
/**
* Returns a list of messages matching the specified body, in summary form.
* The messages are returned sorted by received date, with the most recently-received messages appearing first.
* @param serverId The unique identifier of the server to search.
* @param body The value to seek within the body of the target message.
*/
mailosaurGetMessagesByBody(serverId, body) {
return cy.mailosaurSearchMessages(serverId, {
body,
});
}
/**
* Returns a list of messages matching the specified sender, in summary form.
* The messages are returned sorted by received date, with the most recently-received messages appearing first.
* @param serverId The unique identifier of the server to search.
* @param sentFrom The full email address (or phone number for SMS) from which the target message was sent.
*/
mailosaurGetMessagesBySentFrom(serverId, sentFrom) {
return cy.mailosaurSearchMessages(serverId, {
sentFrom,
});
}
/**
* Returns a list of messages matching the specified recipient, in summary form.
* The messages are returned sorted by received date, with the most recently-received messages appearing first.
* @param serverId The unique identifier of the server to search.
* @param sentTo The full email address (or phone number for SMS) to which the target message was sent.
*/
mailosaurGetMessagesBySentTo(serverId, sentTo) {
return cy.mailosaurSearchMessages(serverId, {
sentTo,
});
}
/**
* Downloads a single attachment.
* @param attachmentId The identifier for the required attachment.
*/
mailosaurDownloadAttachment(attachmentId) {
return this.init().then((req) => req.get(`api/files/attachments/${attachmentId}`, { encoding: 'binary' }));
}
/**
* Downloads an EML file representing the specified email.
* @param messageId The identifier for the required message.
*/
mailosaurDownloadMessage(messageId) {
return this.init().then((req) => req.get(`api/files/email/${messageId}`));
}
/**
* Permanently deletes a message. Also deletes any attachments related to the message. This operation cannot be undone.
* @param messageId The identifier for the message.
*/
mailosaurDeleteMessage(messageId) {
return this.init().then((req) => req.del(`api/messages/${messageId}`));
}
/**
* Perform a spam analysis of an email.
* @param messageId The identifier of the message to be analyzed.
*/
mailosaurGetSpamAnalysis(messageId) {
return this.init().then((req) => req.get(`api/analysis/spam/${messageId}`));
}
/**
* Perform a deliverability report of an email.
* @param messageId The identifier of the message to be analyzed.
*/
mailosaurGetDeliverabilityReport(messageId) {
return this.init().then((req) => req.get(`api/analysis/deliverability/${messageId}`));
}
/**
* Generates a random email address by appending a random string in front of the server's
* domain name.
* @param serverId The identifier of the server.
*/
mailosaurGenerateEmailAddress(serverId) {
return cy
.env(['MAILOSAUR_SMTP_HOST'])
.then(({ MAILOSAUR_SMTP_HOST: host }) => {
const actualHost = host || 'mailosaur.net';
const random = (Math.random() + 1).toString(36).substring(7);
return cy.wrap(`${random}@${serverId}.${actualHost}`);
});
}
/**
* Retrieve account usage limits. Details the current limits and usage for your account.
* This endpoint requires authentication with an account-level API key.
*/
mailosaurGetUsageLimits() {
return this.init().then((req) => req.get('api/usage/limits'));
}
/**
* Retrieves the last 31 days of transactional usage.
* This endpoint requires authentication with an account-level API key.
*/
mailosaurGetUsageTransactions() {
return this.init().then((req) => req.get('api/usage/transactions'));
}
/**
* Returns a list of your virtual security devices.
*/
mailosaurListDevices() {
return this.init().then((req) => req.get('api/devices'));
}
/**
* Creates a new virtual security device.
* @param options Options used to create a new Mailosaur virtual security device.
*/
mailosaurCreateDevice(options) {
return this.init().then((req) => req.post('api/devices', options));
}
/**
* Retrieves the current one-time password for a saved device, or given base32-encoded shared secret.
* @param query Either the unique identifier of the device, or a base32-encoded shared secret.
*/
mailosaurGetDeviceOtp(query) {
return this.init().then((req) => {
if (!query || query.indexOf('-') > -1) {
return req.get(`api/devices/${query}/otp`);
}
return req.post('api/devices/otp', {
sharedSecret: query,
});
});
}
/**
* Permanently delete a device. This operation cannot be undone.
* @param deviceId The unique identifier of the device.
*/
mailosaurDeleteDevice(deviceId) {
return this.init().then((req) => req.del(`api/devices/${deviceId}`));
}
/**
* List all email clients that can be used to generate email previews.
*/
mailosaurListPreviewEmailClients() {
return this.init().then((req) => req.get('api/screenshots/clients'));
}
/**
* Generates screenshots of an email rendered in the specified email clients.
* @param messageId The identifier of the email to preview.
* @param options The options with which to generate previews.
*/
mailosaurGenerateEmailPreviews(messageId, options) {
return this.init().then((req) => req.post(`api/messages/${messageId}/screenshots`, options));
}
/**
* Downloads a screenshot of your email rendered in a real email client. Simply supply
* the unique identifier for the required preview.
* @param previewId The identifier of the email preview to be downloaded.
*/
mailosaurDownloadPreview(previewId) {
return this.init().then((req) => {
const timeout = 120000;
let pollCount = 0;
const startTime = Date.now();
const fn = (resolve, reject) => () => {
const reqOptions = req.buildOptions('GET', `api/files/screenshots/${previewId}`);
reqOptions.encoding = 'binary';
return Cypress.backend('http:request', reqOptions)
.timeout(timeout)
.then(req.getResponseHandler(true))
.then((result) => {
const { body, headers, status } = result;
if (status === 200) {
return resolve(body);
}
if (status !== 202) {
return reject(new Error(`Failed to download preview. Status code: ${status}`));
}
const delayPattern = (headers['x-ms-delay'] || '1000')
.split(',')
.map((x) => parseInt(x, 10));
const delay = pollCount >= delayPattern.length
? delayPattern[delayPattern.length - 1]
: delayPattern[pollCount];
pollCount += 1;
// Stop if timeout will be exceeded
if (Date.now() - startTime + delay > timeout) {
return reject(new Error(`An email preview was not generated in time. The email client may not be available, or the preview ID ` +
`[${previewId}] may be incorrect.`));
}
return setTimeout(fn(resolve, reject), delay);
});
};
return cy.wrap(new Cypress.Promise((resolve, reject) => {
fn(resolve, reject)();
}), {
log: false,
timeout: timeout + 10000,
});
});
}
}
exports.default = MailosaurCommands;