Copilot commented on code in PR #6526:
URL: https://github.com/apache/texera/pull/6526#discussion_r3609357915


##########
frontend/src/app/dashboard/component/admin/user/admin-user.component.spec.ts:
##########
@@ -18,23 +18,69 @@
  */
 
 import { ComponentFixture, inject, TestBed } from "@angular/core/testing";
+import { of, throwError } from "rxjs";
 import { AdminUserComponent } from "./admin-user.component";
 import { UserService } from "../../../../common/service/user/user.service";
 import { StubUserService } from 
"../../../../common/service/user/stub-user.service";
 import { AdminUserService } from 
"../../../service/admin/user/admin-user.service";
+import { FeedbackService } from 
"../../../service/user/feedback/feedback.service";
+import { Role, User } from "../../../../common/type/user";
+import { UserQuotaComponent } from 
"../../user/user-quota/user-quota.component";
+import { FeedbackComponent } from "../../user/feedback/feedback.component";
 import { HttpClientTestingModule, HttpTestingController } from 
"@angular/common/http/testing";
 import { FormsModule } from "@angular/forms";
 import { NzDropDownModule } from "ng-zorro-antd/dropdown";
-import { NzModalModule } from "ng-zorro-antd/modal";
+import { NzModalModule, NzModalService } from "ng-zorro-antd/modal";
+import { NzMessageService } from "ng-zorro-antd/message";
 import { commonTestProviders } from "../../../../common/testing/test-utils";
 
