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

Email testing #24

Merged
merged 37 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
98bd5aa
config: init testing error messages and endpoints.
narekhovhannisyan Oct 26, 2023
715205b
lib: init axios logger.
narekhovhannisyan Oct 26, 2023
4b9a8c5
lib: add testing api functionality to mailtrap
narekhovhannisyan Oct 26, 2023
3923686
lib: in axios-logger logically separate imports.
narekhovhannisyan Oct 26, 2023
a7aee12
api: implement email testing.
narekhovhannisyan Oct 26, 2023
c581c89
api: implement testing inboxes.
narekhovhannisyan Oct 26, 2023
29ba6e8
api: implement testing messages.
narekhovhannisyan Oct 26, 2023
da217e3
api: implement testing projects.
narekhovhannisyan Oct 26, 2023
f8f3a56
types: update mailtrap client config.
narekhovhannisyan Oct 26, 2023
d95b86a
types: init projects api.
narekhovhannisyan Oct 26, 2023
a54271d
api: tune inbox resource to use types,
narekhovhannisyan Oct 26, 2023
20ce348
api: tune projects resource to use types.
narekhovhannisyan Oct 26, 2023
fb40717
types: init axios.
narekhovhannisyan Oct 26, 2023
5048328
lib: tune axios logger to handle more errors
narekhovhannisyan Oct 26, 2023
64e3f3e
types: init inboxes.
narekhovhannisyan Oct 26, 2023
1fa1c36
types: reuse inboxes types in projects.
narekhovhannisyan Oct 26, 2023
346f9a8
examples: init projects api usage.
narekhovhannisyan Oct 26, 2023
d4b1b13
examples: init inboxes api usage.
narekhovhannisyan Oct 26, 2023
6d173a8
examples: in inboxes ad newline at the end of file
narekhovhannisyan Oct 27, 2023
a6d7010
api: in testing temporary disable warn.
narekhovhannisyan Oct 27, 2023
f51d5cc
tests: support mailtrap client new config.
narekhovhannisyan Oct 27, 2023
84b7817
examples: rename testing api directory.
narekhovhannisyan Nov 1, 2023
ec5cb71
api: in Inboxes resource update docs.
narekhovhannisyan Nov 1, 2023
6937df7
api: in Projects resource update docs.
narekhovhannisyan Nov 1, 2023
f7e154d
resources: add return types to Messages.
narekhovhannisyan Nov 1, 2023
df054cf
types: init messages api.
narekhovhannisyan Nov 1, 2023
a8986b0
types: add base to axios.
narekhovhannisyan Nov 1, 2023
abe5024
lib: tune axios logger to handle base errors.
narekhovhannisyan Nov 1, 2023
69fffc4
examples: add testing messages sample.
narekhovhannisyan Nov 1, 2023
befde10
lib: in mailtrap client introduce testing getter.
narekhovhannisyan Nov 2, 2023
fa1c635
api: remove warning from testing api.
narekhovhannisyan Nov 2, 2023
9f677f7
examples: in testing inboxec uncomment create call
narekhovhannisyan Nov 3, 2023
2efe22a
lib: tune axios logger to support error object
narekhovhannisyan Nov 9, 2023
2e3ae15
lib: introduce axios response interceptor.
narekhovhannisyan Nov 9, 2023
f827336
resources: remove error handling from methods.
narekhovhannisyan Nov 9, 2023
437453f
resources: remove error handling from message
narekhovhannisyan Nov 9, 2023
74146d1
resources: remove error handling from projects
narekhovhannisyan Nov 9, 2023
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
35 changes: 35 additions & 0 deletions examples/testing/inboxes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { MailtrapClient } from "../../src"

const TOKEN = "<YOUR-TOKEN-HERE>";
const TEST_INBOX_ID = "<YOUR-TEST-INBOX-ID-HERE>"
const ACCOUNT_ID = "<YOUR-ACCOUNT-ID-HERE>"

