Skip to content

Commit

Permalink
Merge pull request #121 from WildCodeSchool/fix/login-tests
Browse files Browse the repository at this point in the history
Fix/login tests
  • Loading branch information
LightQv authored Feb 7, 2025
2 parents 95baf08 + b0cce1a commit 31686c2
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 47 deletions.
88 changes: 88 additions & 0 deletions back/src/__tests__/UserResolver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { User } from "../entities/User";
import UserResolver from "../resolvers/UserResolver";
import argon2 from "argon2";
import jwt from "jsonwebtoken";

describe("UserResolver", () => {
let userResolver: UserResolver;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let mockContext: any;
let mockUser: User;
let passwordTest: string;

beforeEach(() => {
userResolver = new UserResolver();
mockContext = {
res: {
setHeader: jest.fn(),
},
payload: { id: "e5fb990e-f9d9-4858-82d1-1fd1755485a5" },
};
mockUser = {
id: "e5fb990e-f9d9-4858-82d1-1fd1755485a5",
username: "Pierre",
email: "[email protected]",
} as User;
passwordTest = "password123";
process.env.JWT_SECRET_KEY = "TEST_KEY";
});

it("createUser should hash password, save user, generate token, and return user info", async () => {
jest.spyOn(argon2, "hash").mockResolvedValue("hashedPassword");
jest.spyOn(User, "save").mockResolvedValue(mockUser);
jest.spyOn(jwt, "sign").mockImplementation(() => "mockToken");

const result = await userResolver.createUser(
mockUser.username,
mockUser.email,
passwordTest,
mockContext,
);

expect(User.save).toHaveBeenCalled();
expect(mockContext.res.setHeader).toHaveBeenCalledWith(
"Set-Cookie",
expect.stringContaining("token=mockToken"),
);
expect(JSON.parse(result)).toEqual({
id: mockUser.id,
username: mockUser.username,
email: mockUser.email,
});
});

it("should log in a user and set a cookie", async () => {
jest.spyOn(User, "findOneByOrFail").mockResolvedValue(mockUser);
jest.spyOn(argon2, "verify").mockResolvedValue(true);
jest.spyOn(jwt, "sign").mockImplementation(() => "mockToken");

const result = await userResolver.login(
mockUser.username,
passwordTest,
mockContext,
);

expect(User.findOneByOrFail).toHaveBeenCalledWith({
email: mockUser.username,
});
expect(mockContext.res.setHeader).toHaveBeenCalledWith(
"Set-Cookie",
expect.stringContaining("token=mockToken"),
);
expect(JSON.parse(result)).toEqual({
id: mockUser.id,
username: mockUser.username,
email: mockUser.email,
});
});

it("should log out a user", async () => {
const result = await userResolver.logout(mockContext);

expect(mockContext.res.setHeader).toHaveBeenCalledWith(
"Set-Cookie",
"token=;Max-Age=0",
);
expect(result).toBe("Logged out");
});
});
94 changes: 47 additions & 47 deletions back/src/resolvers/UserResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ import MyContext from "../types/MyContext";
import { Roles } from "../entities/User";
import { NotifFrequency } from "../entities/NotifFrequency";

function setCookie(context: MyContext, token: string) {
export function setCookie(context: MyContext, token: string) {
const expireCookieUTC = new Date();
expireCookieUTC.setSeconds(
expireCookieUTC.getSeconds() + Number(process.env.COOKIE_TTL),
);
)

const secureCookie = process.env.APP_ENV === "production" ? "; Secure" : "";
const secureCookie = process.env.APP_ENV === "production" ? "; Secure" : ""

context.res.setHeader(
"Set-Cookie",
`token=${token}${secureCookie};httpOnly;expires=${expireCookieUTC.toUTCString()}`,
);
)
}

function getUserBasicInfo(user: User) {
Expand All @@ -26,7 +26,7 @@ function getUserBasicInfo(user: User) {
email: user.email,
username: user.username,
role: user.role,
};
}
}

class UserResolver {
Expand All @@ -38,24 +38,24 @@ class UserResolver {
@Ctx() context: MyContext,
) {
if (process.env.JWT_SECRET_KEY === undefined) {
throw new Error("NO JWT SECRET KEY DEFINED");
throw new Error("NO JWT SECRET KEY DEFINED")
}

const hashedPassword = await argon2.hash(password);
const hashedPassword = await argon2.hash(password)
const userFromDB = await User.save({
username: username,
email: email,
hashedPassword: hashedPassword,
});
})

