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
9 changes: 9 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
./__tests__/**
./github/**
./aseets/**
./docs/**
./examples/**
./src/**
.editorconfig
jest.config.js
tsconfig.json
40 changes: 40 additions & 0 deletions __tests__/core/init.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { Context } from "@/types";
import { init } from "@/core/init";
import Service from "@/core/service";
import Config from "@/global/config";
import useServices from "@/hooks/useServices";

enum Test {
endpoint1 = "/endpoint1",
endpoint2 = "/endpoint2",
endpoint3 = "/endpoint3",
}

describe("init", () => {
const baseURL = "http://api.example.io";
beforeEach(() => {
jest.clearAllMocks();
init({ baseURL, endpoints: Test });
});

it("should set the baseURL correctly", () => {
expect(Config.instance().baseURL).toBe(baseURL);
});

it("should define globalThis.useRequests correctly", () => {
const ctx = globalThis as unknown as Context;
expect(ctx.useRequests).toBeDefined();
});

it("should create services correctly", () => {
const svs = useServices<typeof Test>();
expect(svs.endpoint1).toBeDefined();
expect(svs.endpoint1).toBeInstanceOf(Service);

expect(svs.endpoint2).toBeDefined();
expect(svs.endpoint2).toBeInstanceOf(Service);

expect(svs.endpoint3).toBeDefined();
expect(svs.endpoint3).toBeInstanceOf(Service);
});
});
50 changes: 27 additions & 23 deletions __tests__/service.spec.ts → __tests__/core/service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import Service from "@/service";
import Options from "@/options";
import Service from "@/core/service";
import Config from "@/global/config";

describe("service", () => {
beforeEach(() => {
Options.instance = jest.fn().mockReturnValue({
Config.instance = jest.fn().mockReturnValue({
baseURL: "https://api.example.com",
useBaseURL: true,
});
});

Expand Down Expand Up @@ -39,14 +40,16 @@ describe("service", () => {
expect(url).toBe("/resource/123");
});

it("should throw an error if path parameters are missing", () => {
it("should throw error if one path parameters are missing", () => {
const service = new Service("/resource/:id");
expect(() => service["buildUrl"]({})).toThrow("Missing path parameters");
expect(() => service["buildUrl"]({})).toThrow("Missing parameters :id");
});

it("should throw an error if multiple path parameters are missing", () => {
it("should throw error if multiple path parameters are missing", () => {
const service = new Service("/resource/:a/test/:b/test/:c");
expect(() => service["buildUrl"]({})).toThrow("Missing path parameters");
expect(() => service["buildUrl"]({})).toThrow(
"Missing parameters :a, :b, :c"
);
});

it("should include query parameters", () => {
Expand Down Expand Up @@ -78,27 +81,28 @@ describe("service", () => {
expect(req.url).toBe("https://api.example.com/resource/hello");
});

it("should throw an error if baseURL is not provided", () => {
Options.instance = jest.fn().mockReturnValue({});
const service = new Service("/resource");
expect(() => service["buildRequest"]({ method: "GET" })).toThrow(
"Missing baseURL in options"
);
});

it("should use the resource as baseURL if bypass is true", async () => {
const url = "https://api.example.com/resource";
const service = new Service(url, { bypass: true });
const req = await service["buildRequest"]({ method: "GET" });
expect(req.url).toBe(url);
});
// it("should throw an error if baseURL is not provided", () => {
// Config.instance = jest.fn().mockReturnValue({});
// const service = new Service("/resource");
// expect(() => service["buildRequest"]({ method: "GET" })).toThrow(
// "Missing `base` url in options"
// );
// });

// it("should use the resource as baseURL when `useBaseURL` is false", async () => {
// const url = "https://api.example.com/resource";
// Config.instance().useBaseURL = false;
// const service = new Service(url);
// const req = await service["buildRequest"]({ method: "GET" });
// expect(req.url).toBe(url);
// });
});

describe("buildResponse", () => {
it("should return data undefined when body is not present", async () => {
const service = new Service("/resource");
const res = await service["buildResponse"](new Response());
expect(await res.data).toBeNull();
expect(await res?.data).toBeNull();
});

it("should return an object with data", async () => {
Expand All @@ -107,7 +111,7 @@ describe("service", () => {
const res = await service["buildResponse"](
new Response(JSON.stringify(dummy))
);
expect(await res.data).toEqual(dummy.data);
expect(await res?.data).toEqual(dummy.data);
});
});
});
25 changes: 25 additions & 0 deletions __tests__/global/config.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Config from "@/global/config";

const baseURL = "https://test.io";
const endpoints = { test: "/test" };

describe("Options", () => {
it("should create a new instance with given options", () => {
const ins = Config.instance({ baseURL, endpoints });
expect(ins).toBeDefined();
expect(ins.baseURL).toEqual(baseURL);
});

it("should maintain the same singleton instance", () => {
const instance1 = Config.instance();
const instance2 = Config.instance({ baseURL, endpoints });

expect(instance1).toBe(instance2);
expect(instance1.baseURL).toEqual(baseURL);
});

it("should have a default headers property as an instance of Headers", () => {
const instance = Config.instance();
expect(instance.headers).toBeInstanceOf(Headers);
});
});
21 changes: 21 additions & 0 deletions __tests__/global/context.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Context } from "@/types";
import context from "@/global/context";
import init from "@/core/init";

const dummy: Context = {
useRequests: {
config: { baseURL: "https://test.io", endpoints: {} },
services: {},
},
};

describe("global context", () => {
beforeEach(() => {
init({ baseURL: "https://test.io", endpoints: {} });
});

it("should return the useRequests property from globalThis", () => {
const result = context();
expect(result).toEqual(dummy.useRequests);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useRawRequest } from "@/index";
import Service from "@/service";
import Service from "@/core/service";

global.fetch = jest.fn(() => ({
status: 200,
Expand All @@ -21,20 +21,20 @@ describe("useRawRequest", () => {

it("should make a GET request", async () => {
const raw = useRawRequest();
const { status } = await raw("http://api.test.com").get();
expect(status).toBe(200);
const res = await raw("http://api.test.com").get();
expect(res?.status).toBe(200);
});

it("should make a POST request", async () => {
const raw = useRawRequest();
const { status } = await raw("http://api.test.com").post({});
expect(status).toBe(200);
const res = await raw("http://api.test.com").post({});
expect(res?.status).toBe(200);
});

it("should make a PUT request", async () => {
const raw = useRawRequest();
const { status } = await raw("http://api.test.com").put({});
expect(status).toBe(200);
const res = await raw("http://api.test.com").put({});
expect(res?.status).toBe(200);
});
});

Expand All @@ -46,29 +46,29 @@ describe("useRawRequest: http methods", () => {
});

it("should make a GET request", async () => {
const { status } = await raw("http://api.test.com").get();
expect(status).toBe(200);
const res = await raw("http://api.test.com").get();
expect(res?.status).toBe(200);
});

it("should make a POST request", async () => {
const { status } = await raw("http://api.test.com").post({});
expect(status).toBe(200);
const res = await raw("http://api.test.com").post({});
expect(res?.status).toBe(200);
});

it("should make a PUT request", async () => {
const { status } = await raw("http://api.test.com").put({});
expect(status).toBe(200);
const res = await raw("http://api.test.com").put({});
expect(res?.status).toBe(200);
});

it("should make a DELETE request", async () => {
const { status } = await raw("http://api.test.com").delete();
expect(status).toBe(200);
const res = await raw("http://api.test.com").delete();
expect(res?.status).toBe(200);
});

it("should make a PATCH request", async () => {
const { status } = await raw("http://api.test.com").patch([
const res = await raw("http://api.test.com").patch([
{ op: "add", path: "/test", value: "test" },
]);
expect(status).toBe(200);
expect(res?.status).toBe(200);
});
});
21 changes: 21 additions & 0 deletions __tests__/hooks/useRequestConfig.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import useRequestsConfig from "@/hooks/useRequestsConfig";

describe("useRequestsConfig", () => {
it("should return a singleton instance", () => {
const instance1 = useRequestsConfig();
const instance2 = useRequestsConfig();
expect(instance1).toBe(instance2);
});

it("should set and retrieve baseURL correctly", () => {
const opts = useRequestsConfig();
opts.baseURL = "http://example.com";
expect(opts.baseURL).toBe("http://example.com");
});

it("should set and retrieve headers correctly", () => {
const { headers } = useRequestsConfig();
headers.set("authorization", "token");
expect(headers.get("authorization")).toBe("token");
});
});
73 changes: 73 additions & 0 deletions __tests__/hooks/useServices.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useServices, init } from "@/index";
import context from "@/global/context";

global.fetch = jest.fn(() => ({
status: 200,
json: () => Promise.resolve(),
data: {},
})) as jest.Mock;

enum Api {
test = "/test",
}

describe("useServices: without init", () => {
it("should throw an error if not initialized first", () => {
expect(() => useServices<typeof Api>()).toThrow(
"init must be called before using useServices hook"
);
});
});

describe("useServices", () => {
beforeEach(() => {
init({ baseURL: "http://api.test.com", endpoints: Api });
});

it("should return the context.useServices object", () => {
const result = useServices<typeof Api>();
expect(result).toHaveProperty("test");
});

it("should return an instance of ServiceResponse", async () => {
const { test } = useServices<typeof Api>();
const r = await test.get();
expect(r).toHaveProperty("data");
});

it("should make a GET request", async () => {
const { test } = useServices<typeof Api>();
const res = await test.get();
expect(res?.status).toBe(200);
});

it("should make a POST request", async () => {
const { test } = useServices<typeof Api>();
const res = await test.post({ data: "test" });
expect(res?.status).toBe(200);
});

it("should make a PUT request", async () => {
const { test } = useServices<typeof Api>();
const res = await test.put({});
expect(res?.status).toBe(200);
});

it("should make a DELETE request", async () => {
const { test } = useServices<typeof Api>();
const res = await test.delete();
expect(res?.status).toBe(200);
});

it("should make a PATCH request", async () => {
const { test } = useServices<typeof Api>();
const res = await test.patch([{ op: "add", path: "/test", value: "test" }]);
expect(res?.status).toBe(200);
});

it("should make a request with query params", async () => {
const { test } = useServices<typeof Api>();
const res = await test.get({ query: { test: "test" } });
expect(res?.status).toBe(200);
});
});
39 changes: 0 additions & 39 deletions __tests__/init.spec.ts

This file was deleted.

Loading