@lokalise/node-api
Version:
Official Lokalise API 2.0 Node.js client
237 lines (196 loc) • 6.04 kB
text/typescript
import type { ProjectWithPagination } from "../../src/main.js";
import { ApiError } from "../../src/main.js";
import { describe, expect, it, LokaliseApi, Stub, vi } from "../setup.js";
describe("Errors", () => {
const lokaliseApi = new LokaliseApi({ apiKey: process.env.API_KEY });
const project_id = "803826145ba90b42d5d860.46800099";
it("is expected to reject with when there are too many requests", async () => {
const stub = new Stub({
fixture: "errors/error_429.json",
uri: `projects/${project_id}`,
status: 429,
});
await stub.setStub();
await expect(lokaliseApi.projects().get(project_id)).rejects.toMatchObject({
message: "Too many requests",
code: 429,
details: { reason: "server error without details" },
});
});
it("is expected to throw when JSON processing failed", async () => {
const stub = new Stub({
uri: `projects/${project_id}`,
status: 200,
});
await stub.setStub();
await expect(lokaliseApi.projects().get(project_id)).rejects.toMatchObject({
message: "Unexpected end of JSON input",
code: 200,
details: {
statusText: "OK",
reason: "JSON parsing error",
},
});
});
it("is expected to handle cases when error codes are not numbers", async () => {
const stub = new Stub({
uri: `projects/${project_id}`,
status: 500,
fixture: "errors/error_with_malformed_code.json",
});
await stub.setStub();
await expect(lokaliseApi.projects().get(project_id)).rejects.toMatchObject({
message: "An unknown error occurred",
code: 500,
details: {
reason: "unhandled error format",
data: '{"code":"invalid","message":"Server error"}',
},
});
});
it("is expected to handle cases when error is nested and error codes are not numbers", async () => {
const stub = new Stub({
uri: `projects/${project_id}`,
status: 404,
fixture: "errors/nested_error_with_malformed_code.json",
});
await stub.setStub();
await expect(lokaliseApi.projects().get(project_id)).rejects.toMatchObject({
message: "Server error",
code: 500,
details: {
reason: "server error without details",
},
});
});
it("handles exceptions", async () => {
const fakeProjectId = "803";
const stub = new Stub({
uri: `projects/${fakeProjectId}/branches`,
doFail: true,
});
await stub.setStub();
try {
await lokaliseApi.branches().list({
project_id: fakeProjectId,
});
} catch (e) {
expect(e).toBeInstanceOf(ApiError);
expect(e.message).toBe("fetch failed");
expect(e.code).toBe(500);
expect(e.details).toEqual({ reason: "network or fetch error" });
}
});
it("handles plain errors", async () => {
const fakeProjectId = "803";
const stub = new Stub({
fixture: "errors/error_plain.json",
uri: `projects/${fakeProjectId}/branches`,
status: 401,
});
await stub.setStub();
await expect(
lokaliseApi.branches().list({ project_id: fakeProjectId }),
).rejects.toMatchObject({
message: "Auth error",
code: 401,
details: { reason: "server error without details" },
});
});
it("handles plain errors with errorCode", async () => {
const stub = new Stub({
fixture: "errors/error_code.json",
uri: `projects/${project_id}/branches`,
status: 401,
});
await stub.setStub();
await expect(
lokaliseApi.branches().list({ project_id: project_id }),
).rejects.toMatchObject({
message: "Auth error",
code: 401,
details: { status: "failed" },
});
});
it("handles empty nested errors", async () => {
const stub = new Stub({
fixture: "errors/error_empty.json",
uri: `projects/${project_id}/branches`,
status: 401,
});
await stub.setStub();
await expect(
lokaliseApi.branches().list({ project_id: project_id }),
).rejects.toMatchObject({
message: "Unknown error",
code: 500,
details: { reason: "server error without details" },
});
});
it("handles unexpected fetch errors", async () => {
const originalFetch = global.fetch;
global.fetch = vi.fn().mockRejectedValueOnce("unexpected fetch error");
await expect(
lokaliseApi.branches().list({ project_id: project_id }),
).rejects.toMatchObject({
message: "An unknown error occurred",
code: 500,
details: { reason: "unexpected fetch error" },
});
global.fetch = originalFetch;
});
it("handles errors when the response is unexpected", async () => {
const originalFetch = global.fetch;
global.fetch = vi.fn().mockResolvedValueOnce({
ok: false,
status: 400,
statusText: "Bad Request",
json: async () => "Very unexpected string in response",
headers: new Headers(),
} as Response);
await expect(
lokaliseApi.branches().list({ project_id: project_id }),
).rejects.toMatchObject({
message: "An unknown error occurred",
code: 500,
details: { reason: "unexpected response format" },
});
global.fetch = originalFetch;
});
it("handles params-related errors", async () => {
const params = <ProjectWithPagination>{};
await expect(lokaliseApi.branches().list(params)).rejects.toThrow(
"Missing required parameter: project_id",
);
});
it("handles error 500", async () => {
const fakeProjectId = "803";
const params = {
name: "hotfix/really-important",
};
const stub = new Stub({
fixture: "errors/error_500.json",
uri: `projects/${fakeProjectId}/branches`,
status: 500,
body: params,
method: "POST",
});
await stub.setStub();
try {
await lokaliseApi
.branches()
.create(params, { project_id: fakeProjectId });
} catch (error) {
expect(error.message).toEqual("Something very bad has happened");
expect(error.code).toEqual(500);
expect(error.details).toEqual({ status: "failed" });
expect(String(error)).toEqual(
"LokaliseError: Something very bad has happened (Code: 500) | Details: status: failed",
);
}
});
it("converts errors without details to string", () => {
const error = new ApiError("Sample error", 404);
expect(String(error)).toEqual("LokaliseError: Sample error (Code: 404)");
});
});