const token = jwt.sign(
{ id: userFromDB.id, email: userFromDB.email },
process.env.JWT_SECRET_KEY,
);
)

setCookie(context, token);
setCookie(context, token)

return JSON.stringify(getUserBasicInfo(userFromDB));
return JSON.stringify(getUserBasicInfo(userFromDB))
}

@Mutation(() => String)
Expand All @@ -69,34 +69,34 @@ class UserResolver {
throw new Error("NO JWT SECRET KEY DEFINED");
}

const userFromDB = await User.findOneByOrFail({ email });
const userFromDB = await User.findOneByOrFail({ email })

const isCorrectPassword = await argon2.verify(
userFromDB.hashedPassword,
password,
);
)

if (!isCorrectPassword) {
throw new Error();
throw new Error()
}

const token = jwt.sign(
{ id: userFromDB.id, email: userFromDB.email },
process.env.JWT_SECRET_KEY,
);
setCookie(context, token);
)
setCookie(context, token)

return JSON.stringify(getUserBasicInfo(userFromDB));
return JSON.stringify(getUserBasicInfo(userFromDB))
} catch (error) {
console.log(error);
throw new Error("Bad request");
console.log(error)
throw new Error("Bad request")
}
}

@Query(() => String)
async logout(@Ctx() context: MyContext) {
context.res.setHeader("Set-Cookie", `token=;Max-Age=0`);
return "Logged out";
context.res.setHeader("Set-Cookie", `token=;Max-Age=0`)
return "Logged out"
}

@Query(() => String)
Expand All @@ -105,12 +105,12 @@ class UserResolver {
if (context.payload) {
const userFromDB = await User.findOneByOrFail({
id: context.payload.id,
});
return JSON.stringify(getUserBasicInfo(userFromDB));
} else throw new Error();
})
return JSON.stringify(getUserBasicInfo(userFromDB))
} else throw new Error()
} catch (error) {
console.log(error);
throw new Error("Bad request");
console.log(error)
throw new Error("Bad request")
}
}

Expand All @@ -120,18 +120,18 @@ class UserResolver {
if (context.payload) {
const requestingUser = await User.findOneByOrFail({
id: context.payload.id,
});
})

if (requestingUser.role !== Roles.ADMIN) {
throw new Error("Unauthorized");
throw new Error("Unauthorized")
}

const users = await User.find();
return JSON.stringify(users.map(getUserBasicInfo));
} else throw new Error();
const users = await User.find()
return JSON.stringify(users.map(getUserBasicInfo))
} else throw new Error()
} catch (error) {
console.log(error);
throw new Error("Bad request");
console.log(error)
throw new Error("Bad request")
}
}

Expand All @@ -140,15 +140,15 @@ class UserResolver {
try {
const user = await User.findOneByOrFail({
id: context.payload?.id,
});
if (!user) throw new Error("User not found");
})
if (!user) throw new Error("User not found")
const userNotifFrequency = await NotifFrequency.findOneByOrFail({
id: user.notifFrequency?.id,
});
if (!userNotifFrequency) throw new Error("Frequency not found");
return userNotifFrequency.interval;
})
if (!userNotifFrequency) throw new Error("Frequency not found")
return userNotifFrequency.interval
} catch (err) {
throw new Error(err);
throw new Error(err)
}
}

Expand All @@ -161,20 +161,20 @@ class UserResolver {
if (context.payload) {
const user = await User.findOneByOrFail({
id: context.payload.id,
});
})
try {
const resFrequency = await NotifFrequency.findOneByOrFail({
interval: frequency,
});
user.notifFrequency = resFrequency;
await User.save(user);
return JSON.stringify(getUserBasicInfo(user));
})
user.notifFrequency = resFrequency
await User.save(user)
return JSON.stringify(getUserBasicInfo(user))
} catch {
throw new Error("Frequency not found");
throw new Error("Frequency not found")
}
} else throw new Error();
} else throw new Error()
} catch (err) {
throw new Error(err);
throw new Error(err)
}
}
}
Expand Down

0 comments on commit 31686c2

Please sign in to comment.