From 0cee600371564a161ca7150b0176dc5de9b6870f Mon Sep 17 00:00:00 2001 From: Johanna Thalmann Date: Tue, 14 Jan 2025 17:42:24 +0100 Subject: [PATCH 01/16] CXEC-45758: add possibility to enable SCI for CAS. --- .env-cmdrc | 3 +- integration-libs/cds/src/cds.module.ts | 15 +- integration-libs/cds/src/config/cds-config.ts | 1 + .../cds/src/config/default-cds-config.ts | 43 ++- .../cds/src/config/profile-tag.config.ts | 1 + ...cds-merchandising-strategy.adapter.spec.ts | 323 +++++++++--------- .../cds-merchandising-strategy.adapter.ts | 32 +- .../src/profiletag/model/profile-tag.model.ts | 7 +- .../cds/src/schematics/add-cds/schema.json | 6 + .../integration-libs/cds-schematics-config.ts | 8 +- .../features/cds/cds-feature.module.ts | 36 +- .../src/environments/environment.prod.ts | 1 + .../src/environments/environment.ts | 1 + .../models/build.process.env.d.ts | 1 + .../environments/models/environment.model.ts | 1 + 15 files changed, 268 insertions(+), 211 deletions(-) diff --git a/.env-cmdrc b/.env-cmdrc index aeb0f17cde2..3e07f3a5afd 100644 --- a/.env-cmdrc +++ b/.env-cmdrc @@ -15,7 +15,8 @@ "CX_BASE_URL": "https://api.cg79x9wuu9-eccommerc1-p1-public.model-t.myhybris.cloud" }, "cds": { - "CX_CDS": "true" + "CX_CDS": "true", + "CX_SCI": "true" }, "lighthouse": { "CX_BASE_URL": "https://api.spartacus.rocks" diff --git a/integration-libs/cds/src/cds.module.ts b/integration-libs/cds/src/cds.module.ts index e0a28705772..5fe08751493 100644 --- a/integration-libs/cds/src/cds.module.ts +++ b/integration-libs/cds/src/cds.module.ts @@ -5,8 +5,16 @@ */ import { ModuleWithProviders, NgModule } from '@angular/core'; -import { provideConfigValidator, provideDefaultConfig } from '@spartacus/core'; -import { CdsConfig, cdsConfigValidator, DEFAULT_CDS_CONFIG } from './config'; +import { + provideConfigValidator, + provideDefaultConfig, + provideDefaultConfigFactory, +} from '@spartacus/core'; +import { + CdsConfig, + cdsConfigValidator, + defaultCdsConfigFactory, +} from './config'; import { MerchandisingModule } from './merchandising'; import { ProfileTagModule, @@ -15,7 +23,6 @@ import { } from './profiletag'; import { RecentSearchesModule } from './recent-searches/recent-searches.module'; import { TrendingSearchesModule } from './trending-searches/trending-searches.module'; - @NgModule({ imports: [ ProfileTagModule, @@ -30,7 +37,7 @@ export class CdsModule { return { ngModule: CdsModule, providers: [ - provideDefaultConfig(DEFAULT_CDS_CONFIG), + provideDefaultConfigFactory(defaultCdsConfigFactory), provideDefaultConfig(config), provideConfigValidator(cdsConfigValidator), ProfileTagPushEventsService, diff --git a/integration-libs/cds/src/config/cds-config.ts b/integration-libs/cds/src/config/cds-config.ts index 98db9bb90c1..004a113cfbe 100644 --- a/integration-libs/cds/src/config/cds-config.ts +++ b/integration-libs/cds/src/config/cds-config.ts @@ -23,6 +23,7 @@ export abstract class CdsConfig { endpoints?: CdsEndpoints; merchandising?: MerchandisingConfig; profileTag?: ProfileTagConfig; + sciEnabled?: boolean; }; } diff --git a/integration-libs/cds/src/config/default-cds-config.ts b/integration-libs/cds/src/config/default-cds-config.ts index 3b6e99485d7..b459a1b4169 100644 --- a/integration-libs/cds/src/config/default-cds-config.ts +++ b/integration-libs/cds/src/config/default-cds-config.ts @@ -4,23 +4,32 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { environment } from 'projects/storefrontapp/src/environments/environment'; import { CdsConfig } from './cds-config'; -export const DEFAULT_CDS_CONFIG: CdsConfig = { - cds: { - tenant: '', - baseUrl: '', - endpoints: { - strategyProducts: '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', +export function defaultCdsConfigFactory(): CdsConfig { + + const sciEnabled = environment.sciEnabled; + + return { + cds: { + tenant: '', + baseUrl: '', + endpoints: { + strategyProducts: sciEnabled + ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' + : '/strategy/${tenant}/strategies/${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', + }, + merchandising: { + defaultCarouselViewportThreshold: 80, + }, + consentTemplateId: 'PROFILE', + profileTag: { + allowInsecureCookies: false, + sciEnabled: sciEnabled, + }, }, - merchandising: { - defaultCarouselViewportThreshold: 80, - }, - consentTemplateId: 'PROFILE', - profileTag: { - allowInsecureCookies: false, - }, - }, -}; + }; +} \ No newline at end of file diff --git a/integration-libs/cds/src/config/profile-tag.config.ts b/integration-libs/cds/src/config/profile-tag.config.ts index 6ad8ef701e0..b99f9084b69 100644 --- a/integration-libs/cds/src/config/profile-tag.config.ts +++ b/integration-libs/cds/src/config/profile-tag.config.ts @@ -9,4 +9,5 @@ export interface ProfileTagConfig { configUrl?: string; allowInsecureCookies?: boolean; gtmId?: string; + sciEnabled?: boolean; } diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts index 63e62167976..35aa2a9c897 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts @@ -1,166 +1,183 @@ import { - HttpClientTestingModule, - HttpTestingController, -} from '@angular/common/http/testing'; -import { TestBed } from '@angular/core/testing'; -import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; -import { StrategyProducts } from '../../model/strategy-products.model'; -import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; -import createSpy = jasmine.createSpy; - -const STRATEGY_ID = 'test-strategy-id'; -const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; -const strategyIdObject = { strategyId: STRATEGY_ID }; - -const expectedProductsFromStrategy: StrategyProducts = { - resultCount: 1, - products: [ - { - id: 'test-product-id', - metadata: { - 'test-product-metadata-field': 'test-product-metadata-value', + HttpClientTestingModule, + HttpTestingController, + } from '@angular/common/http/testing'; + import { TestBed } from '@angular/core/testing'; + import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; + import { StrategyProducts } from '../../model/strategy-products.model'; + import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; + import createSpy = jasmine.createSpy; + import { BaseSiteService } from '@spartacus/core'; + import { of } from 'rxjs'; + + const STRATEGY_ID = 'test-strategy-id'; + const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; + const TEST_BASE_SITE = 'testBaseSite'; + + const TEST_URL_PARAMS = { + baseSite: TEST_BASE_SITE, + strategyId: STRATEGY_ID, + }; + + const expectedProductsFromStrategy: StrategyProducts = { + resultCount: 1, + products: [ + { + id: 'test-product-id', + metadata: { + 'test-product-metadata-field': 'test-product-metadata-value', + }, }, + ], + paged: { + from: 1, + size: 5, }, - ], - paged: { - from: 1, - size: 5, - }, - metadata: { - 'test-metadata-field': 'test-metadata-value', - }, -}; -const strategyRequest = { - queryParams: { - site: 'electronics-spa', - language: 'en', - pageSize: 10, - }, -}; -const strategyRequestUndefinedConsentReference = { - ...strategyRequest, - headers: { - consentReference: undefined, - }, -}; - -class MockCdsEndpointsService { - getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( - (endpoint) => endpoint - ); -} - -describe('MerchandisingStrategyAdapter', () => { - let strategyAdapter: CdsMerchandisingStrategyAdapter; - let httpMock: HttpTestingController; - let cdsEndpointsService: CdsEndpointsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: CdsEndpointsService, - useClass: MockCdsEndpointsService, - }, - CdsMerchandisingStrategyAdapter, - ], + metadata: { + 'test-metadata-field': 'test-metadata-value', + }, + }; + const strategyRequest = { + queryParams: { + site: 'electronics-spa', + language: 'en', + pageSize: 10, + }, + }; + const strategyRequestUndefinedConsentReference = { + ...strategyRequest, + headers: { + consentReference: undefined, + }, + }; + + class MockCdsEndpointsService { + getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( + (endpoint: string) => endpoint + ); + } + + class MockBaseSiteService { + getActive = createSpy('MockBaseSiteService.getActive').and.callFake(() => + of(TEST_BASE_SITE) + ); + } + + describe('MerchandisingStrategyAdapter', () => { + let strategyAdapter: CdsMerchandisingStrategyAdapter; + let httpMock: HttpTestingController; + let cdsEndpointsService: CdsEndpointsService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + { + provide: CdsEndpointsService, + useClass: MockCdsEndpointsService, + }, + { + provide: BaseSiteService, + useClass: MockBaseSiteService, + }, + CdsMerchandisingStrategyAdapter, + ], + }); + + httpMock = TestBed.inject(HttpTestingController); + strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); + cdsEndpointsService = TestBed.inject(CdsEndpointsService); }); - - httpMock = TestBed.inject(HttpTestingController); - strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); - cdsEndpointsService = TestBed.inject(CdsEndpointsService); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should be created', () => { - expect(strategyAdapter).toBeTruthy(); - }); - - describe('load products for strategy', () => { - it('should load products for the given strategy id', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); + + afterEach(() => { + httpMock.verify(); + }); + + it('should be created', () => { + expect(strategyAdapter).toBeTruthy(); + }); + + describe('load products for strategy', () => { + it('should load products for the given strategy id', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); + }); + + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); + expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); - expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); - }); - - it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID, strategyRequest) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); + + it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID, strategyRequest) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); + }); + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - strategyIdObject, - strategyRequest.queryParams - ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); - }); - - it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { - strategyAdapter - .loadProductsForStrategy( - STRATEGY_ID, - strategyRequestUndefinedConsentReference - ) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); + + it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { + strategyAdapter + .loadProductsForStrategy( + STRATEGY_ID, + strategyRequestUndefinedConsentReference + ) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); + }); + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + + expect( + mockStrategyProductsRequest.request.headers.get('consent-reference') + ).toBeFalsy(); + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - - expect( - mockStrategyProductsRequest.request.headers.get('consent-reference') - ).toBeFalsy(); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - strategyIdObject, - strategyRequest.queryParams - ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - }); -}); + }); \ No newline at end of file diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index d7f547cc788..53d0e444792 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -1,16 +1,17 @@ /* - * SPDX-FileCopyrightText: 2025 SAP Spartacus team + * SPDX-FileCopyrightText: 2024 SAP Spartacus team * * SPDX-License-Identifier: Apache-2.0 */ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable, switchMap, take } from 'rxjs'; import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; import { MerchandisingStrategyAdapter } from '../../connectors/strategy/merchandising-strategy.adapter'; import { StrategyProducts } from '../../model/strategy-products.model'; import { StrategyRequest } from './../../../cds-models/cds-strategy-request.model'; +import { BaseSiteService } from '@spartacus/core'; const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; @@ -20,6 +21,7 @@ export class CdsMerchandisingStrategyAdapter { constructor( private cdsEndpointsService: CdsEndpointsService, + private baseSiteService: BaseSiteService, protected http: HttpClient ) {} @@ -34,15 +36,21 @@ export class CdsMerchandisingStrategyAdapter strategyRequest.headers.consentReference ); } - return this.http.get( - this.cdsEndpointsService.getUrl( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - { - strategyId, - }, - strategyRequest.queryParams - ), - { headers } + return this.baseSiteService.getActive().pipe( + take(1), + switchMap((baseSite) => + this.http.get( + this.cdsEndpointsService.getUrl( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + { + baseSite, + strategyId, + }, + strategyRequest.queryParams + ), + { headers } + ) + ) ); } -} +} \ No newline at end of file diff --git a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts index d5433b4635b..908ab041b3f 100644 --- a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts +++ b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts @@ -22,6 +22,7 @@ export interface ProfileTagJsConfig { configUrl?: string; allowInsecureCookies?: boolean; gtmId?: string; + sciEnabled?: boolean; } export interface ConsentReferenceEvent extends CustomEvent { @@ -53,15 +54,15 @@ export interface ProfileTagPushEvent { export class NavigatedPushEvent implements ProfileTagPushEvent { name = 'Navigated'; data: any; - constructor(data?) { + constructor(data?: any) { this.data = data; } } export class ConsentChangedPushEvent implements ProfileTagPushEvent { name = 'ConsentChanged'; - data: { granted: boolean } = { granted: undefined }; - constructor(granted: boolean) { + data: { granted?: boolean } = { granted: undefined }; + constructor(granted: boolean) { this.data.granted = granted; } } diff --git a/integration-libs/cds/src/schematics/add-cds/schema.json b/integration-libs/cds/src/schematics/add-cds/schema.json index 529a264cdb9..023cda762cf 100644 --- a/integration-libs/cds/src/schematics/add-cds/schema.json +++ b/integration-libs/cds/src/schematics/add-cds/schema.json @@ -47,6 +47,12 @@ "type": "string", "description": "Configuration URL for ProfileTag. (e.g. https://tag.static.stage.context.cloud.sap/config/my-config123)", "x-prompt": "[CDS] What is the ProfileTag configuration URL?" + }, + "sciEnabled": { + "type": "boolean", + "description": "CDS/ISS is integrated into the SAP Cloud Identity Service (SCI). The downstream services use different domains and URL formats. This property enables the CDS module to use these new URLs.", + "default": false, + "x-prompt": "[CDS] Do you want to enable SCI?" } } } diff --git a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts index 35a1203697e..502d2a9e3a2 100644 --- a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts +++ b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts @@ -22,6 +22,7 @@ export interface SpartacusCdsOptions extends LibraryOptions { baseUrl?: string; profileTagLoadUrl?: string; profileTagConfigUrl?: string; + sciEnabled?: boolean; } export const CDS_FOLDER_NAME = 'cds'; @@ -69,7 +70,11 @@ function buildCdsConfig( tenant: '${options.tenant || 'TENANT_PLACEHOLDER'}', baseUrl: '${options.baseUrl || 'BASE_URL_PLACEHOLDER'}', endpoints: { - strategyProducts: '/strategy/\${tenant}/strategies/\${strategyId}/products', + strategyProducts: '${options.sciEnabled || false }' + ? '/strategy/v1/sites/\${baseSite}/strategies/\${strategyId}/products' + : '/strategy/\${tenant}/strategies/\${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/\${cdsSiteId}/trendingSearches', }, merchandising: { defaultCarouselViewportThreshold: 80, @@ -100,6 +105,7 @@ function buildCdsConfig( 'PROFILE_TAG_CONFIG_URL_PLACEHOLDER' }', allowInsecureCookies: true, + sciEnabled: '${options.sciEnabled || false}', }, }, }`, diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index c073c636b47..715030faccf 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -17,19 +17,17 @@ import { cdsTranslations, } from '@spartacus/cds/assets'; +/** + * Only differences to the default cds config, they are merged together. + * + * @see defaultCdsConfigFactory + * @see CdsModule.forRoot + */ const cds1: CdsConfig = { cds: { baseSite: ['electronics-spa', 'electronics', 'electronics-standalone'], tenant: 'argotest', baseUrl: 'https://api.stage.context.cloud.sap', - endpoints: { - strategyProducts: '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', - }, - merchandising: { - defaultCarouselViewportThreshold: 80, - }, profileTag: { javascriptUrl: 'https://tag.static.stage.context.cloud.sap/js/profile-tag.js', @@ -40,7 +38,13 @@ const cds1: CdsConfig = { }, }; -const cds2 = { +/** + * Only differences to the default cds config, they are merged together. + * + * @see defaultCdsConfigFactory + * @see CdsModule.forRoot + */ +const cds2: CdsConfig = { cds: { baseSite: [ 'apparel-de', @@ -50,14 +54,6 @@ const cds2 = { ], tenant: 'A_CDS_TENANT', baseUrl: 'A_CDS_BASE_URL', - endpoints: { - strategyProducts: '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', - }, - merchandising: { - defaultCarouselViewportThreshold: 80, - }, profileTag: { javascriptUrl: 'A_CDS_PROFILE_TAG_LOAD_URL', configUrl: 'A_CDS_PROFILE_TAG_CONFIG_URL', @@ -66,9 +62,9 @@ const cds2 = { }, }; -const cdsConfigArray = [cds1, cds2]; +function cdsConfigFactory(windowRef: WindowRef): CdsConfig { + const cdsConfigArray = [cds1, cds2]; -const cdsConfig = (windowRef: WindowRef): CdsConfig => { if (!windowRef.isBrowser()) { return cds1; } @@ -90,7 +86,7 @@ const cdsConfig = (windowRef: WindowRef): CdsConfig => { fallbackLang: 'en', }, }), - provideConfigFactory(cdsConfig, [WindowRef]), + provideConfigFactory(cdsConfigFactory, [WindowRef]), ], }) export class CdsFeatureModule {} diff --git a/projects/storefrontapp/src/environments/environment.prod.ts b/projects/storefrontapp/src/environments/environment.prod.ts index 6037371c0e8..5e273ae1df7 100644 --- a/projects/storefrontapp/src/environments/environment.prod.ts +++ b/projects/storefrontapp/src/environments/environment.prod.ts @@ -11,6 +11,7 @@ export const environment: Environment = { occBaseUrl: buildProcess.env.CX_BASE_URL, occApiPrefix: '/occ/v2/', cds: buildProcess.env.CX_CDS, + sciEnabled: buildProcess.env.CX_SCI, b2b: buildProcess.env.CX_B2B, cdc: buildProcess.env.CX_CDC, cdp: buildProcess.env.CX_CDP, diff --git a/projects/storefrontapp/src/environments/environment.ts b/projects/storefrontapp/src/environments/environment.ts index be90972448d..928c00350e2 100644 --- a/projects/storefrontapp/src/environments/environment.ts +++ b/projects/storefrontapp/src/environments/environment.ts @@ -24,6 +24,7 @@ export const environment: Environment = { occBaseUrl: buildProcess.env.CX_BASE_URL, occApiPrefix: '/occ/v2/', cds: buildProcess.env.CX_CDS ?? false, + sciEnabled: buildProcess.env.CX_SCI ?? false, b2b: buildProcess.env.CX_B2B ?? false, cdc: buildProcess.env.CX_CDC ?? false, cdp: buildProcess.env.CX_CDP ?? false, diff --git a/projects/storefrontapp/src/environments/models/build.process.env.d.ts b/projects/storefrontapp/src/environments/models/build.process.env.d.ts index 344f31b0ffa..f7dee503fd7 100644 --- a/projects/storefrontapp/src/environments/models/build.process.env.d.ts +++ b/projects/storefrontapp/src/environments/models/build.process.env.d.ts @@ -13,6 +13,7 @@ interface BuildProcess { interface Env { CX_BASE_URL: string; CX_CDS: boolean; + CX_SCI: boolean; CX_CDC: boolean; CX_CDP: boolean; CX_B2B: boolean; diff --git a/projects/storefrontapp/src/environments/models/environment.model.ts b/projects/storefrontapp/src/environments/models/environment.model.ts index bfd0088e6d8..6d603752425 100644 --- a/projects/storefrontapp/src/environments/models/environment.model.ts +++ b/projects/storefrontapp/src/environments/models/environment.model.ts @@ -10,6 +10,7 @@ export interface Environment { occApiPrefix: string; b2b: boolean; cds: boolean; + sciEnabled: boolean; cdc: boolean; cdp: boolean; cpq: boolean; From 35e478e20af69f1467a7575d43d83be0d5d06bb1 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Wed, 15 Jan 2025 11:43:57 +0100 Subject: [PATCH 02/16] CXCDS-13558: add possibility to enable SCI for CAS, fix tests and style. --- .../cds/src/config/default-cds-config.ts | 5 +- ...cds-merchandising-strategy.adapter.spec.ts | 340 +++++++++--------- .../cds-merchandising-strategy.adapter.ts | 2 +- .../src/profiletag/model/profile-tag.model.ts | 2 +- .../services/profiletag-event.service.spec.ts | 1 + .../recent-searches.component.spec.ts | 2 +- .../add-cds/__snapshots__/index_spec.ts.snap | 6 - .../integration-libs/cds-schematics-config.ts | 9 - .../features/cds/cds-feature.module.ts | 2 +- 9 files changed, 177 insertions(+), 192 deletions(-) diff --git a/integration-libs/cds/src/config/default-cds-config.ts b/integration-libs/cds/src/config/default-cds-config.ts index b459a1b4169..22aebefc647 100644 --- a/integration-libs/cds/src/config/default-cds-config.ts +++ b/integration-libs/cds/src/config/default-cds-config.ts @@ -8,9 +8,8 @@ import { environment } from 'projects/storefrontapp/src/environments/environment import { CdsConfig } from './cds-config'; export function defaultCdsConfigFactory(): CdsConfig { - const sciEnabled = environment.sciEnabled; - + return { cds: { tenant: '', @@ -32,4 +31,4 @@ export function defaultCdsConfigFactory(): CdsConfig { }, }, }; -} \ No newline at end of file +} diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts index 35aa2a9c897..52e28143651 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts @@ -1,183 +1,183 @@ import { - HttpClientTestingModule, - HttpTestingController, - } from '@angular/common/http/testing'; - import { TestBed } from '@angular/core/testing'; - import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; - import { StrategyProducts } from '../../model/strategy-products.model'; - import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; - import createSpy = jasmine.createSpy; - import { BaseSiteService } from '@spartacus/core'; - import { of } from 'rxjs'; - - const STRATEGY_ID = 'test-strategy-id'; - const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; - const TEST_BASE_SITE = 'testBaseSite'; - - const TEST_URL_PARAMS = { - baseSite: TEST_BASE_SITE, - strategyId: STRATEGY_ID, - }; - - const expectedProductsFromStrategy: StrategyProducts = { - resultCount: 1, - products: [ - { - id: 'test-product-id', - metadata: { - 'test-product-metadata-field': 'test-product-metadata-value', - }, + HttpClientTestingModule, + HttpTestingController, +} from '@angular/common/http/testing'; +import { TestBed } from '@angular/core/testing'; +import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; +import { StrategyProducts } from '../../model/strategy-products.model'; +import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; +import createSpy = jasmine.createSpy; +import { BaseSiteService } from '@spartacus/core'; +import { of } from 'rxjs'; + +const STRATEGY_ID = 'test-strategy-id'; +const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; +const TEST_BASE_SITE = 'testBaseSite'; + +const TEST_URL_PARAMS = { + baseSite: TEST_BASE_SITE, + strategyId: STRATEGY_ID, +}; + +const expectedProductsFromStrategy: StrategyProducts = { + resultCount: 1, + products: [ + { + id: 'test-product-id', + metadata: { + 'test-product-metadata-field': 'test-product-metadata-value', }, - ], - paged: { - from: 1, - size: 5, - }, - metadata: { - 'test-metadata-field': 'test-metadata-value', - }, - }; - const strategyRequest = { - queryParams: { - site: 'electronics-spa', - language: 'en', - pageSize: 10, }, - }; - const strategyRequestUndefinedConsentReference = { - ...strategyRequest, - headers: { - consentReference: undefined, - }, - }; - - class MockCdsEndpointsService { - getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( - (endpoint: string) => endpoint - ); - } - - class MockBaseSiteService { - getActive = createSpy('MockBaseSiteService.getActive').and.callFake(() => - of(TEST_BASE_SITE) - ); - } - - describe('MerchandisingStrategyAdapter', () => { - let strategyAdapter: CdsMerchandisingStrategyAdapter; - let httpMock: HttpTestingController; - let cdsEndpointsService: CdsEndpointsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: CdsEndpointsService, - useClass: MockCdsEndpointsService, - }, - { - provide: BaseSiteService, - useClass: MockBaseSiteService, - }, - CdsMerchandisingStrategyAdapter, - ], - }); - - httpMock = TestBed.inject(HttpTestingController); - strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); - cdsEndpointsService = TestBed.inject(CdsEndpointsService); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should be created', () => { - expect(strategyAdapter).toBeTruthy(); + ], + paged: { + from: 1, + size: 5, + }, + metadata: { + 'test-metadata-field': 'test-metadata-value', + }, +}; +const strategyRequest = { + queryParams: { + site: 'electronics-spa', + language: 'en', + pageSize: 10, + }, +}; +const strategyRequestUndefinedConsentReference = { + ...strategyRequest, + headers: { + consentReference: undefined, + }, +}; + +class MockCdsEndpointsService { + getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( + (endpoint: string) => endpoint + ); +} + +class MockBaseSiteService { + getActive = createSpy('MockBaseSiteService.getActive').and.callFake(() => + of(TEST_BASE_SITE) + ); +} + +describe('MerchandisingStrategyAdapter', () => { + let strategyAdapter: CdsMerchandisingStrategyAdapter; + let httpMock: HttpTestingController; + let cdsEndpointsService: CdsEndpointsService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + { + provide: CdsEndpointsService, + useClass: MockCdsEndpointsService, + }, + { + provide: BaseSiteService, + useClass: MockBaseSiteService, + }, + CdsMerchandisingStrategyAdapter, + ], }); - - describe('load products for strategy', () => { - it('should load products for the given strategy id', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); - }); - - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + + httpMock = TestBed.inject(HttpTestingController); + strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); + cdsEndpointsService = TestBed.inject(CdsEndpointsService); + }); + + afterEach(() => { + httpMock.verify(); + }); + + it('should be created', () => { + expect(strategyAdapter).toBeTruthy(); + }); + + describe('load products for strategy', () => { + it('should load products for the given strategy id', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); }); - expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); - expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); + + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - - it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID, strategyRequest) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); - }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); + expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); + }); + + it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID, strategyRequest) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); }); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - TEST_URL_PARAMS, - strategyRequest.queryParams + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - - it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { - strategyAdapter - .loadProductsForStrategy( - STRATEGY_ID, - strategyRequestUndefinedConsentReference - ) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); - }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams + ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); + }); + + it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { + strategyAdapter + .loadProductsForStrategy( + STRATEGY_ID, + strategyRequestUndefinedConsentReference + ) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); }); - - expect( - mockStrategyProductsRequest.request.headers.get('consent-reference') - ).toBeFalsy(); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - TEST_URL_PARAMS, - strategyRequest.queryParams + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); + + expect( + mockStrategyProductsRequest.request.headers.get('consent-reference') + ).toBeFalsy(); + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams + ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - }); \ No newline at end of file + }); +}); diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index 53d0e444792..957e7d1f8ad 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -53,4 +53,4 @@ export class CdsMerchandisingStrategyAdapter ) ); } -} \ No newline at end of file +} diff --git a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts index 908ab041b3f..fee2e205674 100644 --- a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts +++ b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts @@ -62,7 +62,7 @@ export class NavigatedPushEvent implements ProfileTagPushEvent { export class ConsentChangedPushEvent implements ProfileTagPushEvent { name = 'ConsentChanged'; data: { granted?: boolean } = { granted: undefined }; - constructor(granted: boolean) { + constructor(granted: boolean) { this.data.granted = granted; } } diff --git a/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts b/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts index 8321bb79a6e..def97822e89 100644 --- a/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts +++ b/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts @@ -26,6 +26,7 @@ const mockCDSConfig: CdsConfig = { configUrl: 'https:tag.static.us.context.cloud.sap', allowInsecureCookies: false, gtmId: 'test-id-1234567', + sciEnabled: false, }, }, }; diff --git a/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts b/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts index 79fd8b336dd..a190fbcbc2a 100644 --- a/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts +++ b/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts @@ -144,6 +144,6 @@ describe('RecentSearchesComponent', () => { expect(() => { component.shareEvent(ev); - }).toThrowError(); + }).toThrow(); }); }); diff --git a/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap b/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap index 3e158a7be46..c0513c71843 100644 --- a/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap +++ b/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap @@ -21,9 +21,6 @@ import { I18nConfig, provideConfig } from "@spartacus/core"; cds: { tenant: 'my-tenant', baseUrl: 'my-base-url.com', - endpoints: { - strategyProducts: '/strategy/\${tenant}/strategies/\${strategyId}/products', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, @@ -67,9 +64,6 @@ import { I18nConfig, provideConfig } from "@spartacus/core"; cds: { tenant: 'my-tenant', baseUrl: 'my-base-url.com', - endpoints: { - strategyProducts: '/strategy/\${tenant}/strategies/\${strategyId}/products', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, diff --git a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts index 502d2a9e3a2..a67efe10df0 100644 --- a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts +++ b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts @@ -22,7 +22,6 @@ export interface SpartacusCdsOptions extends LibraryOptions { baseUrl?: string; profileTagLoadUrl?: string; profileTagConfigUrl?: string; - sciEnabled?: boolean; } export const CDS_FOLDER_NAME = 'cds'; @@ -69,13 +68,6 @@ function buildCdsConfig( cds: { tenant: '${options.tenant || 'TENANT_PLACEHOLDER'}', baseUrl: '${options.baseUrl || 'BASE_URL_PLACEHOLDER'}', - endpoints: { - strategyProducts: '${options.sciEnabled || false }' - ? '/strategy/v1/sites/\${baseSite}/strategies/\${strategyId}/products' - : '/strategy/\${tenant}/strategies/\${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/\${cdsSiteId}/trendingSearches', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, @@ -105,7 +97,6 @@ function buildCdsConfig( 'PROFILE_TAG_CONFIG_URL_PLACEHOLDER' }', allowInsecureCookies: true, - sciEnabled: '${options.sciEnabled || false}', }, }, }`, diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index 715030faccf..02477843fc8 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -74,7 +74,7 @@ function cdsConfigFactory(windowRef: WindowRef): CdsConfig { ); }); return cds ?? cds1; -}; +} @NgModule({ imports: [CdsModule.forRoot()], From 13f2b52f1c607977c1fe9b85f6b4f444ffa893a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 Jan 2025 11:11:13 +0000 Subject: [PATCH 03/16] Add license header --- .../adapters/strategy/cds-merchandising-strategy.adapter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index 957e7d1f8ad..c99ec4fe8d7 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2024 SAP Spartacus team + * SPDX-FileCopyrightText: 2025 SAP Spartacus team * * SPDX-License-Identifier: Apache-2.0 */ From a214f48f4f40d66e936037988f3a3f38b99d2ec9 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Wed, 15 Jan 2025 12:15:42 +0100 Subject: [PATCH 04/16] CXCDS-13558: default should be false. --- .env-cmdrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env-cmdrc b/.env-cmdrc index 3e07f3a5afd..bd6d80d2ec3 100644 --- a/.env-cmdrc +++ b/.env-cmdrc @@ -16,7 +16,7 @@ }, "cds": { "CX_CDS": "true", - "CX_SCI": "true" + "CX_SCI": "false" }, "lighthouse": { "CX_BASE_URL": "https://api.spartacus.rocks" From dfa6a767be31f60d69024155960a496d881ebc13 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Wed, 15 Jan 2025 12:16:12 +0100 Subject: [PATCH 05/16] CXCDS-13558: remove not needed code. --- integration-libs/cds/src/schematics/add-cds/schema.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/integration-libs/cds/src/schematics/add-cds/schema.json b/integration-libs/cds/src/schematics/add-cds/schema.json index 023cda762cf..529a264cdb9 100644 --- a/integration-libs/cds/src/schematics/add-cds/schema.json +++ b/integration-libs/cds/src/schematics/add-cds/schema.json @@ -47,12 +47,6 @@ "type": "string", "description": "Configuration URL for ProfileTag. (e.g. https://tag.static.stage.context.cloud.sap/config/my-config123)", "x-prompt": "[CDS] What is the ProfileTag configuration URL?" - }, - "sciEnabled": { - "type": "boolean", - "description": "CDS/ISS is integrated into the SAP Cloud Identity Service (SCI). The downstream services use different domains and URL formats. This property enables the CDS module to use these new URLs.", - "default": false, - "x-prompt": "[CDS] Do you want to enable SCI?" } } } From d6ec51a86656e6cb09f29e77e47ca62299f6b0f8 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Thu, 16 Jan 2025 10:43:24 +0100 Subject: [PATCH 06/16] CXCDS-13558: move evaluation of sciEnabled to cds-feature.module --- .../cds/src/config/default-cds-config.ts | 11 ---------- .../features/cds/cds-feature.module.ts | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/integration-libs/cds/src/config/default-cds-config.ts b/integration-libs/cds/src/config/default-cds-config.ts index 22aebefc647..fba4b6f7185 100644 --- a/integration-libs/cds/src/config/default-cds-config.ts +++ b/integration-libs/cds/src/config/default-cds-config.ts @@ -4,30 +4,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { environment } from 'projects/storefrontapp/src/environments/environment'; import { CdsConfig } from './cds-config'; export function defaultCdsConfigFactory(): CdsConfig { - const sciEnabled = environment.sciEnabled; - return { cds: { tenant: '', baseUrl: '', - endpoints: { - strategyProducts: sciEnabled - ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' - : '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, consentTemplateId: 'PROFILE', profileTag: { allowInsecureCookies: false, - sciEnabled: sciEnabled, }, }, }; diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index 02477843fc8..11229e00b2a 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -16,6 +16,7 @@ import { cdsTranslationChunksConfig, cdsTranslations, } from '@spartacus/cds/assets'; +import { environment } from '../../../../environments/environment'; /** * Only differences to the default cds config, they are merged together. @@ -23,17 +24,28 @@ import { * @see defaultCdsConfigFactory * @see CdsModule.forRoot */ + +const sciEnabled = environment.sciEnabled; + const cds1: CdsConfig = { cds: { baseSite: ['electronics-spa', 'electronics', 'electronics-standalone'], tenant: 'argotest', baseUrl: 'https://api.stage.context.cloud.sap', + endpoints: { + strategyProducts: sciEnabled + ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' + : '/strategy/${tenant}/strategies/${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', + }, profileTag: { javascriptUrl: 'https://tag.static.stage.context.cloud.sap/js/profile-tag.js', configUrl: 'https://tag.static.stage.context.cloud.sap/config/mytenant-main-default', allowInsecureCookies: true, + sciEnabled: sciEnabled, }, }, }; @@ -54,10 +66,18 @@ const cds2: CdsConfig = { ], tenant: 'A_CDS_TENANT', baseUrl: 'A_CDS_BASE_URL', + endpoints: { + strategyProducts: sciEnabled + ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' + : '/strategy/${tenant}/strategies/${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', + }, profileTag: { javascriptUrl: 'A_CDS_PROFILE_TAG_LOAD_URL', configUrl: 'A_CDS_PROFILE_TAG_CONFIG_URL', allowInsecureCookies: true, + sciEnabled: sciEnabled, }, }, }; From 300dbd76ecc068c63f621ad0f4b160592882ecd9 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Thu, 16 Jan 2025 10:55:58 +0100 Subject: [PATCH 07/16] CXCDS-13558: remove accidentally added header line. --- .../adapters/strategy/cds-merchandising-strategy.adapter.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index c99ec4fe8d7..9eb5cf88f94 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -1,5 +1,4 @@ /* - * SPDX-FileCopyrightText: 2024 SAP Spartacus team * SPDX-FileCopyrightText: 2025 SAP Spartacus team * * SPDX-License-Identifier: Apache-2.0 From 79b1166f8689cbf1026b2b43999c1ceecce48784 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Fri, 17 Jan 2025 13:14:45 +0100 Subject: [PATCH 08/16] CXCDS-13558: add switch for configurl. --- .../src/app/spartacus/features/cds/cds-feature.module.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index 11229e00b2a..0ea1b669144 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -42,8 +42,9 @@ const cds1: CdsConfig = { profileTag: { javascriptUrl: 'https://tag.static.stage.context.cloud.sap/js/profile-tag.js', - configUrl: - 'https://tag.static.stage.context.cloud.sap/config/mytenant-main-default', + configUrl: sciEnabled + ? 'https://tag.static.stage.context.cloud.sap/config/profiletag-default-config' + : 'https://tag.static.stage.context.cloud.sap/config/mytenant-main-default', allowInsecureCookies: true, sciEnabled: sciEnabled, }, @@ -75,7 +76,9 @@ const cds2: CdsConfig = { }, profileTag: { javascriptUrl: 'A_CDS_PROFILE_TAG_LOAD_URL', - configUrl: 'A_CDS_PROFILE_TAG_CONFIG_URL', + configUrl: sciEnabled + ? 'https://tag.static.stage.context.cloud.sap/config/profiletag-default-config' + : 'A_CDS_PROFILE_TAG_CONFIG_URL', allowInsecureCookies: true, sciEnabled: sciEnabled, }, From 5c48f34ea704ed8d75e594d8b5c51ff0f5fc446f Mon Sep 17 00:00:00 2001 From: Johanna Thalmann Date: Tue, 14 Jan 2025 17:42:24 +0100 Subject: [PATCH 09/16] CXEC-45758: add possibility to enable SCI for CAS. --- .env-cmdrc | 3 +- integration-libs/cds/src/cds.module.ts | 15 +- integration-libs/cds/src/config/cds-config.ts | 1 + .../cds/src/config/default-cds-config.ts | 43 ++- .../cds/src/config/profile-tag.config.ts | 1 + ...cds-merchandising-strategy.adapter.spec.ts | 323 +++++++++--------- .../cds-merchandising-strategy.adapter.ts | 32 +- .../src/profiletag/model/profile-tag.model.ts | 7 +- .../cds/src/schematics/add-cds/schema.json | 6 + .../integration-libs/cds-schematics-config.ts | 8 +- .../features/cds/cds-feature.module.ts | 36 +- .../src/environments/environment.prod.ts | 1 + .../src/environments/environment.ts | 1 + .../models/build.process.env.d.ts | 1 + .../environments/models/environment.model.ts | 1 + 15 files changed, 268 insertions(+), 211 deletions(-) diff --git a/.env-cmdrc b/.env-cmdrc index aeb0f17cde2..3e07f3a5afd 100644 --- a/.env-cmdrc +++ b/.env-cmdrc @@ -15,7 +15,8 @@ "CX_BASE_URL": "https://api.cg79x9wuu9-eccommerc1-p1-public.model-t.myhybris.cloud" }, "cds": { - "CX_CDS": "true" + "CX_CDS": "true", + "CX_SCI": "true" }, "lighthouse": { "CX_BASE_URL": "https://api.spartacus.rocks" diff --git a/integration-libs/cds/src/cds.module.ts b/integration-libs/cds/src/cds.module.ts index e0a28705772..5fe08751493 100644 --- a/integration-libs/cds/src/cds.module.ts +++ b/integration-libs/cds/src/cds.module.ts @@ -5,8 +5,16 @@ */ import { ModuleWithProviders, NgModule } from '@angular/core'; -import { provideConfigValidator, provideDefaultConfig } from '@spartacus/core'; -import { CdsConfig, cdsConfigValidator, DEFAULT_CDS_CONFIG } from './config'; +import { + provideConfigValidator, + provideDefaultConfig, + provideDefaultConfigFactory, +} from '@spartacus/core'; +import { + CdsConfig, + cdsConfigValidator, + defaultCdsConfigFactory, +} from './config'; import { MerchandisingModule } from './merchandising'; import { ProfileTagModule, @@ -15,7 +23,6 @@ import { } from './profiletag'; import { RecentSearchesModule } from './recent-searches/recent-searches.module'; import { TrendingSearchesModule } from './trending-searches/trending-searches.module'; - @NgModule({ imports: [ ProfileTagModule, @@ -30,7 +37,7 @@ export class CdsModule { return { ngModule: CdsModule, providers: [ - provideDefaultConfig(DEFAULT_CDS_CONFIG), + provideDefaultConfigFactory(defaultCdsConfigFactory), provideDefaultConfig(config), provideConfigValidator(cdsConfigValidator), ProfileTagPushEventsService, diff --git a/integration-libs/cds/src/config/cds-config.ts b/integration-libs/cds/src/config/cds-config.ts index 98db9bb90c1..004a113cfbe 100644 --- a/integration-libs/cds/src/config/cds-config.ts +++ b/integration-libs/cds/src/config/cds-config.ts @@ -23,6 +23,7 @@ export abstract class CdsConfig { endpoints?: CdsEndpoints; merchandising?: MerchandisingConfig; profileTag?: ProfileTagConfig; + sciEnabled?: boolean; }; } diff --git a/integration-libs/cds/src/config/default-cds-config.ts b/integration-libs/cds/src/config/default-cds-config.ts index 3b6e99485d7..b459a1b4169 100644 --- a/integration-libs/cds/src/config/default-cds-config.ts +++ b/integration-libs/cds/src/config/default-cds-config.ts @@ -4,23 +4,32 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { environment } from 'projects/storefrontapp/src/environments/environment'; import { CdsConfig } from './cds-config'; -export const DEFAULT_CDS_CONFIG: CdsConfig = { - cds: { - tenant: '', - baseUrl: '', - endpoints: { - strategyProducts: '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', +export function defaultCdsConfigFactory(): CdsConfig { + + const sciEnabled = environment.sciEnabled; + + return { + cds: { + tenant: '', + baseUrl: '', + endpoints: { + strategyProducts: sciEnabled + ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' + : '/strategy/${tenant}/strategies/${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', + }, + merchandising: { + defaultCarouselViewportThreshold: 80, + }, + consentTemplateId: 'PROFILE', + profileTag: { + allowInsecureCookies: false, + sciEnabled: sciEnabled, + }, }, - merchandising: { - defaultCarouselViewportThreshold: 80, - }, - consentTemplateId: 'PROFILE', - profileTag: { - allowInsecureCookies: false, - }, - }, -}; + }; +} \ No newline at end of file diff --git a/integration-libs/cds/src/config/profile-tag.config.ts b/integration-libs/cds/src/config/profile-tag.config.ts index 6ad8ef701e0..b99f9084b69 100644 --- a/integration-libs/cds/src/config/profile-tag.config.ts +++ b/integration-libs/cds/src/config/profile-tag.config.ts @@ -9,4 +9,5 @@ export interface ProfileTagConfig { configUrl?: string; allowInsecureCookies?: boolean; gtmId?: string; + sciEnabled?: boolean; } diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts index 63e62167976..35aa2a9c897 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts @@ -1,166 +1,183 @@ import { - HttpClientTestingModule, - HttpTestingController, -} from '@angular/common/http/testing'; -import { TestBed } from '@angular/core/testing'; -import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; -import { StrategyProducts } from '../../model/strategy-products.model'; -import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; -import createSpy = jasmine.createSpy; - -const STRATEGY_ID = 'test-strategy-id'; -const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; -const strategyIdObject = { strategyId: STRATEGY_ID }; - -const expectedProductsFromStrategy: StrategyProducts = { - resultCount: 1, - products: [ - { - id: 'test-product-id', - metadata: { - 'test-product-metadata-field': 'test-product-metadata-value', + HttpClientTestingModule, + HttpTestingController, + } from '@angular/common/http/testing'; + import { TestBed } from '@angular/core/testing'; + import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; + import { StrategyProducts } from '../../model/strategy-products.model'; + import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; + import createSpy = jasmine.createSpy; + import { BaseSiteService } from '@spartacus/core'; + import { of } from 'rxjs'; + + const STRATEGY_ID = 'test-strategy-id'; + const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; + const TEST_BASE_SITE = 'testBaseSite'; + + const TEST_URL_PARAMS = { + baseSite: TEST_BASE_SITE, + strategyId: STRATEGY_ID, + }; + + const expectedProductsFromStrategy: StrategyProducts = { + resultCount: 1, + products: [ + { + id: 'test-product-id', + metadata: { + 'test-product-metadata-field': 'test-product-metadata-value', + }, }, + ], + paged: { + from: 1, + size: 5, }, - ], - paged: { - from: 1, - size: 5, - }, - metadata: { - 'test-metadata-field': 'test-metadata-value', - }, -}; -const strategyRequest = { - queryParams: { - site: 'electronics-spa', - language: 'en', - pageSize: 10, - }, -}; -const strategyRequestUndefinedConsentReference = { - ...strategyRequest, - headers: { - consentReference: undefined, - }, -}; - -class MockCdsEndpointsService { - getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( - (endpoint) => endpoint - ); -} - -describe('MerchandisingStrategyAdapter', () => { - let strategyAdapter: CdsMerchandisingStrategyAdapter; - let httpMock: HttpTestingController; - let cdsEndpointsService: CdsEndpointsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: CdsEndpointsService, - useClass: MockCdsEndpointsService, - }, - CdsMerchandisingStrategyAdapter, - ], + metadata: { + 'test-metadata-field': 'test-metadata-value', + }, + }; + const strategyRequest = { + queryParams: { + site: 'electronics-spa', + language: 'en', + pageSize: 10, + }, + }; + const strategyRequestUndefinedConsentReference = { + ...strategyRequest, + headers: { + consentReference: undefined, + }, + }; + + class MockCdsEndpointsService { + getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( + (endpoint: string) => endpoint + ); + } + + class MockBaseSiteService { + getActive = createSpy('MockBaseSiteService.getActive').and.callFake(() => + of(TEST_BASE_SITE) + ); + } + + describe('MerchandisingStrategyAdapter', () => { + let strategyAdapter: CdsMerchandisingStrategyAdapter; + let httpMock: HttpTestingController; + let cdsEndpointsService: CdsEndpointsService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + { + provide: CdsEndpointsService, + useClass: MockCdsEndpointsService, + }, + { + provide: BaseSiteService, + useClass: MockBaseSiteService, + }, + CdsMerchandisingStrategyAdapter, + ], + }); + + httpMock = TestBed.inject(HttpTestingController); + strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); + cdsEndpointsService = TestBed.inject(CdsEndpointsService); }); - - httpMock = TestBed.inject(HttpTestingController); - strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); - cdsEndpointsService = TestBed.inject(CdsEndpointsService); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should be created', () => { - expect(strategyAdapter).toBeTruthy(); - }); - - describe('load products for strategy', () => { - it('should load products for the given strategy id', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); + + afterEach(() => { + httpMock.verify(); + }); + + it('should be created', () => { + expect(strategyAdapter).toBeTruthy(); + }); + + describe('load products for strategy', () => { + it('should load products for the given strategy id', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); + }); + + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); + expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); - expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); - }); - - it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID, strategyRequest) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); + + it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID, strategyRequest) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); + }); + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - strategyIdObject, - strategyRequest.queryParams - ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); - }); - - it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { - strategyAdapter - .loadProductsForStrategy( - STRATEGY_ID, - strategyRequestUndefinedConsentReference - ) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); + + it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { + strategyAdapter + .loadProductsForStrategy( + STRATEGY_ID, + strategyRequestUndefinedConsentReference + ) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); + }); + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + + expect( + mockStrategyProductsRequest.request.headers.get('consent-reference') + ).toBeFalsy(); + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - - expect( - mockStrategyProductsRequest.request.headers.get('consent-reference') - ).toBeFalsy(); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - strategyIdObject, - strategyRequest.queryParams - ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - }); -}); + }); \ No newline at end of file diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index d7f547cc788..53d0e444792 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -1,16 +1,17 @@ /* - * SPDX-FileCopyrightText: 2025 SAP Spartacus team + * SPDX-FileCopyrightText: 2024 SAP Spartacus team * * SPDX-License-Identifier: Apache-2.0 */ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable, switchMap, take } from 'rxjs'; import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; import { MerchandisingStrategyAdapter } from '../../connectors/strategy/merchandising-strategy.adapter'; import { StrategyProducts } from '../../model/strategy-products.model'; import { StrategyRequest } from './../../../cds-models/cds-strategy-request.model'; +import { BaseSiteService } from '@spartacus/core'; const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; @@ -20,6 +21,7 @@ export class CdsMerchandisingStrategyAdapter { constructor( private cdsEndpointsService: CdsEndpointsService, + private baseSiteService: BaseSiteService, protected http: HttpClient ) {} @@ -34,15 +36,21 @@ export class CdsMerchandisingStrategyAdapter strategyRequest.headers.consentReference ); } - return this.http.get( - this.cdsEndpointsService.getUrl( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - { - strategyId, - }, - strategyRequest.queryParams - ), - { headers } + return this.baseSiteService.getActive().pipe( + take(1), + switchMap((baseSite) => + this.http.get( + this.cdsEndpointsService.getUrl( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + { + baseSite, + strategyId, + }, + strategyRequest.queryParams + ), + { headers } + ) + ) ); } -} +} \ No newline at end of file diff --git a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts index d5433b4635b..908ab041b3f 100644 --- a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts +++ b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts @@ -22,6 +22,7 @@ export interface ProfileTagJsConfig { configUrl?: string; allowInsecureCookies?: boolean; gtmId?: string; + sciEnabled?: boolean; } export interface ConsentReferenceEvent extends CustomEvent { @@ -53,15 +54,15 @@ export interface ProfileTagPushEvent { export class NavigatedPushEvent implements ProfileTagPushEvent { name = 'Navigated'; data: any; - constructor(data?) { + constructor(data?: any) { this.data = data; } } export class ConsentChangedPushEvent implements ProfileTagPushEvent { name = 'ConsentChanged'; - data: { granted: boolean } = { granted: undefined }; - constructor(granted: boolean) { + data: { granted?: boolean } = { granted: undefined }; + constructor(granted: boolean) { this.data.granted = granted; } } diff --git a/integration-libs/cds/src/schematics/add-cds/schema.json b/integration-libs/cds/src/schematics/add-cds/schema.json index 529a264cdb9..023cda762cf 100644 --- a/integration-libs/cds/src/schematics/add-cds/schema.json +++ b/integration-libs/cds/src/schematics/add-cds/schema.json @@ -47,6 +47,12 @@ "type": "string", "description": "Configuration URL for ProfileTag. (e.g. https://tag.static.stage.context.cloud.sap/config/my-config123)", "x-prompt": "[CDS] What is the ProfileTag configuration URL?" + }, + "sciEnabled": { + "type": "boolean", + "description": "CDS/ISS is integrated into the SAP Cloud Identity Service (SCI). The downstream services use different domains and URL formats. This property enables the CDS module to use these new URLs.", + "default": false, + "x-prompt": "[CDS] Do you want to enable SCI?" } } } diff --git a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts index 35a1203697e..502d2a9e3a2 100644 --- a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts +++ b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts @@ -22,6 +22,7 @@ export interface SpartacusCdsOptions extends LibraryOptions { baseUrl?: string; profileTagLoadUrl?: string; profileTagConfigUrl?: string; + sciEnabled?: boolean; } export const CDS_FOLDER_NAME = 'cds'; @@ -69,7 +70,11 @@ function buildCdsConfig( tenant: '${options.tenant || 'TENANT_PLACEHOLDER'}', baseUrl: '${options.baseUrl || 'BASE_URL_PLACEHOLDER'}', endpoints: { - strategyProducts: '/strategy/\${tenant}/strategies/\${strategyId}/products', + strategyProducts: '${options.sciEnabled || false }' + ? '/strategy/v1/sites/\${baseSite}/strategies/\${strategyId}/products' + : '/strategy/\${tenant}/strategies/\${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/\${cdsSiteId}/trendingSearches', }, merchandising: { defaultCarouselViewportThreshold: 80, @@ -100,6 +105,7 @@ function buildCdsConfig( 'PROFILE_TAG_CONFIG_URL_PLACEHOLDER' }', allowInsecureCookies: true, + sciEnabled: '${options.sciEnabled || false}', }, }, }`, diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index c073c636b47..715030faccf 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -17,19 +17,17 @@ import { cdsTranslations, } from '@spartacus/cds/assets'; +/** + * Only differences to the default cds config, they are merged together. + * + * @see defaultCdsConfigFactory + * @see CdsModule.forRoot + */ const cds1: CdsConfig = { cds: { baseSite: ['electronics-spa', 'electronics', 'electronics-standalone'], tenant: 'argotest', baseUrl: 'https://api.stage.context.cloud.sap', - endpoints: { - strategyProducts: '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', - }, - merchandising: { - defaultCarouselViewportThreshold: 80, - }, profileTag: { javascriptUrl: 'https://tag.static.stage.context.cloud.sap/js/profile-tag.js', @@ -40,7 +38,13 @@ const cds1: CdsConfig = { }, }; -const cds2 = { +/** + * Only differences to the default cds config, they are merged together. + * + * @see defaultCdsConfigFactory + * @see CdsModule.forRoot + */ +const cds2: CdsConfig = { cds: { baseSite: [ 'apparel-de', @@ -50,14 +54,6 @@ const cds2 = { ], tenant: 'A_CDS_TENANT', baseUrl: 'A_CDS_BASE_URL', - endpoints: { - strategyProducts: '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', - }, - merchandising: { - defaultCarouselViewportThreshold: 80, - }, profileTag: { javascriptUrl: 'A_CDS_PROFILE_TAG_LOAD_URL', configUrl: 'A_CDS_PROFILE_TAG_CONFIG_URL', @@ -66,9 +62,9 @@ const cds2 = { }, }; -const cdsConfigArray = [cds1, cds2]; +function cdsConfigFactory(windowRef: WindowRef): CdsConfig { + const cdsConfigArray = [cds1, cds2]; -const cdsConfig = (windowRef: WindowRef): CdsConfig => { if (!windowRef.isBrowser()) { return cds1; } @@ -90,7 +86,7 @@ const cdsConfig = (windowRef: WindowRef): CdsConfig => { fallbackLang: 'en', }, }), - provideConfigFactory(cdsConfig, [WindowRef]), + provideConfigFactory(cdsConfigFactory, [WindowRef]), ], }) export class CdsFeatureModule {} diff --git a/projects/storefrontapp/src/environments/environment.prod.ts b/projects/storefrontapp/src/environments/environment.prod.ts index 6037371c0e8..5e273ae1df7 100644 --- a/projects/storefrontapp/src/environments/environment.prod.ts +++ b/projects/storefrontapp/src/environments/environment.prod.ts @@ -11,6 +11,7 @@ export const environment: Environment = { occBaseUrl: buildProcess.env.CX_BASE_URL, occApiPrefix: '/occ/v2/', cds: buildProcess.env.CX_CDS, + sciEnabled: buildProcess.env.CX_SCI, b2b: buildProcess.env.CX_B2B, cdc: buildProcess.env.CX_CDC, cdp: buildProcess.env.CX_CDP, diff --git a/projects/storefrontapp/src/environments/environment.ts b/projects/storefrontapp/src/environments/environment.ts index be90972448d..928c00350e2 100644 --- a/projects/storefrontapp/src/environments/environment.ts +++ b/projects/storefrontapp/src/environments/environment.ts @@ -24,6 +24,7 @@ export const environment: Environment = { occBaseUrl: buildProcess.env.CX_BASE_URL, occApiPrefix: '/occ/v2/', cds: buildProcess.env.CX_CDS ?? false, + sciEnabled: buildProcess.env.CX_SCI ?? false, b2b: buildProcess.env.CX_B2B ?? false, cdc: buildProcess.env.CX_CDC ?? false, cdp: buildProcess.env.CX_CDP ?? false, diff --git a/projects/storefrontapp/src/environments/models/build.process.env.d.ts b/projects/storefrontapp/src/environments/models/build.process.env.d.ts index 344f31b0ffa..f7dee503fd7 100644 --- a/projects/storefrontapp/src/environments/models/build.process.env.d.ts +++ b/projects/storefrontapp/src/environments/models/build.process.env.d.ts @@ -13,6 +13,7 @@ interface BuildProcess { interface Env { CX_BASE_URL: string; CX_CDS: boolean; + CX_SCI: boolean; CX_CDC: boolean; CX_CDP: boolean; CX_B2B: boolean; diff --git a/projects/storefrontapp/src/environments/models/environment.model.ts b/projects/storefrontapp/src/environments/models/environment.model.ts index bfd0088e6d8..6d603752425 100644 --- a/projects/storefrontapp/src/environments/models/environment.model.ts +++ b/projects/storefrontapp/src/environments/models/environment.model.ts @@ -10,6 +10,7 @@ export interface Environment { occApiPrefix: string; b2b: boolean; cds: boolean; + sciEnabled: boolean; cdc: boolean; cdp: boolean; cpq: boolean; From 8e3bc5e14895a59e00522d1afa3fb07f6f8eb816 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Wed, 15 Jan 2025 11:43:57 +0100 Subject: [PATCH 10/16] CXCDS-13558: add possibility to enable SCI for CAS, fix tests and style. --- .../cds/src/config/default-cds-config.ts | 5 +- ...cds-merchandising-strategy.adapter.spec.ts | 340 +++++++++--------- .../cds-merchandising-strategy.adapter.ts | 2 +- .../src/profiletag/model/profile-tag.model.ts | 2 +- .../services/profiletag-event.service.spec.ts | 1 + .../recent-searches.component.spec.ts | 2 +- .../add-cds/__snapshots__/index_spec.ts.snap | 6 - .../integration-libs/cds-schematics-config.ts | 9 - .../features/cds/cds-feature.module.ts | 2 +- 9 files changed, 177 insertions(+), 192 deletions(-) diff --git a/integration-libs/cds/src/config/default-cds-config.ts b/integration-libs/cds/src/config/default-cds-config.ts index b459a1b4169..22aebefc647 100644 --- a/integration-libs/cds/src/config/default-cds-config.ts +++ b/integration-libs/cds/src/config/default-cds-config.ts @@ -8,9 +8,8 @@ import { environment } from 'projects/storefrontapp/src/environments/environment import { CdsConfig } from './cds-config'; export function defaultCdsConfigFactory(): CdsConfig { - const sciEnabled = environment.sciEnabled; - + return { cds: { tenant: '', @@ -32,4 +31,4 @@ export function defaultCdsConfigFactory(): CdsConfig { }, }, }; -} \ No newline at end of file +} diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts index 35aa2a9c897..52e28143651 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.spec.ts @@ -1,183 +1,183 @@ import { - HttpClientTestingModule, - HttpTestingController, - } from '@angular/common/http/testing'; - import { TestBed } from '@angular/core/testing'; - import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; - import { StrategyProducts } from '../../model/strategy-products.model'; - import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; - import createSpy = jasmine.createSpy; - import { BaseSiteService } from '@spartacus/core'; - import { of } from 'rxjs'; - - const STRATEGY_ID = 'test-strategy-id'; - const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; - const TEST_BASE_SITE = 'testBaseSite'; - - const TEST_URL_PARAMS = { - baseSite: TEST_BASE_SITE, - strategyId: STRATEGY_ID, - }; - - const expectedProductsFromStrategy: StrategyProducts = { - resultCount: 1, - products: [ - { - id: 'test-product-id', - metadata: { - 'test-product-metadata-field': 'test-product-metadata-value', - }, + HttpClientTestingModule, + HttpTestingController, +} from '@angular/common/http/testing'; +import { TestBed } from '@angular/core/testing'; +import { CdsEndpointsService } from '../../../services/cds-endpoints.service'; +import { StrategyProducts } from '../../model/strategy-products.model'; +import { CdsMerchandisingStrategyAdapter } from './cds-merchandising-strategy.adapter'; +import createSpy = jasmine.createSpy; +import { BaseSiteService } from '@spartacus/core'; +import { of } from 'rxjs'; + +const STRATEGY_ID = 'test-strategy-id'; +const STRATEGY_PRODUCTS_ENDPOINT_KEY = 'strategyProducts'; +const TEST_BASE_SITE = 'testBaseSite'; + +const TEST_URL_PARAMS = { + baseSite: TEST_BASE_SITE, + strategyId: STRATEGY_ID, +}; + +const expectedProductsFromStrategy: StrategyProducts = { + resultCount: 1, + products: [ + { + id: 'test-product-id', + metadata: { + 'test-product-metadata-field': 'test-product-metadata-value', }, - ], - paged: { - from: 1, - size: 5, - }, - metadata: { - 'test-metadata-field': 'test-metadata-value', - }, - }; - const strategyRequest = { - queryParams: { - site: 'electronics-spa', - language: 'en', - pageSize: 10, }, - }; - const strategyRequestUndefinedConsentReference = { - ...strategyRequest, - headers: { - consentReference: undefined, - }, - }; - - class MockCdsEndpointsService { - getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( - (endpoint: string) => endpoint - ); - } - - class MockBaseSiteService { - getActive = createSpy('MockBaseSiteService.getActive').and.callFake(() => - of(TEST_BASE_SITE) - ); - } - - describe('MerchandisingStrategyAdapter', () => { - let strategyAdapter: CdsMerchandisingStrategyAdapter; - let httpMock: HttpTestingController; - let cdsEndpointsService: CdsEndpointsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: CdsEndpointsService, - useClass: MockCdsEndpointsService, - }, - { - provide: BaseSiteService, - useClass: MockBaseSiteService, - }, - CdsMerchandisingStrategyAdapter, - ], - }); - - httpMock = TestBed.inject(HttpTestingController); - strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); - cdsEndpointsService = TestBed.inject(CdsEndpointsService); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should be created', () => { - expect(strategyAdapter).toBeTruthy(); + ], + paged: { + from: 1, + size: 5, + }, + metadata: { + 'test-metadata-field': 'test-metadata-value', + }, +}; +const strategyRequest = { + queryParams: { + site: 'electronics-spa', + language: 'en', + pageSize: 10, + }, +}; +const strategyRequestUndefinedConsentReference = { + ...strategyRequest, + headers: { + consentReference: undefined, + }, +}; + +class MockCdsEndpointsService { + getUrl = createSpy('MockCdsEndpointsService.getUrl').and.callFake( + (endpoint: string) => endpoint + ); +} + +class MockBaseSiteService { + getActive = createSpy('MockBaseSiteService.getActive').and.callFake(() => + of(TEST_BASE_SITE) + ); +} + +describe('MerchandisingStrategyAdapter', () => { + let strategyAdapter: CdsMerchandisingStrategyAdapter; + let httpMock: HttpTestingController; + let cdsEndpointsService: CdsEndpointsService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + { + provide: CdsEndpointsService, + useClass: MockCdsEndpointsService, + }, + { + provide: BaseSiteService, + useClass: MockBaseSiteService, + }, + CdsMerchandisingStrategyAdapter, + ], }); - - describe('load products for strategy', () => { - it('should load products for the given strategy id', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); - }); - - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + + httpMock = TestBed.inject(HttpTestingController); + strategyAdapter = TestBed.inject(CdsMerchandisingStrategyAdapter); + cdsEndpointsService = TestBed.inject(CdsEndpointsService); + }); + + afterEach(() => { + httpMock.verify(); + }); + + it('should be created', () => { + expect(strategyAdapter).toBeTruthy(); + }); + + describe('load products for strategy', () => { + it('should load products for the given strategy id', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); }); - expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); - expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); + + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY + ); }); - - it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { - strategyAdapter - .loadProductsForStrategy(STRATEGY_ID, strategyRequest) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); - }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + expect(mockStrategyProductsRequest.cancelled).toBeFalsy(); + expect(mockStrategyProductsRequest.request.responseType).toEqual('json'); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); + }); + + it('should load the products for a given strategy id, and the request URL should include the parameters in the StrategyRequest', () => { + strategyAdapter + .loadProductsForStrategy(STRATEGY_ID, strategyRequest) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); }); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - TEST_URL_PARAMS, - strategyRequest.queryParams + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - - it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { - strategyAdapter - .loadProductsForStrategy( - STRATEGY_ID, - strategyRequestUndefinedConsentReference - ) - .subscribe((products) => { - expect(products).toEqual(expectedProductsFromStrategy); - }); - const mockStrategyProductsRequest = httpMock.expectOne((request) => { - /* - * Our mock CdsEndpointsService returns the given endpoint key as the url, - * so the adapter will make the http request with the endpoint key rather than a url - */ - return ( - request.method === 'GET' && - request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY - ); + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams + ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); + }); + + it('should load the products for a given strategy id, the request URL should include the parameters in the StrategyRequest, and no HTTP header for consent-reference', () => { + strategyAdapter + .loadProductsForStrategy( + STRATEGY_ID, + strategyRequestUndefinedConsentReference + ) + .subscribe((products) => { + expect(products).toEqual(expectedProductsFromStrategy); }); - - expect( - mockStrategyProductsRequest.request.headers.get('consent-reference') - ).toBeFalsy(); - - expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( - STRATEGY_PRODUCTS_ENDPOINT_KEY, - TEST_URL_PARAMS, - strategyRequest.queryParams + const mockStrategyProductsRequest = httpMock.expectOne((request) => { + /* + * Our mock CdsEndpointsService returns the given endpoint key as the url, + * so the adapter will make the http request with the endpoint key rather than a url + */ + return ( + request.method === 'GET' && + request.url === STRATEGY_PRODUCTS_ENDPOINT_KEY ); - - mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); + + expect( + mockStrategyProductsRequest.request.headers.get('consent-reference') + ).toBeFalsy(); + + expect(cdsEndpointsService.getUrl).toHaveBeenCalledWith( + STRATEGY_PRODUCTS_ENDPOINT_KEY, + TEST_URL_PARAMS, + strategyRequest.queryParams + ); + + mockStrategyProductsRequest.flush(expectedProductsFromStrategy); }); - }); \ No newline at end of file + }); +}); diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index 53d0e444792..957e7d1f8ad 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -53,4 +53,4 @@ export class CdsMerchandisingStrategyAdapter ) ); } -} \ No newline at end of file +} diff --git a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts index 908ab041b3f..fee2e205674 100644 --- a/integration-libs/cds/src/profiletag/model/profile-tag.model.ts +++ b/integration-libs/cds/src/profiletag/model/profile-tag.model.ts @@ -62,7 +62,7 @@ export class NavigatedPushEvent implements ProfileTagPushEvent { export class ConsentChangedPushEvent implements ProfileTagPushEvent { name = 'ConsentChanged'; data: { granted?: boolean } = { granted: undefined }; - constructor(granted: boolean) { + constructor(granted: boolean) { this.data.granted = granted; } } diff --git a/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts b/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts index 8321bb79a6e..def97822e89 100644 --- a/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts +++ b/integration-libs/cds/src/profiletag/services/profiletag-event.service.spec.ts @@ -26,6 +26,7 @@ const mockCDSConfig: CdsConfig = { configUrl: 'https:tag.static.us.context.cloud.sap', allowInsecureCookies: false, gtmId: 'test-id-1234567', + sciEnabled: false, }, }, }; diff --git a/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts b/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts index 79fd8b336dd..a190fbcbc2a 100644 --- a/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts +++ b/integration-libs/cds/src/recent-searches/recent-searches.component.spec.ts @@ -144,6 +144,6 @@ describe('RecentSearchesComponent', () => { expect(() => { component.shareEvent(ev); - }).toThrowError(); + }).toThrow(); }); }); diff --git a/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap b/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap index 3e158a7be46..c0513c71843 100644 --- a/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap +++ b/integration-libs/cds/src/schematics/add-cds/__snapshots__/index_spec.ts.snap @@ -21,9 +21,6 @@ import { I18nConfig, provideConfig } from "@spartacus/core"; cds: { tenant: 'my-tenant', baseUrl: 'my-base-url.com', - endpoints: { - strategyProducts: '/strategy/\${tenant}/strategies/\${strategyId}/products', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, @@ -67,9 +64,6 @@ import { I18nConfig, provideConfig } from "@spartacus/core"; cds: { tenant: 'my-tenant', baseUrl: 'my-base-url.com', - endpoints: { - strategyProducts: '/strategy/\${tenant}/strategies/\${strategyId}/products', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, diff --git a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts index 502d2a9e3a2..a67efe10df0 100644 --- a/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts +++ b/projects/schematics/src/shared/lib-configs/integration-libs/cds-schematics-config.ts @@ -22,7 +22,6 @@ export interface SpartacusCdsOptions extends LibraryOptions { baseUrl?: string; profileTagLoadUrl?: string; profileTagConfigUrl?: string; - sciEnabled?: boolean; } export const CDS_FOLDER_NAME = 'cds'; @@ -69,13 +68,6 @@ function buildCdsConfig( cds: { tenant: '${options.tenant || 'TENANT_PLACEHOLDER'}', baseUrl: '${options.baseUrl || 'BASE_URL_PLACEHOLDER'}', - endpoints: { - strategyProducts: '${options.sciEnabled || false }' - ? '/strategy/v1/sites/\${baseSite}/strategies/\${strategyId}/products' - : '/strategy/\${tenant}/strategies/\${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/\${cdsSiteId}/trendingSearches', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, @@ -105,7 +97,6 @@ function buildCdsConfig( 'PROFILE_TAG_CONFIG_URL_PLACEHOLDER' }', allowInsecureCookies: true, - sciEnabled: '${options.sciEnabled || false}', }, }, }`, diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index 715030faccf..02477843fc8 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -74,7 +74,7 @@ function cdsConfigFactory(windowRef: WindowRef): CdsConfig { ); }); return cds ?? cds1; -}; +} @NgModule({ imports: [CdsModule.forRoot()], From 0fbe4ea3e4937246fdb68d8d680231bba4291855 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Wed, 15 Jan 2025 12:15:42 +0100 Subject: [PATCH 11/16] CXCDS-13558: default should be false. --- .env-cmdrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env-cmdrc b/.env-cmdrc index 3e07f3a5afd..bd6d80d2ec3 100644 --- a/.env-cmdrc +++ b/.env-cmdrc @@ -16,7 +16,7 @@ }, "cds": { "CX_CDS": "true", - "CX_SCI": "true" + "CX_SCI": "false" }, "lighthouse": { "CX_BASE_URL": "https://api.spartacus.rocks" From 62f76068a2f21ef7602304e0b0f5828b71e2516c Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Wed, 15 Jan 2025 12:16:12 +0100 Subject: [PATCH 12/16] CXCDS-13558: remove not needed code. --- integration-libs/cds/src/schematics/add-cds/schema.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/integration-libs/cds/src/schematics/add-cds/schema.json b/integration-libs/cds/src/schematics/add-cds/schema.json index 023cda762cf..529a264cdb9 100644 --- a/integration-libs/cds/src/schematics/add-cds/schema.json +++ b/integration-libs/cds/src/schematics/add-cds/schema.json @@ -47,12 +47,6 @@ "type": "string", "description": "Configuration URL for ProfileTag. (e.g. https://tag.static.stage.context.cloud.sap/config/my-config123)", "x-prompt": "[CDS] What is the ProfileTag configuration URL?" - }, - "sciEnabled": { - "type": "boolean", - "description": "CDS/ISS is integrated into the SAP Cloud Identity Service (SCI). The downstream services use different domains and URL formats. This property enables the CDS module to use these new URLs.", - "default": false, - "x-prompt": "[CDS] Do you want to enable SCI?" } } } From e1acbe9de41dd48ff5f74c54a6f801f118c8fcb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 Jan 2025 11:11:13 +0000 Subject: [PATCH 13/16] Add license header --- .../adapters/strategy/cds-merchandising-strategy.adapter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index 957e7d1f8ad..c99ec4fe8d7 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2024 SAP Spartacus team + * SPDX-FileCopyrightText: 2025 SAP Spartacus team * * SPDX-License-Identifier: Apache-2.0 */ From c637b6f388d37626c572ae1dad8706a59982a779 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Thu, 16 Jan 2025 10:43:24 +0100 Subject: [PATCH 14/16] CXCDS-13558: move evaluation of sciEnabled to cds-feature.module --- .../cds/src/config/default-cds-config.ts | 11 ---------- .../features/cds/cds-feature.module.ts | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/integration-libs/cds/src/config/default-cds-config.ts b/integration-libs/cds/src/config/default-cds-config.ts index 22aebefc647..fba4b6f7185 100644 --- a/integration-libs/cds/src/config/default-cds-config.ts +++ b/integration-libs/cds/src/config/default-cds-config.ts @@ -4,30 +4,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { environment } from 'projects/storefrontapp/src/environments/environment'; import { CdsConfig } from './cds-config'; export function defaultCdsConfigFactory(): CdsConfig { - const sciEnabled = environment.sciEnabled; - return { cds: { tenant: '', baseUrl: '', - endpoints: { - strategyProducts: sciEnabled - ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' - : '/strategy/${tenant}/strategies/${strategyId}/products', - searchIntelligence: - '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', - }, merchandising: { defaultCarouselViewportThreshold: 80, }, consentTemplateId: 'PROFILE', profileTag: { allowInsecureCookies: false, - sciEnabled: sciEnabled, }, }, }; diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index 02477843fc8..11229e00b2a 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -16,6 +16,7 @@ import { cdsTranslationChunksConfig, cdsTranslations, } from '@spartacus/cds/assets'; +import { environment } from '../../../../environments/environment'; /** * Only differences to the default cds config, they are merged together. @@ -23,17 +24,28 @@ import { * @see defaultCdsConfigFactory * @see CdsModule.forRoot */ + +const sciEnabled = environment.sciEnabled; + const cds1: CdsConfig = { cds: { baseSite: ['electronics-spa', 'electronics', 'electronics-standalone'], tenant: 'argotest', baseUrl: 'https://api.stage.context.cloud.sap', + endpoints: { + strategyProducts: sciEnabled + ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' + : '/strategy/${tenant}/strategies/${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', + }, profileTag: { javascriptUrl: 'https://tag.static.stage.context.cloud.sap/js/profile-tag.js', configUrl: 'https://tag.static.stage.context.cloud.sap/config/mytenant-main-default', allowInsecureCookies: true, + sciEnabled: sciEnabled, }, }, }; @@ -54,10 +66,18 @@ const cds2: CdsConfig = { ], tenant: 'A_CDS_TENANT', baseUrl: 'A_CDS_BASE_URL', + endpoints: { + strategyProducts: sciEnabled + ? '/strategy/v1/sites/${baseSite}/strategies/${strategyId}/products' + : '/strategy/${tenant}/strategies/${strategyId}/products', + searchIntelligence: + '/search-intelligence/v1/sites/${cdsSiteId}/trendingSearches', + }, profileTag: { javascriptUrl: 'A_CDS_PROFILE_TAG_LOAD_URL', configUrl: 'A_CDS_PROFILE_TAG_CONFIG_URL', allowInsecureCookies: true, + sciEnabled: sciEnabled, }, }, }; From 4356428cb67c48532db3a6a2f80e7dc400019696 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Thu, 16 Jan 2025 10:55:58 +0100 Subject: [PATCH 15/16] CXCDS-13558: remove accidentally added header line. --- .../adapters/strategy/cds-merchandising-strategy.adapter.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts index c99ec4fe8d7..9eb5cf88f94 100644 --- a/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts +++ b/integration-libs/cds/src/merchandising/adapters/strategy/cds-merchandising-strategy.adapter.ts @@ -1,5 +1,4 @@ /* - * SPDX-FileCopyrightText: 2024 SAP Spartacus team * SPDX-FileCopyrightText: 2025 SAP Spartacus team * * SPDX-License-Identifier: Apache-2.0 From 8f5c54001d84c1153c26917bc3d4a8147384ba85 Mon Sep 17 00:00:00 2001 From: johannathalmann-SAP Date: Fri, 17 Jan 2025 13:14:45 +0100 Subject: [PATCH 16/16] CXCDS-13558: add switch for configurl. --- .../src/app/spartacus/features/cds/cds-feature.module.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts index 11229e00b2a..0ea1b669144 100644 --- a/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts +++ b/projects/storefrontapp/src/app/spartacus/features/cds/cds-feature.module.ts @@ -42,8 +42,9 @@ const cds1: CdsConfig = { profileTag: { javascriptUrl: 'https://tag.static.stage.context.cloud.sap/js/profile-tag.js', - configUrl: - 'https://tag.static.stage.context.cloud.sap/config/mytenant-main-default', + configUrl: sciEnabled + ? 'https://tag.static.stage.context.cloud.sap/config/profiletag-default-config' + : 'https://tag.static.stage.context.cloud.sap/config/mytenant-main-default', allowInsecureCookies: true, sciEnabled: sciEnabled, }, @@ -75,7 +76,9 @@ const cds2: CdsConfig = { }, profileTag: { javascriptUrl: 'A_CDS_PROFILE_TAG_LOAD_URL', - configUrl: 'A_CDS_PROFILE_TAG_CONFIG_URL', + configUrl: sciEnabled + ? 'https://tag.static.stage.context.cloud.sap/config/profiletag-default-config' + : 'A_CDS_PROFILE_TAG_CONFIG_URL', allowInsecureCookies: true, sciEnabled: sciEnabled, },