Skip to content
Merged
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
5 changes: 2 additions & 3 deletions examples/general/accounts.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
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 });
// Listing accounts does not need an accountId, so you can use it to find yours.
const client = new MailtrapClient({ token: TOKEN });
Comment thread
izikaj marked this conversation as resolved.
Resolved

const accountsClient = client.general.accounts

Expand Down
37 changes: 13 additions & 24 deletions src/__tests__/lib/api/General.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import axios from "axios";

import General from "../../../lib/api/General";
import MailtrapError from "../../../lib/MailtrapError";

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

const { ACCOUNT_ID_MISSING } = CONFIG.ERRORS;

describe("lib/api/General: ", () => {
const testAccountId = 100;
Expand Down Expand Up @@ -44,39 +49,23 @@ describe("lib/api/General: ", () => {
const generalAPI = new General(axios);

it("throws error when accessing accountAccesses without accountId.", () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
generalAPI.accountAccesses;
}).toThrow(
"Account ID is required for this operation. Please provide accountId when creating GeneralAPI instance."
);
expect(() => generalAPI.accountAccesses).toThrow(MailtrapError);
expect(() => generalAPI.accountAccesses).toThrow(ACCOUNT_ID_MISSING);
});

it("throws error when accessing permissions without accountId.", () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
generalAPI.permissions;
}).toThrow(
"Account ID is required for this operation. Please provide accountId when creating GeneralAPI instance."
);
expect(() => generalAPI.permissions).toThrow(MailtrapError);
expect(() => generalAPI.permissions).toThrow(ACCOUNT_ID_MISSING);
});

it("throws error when accessing billing without accountId.", () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
generalAPI.billing;
}).toThrow(
"Account ID is required for this operation. Please provide accountId when creating GeneralAPI instance."
);
expect(() => generalAPI.billing).toThrow(MailtrapError);
expect(() => generalAPI.billing).toThrow(ACCOUNT_ID_MISSING);
});

it("throws error when accessing apiTokens without accountId.", () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
generalAPI.apiTokens;
}).toThrow(
"Account ID is required for this operation. Please provide accountId when creating GeneralAPI instance."
);
expect(() => generalAPI.apiTokens).toThrow(MailtrapError);
expect(() => generalAPI.apiTokens).toThrow(ACCOUNT_ID_MISSING);
});
});

Expand Down
60 changes: 45 additions & 15 deletions src/__tests__/lib/mailtrap-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import ContactEventsBaseAPI from "../../lib/api/ContactEvents";
import MarketingStatsBaseAPI from "../../lib/api/MarketingStats";

const { ERRORS, CLIENT_SETTINGS } = CONFIG;
const { TESTING_ENDPOINT, BULK_ENDPOINT, SENDING_ENDPOINT } = CLIENT_SETTINGS;
const { TESTING_ENDPOINT, BULK_ENDPOINT, SENDING_ENDPOINT, GENERAL_ENDPOINT } =
CLIENT_SETTINGS;
const { ACCOUNT_ID_MISSING, BULK_SANDBOX_INCOMPATIBLE, TEST_INBOX_ID_MISSING } =
ERRORS;

Expand Down Expand Up @@ -751,28 +752,57 @@ describe("lib/mailtrap-client: ", () => {
});

describe("get general(): ", () => {
it("rejects with Mailtrap error, when `accountId` is missing.", () => {
const client = new MailtrapClient({
token: "MY_API_TOKEN",
});
expect.assertions(1);
it("returns general API object with accounts, but rejects account-scoped resources, when `accountId` is missing.", async () => {
const accountsMock = new AxiosMockAdapter(axios);
const accounts = [{ id: 1, name: "Account", access_levels: [1000] }];
accountsMock
.onGet(`${GENERAL_ENDPOINT}/api/accounts`)
.reply(200, accounts);

try {
client.general;
} catch (error) {
expect(error).toEqual(new MailtrapError(ACCOUNT_ID_MISSING));
const { general } = new MailtrapClient({ token: "MY_API_TOKEN" });

expect(general).toBeInstanceOf(GeneralAPI);
await expect(general.accounts.getAllAccounts()).resolves.toEqual(
accounts
);
expect(() => general.billing).toThrow(MailtrapError);
expect(() => general.billing).toThrow(ACCOUNT_ID_MISSING);
} finally {
accountsMock.restore();
}
});

it("returns general API object when accountId is provided.", () => {
const client = new MailtrapClient({
it("rejects account-scoped resources, when `accountId` is 0.", () => {
const { general } = new MailtrapClient({
token: "MY_API_TOKEN",
accountId: 10,
accountId: 0,
});
expect.assertions(1);

const generalClient = client.general;
expect(generalClient).toBeInstanceOf(GeneralAPI);
expect(() => general.billing).toThrow(MailtrapError);
expect(() => general.billing).toThrow(ACCOUNT_ID_MISSING);
});

it("returns general API object scoped to the provided accountId.", async () => {
const billingMock = new AxiosMockAdapter(axios);
const usage = { billing: { cycle_start: "2026-11-01" } };
billingMock
.onGet(`${GENERAL_ENDPOINT}/api/accounts/10/billing/usage`)
.reply(200, usage);

try {
const { general } = new MailtrapClient({
token: "MY_API_TOKEN",
accountId: 10,
});

expect(general).toBeInstanceOf(GeneralAPI);
await expect(
general.billing.getCurrentBillingCycleUsage()
).resolves.toEqual(usage);
} finally {
billingMock.restore();
}
});
});

Expand Down
5 changes: 2 additions & 3 deletions src/lib/MailtrapClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,10 @@ export default class MailtrapClient {
}

/**
* Getter for General API.
* Getter for General API. `accounts` works without accountId; other resources require it.
*/
get general() {
const accountId = this.validateAccountIdPresence();
return new GeneralAPI(this.axios, accountId);
return new GeneralAPI(this.axios, this.accountId || undefined);
Comment thread
izikaj marked this conversation as resolved.
Resolved
}

/**
Expand Down
8 changes: 5 additions & 3 deletions src/lib/api/General.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { AxiosInstance } from "axios";

import CONFIG from "../../config";
import MailtrapError from "../MailtrapError";
import AccountAccessesApi from "./resources/AccountAccesses";
import AccountsApi from "./resources/Accounts";
import ApiTokensApi from "./resources/ApiTokens";
import BillingApi from "./resources/Billing";
import PermissionsApi from "./resources/Permissions";

const { ACCOUNT_ID_MISSING } = CONFIG.ERRORS;

export default class GeneralAPI {
public accounts: AccountsApi;

Expand Down Expand Up @@ -41,9 +45,7 @@ export default class GeneralAPI {
*/
private checkAccountIdPresence(): number {
if (this.accountId === null) {
throw new Error(
"Account ID is required for this operation. Please provide accountId when creating GeneralAPI instance."
);
throw new MailtrapError(ACCOUNT_ID_MISSING);
}
return this.accountId;
}
Expand Down
Loading