Add more tests (#2965) Bruception and sondrekje

* Cover updateName

* Test clearPb, export getUsersCollection for testing purposes

* Add base coverage

* Month -> thirty days

Co-authored-by: Sondre Kjempekjenn <sondre.kjempekjenn@gmail.com>
This commit is contained in:
Bruce Berrios 2022-05-11 08:08:06 -04:00 committed by GitHub
parent 526a343e12
commit 0a371b531a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 154 additions and 18 deletions

View file

@ -1,30 +1,55 @@
import { addUser, getUser, updateName } from "../../src/dal/user";
import _ from "lodash";
import {
addUser,
clearPb,
getUser,
getUsersCollection,
updateName,
} from "../../src/dal/user";
const mockPersonalBest = {
acc: 1,
consistency: 1,
difficulty: "normal" as const,
lazyMode: true,
language: "no",
punctuation: false,
raw: 230,
wpm: 215,
timestamp: 13123123,
};
describe("UserDal", () => {
it("should be able to insert users", async () => {
// given
const newUser = {
name: "Test",
email: "mockemail@email.com",
uid: "userId",
};
// when
await addUser(newUser.name, newUser.email, newUser.uid);
const insertedUser = await getUser("userId", "test");
// then
expect(insertedUser.email).toBe(newUser.email);
expect(insertedUser.uid).toBe(newUser.uid);
expect(insertedUser.name).toBe(newUser.name);
});
it("should error if the user already exists", async () => {
// given
const newUser = {
name: "Test",
email: "mockemail@email.com",
uid: "userId",
};
// when
await addUser(newUser.name, newUser.email, newUser.uid);
// then
// should error because user already exists
await expect(
addUser(newUser.name, newUser.email, newUser.uid)
@ -32,6 +57,7 @@ describe("UserDal", () => {
});
it("updatename should not allow unavailable usernames", async () => {
// given
const mockUsers = [...Array(3).keys()]
.map((id) => ({
name: `Test${id}`,
@ -39,14 +65,125 @@ describe("UserDal", () => {
uid: `userId${id}`,
}))
.map(({ name, email, uid }) => addUser(name, email, uid));
await Promise.all(mockUsers);
const userToUpdateNameFor = await getUser("userId0", "test");
const userWithNameTaken = await getUser("userId1", "test");
// when, then
await expect(
updateName(userToUpdateNameFor.uid, userWithNameTaken.name)
).rejects.toThrow("Username already taken");
});
it("updatename should not allow invalid usernames", async () => {
// given
const testUser = {
name: "Test",
email: "mockemail@email.com",
uid: "userId",
};
await addUser(testUser.name, testUser.email, testUser.uid);
const invalidNames = [
null, // falsy
undefined, // falsy
"", // empty
" ".repeat(16), // too long
".testName", // cant begin with period
"miodec", // profanity
"asdasdAS$", // invalid characters
];
// when, then
invalidNames.forEach(
async (invalidName) =>
await expect(
updateName(testUser.uid, invalidName as unknown as string)
).rejects.toThrow("Invalid username")
);
});
it("updateName should fail if user has changed name recently", async () => {
// given
const testUser = {
name: "Test",
email: "mockemail@email.com",
uid: "userId",
};
await addUser(testUser.name, testUser.email, testUser.uid);
// when
await updateName(testUser.uid, "renamedTestUser");
const updatedUser = await getUser(testUser.uid, "test");
// then
expect(updatedUser.name).toBe("renamedTestUser");
await expect(updateName(updatedUser.uid, "NewValidName")).rejects.toThrow(
"You can change your name once every 30 days"
);
});
it("updateName should change the name of a user", async () => {
// given
const testUser = {
name: "Test",
email: "mockemail@email.com",
uid: "userId",
};
await addUser(testUser.name, testUser.email, testUser.uid);
// when
await updateName(testUser.uid, "renamedTestUser");
// then
const updatedUser = await getUser(testUser.uid, "test");
expect(updatedUser.name).toBe("renamedTestUser");
});
it("clearPb should clear the personalBests of a user", async () => {
// given
const testUser = {
name: "Test",
email: "mockemail@email.com",
uid: "userId",
};
await addUser(testUser.name, testUser.email, testUser.uid);
await getUsersCollection().updateOne(
{ uid: testUser.uid },
{
$set: {
personalBests: {
time: { 20: [mockPersonalBest] },
words: {},
quote: {},
custom: {},
zen: {},
},
},
}
);
const { personalBests } = (await getUser(testUser.uid, "test")) ?? {};
expect(personalBests).toStrictEqual({
time: { 20: [mockPersonalBest] },
words: {},
quote: {},
custom: {},
zen: {},
});
// when
await clearPb(testUser.uid);
// then
const updatedUser = (await getUser(testUser.uid, "test")) ?? {};
expect(_.values(updatedUser.personalBests).filter(_.isEmpty)).toHaveLength(
5
);
});
});

View file

@ -6,10 +6,10 @@ export default {
setupFilesAfterEnv: ["<rootDir>/setup-tests.ts"],
coverageThreshold: {
global: {
branches: 0,
functions: 0,
lines: 0,
statements: 0,
branches: 36,
functions: 18,
lines: 39,
statements: 35,
},
},
};

View file

@ -13,15 +13,9 @@ import {
WithId,
} from "mongodb";
let usersCollection: Collection<WithId<MonkeyTypes.User>>;
function getUsersCollection(): Collection<WithId<MonkeyTypes.User>> {
if (!usersCollection) {
usersCollection = db.collection<MonkeyTypes.User>("users");
}
return usersCollection;
}
// Export for use in tests
export const getUsersCollection = (): Collection<WithId<MonkeyTypes.User>> =>
db.collection<MonkeyTypes.User>("users");
export async function addUser(
name: string,
@ -47,6 +41,9 @@ export async function deleteUser(uid: string): Promise<DeleteResult> {
return await getUsersCollection().deleteOne({ uid });
}
const DAY_IN_SECONDS = 24 * 60 * 60;
const THIRTY_DAYS_IN_SECONDS = DAY_IN_SECONDS * 30;
export async function updateName(
uid: string,
name: string
@ -62,7 +59,7 @@ export async function updateName(
if (
!user?.needsToChangeName &&
Date.now() - (user.lastNameChange ?? 0) < 2592000000
Date.now() - (user.lastNameChange ?? 0) < THIRTY_DAYS_IN_SECONDS
) {
throw new MonkeyError(409, "You can change your name once every 30 days");
}

View file

@ -5,6 +5,8 @@ export function inRange(value: number, min: number, max: number): boolean {
return value >= min && value <= max;
}
const VALID_NAME_PATTERN = /^[\da-zA-Z_.-]+$/;
export function isUsernameValid(name: string): boolean {
if (_.isNil(name) || !inRange(name.length, 1, 16)) {
return false;
@ -24,7 +26,7 @@ export function isUsernameValid(name: string): boolean {
return false;
}
return /^[0-9a-zA-Z_.-]+$/.test(name);
return VALID_NAME_PATTERN.test(name);
}
export function isTagPresetNameValid(name: string): boolean {
@ -32,7 +34,7 @@ export function isTagPresetNameValid(name: string): boolean {
return false;
}
return /^[0-9a-zA-Z_.-]+$/.test(name);
return VALID_NAME_PATTERN.test(name);
}
export function isTestTooShort(result: MonkeyTypes.CompletedEvent): boolean {