From: Kefu Chai Date: Thu, 2 Jul 2026 03:04:45 +0000 (+0800) Subject: mgr/dashboard: fix stale nvmeof spec tests from a semantic merge conflict X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7edbd7c61d24359bddb4884d7a31ff85d51926ef;p=ceph.git mgr/dashboard: fix stale nvmeof spec tests from a semantic merge conflict mgr-dashboard-frontend-unittests has been failing on main since 2026-07-01, unrelated to whatever PR triggers it. Bisected to cfe12305fb1, the merge commit for PR #68180. 6182e67ea4 ("mgr/dashboard: NVMe Onboarding Setup Cards") moved gateway group selection out of NvmeofSubsystemsComponent and NvmeofNamespacesListComponent into a new NvmeofGatewayGroupFilterComponent, dropping gwGroups, updateGroupSelectionState, handleGatewayGroupsError, onGroupClear, and getSubsystems from both. Clean on its own. PR #68180 forked from main in April, before that refactor existed, and added three new tests against the old API. Also clean on its own, and never rebased. Both PRs only touch lines the other doesn't, so when #68180 merged 34 minutes after 6182e67ea4, git's 3-way merge combined them without a conflict. The merge is the only place the bug exists: new tests calling methods the sibling parent had already deleted. TypeError at runtime, TS2339/TS2551 from tsc, every run since. CI never caught it: GitHub was showing #68180's make check as green from a run a full day older than 6182e67ea4. nvmeof-namespaces-list.component.spec.ts: the dedup test is real, current logic, it just called the old listNamespaces() instead of fetchData(). Fixed the call. The other two duplicate NvmeofGatewayGroupFilterComponent's own spec; removed. nvmeof-subsystems.component.spec.ts: same story, all three duplicate the filter component's spec; removed. Both removed error tests also checked preventDefault() on the error object, which had no coverage elsewhere. Added that to NvmeofGatewayGroupFilterComponent's spec, and hit a second bug while writing it: the file's throwError(() => err) is the RxJS 7 factory overload, this project is on RxJS 6.6.3, so it was emitting the arrow function itself as the error. The existing error test never noticed since it only checks side effects, not the error's identity. Used throwError(err) instead. Verified: jest passes on all three spec files (was 6 failing), tsc -p tsconfig.spec.json --noEmit is clean (was 17 errors), full block/nvmeof sweep is 29/29 suites, 216/216 tests. Fixes: cfe12305fb1 Signed-off-by: Kefu Chai --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group-filter/nvmeof-gateway-group-filter.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group-filter/nvmeof-gateway-group-filter.component.spec.ts index aef321896f5..2324b2ce161 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group-filter/nvmeof-gateway-group-filter.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group-filter/nvmeof-gateway-group-filter.component.spec.ts @@ -103,6 +103,13 @@ describe('NvmeofGatewayGroupFilterComponent', () => { expect(component.placeholder).toBe('Unable to fetch Gateway groups'); }); + it('should call preventDefault on the error when the API call fails', () => { + const err = { preventDefault: jest.fn() }; + (nvmeofService.listGatewayGroups as jest.Mock).mockReturnValue(throwError(err)); + fixture.detectChanges(); + expect(err.preventDefault).toHaveBeenCalled(); + }); + it('should render a cds-combo-box', () => { fixture.detectChanges(); const combo = fixture.nativeElement.querySelector('cds-combo-box'); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-namespaces-list/nvmeof-namespaces-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-namespaces-list/nvmeof-namespaces-list.component.spec.ts index f7f6b4261b1..945c99ea040 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-namespaces-list/nvmeof-namespaces-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-namespaces-list/nvmeof-namespaces-list.component.spec.ts @@ -148,28 +148,6 @@ describe('NvmeofNamespacesListComponent', () => { done(); }); - component.listNamespaces(); - }); - - it('should default to first group and keep default placeholder when groups exist', () => { - component.group = null; - component.gwGroups = [{ content: 'g1', selected: false }] as any; - - component.updateGroupSelectionState(); - - expect(component.group).toBe('g1'); - expect(component.gwGroupsEmpty).toBe(false); - expect(component.gwGroupPlaceholder).toBe('Enter group name'); - }); - - it('should set error placeholder and call preventDefault on group fetch failure', () => { - const preventDefault = jasmine.createSpy('preventDefault'); - - component.handleGatewayGroupsError({ preventDefault }); - - expect(component.gwGroups).toEqual([]); - expect(component.gwGroupsEmpty).toBe(true); - expect(component.gwGroupPlaceholder).toBe('Unable to fetch Gateway groups'); - expect(preventDefault).toHaveBeenCalled(); + component.fetchData(); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.spec.ts index 0acf8711376..f848d67c66e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-subsystems/nvmeof-subsystems.component.spec.ts @@ -160,39 +160,4 @@ describe('NvmeofSubsystemsComponent', () => { it('should set first group as default initially', () => { expect(component.group).toBe('default'); }); - - it('should mark only current group as selected', () => { - component.group = 'foo'; - component.gwGroups = [{ content: 'default' }, { content: 'foo' }] as any; - - component.updateGroupSelectionState(); - - expect(component.gwGroups).toEqual([ - { content: 'default', selected: false }, - { content: 'foo', selected: true } - ]); - }); - - it('should clear selected group and refresh subsystem list', () => { - component.group = 'default'; - const getSubsystemsSpy = spyOn(component, 'getSubsystems'); - - component.onGroupClear(); - - expect(component.group).toBeNull(); - expect(getSubsystemsSpy).toHaveBeenCalled(); - }); - - it('should set error placeholder and prevent default on groups load error', () => { - const preventDefault = jasmine.createSpy('preventDefault'); - component.context = { error: jasmine.createSpy('error') } as any; - - component.handleGatewayGroupsError({ preventDefault }); - - expect(component.gwGroups).toEqual([]); - expect(component.gwGroupsEmpty).toBe(true); - expect(component.gwGroupPlaceholder).toBe('Unable to fetch Gateway groups'); - expect(preventDefault).toHaveBeenCalled(); - expect(component.context.error).toHaveBeenCalled(); - }); });