const client = new MailtrapClient({ token: TOKEN, testInboxId: TEST_INBOX_ID, accountId: ACCOUNT_ID });

const projectsClient = client.testing.projects
const inboxesClient = client.testing.inboxes

projectsClient.getList()
.then(async (projects) => {
if (projects && projects.length > 0) {
const firstProjectId = projects[0].id

// const inbox = await inboxesClient.create(firstProjectId, 'test-inbox')
narekhovhannisyan marked this conversation as resolved.
Show resolved Hide resolved

const inboxes = await inboxesClient.getList()

if (inboxes && inboxes.length > 0) {
const firstInboxId = inboxes[0].id

const inboxAttributes = await inboxesClient.getInboxAttributes(firstInboxId)
await inboxesClient.updateInbox(firstInboxId, {name: 'mock-name', emailUsername: 'mocker'})
await inboxesClient.cleanInbox(firstInboxId)
await inboxesClient.markAsRead(firstInboxId)
await inboxesClient.resetCredentials(firstInboxId)
await inboxesClient.enableEmailAddress(firstInboxId)
const response = await inboxesClient.resetEmailAddress(firstInboxId)

console.log(response)
}
}
})
41 changes: 41 additions & 0 deletions examples/testing/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { MailtrapClient } from "../../src"

const TOKEN = "<YOUR-TOKEN-HERE>";
const TEST_INBOX_ID = "<YOUR-TEST-INBOX-ID-HERE>"
const ACCOUNT_ID = "<YOUR-ACCOUNT-ID-HERE>"

const client = new MailtrapClient({ token: TOKEN, testInboxId: TEST_INBOX_ID, accountId: ACCOUNT_ID });

const inboxesClient = client.testing.inboxes
const messagesClient = client.testing.messages

inboxesClient.getList()
.then(async (inboxes) => {
if (inboxes && inboxes.length > 0) {
const firstInboxId = inboxes[0].id

const messages = await messagesClient.get(firstInboxId)

if (messages && messages.length > 0) {
const firstMessageId = messages[0].id

await messagesClient.get(firstInboxId)
await messagesClient.getHtmlAnalysis(firstInboxId, firstMessageId)
await messagesClient.getHtmlMessage(firstInboxId, firstMessageId)
await messagesClient.getTextMessage(firstInboxId, firstMessageId)
await messagesClient.getMailHeaders(firstInboxId, firstMessageId)
await messagesClient.getMessageAsEml(firstInboxId, firstMessageId)
await messagesClient.getMessageHtmlSource(firstInboxId, firstMessageId)
await messagesClient.getRawMessage(firstInboxId, firstMessageId)
await messagesClient.getSpamScore(firstInboxId, firstMessageId)
await messagesClient.showEmailMessage(firstInboxId, firstMessageId)
await messagesClient.updateMessage(firstInboxId, firstMessageId, {
isRead: false
})
await messagesClient.forward(firstInboxId, firstMessageId, 'mock@mail.com')
const response = await messagesClient.deleteMessage(firstInboxId, firstMessageId)

console.log(response)
}
}
})
22 changes: 22 additions & 0 deletions examples/testing/projects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { MailtrapClient } from "mailtrap"

const TOKEN = "<YOUR-TOKEN-HERE>";
const TEST_INBOX_ID = "<YOUR-TEST-INBOX-ID-HERE>"
const ACCOUNT_ID = "<YOUR-ACCOUNT-ID-HERE>"

const client = new MailtrapClient({ token: TOKEN, testInboxId: TEST_INBOX_ID, accountId: ACCOUNT_ID });

const projectsClient = client.testing.projects