+const userA: User = {
+  uid: 1,
+  name: "Alice",
+  email: "[email protected]",
+  role: Role.REGULAR,
+  comment: "c1",
+  joiningReason: "r1",
+  accountCreation: 1000,
+  lastLogin: 2000,
+};
+
+const userB: User = {
+  uid: 2,
+  name: "Bob",
+  email: "[email protected]",
+  role: Role.ADMIN,
+  comment: "c2",
+  joiningReason: "r2",
+  accountCreation: 3000,
+};
+
 describe("AdminUserComponent", () => {
   let component: AdminUserComponent;
   let fixture: ComponentFixture<AdminUserComponent>;
 
+  let adminUserServiceSpy: {
+    getUserList: ReturnType<typeof vi.fn>;
+    addUser: ReturnType<typeof vi.fn>;
+    updateUser: ReturnType<typeof vi.fn>;
+  };
+  let feedbackServiceSpy: { getFeedbackCounts: ReturnType<typeof vi.fn> };
+
   beforeEach(async () => {
+    adminUserServiceSpy = {
+      getUserList: vi.fn().mockReturnValue(of([])),
+      addUser: vi.fn().mockReturnValue(of(undefined)),
+      updateUser: vi.fn().mockReturnValue(of(undefined)),
+    };
+    feedbackServiceSpy = { getFeedbackCounts: vi.fn().mockReturnValue(of([])) 
};

Review Comment:
   This file now adds vi.spyOn() calls (e.g., for NzMessageService.error / 
NzModalService.create), but Vitest isn't configured to auto-restore mocks. To 
prevent spies from leaking across tests, restore mocks at the start of each 
test run.



##########
frontend/src/app/dashboard/component/admin/user/admin-user.component.spec.ts:
##########
@@ -157,4 +203,174 @@ describe("AdminUserComponent", () => {
     expect(component.nameSearchValue).toBe("");
     expect(component.emailSearchValue).toBe("");
   });
+
+  it("addUser creates a user through the service and reloads the list", () => {
+    const listCallsBefore = adminUserServiceSpy.getUserList.mock.calls.length;
+
+    component.addUser();
+
+    expect(adminUserServiceSpy.addUser).toHaveBeenCalledTimes(1);
+    // the subscribe callback re-runs ngOnInit, which re-fetches the user list
+    
expect(adminUserServiceSpy.getUserList.mock.calls.length).toBe(listCallsBefore 
+ 1);
+  });
+
+  it("startEdit loads the target row's values into the edit fields", () => {
+    component.startEdit(userB, "email");
+
+    expect(component.editUid).toBe(userB.uid);
+    expect(component.editAttribute).toBe("email");
+    expect(component.editName).toBe(userB.name);
+    expect(component.editEmail).toBe(userB.email);
+    expect(component.editRole).toBe(userB.role);
+    expect(component.editComment).toBe(userB.comment);
+  });
+
+  it("saveEdit persists a changed row and updates the local lists", () => {
+    component.userList = [userA];
+    component.listOfDisplayUser = [userA];
+    component.editUid = userA.uid;
+    component.editName = "Alice Updated";
+    component.editEmail = userA.email;
+    component.editRole = userA.role;
+    component.editComment = userA.comment;
+
+    component.saveEdit();
+
+    expect(adminUserServiceSpy.updateUser).toHaveBeenCalledWith(
+      userA.uid,
+      "Alice Updated",
+      userA.email,
+      userA.role,
+      userA.comment
+    );
+    expect(component.userList.find(u => u.uid === 
userA.uid)?.name).toBe("Alice Updated");
+    expect(component.listOfDisplayUser.find(u => u.uid === 
userA.uid)?.name).toBe("Alice Updated");
+    expect(component.editUid).toBe(0); // stopEdit ran
+  });
+
+  it("saveEdit is a no-op when nothing changed", () => {
+    component.userList = [userA];
+    component.editUid = userA.uid;
+    component.editName = userA.name;
+    component.editEmail = userA.email;
+    component.editRole = userA.role;
+    component.editComment = userA.comment;
+
+    component.saveEdit();
+
+    expect(adminUserServiceSpy.updateUser).not.toHaveBeenCalled();
+    expect(component.editUid).toBe(0);
+  });
+
+  it("saveEdit surfaces a service error through the message service", () => {
+    const errorSpy = vi.spyOn(TestBed.inject(NzMessageService), 
"error").mockReturnValue({} as any);
+    adminUserServiceSpy.updateUser.mockReturnValue(throwError(() => ({ error: 
{ message: "update failed" } })));
+
+    component.userList = [userA];
+    component.editUid = userA.uid;
+    component.editName = "Changed";
+    component.editEmail = userA.email;
+    component.editRole = userA.role;
+    component.editComment = userA.comment;
+
+    component.saveEdit();
+
+    expect(errorSpy).toHaveBeenCalledWith("update failed");
+  });
+
+  it("stopEdit clears the edit target", () => {
+    component.editUid = 5;
+    component.editAttribute = "name";
+
+    component.stopEdit();
+
+    expect(component.editUid).toBe(0);
+    expect(component.editAttribute).toBe("");
+  });
+
+  it("reset clears search state and restores the full display list", () => {
+    component.userList = [userA, userB];
+    component.nameSearchValue = "Alice";
+    component.emailSearchValue = "[email protected]";
+    component.commentSearchValue = "c";
+    component.nameSearchVisible = true;
+    component.emailSearchVisible = true;
+    component.commentSearchVisible = true;
+    component.listOfDisplayUser = [userA];
+
+    component.reset();
+
+    expect(component.nameSearchValue).toBe("");
+    expect(component.emailSearchValue).toBe("");
+    expect(component.commentSearchValue).toBe("");
+    expect(component.nameSearchVisible).toBe(false);
+    expect(component.emailSearchVisible).toBe(false);
+    expect(component.commentSearchVisible).toBe(false);
+    expect(component.listOfDisplayUser).toEqual([userA, userB]);
+  });
+
+  it("updateRole edits only the role and persists it", () => {
+    component.userList = [userA];
+    component.listOfDisplayUser = [userA];
+
+    component.updateRole(userA, Role.ADMIN);
+
+    expect(adminUserServiceSpy.updateUser).toHaveBeenCalledWith(
+      userA.uid,
+      userA.name,
+      userA.email,
+      Role.ADMIN,
+      userA.comment
+    );
+    expect(component.userList.find(u => u.uid === 
userA.uid)?.role).toBe(Role.ADMIN);
+  });
+
+  it("isUserActive reflects the recent-login window", () => {
+    const nowSeconds = Math.floor(Date.now() / 1000);
+    expect(component.isUserActive({ ...userA, lastLogin: nowSeconds } as 
User)).toBe(true);
+    expect(component.isUserActive({ ...userA, lastLogin: nowSeconds - 100000 } 
as User)).toBe(false);
+    expect(component.isUserActive({ ...userA, lastLogin: undefined } as 
User)).toBe(false);
+  });

Review Comment:
   The inactivity assertion uses a hard-coded 100000-second offset, which 
implicitly depends on the configured active-time window. Derive the "just 
outside" timestamp from the component's configured activeTimeInMinutes so the 
test remains correct if the config default changes.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to