From d4596af52b9e3153e5ae3197483478239ad89153 Mon Sep 17 00:00:00 2001 From: steinsebastian <54309425+steinsebastian@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:28:26 +0200 Subject: [PATCH 1/2] fix: clear persisted focus on entering configuration (#19413) --- .../form/configurator-form.component.spec.ts | 14 ++++++++++++++ .../components/form/configurator-form.component.ts | 11 ++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.spec.ts b/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.spec.ts index d1bb77eaa51..37efa156106 100644 --- a/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.spec.ts +++ b/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.spec.ts @@ -31,6 +31,7 @@ import { productConfiguration } from '../../testing/configurator-test-data'; import { ConfiguratorTestUtils } from '../../testing/configurator-test-utils'; import { ConfiguratorAttributeHeaderComponent } from '../attribute/header/configurator-attribute-header.component'; import { ConfiguratorFormComponent } from './configurator-form.component'; +import { KeyboardFocusService } from '@spartacus/storefront'; @Component({ selector: 'cx-configurator-group', @@ -258,6 +259,7 @@ let component: ConfiguratorFormComponent; let htmlElem: HTMLElement; let configExpertModeService: ConfiguratorExpertModeService; let hasConfigurationConflictsObservable: Observable = EMPTY; +let keyboardFocusService: KeyboardFocusService; describe('ConfigurationFormComponent', () => { beforeEach(waitForAsync(() => { @@ -347,6 +349,10 @@ describe('ConfigurationFormComponent', () => { LaunchDialogService as Type ); spyOn(launchDialogService, 'openDialogAndSubscribe').and.callThrough(); + keyboardFocusService = TestBed.inject( + KeyboardFocusService as Type + ); + spyOn(keyboardFocusService, 'clear').and.callThrough(); }); describe('resolve issues navigation', () => { @@ -421,6 +427,14 @@ describe('ConfigurationFormComponent', () => { }); }); + it('should reset persisted focus when UI is opened without resolve issue mode', () => { + routerStateObservable = mockRouterStateWithQueryParams({ + resolveIssues: 'false', + }); + createComponentWithData(); + expect(keyboardFocusService.clear).toHaveBeenCalledTimes(1); + }); + describe('Rendering', () => { it('should render ghost view if no data is present', () => { createComponentWithoutData(); diff --git a/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.ts b/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.ts index 580b92349af..fbc0a2a2ee6 100644 --- a/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.ts +++ b/feature-libs/product-configurator/rulebased/components/form/configurator-form.component.ts @@ -9,13 +9,18 @@ import { Component, OnDestroy, OnInit, + inject, } from '@angular/core'; import { GlobalMessageService, GlobalMessageType } from '@spartacus/core'; import { ConfiguratorRouter, ConfiguratorRouterExtractorService, } from '@spartacus/product-configurator/common'; -import { LAUNCH_CALLER, LaunchDialogService } from '@spartacus/storefront'; +import { + LAUNCH_CALLER, + LaunchDialogService, + KeyboardFocusService, +} from '@spartacus/storefront'; import { Observable, Subscription } from 'rxjs'; import { delay, @@ -38,6 +43,7 @@ import { ConfiguratorExpertModeService } from '../../core/services/configurator- export class ConfiguratorFormComponent implements OnInit, OnDestroy { protected subscription = new Subscription(); + protected keyboardFocusService = inject(KeyboardFocusService); routerData$: Observable = this.configRouterExtractorService.extractRouterData(); @@ -157,6 +163,9 @@ export class ConfiguratorFormComponent implements OnInit, OnDestroy { ); } }); + } else { + // Clear persisted focus before entering the configurator UI + this.keyboardFocusService.clear(); } if (routingData.expMode) { From 40dc5982031f01e7c5c16b292c4b114f091fbfff Mon Sep 17 00:00:00 2001 From: steinsebastian <54309425+steinsebastian@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:57:06 +0200 Subject: [PATCH 2/2] chore: Adapt tests that output is cleared afterwards (#19430) Co-authored-by: Ulrich Stellmacher --- ...te-multi-selection-image.component.spec.ts | 1 + ...e-single-selection-image.component.spec.ts | 1 + ...nfigurator-overview-menu.component.spec.ts | 20 ++----------------- ...figurator-storefront-utils.service.spec.ts | 2 +- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/feature-libs/product-configurator/rulebased/components/attribute/types/multi-selection-image/configurator-attribute-multi-selection-image.component.spec.ts b/feature-libs/product-configurator/rulebased/components/attribute/types/multi-selection-image/configurator-attribute-multi-selection-image.component.spec.ts index ec6728bd71d..11512ee1324 100644 --- a/feature-libs/product-configurator/rulebased/components/attribute/types/multi-selection-image/configurator-attribute-multi-selection-image.component.spec.ts +++ b/feature-libs/product-configurator/rulebased/components/attribute/types/multi-selection-image/configurator-attribute-multi-selection-image.component.spec.ts @@ -241,6 +241,7 @@ describe('ConfiguratorAttributeMultiSelectionImageComponent', () => { expect(description.nativeElement.innerText).toBe( (component.attribute.values ?? [{ description: '' }])[1]?.description ); + infoButton.click(); // hide popover after test again }); it('should mark two values as selected', () => { diff --git a/feature-libs/product-configurator/rulebased/components/attribute/types/single-selection-image/configurator-attribute-single-selection-image.component.spec.ts b/feature-libs/product-configurator/rulebased/components/attribute/types/single-selection-image/configurator-attribute-single-selection-image.component.spec.ts index 47746608851..fb1a21c26d0 100644 --- a/feature-libs/product-configurator/rulebased/components/attribute/types/single-selection-image/configurator-attribute-single-selection-image.component.spec.ts +++ b/feature-libs/product-configurator/rulebased/components/attribute/types/single-selection-image/configurator-attribute-single-selection-image.component.spec.ts @@ -222,6 +222,7 @@ describe('ConfiguratorAttributeSingleSelectionImageComponent', () => { expect(description.nativeElement.innerText).toBe( (component.attribute.values ?? [{}])[1].description ); + infoButton.click(); // hide popover after test again }); it('should init with val3', () => { diff --git a/feature-libs/product-configurator/rulebased/components/overview-menu/configurator-overview-menu.component.spec.ts b/feature-libs/product-configurator/rulebased/components/overview-menu/configurator-overview-menu.component.spec.ts index 704f18c8073..f9f4ef3483a 100644 --- a/feature-libs/product-configurator/rulebased/components/overview-menu/configurator-overview-menu.component.spec.ts +++ b/feature-libs/product-configurator/rulebased/components/overview-menu/configurator-overview-menu.component.spec.ts @@ -124,10 +124,6 @@ describe('ConfigurationOverviewMenuComponent', () => { }).compileComponents(); })); - afterEach(() => { - document.body.removeChild(htmlElem); - }); - it('should create component', () => { initialize(); expect(component).toBeDefined(); @@ -417,12 +413,6 @@ describe('ConfigurationOverviewMenuComponent', () => { initialize(); }); - afterEach(() => { - groups?.forEach((group: any) => { - ConfiguratorTestUtils.remove(group); - }); - }); - it('should not get menu item to highlight because getElements method return undefined', () => { spyOn(configuratorStorefrontUtilsService, 'getElements').and.returnValue( undefined @@ -435,10 +425,7 @@ describe('ConfigurationOverviewMenuComponent', () => { it('should not get menu item to highlight because getScrollY method return undefined', () => { groups = createElements('div'); - document.querySelectorAll = jasmine - .createSpy('div.cx-group') - .and.returnValue(groups); - + spyOn(document, 'querySelectorAll').and.returnValue(groups); spyOn(configuratorStorefrontUtilsService, 'getElements').and.returnValue( groups ); @@ -456,10 +443,7 @@ describe('ConfigurationOverviewMenuComponent', () => { it('should get menu item to highlight', () => { groups = createElements('div'); - document.querySelectorAll = jasmine - .createSpy('div.cx-group') - .and.returnValue(groups); - + spyOn(document, 'querySelectorAll').and.returnValue(groups); spyOn(configuratorStorefrontUtilsService, 'getElements').and.returnValue( groups ); diff --git a/feature-libs/product-configurator/rulebased/components/service/configurator-storefront-utils.service.spec.ts b/feature-libs/product-configurator/rulebased/components/service/configurator-storefront-utils.service.spec.ts index 71802a32209..a7e4d002fa8 100644 --- a/feature-libs/product-configurator/rulebased/components/service/configurator-storefront-utils.service.spec.ts +++ b/feature-libs/product-configurator/rulebased/components/service/configurator-storefront-utils.service.spec.ts @@ -609,7 +609,7 @@ describe('ConfiguratorStorefrontUtilsService', () => { spyOn(windowRef, 'isBrowser').and.returnValue(true); const elements: Array = createElements('section', 10); - asSpy(windowRef.document.querySelectorAll).and.returnValue(elements); + spyOn(document, 'querySelectorAll').and.returnValue(elements); const htmlElements = classUnderTest.getElements('section');