Skip to content

Commit

Permalink
chore: add further auth related tests (#626)
Browse files Browse the repository at this point in the history
  • Loading branch information
iuioiua authored Oct 16, 2023
1 parent 5e13b39 commit d198e6b
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 31 deletions.
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"std/": "https://deno.land/[email protected]/",
"stripe": "npm:/[email protected]",
"feed": "npm:/[email protected]",
"kv_oauth": "https://deno.land/x/[email protected]/mod.ts",
"kv_oauth/": "https://deno.land/x/[email protected]/",
"tabler_icons_tsx/": "https://deno.land/x/[email protected]/tsx/",
"@twind/core": "https://esm.sh/@twind/[email protected]",
"fresh_charts/": "https://deno.land/x/[email protected]/"
Expand Down
86 changes: 80 additions & 6 deletions e2e_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import {
assertArrayIncludes,
assertEquals,
assertInstanceOf,
assertNotEquals,
assertObjectMatch,
assertStringIncludes,
} from "std/assert/mod.ts";
import { isRedirectStatus } from "std/http/http_status.ts";
import { resolvesNext, returnsNext, stub } from "std/testing/mock.ts";
import Stripe from "stripe";
import options from "./fresh.config.ts";
import { _internals } from "./plugins/kv_oauth.ts";

/**
* These tests are end-to-end tests, which follow this rule-set:
Expand Down Expand Up @@ -96,13 +98,85 @@ Deno.test("[e2e] GET /", async () => {
assertHtml(resp);
});

Deno.test("[e2e] GET /callback", async () => {
const resp = await handler(
new Request("http://localhost/callback"),
);
Deno.test("[e2e] GET /callback", async (test) => {
const login = crypto.randomUUID();
const sessionId = crypto.randomUUID();

assertEquals(resp.status, Status.InternalServerError);
assertHtml(resp);
await test.step("creates a new user if it doesn't already exist", async () => {
const handleCallbackResp = {
response: new Response(),
tokens: {
accessToken: crypto.randomUUID(),
tokenType: crypto.randomUUID(),
},
sessionId,
};
const id = crypto.randomUUID();
const handleCallbackStub = stub(
_internals,
"handleCallback",
returnsNext([Promise.resolve(handleCallbackResp)]),
);
const githubRespBody = {
login,
email: crypto.randomUUID(),
};
const stripeRespBody: Partial<Stripe.Response<Stripe.Customer>> = { id };
const fetchStub = stub(
window,
"fetch",
returnsNext([
Promise.resolve(Response.json(githubRespBody)),
Promise.resolve(Response.json(stripeRespBody)),
]),
);
const req = new Request("http://localhost/callback");
await handler(req);
handleCallbackStub.restore();
fetchStub.restore();

const user = await getUser(githubRespBody.login);
assert(user !== null);
assertEquals(user.sessionId, handleCallbackResp.sessionId);
});

await test.step("updates the user session ID if they already exist", async () => {
const handleCallbackResp = {
response: new Response(),
tokens: {
accessToken: crypto.randomUUID(),
tokenType: crypto.randomUUID(),
},
sessionId: crypto.randomUUID(),
};
const id = crypto.randomUUID();
const handleCallbackStub = stub(
_internals,
"handleCallback",
returnsNext([Promise.resolve(handleCallbackResp)]),
);
const githubRespBody = {
login,
email: crypto.randomUUID(),
};
const stripeRespBody: Partial<Stripe.Response<Stripe.Customer>> = { id };
const fetchStub = stub(
window,
"fetch",
returnsNext([
Promise.resolve(Response.json(githubRespBody)),
Promise.resolve(Response.json(stripeRespBody)),
]),
);
const req = new Request("http://localhost/callback");
await handler(req);
handleCallbackStub.restore();
fetchStub.restore();

const user = await getUser(githubRespBody.login);
assert(user !== null);
assertNotEquals(user.sessionId, sessionId);
});
});

Deno.test("[e2e] GET /blog", async () => {
Expand Down
7 changes: 5 additions & 2 deletions plugins/kv_oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
handleCallback,
signIn,
signOut,
} from "kv_oauth";
} from "kv_oauth/mod.ts";
import {
createUser,
getUser,
Expand All @@ -15,6 +15,9 @@ import {
import { isStripeEnabled, stripe } from "@/utils/stripe.ts";
import { getGitHubUser } from "@/utils/github.ts";

// Exported for mocking and spying in e2e tests
export const _internals = { handleCallback };

/**
* This custom plugin centralizes all authentication logic using the
* {@link https://deno.land/x/deno_kv_oauth|Deno KV OAuth} module.
Expand All @@ -33,7 +36,7 @@ export default {
{
path: "/callback",
handler: async (req) => {
const { response, tokens, sessionId } = await handleCallback(
const { response, tokens, sessionId } = await _internals.handleCallback(
req,
createGitHubOAuthConfig(),
);
Expand Down
2 changes: 1 addition & 1 deletion plugins/session.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { Plugin } from "$fresh/server.ts";
import type { MiddlewareHandlerContext } from "$fresh/server.ts";
import { getSessionId } from "kv_oauth";
import { getSessionId } from "kv_oauth/mod.ts";
import { getUserBySession } from "@/utils/db.ts";
import type { User } from "@/utils/db.ts";
import { createHttpError } from "std/http/http_errors.ts";
Expand Down
2 changes: 1 addition & 1 deletion utils/github.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { createHttpError } from "std/http/http_errors.ts";
import { createGitHubOAuthConfig } from "kv_oauth";
import { createGitHubOAuthConfig } from "kv_oauth/mod.ts";

export function isGitHubSetup() {
try {
Expand Down
50 changes: 30 additions & 20 deletions utils/github_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,38 @@
import { assertRejects } from "std/assert/assert_rejects.ts";
import { getGitHubUser } from "./github.ts";
import { returnsNext, stub } from "std/testing/mock.ts";
import { Status } from "$fresh/server.ts";
import { errors } from "std/http/http_errors.ts";
import { assertEquals } from "std/assert/assert_equals.ts";
import { Status } from "kv_oauth/deps.ts";

Deno.test("[plugins] getGitHubUser()", async () => {
const message = crypto.randomUUID();
const resp1Body = { message };
const resp1 = Promise.resolve(
Response.json(resp1Body, { status: Status.BadRequest }),
);
const resp2Body = { login: crypto.randomUUID(), email: crypto.randomUUID() };
const resp2 = Promise.resolve(Response.json(resp2Body));
const fetchStub = stub(globalThis, "fetch", returnsNext([resp1, resp2]));
Deno.test("[plugins] getGitHubUser()", async (test) => {
await test.step("rejects on error message", async () => {
const message = crypto.randomUUID();
const fetchStub = stub(
window,
"fetch",
returnsNext([
Promise.resolve(
Response.json({ message }, { status: Status.BadRequest }),
),
]),
);
await assertRejects(
async () => await getGitHubUser(crypto.randomUUID()),
errors.BadRequest,
message,
);
fetchStub.restore();
});

const accessToken1 = crypto.randomUUID();
const accessToken2 = crypto.randomUUID();
await assertRejects(
async () => await getGitHubUser(accessToken1),
errors.BadRequest,
message,
);
assertEquals(await getGitHubUser(accessToken2), resp2Body);

fetchStub.restore();
await test.step("resolves to a GitHub user object", async () => {
const body = { login: crypto.randomUUID(), email: crypto.randomUUID() };
const fetchStub = stub(
window,
"fetch",
returnsNext([Promise.resolve(Response.json(body))]),
);
assertEquals(await getGitHubUser(crypto.randomUUID()), body);
fetchStub.restore();
});
});

0 comments on commit d198e6b

Please sign in to comment.