adding monkeytype
Some checks failed
Mark Stale PRs / stale (push) Has been cancelled

This commit is contained in:
Benjamin Falch
2026-04-23 13:53:44 +02:00
parent e214a2fd35
commit 2bc741fb78
1930 changed files with 7590652 additions and 0 deletions

View 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,
});
},
};
}

View 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 };
}

View 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 };
}

View 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 },
};
},
});
}

View 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,
};
},
});
}

View 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,
};
}