Skip to content

Commit

Permalink
Adding tests to base-client and instructions on how to run tests to t…
Browse files Browse the repository at this point in the history
…he README. (#3)
  • Loading branch information
Fil Maj authored Apr 6, 2022
1 parent ab35a7b commit 217aca1
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
scripts/api_spec.json
.coverage
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ const client = SlackAPI(token, {
})
```

## Requirements

A recent version of `deno`.

## Running Tests

If you make changes to this repo, or just want to make sure things are working as desired, you can run:

deno fmt ./src
deno lint ./src
deno test --allow-read --coverage=.coverage && deno coverage --exclude="fixtures|test" .coverage

---

### Getting Help
Expand Down
168 changes: 162 additions & 6 deletions src/api_test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,167 @@
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import {
assertEquals,
assertRejects,
} from "https://deno.land/[email protected]/testing/asserts.ts";
import * as mf from "https://deno.land/x/[email protected]/mod.ts";
import { SlackAPI } from "./mod.ts";
import { serializeData } from "./base-client.ts";

Deno.test("SlackAPI", () => {
const client = SlackAPI("test-token", {
slackApiUrl: "https://slack.com/api/",
Deno.test("SlackAPI class", async (t) => {
mf.install(); // mock out calls to `fetch`

await t.step("instantiated with default API URL", async (t) => {
const client = SlackAPI("test-token", {});

await t.step("base methods exist on client", () => {
assertEquals(typeof client.apiCall, "function");
assertEquals(typeof client.response, "function");
});

await t.step("apiCall method", async (t) => {
await t.step("should call the default API URL", async () => {
mf.mock("POST@/api/chat.postMessage", (req: Request) => {
assertEquals(req.url, "https://slack.com/api/chat.postMessage");
return new Response('{"ok":true}');
});

await client.apiCall("chat.postMessage", {});

mf.reset();
});

await t.step(
"should prioritize calling provided token vs. token instantiated client with",
async () => {
mf.mock("POST@/api/chat.postMessage", (req: Request) => {
assertEquals(req.headers.get("authorization"), "Bearer override");
return new Response('{"ok":true}');
});

await client.apiCall("chat.postMessage", { token: "override" });

mf.reset();

mf.mock("POST@/api/chat.postMessage", (req: Request) => {
assertEquals(req.headers.get("authorization"), "Bearer test-token");
return new Response('{"ok":true}');
});

await client.apiCall("chat.postMessage", {});

mf.reset();
},
);

await t.step(
"should throw if response returns an HTTP status code >= 400",
async () => {
mf.mock("POST@/api/chat.postMessage", () => {
return new Response("big explosions", { status: 500 });
});

await assertRejects(
async () => {
return await client.apiCall("chat.postMessage", {});
},
Error,
"500: big explosions",
);

mf.reset();
},
);

await t.step("should return successful response JSON", async () => {
mf.mock("POST@/api/chat.postMessage", () => {
return new Response('{"ok":true}');
});

const res = await client.apiCall("chat.postMessage", {});
assertEquals(res.ok, true);

mf.reset();
});
});

await t.step("response method", async (t) => {
await t.step(
"should throw if response returns an HTTP status code >= 400",
async () => {
mf.mock("POST@/api/chat.postMessage", () => {
return new Response("big explosions", { status: 500 });
});

await assertRejects(
async () => {
return await client.response(
"https://slack.com/api/chat.postMessage",
{},
);
},
Error,
"500: big explosions",
);

mf.reset();
},
);

await t.step("should return successful response JSON", async () => {
mf.mock("POST@/api/chat.postMessage", () => {
return new Response('{"ok":true}');
});

const res = await client.response(
"https://slack.com/api/chat.postMessage",
{},
);
assertEquals(res.ok, true);

mf.reset();
});
});
});

assertEquals(typeof client.apiCall, "function");
assertEquals(typeof client.response, "function");
await t.step("instantiated with custom API URL", async (t) => {
const client = SlackAPI("test-token", {
slackApiUrl: "https://apitown.com/",
});

await t.step("apiCall method", async (t) => {
await t.step("should call the custom API URL", async () => {
mf.mock("POST@/chat.postMessage", (req: Request) => {
assertEquals(req.url, "https://apitown.com/chat.postMessage");
return new Response('{"ok":true}');
});

await client.apiCall("chat.postMessage", {});

mf.reset();
});
});
});

mf.uninstall();
});

Deno.test("serializeData helper function", async (t) => {
await t.step(
"should serialize string values as strings and return a URLSearchParams object",
() => {
assertEquals(
serializeData({ "batman": "robin" }).toString(),
"batman=robin",
);
},
);
await t.step(
"should serialize non-string values as JSON-encoded strings and return a URLSearchParams object",
() => {
assertEquals(
serializeData({ "hockey": { "good": true, "awesome": "yes" } })
.toString(),
"hockey=%7B%22good%22%3Atrue%2C%22awesome%22%3A%22yes%22%7D",
);
},
);
});
2 changes: 1 addition & 1 deletion src/base-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class BaseSlackAPIClient {
}

// Serialize an object into a string so as to be compatible with x-www-form-urlencoded payloads
function serializeData(data: Record<string, unknown>): URLSearchParams {
export function serializeData(data: Record<string, unknown>): URLSearchParams {
const encodedData: Record<string, string> = {};
Object.entries(data).forEach(([key, value]) => {
// Objects/arrays, numbers and booleans get stringified
Expand Down

0 comments on commit 217aca1

Please sign in to comment.