This commit is contained in:
83
backend/__tests__/__testData__/auth.ts
Normal file
83
backend/__tests__/__testData__/auth.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { expect, vi } from "vitest";
|
||||
import { Configuration } from "@monkeytype/schemas/configuration";
|
||||
import { randomBytes } from "crypto";
|
||||
import { hash } from "bcrypt";
|
||||
import { ObjectId } from "mongodb";
|
||||
import { base64UrlEncode } from "../../src/utils/misc";
|
||||
import * as ApeKeyDal from "../../src/dal/ape-keys";
|
||||
import { DecodedIdToken } from "firebase-admin/auth";
|
||||
import * as AuthUtils from "../../src/utils/auth";
|
||||
|
||||
export async function mockAuthenticateWithApeKey(
|
||||
uid: string,
|
||||
config: Configuration,
|
||||
): Promise<string> {
|
||||
if (!config.apeKeys.acceptKeys) {
|
||||
throw Error("config.apeKeys.acceptedKeys needs to be set to true");
|
||||
}
|
||||
const { apeKeyBytes, apeKeySaltRounds } = config.apeKeys;
|
||||
|
||||
const apiKey = randomBytes(apeKeyBytes).toString("base64url");
|
||||
const saltyHash = await hash(apiKey, apeKeySaltRounds);
|
||||
|
||||
const apeKey: ApeKeyDal.DBApeKey = {
|
||||
_id: new ObjectId(),
|
||||
name: "bob",
|
||||
enabled: true,
|
||||
uid,
|
||||
hash: saltyHash,
|
||||
createdOn: Date.now(),
|
||||
modifiedOn: Date.now(),
|
||||
lastUsedOn: -1,
|
||||
useCount: 0,
|
||||
};
|
||||
|
||||
const apeKeyId = new ObjectId().toHexString();
|
||||
|
||||
vi.spyOn(ApeKeyDal, "getApeKey").mockResolvedValue(apeKey);
|
||||
vi.spyOn(ApeKeyDal, "updateLastUsedOn").mockResolvedValue();
|
||||
|
||||
return base64UrlEncode(`${apeKeyId}.${apiKey}`);
|
||||
}
|
||||
|
||||
export function mockBearerAuthentication(uid: string) {
|
||||
const mockDecodedToken = {
|
||||
uid,
|
||||
email: "newuser@mail.com",
|
||||
iat: Date.now(),
|
||||
} as DecodedIdToken;
|
||||
const verifyIdTokenMock = vi.spyOn(AuthUtils, "verifyIdToken");
|
||||
|
||||
return {
|
||||
/**
|
||||
* Reset the mock and return a default token. Call this method in the `beforeEach` of all tests.
|
||||
*/
|
||||
beforeEach: (): void => {
|
||||
verifyIdTokenMock.mockClear();
|
||||
verifyIdTokenMock.mockResolvedValue(mockDecodedToken);
|
||||
},
|
||||
/**
|
||||
* Reset the mock results in the authentication to fail.
|
||||
*/
|
||||
noAuth: (): void => {
|
||||
verifyIdTokenMock.mockClear();
|
||||
},
|
||||
/**
|
||||
* verify the authentication has been called
|
||||
*/
|
||||
expectToHaveBeenCalled: (): void => {
|
||||
expect(verifyIdTokenMock).toHaveBeenCalled();
|
||||
},
|
||||
/**
|
||||
* modify the token returned by the mock. This can be used to e.g. return a stale token.
|
||||
* @param customize
|
||||
*/
|
||||
modifyToken: (customize: Partial<DecodedIdToken>): void => {
|
||||
verifyIdTokenMock.mockClear();
|
||||
verifyIdTokenMock.mockResolvedValue({
|
||||
...mockDecodedToken,
|
||||
...customize,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
24
backend/__tests__/__testData__/connections.ts
Normal file
24
backend/__tests__/__testData__/connections.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ObjectId } from "mongodb";
|
||||
import * as ConnectionsDal from "../../src/dal/connections";
|
||||
|
||||
export async function createConnection(
|
||||
data: Partial<ConnectionsDal.DBConnection>,
|
||||
maxPerUser = 25,
|
||||
): Promise<ConnectionsDal.DBConnection> {
|
||||
const defaultName = "user" + new ObjectId().toHexString();
|
||||
const result = await ConnectionsDal.create(
|
||||
{
|
||||
uid: data.initiatorUid ?? new ObjectId().toHexString(),
|
||||
name: data.initiatorName ?? defaultName,
|
||||
},
|
||||
{
|
||||
uid: data.receiverUid ?? new ObjectId().toHexString(),
|
||||
name: data.receiverName ?? defaultName,
|
||||
},
|
||||
maxPerUser,
|
||||
);
|
||||
await ConnectionsDal.__testing
|
||||
.getCollection()
|
||||
.updateOne({ _id: result._id }, { $set: data });
|
||||
return { ...result, ...data };
|
||||
}
|
||||
17
backend/__tests__/__testData__/controller-test.ts
Normal file
17
backend/__tests__/__testData__/controller-test.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import request from "supertest";
|
||||
import app from "../../src/app";
|
||||
import { ObjectId } from "mongodb";
|
||||
import { mockBearerAuthentication } from "./auth";
|
||||
import { beforeEach } from "vitest";
|
||||
|
||||
export function setup() {
|
||||
const mockApp = request(app);
|
||||
const uid = new ObjectId().toHexString();
|
||||
const mockAuth = mockBearerAuthentication(uid);
|
||||
|
||||
beforeEach(() => {
|
||||
mockAuth.beforeEach();
|
||||
});
|
||||
|
||||
return { mockApp, uid, mockAuth };
|
||||
}
|
||||
21
backend/__tests__/__testData__/monkey-error.ts
Normal file
21
backend/__tests__/__testData__/monkey-error.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { expect } from "vitest";
|
||||
import MonkeyError from "../../src/utils/error";
|
||||
import { MatcherResult } from "../vitest";
|
||||
|
||||
export function enableMonkeyErrorExpects(): void {
|
||||
expect.extend({
|
||||
toMatchMonkeyError(
|
||||
received: MonkeyError,
|
||||
expected: MonkeyError,
|
||||
): MatcherResult {
|
||||
return {
|
||||
pass:
|
||||
received.status === expected.status &&
|
||||
received.message === expected.message,
|
||||
message: () => "MonkeyError does not match:",
|
||||
actual: { status: received.status, message: received.message },
|
||||
expected: { status: expected.status, message: expected.message },
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
30
backend/__tests__/__testData__/rate-limit.ts
Normal file
30
backend/__tests__/__testData__/rate-limit.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { expect } from "vitest";
|
||||
import { REQUEST_MULTIPLIER } from "../../src/middlewares/rate-limit";
|
||||
import { MatcherResult, ExpectedRateLimit } from "../vitest";
|
||||
import { Test as SuperTest } from "supertest";
|
||||
|
||||
export function enableRateLimitExpects(): void {
|
||||
expect.extend({
|
||||
toBeRateLimited: async (
|
||||
received: SuperTest,
|
||||
expected: ExpectedRateLimit,
|
||||
): Promise<MatcherResult> => {
|
||||
const now = Date.now();
|
||||
const { headers } = await received.expect(200);
|
||||
|
||||
const max =
|
||||
parseInt(headers["x-ratelimit-limit"] as string) / REQUEST_MULTIPLIER;
|
||||
const windowMs =
|
||||
parseInt(headers["x-ratelimit-reset"] as string) * 1000 - now;
|
||||
|
||||
return {
|
||||
pass:
|
||||
max === expected.max && Math.abs(expected.windowMs - windowMs) < 2500,
|
||||
message: () =>
|
||||
"Rate limit max not matching or windowMs is off by more then 2500ms",
|
||||
actual: { max, windowMs },
|
||||
expected: expected,
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
45
backend/__tests__/__testData__/users.ts
Normal file
45
backend/__tests__/__testData__/users.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import * as DB from "../../src/init/db";
|
||||
import * as UserDAL from "../../src/dal/user";
|
||||
import { ObjectId } from "mongodb";
|
||||
import { PersonalBest } from "@monkeytype/schemas/shared";
|
||||
|
||||
export async function createUser(
|
||||
user?: Partial<UserDAL.DBUser>,
|
||||
): Promise<UserDAL.DBUser> {
|
||||
const uid = new ObjectId().toHexString();
|
||||
await UserDAL.addUser("user" + uid, uid + "@example.com", uid);
|
||||
await DB.collection("users").updateOne({ uid }, { $set: { ...user } });
|
||||
return await UserDAL.getUser(uid, "test");
|
||||
}
|
||||
|
||||
export async function createUserWithoutMigration(
|
||||
user?: Partial<UserDAL.DBUser>,
|
||||
): Promise<UserDAL.DBUser> {
|
||||
const uid = new ObjectId().toHexString();
|
||||
await UserDAL.addUser("user" + uid, uid + "@example.com", uid);
|
||||
await DB.collection("users").updateOne({ uid }, { $set: { ...user } });
|
||||
await DB.collection("users").updateOne(
|
||||
{ uid },
|
||||
{ $unset: { testActivity: "" } },
|
||||
);
|
||||
|
||||
return await UserDAL.getUser(uid, "test");
|
||||
}
|
||||
|
||||
export function pb(
|
||||
wpm: number,
|
||||
acc: number = 90,
|
||||
timestamp: number = 1,
|
||||
): PersonalBest {
|
||||
return {
|
||||
acc,
|
||||
consistency: 100,
|
||||
difficulty: "normal",
|
||||
lazyMode: false,
|
||||
language: "english",
|
||||
punctuation: false,
|
||||
raw: wpm + 1,
|
||||
wpm,
|
||||
timestamp,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user