chore: Add endpoint to update user state and update test cases
This commit is contained in:
+301
-196
@@ -175,232 +175,337 @@ describe("RestUser", () => {
|
||||
expect(response.body.data.user).toEqual(updatedUser);
|
||||
expect(mockedUserService.clearSpotifyConfigByUUID).toHaveBeenCalledWith("test-user-uuid");
|
||||
});
|
||||
});
|
||||
|
||||
describe("PUT /me/password", () => {
|
||||
const validPasswordData = {
|
||||
password: "newpassword123",
|
||||
passwordConfirmation: "newpassword123"
|
||||
describe("PUT /me/state", () => {
|
||||
const validStateData = {
|
||||
lastState: {
|
||||
global: {
|
||||
mode: "idle",
|
||||
brightness: 50
|
||||
},
|
||||
text: {
|
||||
text: "Hello",
|
||||
align: "center",
|
||||
speed: 3,
|
||||
size: 12,
|
||||
color: [255, 255, 255]
|
||||
},
|
||||
image: {
|
||||
image: ""
|
||||
},
|
||||
clock: {
|
||||
color: [255, 255, 255]
|
||||
},
|
||||
music: {
|
||||
fullscreen: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
it("should update state successfully", async () => {
|
||||
const mockUser = {
|
||||
id: "test-user-id",
|
||||
name: "testuser",
|
||||
uuid: "test-user-uuid"
|
||||
};
|
||||
|
||||
it("should update password successfully", async () => {
|
||||
const {PasswordUtils} = await import("../../src/utils/passwordUtils");
|
||||
mockedUserService.updateUserByUUID.mockResolvedValue(mockUser);
|
||||
|
||||
const mockUser = {
|
||||
id: "test-user-id",
|
||||
name: "testuser",
|
||||
uuid: "test-user-uuid",
|
||||
password: "old-hashed-password"
|
||||
};
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/state")
|
||||
.send(validStateData)
|
||||
.expect(200);
|
||||
|
||||
vi.mocked(PasswordUtils.validatePassword).mockReturnValue({valid: true});
|
||||
vi.mocked(PasswordUtils.hashPassword).mockResolvedValue("new-hashed-password");
|
||||
mockedUserService.updateUserByUUID.mockResolvedValue(mockUser);
|
||||
expect(response.body.data.message).toBe("State updated successfully.");
|
||||
expect(mockedUserService.updateUserByUUID).toHaveBeenCalledWith(
|
||||
"test-user-uuid",
|
||||
{ lastState: validStateData.lastState }
|
||||
);
|
||||
});
|
||||
|
||||
it("should return bad request for missing lastState", async () => {
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/state")
|
||||
.send({})
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("lastState");
|
||||
});
|
||||
|
||||
it("should return bad request for empty lastState object", async () => {
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/state")
|
||||
.send({ lastState: {} })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("lastState");
|
||||
});
|
||||
|
||||
it("should return bad request for null lastState", async () => {
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/state")
|
||||
.send({ lastState: null })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("lastState");
|
||||
});
|
||||
|
||||
it("should return bad request for non-object lastState", async () => {
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/state")
|
||||
.send({ lastState: "not an object" })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("lastState");
|
||||
});
|
||||
|
||||
it("should accept partial state updates", async () => {
|
||||
const partialState = {
|
||||
lastState: {
|
||||
global: {
|
||||
mode: "music",
|
||||
brightness: 75
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mockedUserService.updateUserByUUID.mockResolvedValue({});
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/state")
|
||||
.send(partialState)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data.message).toBe("State updated successfully.");
|
||||
expect(mockedUserService.updateUserByUUID).toHaveBeenCalledWith(
|
||||
"test-user-uuid",
|
||||
{ lastState: partialState.lastState }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PUT /me/password", () => {
|
||||
const validPasswordData = {
|
||||
password: "newpassword123",
|
||||
passwordConfirmation: "newpassword123"
|
||||
};
|
||||
|
||||
it("should update password successfully", async () => {
|
||||
const {PasswordUtils} = await import("../../src/utils/passwordUtils");
|
||||
|
||||
const mockUser = {
|
||||
id: "test-user-id",
|
||||
name: "testuser",
|
||||
uuid: "test-user-uuid",
|
||||
password: "old-hashed-password"
|
||||
};
|
||||
|
||||
vi.mocked(PasswordUtils.validatePassword).mockReturnValue({valid: true});
|
||||
vi.mocked(PasswordUtils.hashPassword).mockResolvedValue("new-hashed-password");
|
||||
mockedUserService.updateUserByUUID.mockResolvedValue(mockUser);
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(validPasswordData)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data.message).toBe("Password changed successfully");
|
||||
expect(PasswordUtils.validatePassword).toHaveBeenCalledWith("newpassword123");
|
||||
expect(PasswordUtils.hashPassword).toHaveBeenCalledWith("newpassword123");
|
||||
expect(mockedUserService.updateUserByUUID).toHaveBeenCalledWith(
|
||||
mockUser.uuid, {
|
||||
password: "new-hashed-password"
|
||||
});
|
||||
});
|
||||
|
||||
it("should return bad request when passwords don't match", async () => {
|
||||
const mockUser = {
|
||||
id: "test-user-id",
|
||||
name: "testuser",
|
||||
uuid: "test-user-uuid"
|
||||
};
|
||||
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
|
||||
|
||||
const invalidData = {
|
||||
password: "newpassword123",
|
||||
passwordConfirmation: "differentpassword"
|
||||
};
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.message).toBe("Passwörter stimmen nicht überein");
|
||||
});
|
||||
|
||||
it("should return bad request for invalid password", async () => {
|
||||
const {PasswordUtils} = await import("../../src/utils/passwordUtils");
|
||||
|
||||
const mockUser = {
|
||||
id: "test-user-id",
|
||||
name: "testuser",
|
||||
uuid: "test-user-uuid"
|
||||
};
|
||||
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
|
||||
vi.mocked(PasswordUtils.validatePassword).mockReturnValue({
|
||||
valid: false,
|
||||
message: "Password too weak"
|
||||
});
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(validPasswordData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.message).toBe("Password too weak");
|
||||
});
|
||||
|
||||
it("should return bad request for missing password", async () => {
|
||||
const invalidData = {passwordConfirmation: "newpassword123"};
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("password");
|
||||
});
|
||||
|
||||
it("should return bad request for missing passwordConfirmation", async () => {
|
||||
const invalidData = {password: "newpassword123"};
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("passwordConfirmation");
|
||||
});
|
||||
|
||||
it("should return bad request for short password", async () => {
|
||||
const invalidData = {
|
||||
password: "short",
|
||||
passwordConfirmation: "short"
|
||||
};
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("password");
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET / (Admin only)", () => {
|
||||
|
||||
describe("when user is an admin", () => {
|
||||
beforeEach(() => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(adminUser);
|
||||
});
|
||||
|
||||
it("should return all users", async () => {
|
||||
const mockUsers = [
|
||||
{id: "1", name: "user1", uuid: "uuid1"},
|
||||
{id: "2", name: "user2", uuid: "uuid2"}
|
||||
];
|
||||
mockedUserService.getAllUsers.mockResolvedValue(mockUsers);
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(validPasswordData)
|
||||
.get("/user/")
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data.message).toBe("Password changed successfully");
|
||||
expect(PasswordUtils.validatePassword).toHaveBeenCalledWith("newpassword123");
|
||||
expect(PasswordUtils.hashPassword).toHaveBeenCalledWith("newpassword123");
|
||||
expect(mockedUserService.updateUserByUUID).toHaveBeenCalledWith(
|
||||
mockUser.uuid, {
|
||||
password: "new-hashed-password"
|
||||
});
|
||||
expect(response.body.data.users).toEqual(mockUsers);
|
||||
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
|
||||
expect(mockedUserService.getAllUsers).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should return bad request when passwords don't match", async () => {
|
||||
const mockUser = {
|
||||
id: "test-user-id",
|
||||
name: "testuser",
|
||||
uuid: "test-user-uuid"
|
||||
};
|
||||
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
|
||||
|
||||
const invalidData = {
|
||||
password: "newpassword123",
|
||||
passwordConfirmation: "differentpassword"
|
||||
};
|
||||
it("should handle empty user list", async () => {
|
||||
mockedUserService.getAllUsers.mockResolvedValue([]);
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
.get("/user/")
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data.message).toBe("Passwörter stimmen nicht überein");
|
||||
});
|
||||
|
||||
it("should return bad request for invalid password", async () => {
|
||||
const {PasswordUtils} = await import("../../src/utils/passwordUtils");
|
||||
|
||||
const mockUser = {
|
||||
id: "test-user-id",
|
||||
name: "testuser",
|
||||
uuid: "test-user-uuid"
|
||||
};
|
||||
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
|
||||
vi.mocked(PasswordUtils.validatePassword).mockReturnValue({
|
||||
valid: false,
|
||||
message: "Password too weak"
|
||||
});
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(validPasswordData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.message).toBe("Password too weak");
|
||||
});
|
||||
|
||||
it("should return bad request for missing password", async () => {
|
||||
const invalidData = {passwordConfirmation: "newpassword123"};
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("password");
|
||||
});
|
||||
|
||||
it("should return bad request for missing passwordConfirmation", async () => {
|
||||
const invalidData = {password: "newpassword123"};
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("passwordConfirmation");
|
||||
});
|
||||
|
||||
it("should return bad request for short password", async () => {
|
||||
const invalidData = {
|
||||
password: "short",
|
||||
passwordConfirmation: "short"
|
||||
};
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.put("/user/me/password")
|
||||
.send(invalidData)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.details[0]).toContain("password");
|
||||
expect(response.body.data.users).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET / (Admin only)", () => {
|
||||
describe("when user is not an admin", () => {
|
||||
it("should return 404 Not Found if user is not an admin", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
|
||||
|
||||
describe("when user is an admin", () => {
|
||||
beforeEach(() => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(adminUser);
|
||||
});
|
||||
|
||||
it("should return all users", async () => {
|
||||
const mockUsers = [
|
||||
{id: "1", name: "user1", uuid: "uuid1"},
|
||||
{id: "2", name: "user2", uuid: "uuid2"}
|
||||
];
|
||||
mockedUserService.getAllUsers.mockResolvedValue(mockUsers);
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.get("/user/")
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data.users).toEqual(mockUsers);
|
||||
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
|
||||
expect(mockedUserService.getAllUsers).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should handle empty user list", async () => {
|
||||
mockedUserService.getAllUsers.mockResolvedValue([]);
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.get("/user/")
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data.users).toEqual([]);
|
||||
});
|
||||
await request(testEnv.app)
|
||||
.get("/user/")
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
describe("when user is not an admin", () => {
|
||||
it("should return 404 Not Found if user is not an admin", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
|
||||
it("should return 404 Not Found if user does not exist", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(null);
|
||||
|
||||
await request(testEnv.app)
|
||||
.get("/user/")
|
||||
.expect(404);
|
||||
});
|
||||
await request(testEnv.app)
|
||||
.get("/user/")
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should return 404 Not Found if user does not exist", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(null);
|
||||
describe("GET /:id (Admin only)", () => {
|
||||
const specificUserId = new Types.ObjectId().toString();
|
||||
const mockUser = {
|
||||
id: specificUserId,
|
||||
name: "specificuser",
|
||||
uuid: "specific-uuid"
|
||||
};
|
||||
|
||||
await request(testEnv.app)
|
||||
.get("/user/")
|
||||
.expect(404);
|
||||
});
|
||||
describe("when user is an admin", () => {
|
||||
beforeEach(() => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(adminUser);
|
||||
});
|
||||
|
||||
it("should return user by id", async () => {
|
||||
mockedUserService.getUserById.mockResolvedValue(mockUser);
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.get(`/user/${specificUserId}`)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data).toEqual(mockUser);
|
||||
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
|
||||
expect(mockedUserService.getUserById).toHaveBeenCalledWith(specificUserId);
|
||||
});
|
||||
|
||||
it("should return bad request when target user is not found", async () => {
|
||||
mockedUserService.getUserById.mockResolvedValue(null);
|
||||
|
||||
const nonExistentUserId = new Types.ObjectId().toString();
|
||||
const response = await request(testEnv.app)
|
||||
.get(`/user/${nonExistentUserId}`)
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.data.message).toBe(`Unable to find matching document with id: ${nonExistentUserId}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET /:id (Admin only)", () => {
|
||||
const specificUserId = new Types.ObjectId().toString();
|
||||
const mockUser = {
|
||||
id: specificUserId,
|
||||
name: "specificuser",
|
||||
uuid: "specific-uuid"
|
||||
};
|
||||
describe("when user is not an admin", () => {
|
||||
it("should return 404 Not Found if user is not an admin", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
|
||||
|
||||
describe("when user is an admin", () => {
|
||||
beforeEach(() => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(adminUser);
|
||||
});
|
||||
|
||||
it("should return user by id", async () => {
|
||||
mockedUserService.getUserById.mockResolvedValue(mockUser);
|
||||
|
||||
const response = await request(testEnv.app)
|
||||
.get(`/user/${specificUserId}`)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.data).toEqual(mockUser);
|
||||
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
|
||||
expect(mockedUserService.getUserById).toHaveBeenCalledWith(specificUserId);
|
||||
});
|
||||
|
||||
it("should return bad request when target user is not found", async () => {
|
||||
mockedUserService.getUserById.mockResolvedValue(null);
|
||||
|
||||
const nonExistentUserId = new Types.ObjectId().toString();
|
||||
const response = await request(testEnv.app)
|
||||
.get(`/user/${nonExistentUserId}`)
|
||||
.expect(400);
|
||||
|
||||
|
||||
|
||||
|
||||
expect(response.body.data.message).toBe(`Unable to find matching document with id: ${nonExistentUserId}`);
|
||||
});
|
||||
await request(testEnv.app)
|
||||
.get(`/user/${specificUserId}`)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
describe("when user is not an admin", () => {
|
||||
it("should return 404 Not Found if user is not an admin", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
|
||||
it("should return 404 Not Found if user does not exist", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(null);
|
||||
|
||||
await request(testEnv.app)
|
||||
.get(`/user/${specificUserId}`)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it("should return 404 Not Found if user does not exist", async () => {
|
||||
mockedUserService.getUserByUUID.mockResolvedValue(null);
|
||||
|
||||
await request(testEnv.app)
|
||||
.get(`/user/${specificUserId}`)
|
||||
.expect(404);
|
||||
});
|
||||
await request(testEnv.app)
|
||||
.get(`/user/${specificUserId}`)
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user