projectsClient.getList()
.then(async (projects) => {
if (projects) {
const firstProject = projects[0].id // Grab the first project.

const updatedProject =
await projectsClient.update(firstProject, 'test-project') // Update the name of the project.

await projectsClient.delete()
}
})
.catch(console.error)
12 changes: 5 additions & 7 deletions src/__tests__/lib/mailtrap-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,9 @@ describe("lib/mailtrap-client: ", () => {
const client = new MailtrapClient({ token: "MY_API_TOKEN" });
const result = await client.send(goodMail);

expect(mock.history.post[0].baseURL).toEqual(
"https://send.api.mailtrap.io"
expect(mock.history.post[0].url).toEqual(
"https://send.api.mailtrap.io/api/send"
);
expect(mock.history.post[0].url).toEqual("/api/send");
expect(mock.history.post[0].headers).toEqual({
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json",
Expand Down Expand Up @@ -94,10 +93,9 @@ describe("lib/mailtrap-client: ", () => {
},
});

expect(mock.history.post[0].baseURL).toEqual(
"https://send.api.mailtrap.io"
expect(mock.history.post[0].url).toEqual(
"https://send.api.mailtrap.io/api/send"
);
expect(mock.history.post[0].url).toEqual("/api/send");
expect(mock.history.post[0].headers).toEqual({
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json",
Expand Down Expand Up @@ -130,7 +128,7 @@ describe("lib/mailtrap-client: ", () => {
} catch (err) {
expect(err).toBeInstanceOf(MailtrapError);
if (err instanceof MailtrapError) {
expect(err.message).toEqual("subject is missing, message is missing");
expect(err.message).toEqual("subject is missing,message is missing");
// @ts-expect-error ES5 types don't know about cause property
expect(err.cause).toBeInstanceOf(AxiosError);
}
Expand Down
7 changes: 6 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ export default {
FROM_REQUIRED: "From is required.",
SENDING_FAILED: "Sending failed.",
NO_DATA_ERROR: "No Data.",
TEST_INBOX_ID_MISSING: "testInboxId is missing, testing API will not work.",
ACCOUNT_ID_MISSING:
"accountId is missing, some features of testing API may not work properly.",
},
CLIENT_SETTINGS: {
MAILTRAP_ENDPOINT: "https://send.api.mailtrap.io",
SENDING_ENDPOINT: "https://send.api.mailtrap.io",
TESTING_ENDPOINT: "https://sandbox.api.mailtrap.io",
GENERAL_ENDPOINT: "https://mailtrap.io",
USER_AGENT:
"mailtrap-nodejs (https://github.com/railsware/mailtrap-nodejs)",
MAX_REDIRECTS: 0,
Expand Down
57 changes: 57 additions & 0 deletions src/lib/api/Testing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import axios, { AxiosInstance } from "axios";

import ProjectsApi from "./resources/Projects";
import InboxesApi from "./resources/Inboxes";
import MessagesApi from "./resources/Messages";
import encodeMailBuffers from "../mail-buffer-encoder";
import handleSendingError from "../axios-logger";

import CONFIG from "../../config";

import { Mail, SendResponse } from "../../types/mailtrap";

const { CLIENT_SETTINGS } = CONFIG;
const { TESTING_ENDPOINT } = CLIENT_SETTINGS;

export default class TestingAPI {
private client: AxiosInstance;

private testInboxId?: number;

private accountId?: number;

public projects: ProjectsApi;

public inboxes: InboxesApi;

public messages: MessagesApi;

constructor(client: AxiosInstance, testInboxId?: number, accountId?: number) {
this.client = client;
this.accountId = accountId;
this.testInboxId = testInboxId;
this.projects = new ProjectsApi(this.client, this.accountId);
this.inboxes = new InboxesApi(this.client, this.accountId);
this.messages = new MessagesApi(this.client, this.accountId);
}

public async send(mail: Mail): Promise<SendResponse> {
const url = `${TESTING_ENDPOINT}/api/send/${this.testInboxId}`;
const preparedMail = encodeMailBuffers(mail);

try {
const axiosResponse = await this.client.post<SendResponse>(
url,
preparedMail
);

return axiosResponse.data;
} catch (error) {
if (axios.isAxiosError(error)) {
handleSendingError(error);
}

throw error; // should not happen, but otherwise rethrow error as is
}
}
}
179 changes: 179 additions & 0 deletions src/lib/api/resources/Inboxes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { AxiosInstance } from "axios";

import handleSendingError from "../../axios-logger";

import CONFIG from "../../../config";

import { Inbox, UpdateInboxParams } from "../../../types/api/inboxes";

const { CLIENT_SETTINGS } = CONFIG;
const { GENERAL_ENDPOINT } = CLIENT_SETTINGS;

export default class InboxesApi {
private client: AxiosInstance;

private accountId?: number;

private inboxesURL: string;

constructor(client: AxiosInstance, accountId?: number) {
this.client = client;
this.accountId = accountId;
this.inboxesURL = `${GENERAL_ENDPOINT}/api/accounts/${this.accountId}/inboxes`;
}

/**
* Creates an inbox in a project.
*/
public async create(projectId: number, inboxName: string) {
const url = `${GENERAL_ENDPOINT}/api/accounts/${this.accountId}/projects/${projectId}/inboxes`;
const data = { inbox: { name: inboxName } };

try {
const apiResponse = await this.client.post<Inbox>(url, data);

return apiResponse.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Gets inbox attributes by inbox id.
*/
public async getInboxAttributes(inboxId: number) {
const url = `${this.inboxesURL}/${inboxId}`;

try {
const apiResponse = await this.client.get<Inbox>(url);

return apiResponse.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Deletes an inbox with all its emails.
*/
public async delete(inboxId: number) {
const url = `${this.inboxesURL}/${inboxId}`;

try {
const apiResponse = await this.client.delete<Inbox>(url);

return apiResponse.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Updates inbox name, inbox email username.
*/
public async updateInbox(inboxId: number, params: UpdateInboxParams) {
const url = `${this.inboxesURL}/${inboxId}`;
const data = {
inbox: {
name: params.name,
email_username: params.emailUsername,
},
};

try {
const apiRespone = await this.client.patch<Inbox>(url, data);

return apiRespone.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Deletes all messages (emails) from inbox.
*/
public async cleanInbox(inboxId: number) {
const url = `${this.inboxesURL}/${inboxId}/clean`;

try {
const apiRespone = await this.client.patch<Inbox>(url);

return apiRespone.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Marks all messages in the inbox as read.
*/
public async markAsRead(inboxId: number) {
const url = `${this.inboxesURL}/${inboxId}/all_read`;

try {
const apiRespone = await this.client.patch<Inbox>(url);

return apiRespone.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Resets SMTP credentials of the inbox.
*/
public async resetCredentials(inboxId: number) {
const url = `${this.inboxesURL}/${inboxId}/reset_credentials`;

try {
const apiRespone = await this.client.patch<Inbox>(url);

return apiRespone.data;
} catch (error) {
return handleSendingError(error);
narekhovhannisyan marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* Turns the email address of the inbox on/off.
*/
public async enableEmailAddress(inboxId: number) {
const url = `${this.inboxesURL}/${inboxId}/toggle_email_username`;

try {
const apiRespone = await this.client.patch<Inbox>(url);

return apiRespone.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Resets username of email address per inbox.
*/
public async resetEmailAddress(inboxId: number) {
const url = `${this.inboxesURL}/${inboxId}/reset_email_username`;

try {
const apiRespone = await this.client.patch<Inbox>(url);

return apiRespone.data;
} catch (error) {
return handleSendingError(error);
}
}

/**
* Gets a list of inboxes.
*/
public async getList() {
try {
const apiRespone = await this.client.get<Inbox[]>(this.inboxesURL);

return apiRespone.data;
} catch (error) {
return handleSendingError(error);
}
}
}
Loading
Loading