mengw15 commented on code in PR #7503:
URL: https://github.com/apache/texera/pull/7503#discussion_r3746769901


##########
frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/user-dataset-file-renderer/user-dataset-file-renderer.component.spec.ts:
##########
@@ -414,6 +416,181 @@ describe("UserDatasetFileRendererComponent", () => {
       loadWith("notes.txt", blob);
       expect(component.isFileTypePreviewUnsupported).toBe(true);
     });
+
+    it("does not fetch when the dataset ids are missing", () => {
+      const datasetService = TestBed.inject(DatasetService);
+      const spy = vi.spyOn(datasetService, "retrieveDatasetVersionSingleFile");
+      // A supported, in-limit file, so the two pre-checks pass and the id 
guard is the
+      // only thing left to stop the request.
+      component.did = undefined;
+      component.dvid = 2;
+      component.filePath = "notes.txt";
+      component.fileSize = 100;
+
+      component.reloadFileContent();
+
+      expect(spy).not.toHaveBeenCalled();
+      expect(component.isLoading).toBe(true);

Review Comment:
   Good catch on the premise — `isLoading = true` is set immediately above the 
id guard and nothing on that path clears it, so a component that gets a 
`filePath` before its `did`/`dvid` spins forever. Rather than drop the 
assertion I've labelled it: the test now says in a comment that it 
characterizes a defect, not an intent, and says what to flip when it's fixed. 
Deleting it would lose a real finding; leaving it unexplained was the actual 
problem you spotted. Added to the defect list in the PR description.



##########
frontend/src/app/dashboard/component/user/user-computing-unit/user-computing-unit.component.spec.ts:
##########
@@ -94,4 +96,109 @@ describe("UserComputingUnitComponent", () => {
     modal.visibleChange.emit(false);
     expect(component.addComputeUnitModalVisible).toBe(false);
   });
+
+  describe("session, polling and termination", () => {
+    function makeUnit(cuid: number): DashboardWorkflowComputingUnit {
+      return {
+        computingUnit: {
+          cuid,
+          uid: 1,
+          name: `unit-${cuid}`,
+          creationTime: 0,
+          terminateTime: undefined,
+          type: "kubernetes",
+          uri: `uri-${cuid}`,
+          resource: {
+            cpuLimit: "1",
+            memoryLimit: "1Gi",
+            gpuLimit: "0",
+            jvmMemorySize: "1Gi",
+            shmSize: "64Mi",
+            nodeAddresses: [],
+          },
+        },
+        status: "Running",
+        metrics: { cpuUsage: "N/A", memoryUsage: "N/A" },
+        isOwner: true,
+        accessPrivilege: "WRITE",
+        ownerGoogleAvatar: "",
+        ownerName: "owner",
+      } as DashboardWorkflowComputingUnit;
+    }
+
+    afterEach(() => {
+      // ngOnInit starts a 1s interval; destroying the fixture unsubscribes it 
so it
+      // cannot tick into a later test.
+      fixture.destroy();
+    });
+
+    it("follows the signed-in user when the session changes", () => {
+      fixture.detectChanges();
+      const stubUserService = TestBed.inject(UserService) as unknown as 
StubUserService;
+
+      stubUserService.user = undefined;
+      stubUserService.userChangeSubject.next(undefined);
+
+      expect(component.isLogin).toBe(false);
+      expect(component.currentUid).toBeUndefined();
+    });
+
+    it("maps the fetched computing units into dashboard entries", () => {
+      const statusService = TestBed.inject(ComputingUnitStatusService);
+      vi.spyOn(statusService, 
"getAllComputingUnits").mockReturnValue(of([makeUnit(7)]));
+
+      fixture.detectChanges();
+
+      expect(component.allComputingUnits.map(u => 
u.computingUnit.cuid)).toEqual([7]);
+      expect(component.entries.map(e => e.id)).toEqual([7]);
+    });
+
+    it("refreshes the list on every poll tick, and stops once destroyed", 
fakeAsync(() => {
+      const statusService = TestBed.inject(ComputingUnitStatusService);
+      const refreshSpy = vi.spyOn(statusService, 
"refreshComputingUnitList").mockImplementation(() => {});
+
+      // ngOnInit directly rather than through detectChanges: the fixture's 
NgZone was
+      // created outside this fakeAsync zone, so a poll scheduled from there 
would land
+      // on the real timer queue and tick() could not drive it.
+      component.ngOnInit();
+      expect(refreshSpy).not.toHaveBeenCalled();
+
+      tick(1000);
+      expect(refreshSpy).toHaveBeenCalledTimes(1);
+      tick(1000);
+      expect(refreshSpy).toHaveBeenCalledTimes(2);
+
+      fixture.destroy();

Review Comment:
   Not applying this one. `ComponentFixture.destroy()` is idempotent — 
`@angular/core/fesm2022/testing.mjs` guards the teardown with `if 
(!this._isDestroyed) { this.componentRef.destroy(); this._isDestroyed = true; 
}` — so the second call from `afterEach` is a no-op and there is no 
double-destroy.
   
   The `destroy()` inside the test is the behaviour under test (the name is 
"…and stops once destroyed"): it asserts the poll stops after a real Angular 
teardown, which is what happens in production. Calling `ngOnDestroy()` alone 
would test less. The `afterEach` stays as the safety net for the tests that 
don't destroy explicitly.



-- 
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