Skip to content

Commit

Permalink
fix: do not proxy then. fixes #107 (#108)
Browse files Browse the repository at this point in the history
  • Loading branch information
filmaj authored Jul 22, 2024
1 parent 26fcdd6 commit 2362b9c
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 18 deletions.
7 changes: 6 additions & 1 deletion src/api-proxy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { BaseSlackAPIClient } from "./base-client.ts";
import { BaseResponse, SlackAPIClient, SlackAPIMethodArgs } from "./types.ts";

const DO_NOT_PROXY = ["then"];

type APICallback = {
(method: string, payload?: SlackAPIMethodArgs): Promise<BaseResponse>;
};
Expand Down Expand Up @@ -46,7 +48,10 @@ export const APIProxy = (
const proxy = new Proxy(objectToProxy, {
get(obj, prop) {
// We're attempting to access a property that doesn't exist, so create a new nested proxy
if (typeof prop === "string" && !(prop in obj)) {
if (
typeof prop === "string" && !DO_NOT_PROXY.includes(prop) &&
!(prop in obj)
) {
return APIProxy(null, apiCallback, ...path, prop);
}

Expand Down
61 changes: 44 additions & 17 deletions src/api-proxy_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,57 @@ import { BaseSlackAPIClient } from "./base-client.ts";
import { SlackAPIMethodArgs } from "./types.ts";
import { assertSpyCall, spy } from "./dev_deps.ts";

Deno.test("APIProxy", async () => {
Deno.test("APIProxy", async (t) => {
const baseClient = new BaseSlackAPIClient("test-token");
const clientToProxy = {
apiCall: baseClient.apiCall.bind(baseClient),
response: baseClient.response.bind(baseClient),
};
const generateClientProxy = (client: BaseSlackAPIClient) => ({
apiCall: client.apiCall.bind(client),
response: client.response.bind(client),
});

await t.step("should proxy legit Slack API calls", async () => {
const clientToProxy = generateClientProxy(baseClient);

const apiCallHandler = (_method: string, _payload?: SlackAPIMethodArgs) => {
return Promise.resolve({
ok: true,
toFetchResponse: () => new Response(),
});
};
const apiCallHandlerSpy = spy(apiCallHandler);

const apiCallHandler = (_method: string, _payload?: SlackAPIMethodArgs) => {
return Promise.resolve({ ok: true, toFetchResponse: () => new Response() });
};
const apiCallHandlerSpy = spy(apiCallHandler);
const client = APIProxy(clientToProxy, apiCallHandlerSpy);

const client = APIProxy(clientToProxy, apiCallHandlerSpy);
const payload = { text: "proxied call", channel: "" };
await client.chat.postMessage(payload);

const payload = { text: "proxied call", channel: "" };
await client.chat.postMessage(payload);
assertSpyCall(apiCallHandlerSpy, 0, {
args: ["chat.postMessage", payload],
});

assertSpyCall(apiCallHandlerSpy, 0, {
args: ["chat.postMessage", payload],
await client.admin.apps.approved.list();

assertSpyCall(apiCallHandlerSpy, 1, {
args: ["admin.apps.approved.list", undefined],
});
});

await client.admin.apps.approved.list();
await t.step("should not proxy Promise methods like `then`", () => {
const clientToProxy = generateClientProxy(baseClient);

const apiCallHandler = (_method: string, _payload?: SlackAPIMethodArgs) => {
return Promise.resolve({
ok: true,
toFetchResponse: () => new Response(),
});
};
const apiCallHandlerSpy = spy(apiCallHandler);

const client = APIProxy(clientToProxy, apiCallHandlerSpy);

assertSpyCall(apiCallHandlerSpy, 1, {
args: ["admin.apps.approved.list", undefined],
// re: https://github.com/slackapi/deno-slack-api/issues/107
// @ts-expect-error client does not have `then` but thenable feature detection at runtime may invoke or test for the method
if (client.then) {
throw new Error("APIProxy should have no `then`!");
}
});
});

0 comments on commit 2362b9c

Please sign in to comment.