Skip to content

Commit

Permalink
fix: added exceptionKey handling
Browse files Browse the repository at this point in the history
  • Loading branch information
HenryT-CG committed Mar 2, 2024
1 parent eaae683 commit 4c7a7a1
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 116 deletions.
9 changes: 9 additions & 0 deletions src/app/product-store/app-search/app-search.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,16 @@
</ocx-search-header>

<ocx-page-content>
<div *ngIf="exceptionKey" id="app_search_criteria_error" class="card px-3 align-items-center">
<p-message
id="app_search_criteria_error_message"
severity="error"
styleClass="p-2"
[text]="exceptionKey | translate"
></p-message>
</div>
<p-dataView
*ngIf="!exceptionKey"
id="product_search_dataview"
[value]="(apps$ | async) ?? []"
[paginator]="true"
Expand Down
5 changes: 2 additions & 3 deletions src/app/product-store/app-search/app-search.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,8 @@ describe('AppSearchComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(AppSearchComponent)
component = fixture.componentInstance
fixture.detectChanges()
apiMfeServiceSpy.searchMicrofrontends.and.returnValue(of({} as MicrofrontendPageResult))
apiMsServiceSpy.searchMicroservice.and.returnValue(of({} as MicroservicePageResult))
// fixture.detectChanges()
fixture.componentInstance.ngOnInit() // solved ExpressionChangedAfterItHasBeenCheckedError
})

afterEach(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/app/product-store/app-search/app-search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export type ChangeMode = 'VIEW' | 'CREATE' | 'EDIT' | 'COPY'
export class AppSearchComponent implements OnInit, OnDestroy {
private readonly destroy$ = new Subject()
private readonly debug = true // to be removed after finalization
public exceptionKey = ''
public exceptionKey: string | undefined
public loading = true
public actions$: Observable<Action[]> | undefined

Expand Down Expand Up @@ -180,7 +180,7 @@ export class AppSearchComponent implements OnInit, OnDestroy {

public searchApps(): void {
this.searchInProgress = true
this.exceptionKey = ''
this.exceptionKey = undefined
switch (this.appSearchCriteriaGroup.controls['appType'].value) {
case 'ALL':
this.apps$ = combineLatest([this.searchMfes(), this.searchMss()]).pipe(
Expand Down
201 changes: 100 additions & 101 deletions src/app/product-store/product-search/product-search.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,120 +28,119 @@
</ocx-search-header>

<ocx-page-content>
<div *ngIf="!products$" id="product_search_criteria_error" class="card px-3 align-items-center">
<div *ngIf="exceptionKey" id="product_search_criteria_error" class="card px-3 align-items-center">
<p-message
id="product_search_criteria_error_message"
severity="error"
styleClass="p-2"
[text]="'ACTIONS.SEARCH.PRODUCT.NOT_EXISTS' | translate"
[text]="exceptionKey | translate"
></p-message>
</div>
<ng-container *ngIf="products$ | async as products">
<p-dataView
id="product_search_dataview"
[value]="products.stream ? products.stream : []"
[paginator]="true"
[alwaysShowPaginator]="false"
[rowsPerPageOptions]="[10, 20, 50]"
[rows]="viewMode === 'grid' ? 12 : 10"
[layout]="viewMode"
[emptyMessage]="'ACTIONS.SEARCH.NOT_FOUND' | translate"
filterBy="name,displayName,classification"
[sortField]="sortField"
[sortOrder]="sortOrder"
>
<ng-template pTemplate="header">
<ocx-data-view-controls
id="product_search_dataview_controls"
[enableFiltering]="true"
[enableSorting]="true"
[supportedViews]="['grid', 'list']"
[initialViewMode]="viewMode"
[sortingOptions]="[
{ label: 'PRODUCT.NAME' | translate, value: 'name' },
{ label: 'PRODUCT.DISPLAY_NAME' | translate, value: 'displayName' }
]"
[defaultSortOption]="sortField"
[defaultSortDirection]="sortOrder === 1"
(dataViewChange)="onLayoutChange($event)"
(filterChange)="onFilterChange($event)"
[filterColumns]="[
'PRODUCT.NAME' | translate,
'PRODUCT.DISPLAY_NAME' | translate,
'PRODUCT.CLASSIFICATIONS' | translate
]"
(sortChange)="onSortChange($event)"
(sortDirectionChange)="onSortDirChange($event)"
[translations]="dataViewControlsTranslations"
>
</ocx-data-view-controls
></ng-template>
<ng-template let-product let-idx="rowIndex" pTemplate="listItem">
<div
[id]="'product_search_data_list_' + idx"
class="col-12 grid grid-nogutter align-items-center row-gap-1 listview-row p-1 hover:bg-gray-200 cursor-pointer"
[routerLink]="['./', product.name]"
>
<div class="col-12 md:col-2 lg:col-2 xl:col-2 text-center">
<div class="flex flex-column justify-content-center align-items-center gap-1 md:gap-2 h-full">
<app-image-container
[id]="'product_search_data_list_' + idx + '_image'"
[imageUrl]="getImageUrl(product)"
[title]="'LOGO.TOOLTIPS.' + (product.imageUrl ? 'IMAGE' : 'PLACEHOLDER') | translate"
[small]="true"
></app-image-container>
</div>
<p-dataView
*ngIf="!exceptionKey"
id="product_search_dataview"
[value]="(products$ | async)?.stream!"
[paginator]="true"
[alwaysShowPaginator]="false"
[rowsPerPageOptions]="[10, 20, 50]"
[rows]="viewMode === 'grid' ? 12 : 10"
[layout]="viewMode"
[emptyMessage]="'ACTIONS.SEARCH.NOT_FOUND' | translate"
filterBy="name,displayName,classification"
[sortField]="sortField"
[sortOrder]="sortOrder"
>
<ng-template pTemplate="header">
<ocx-data-view-controls
id="product_search_dataview_controls"
[enableFiltering]="true"
[enableSorting]="true"
[supportedViews]="['grid', 'list']"
[initialViewMode]="viewMode"
[sortingOptions]="[
{ label: 'PRODUCT.NAME' | translate, value: 'name' },
{ label: 'PRODUCT.DISPLAY_NAME' | translate, value: 'displayName' }
]"
[defaultSortOption]="sortField"
[defaultSortDirection]="sortOrder === 1"
(dataViewChange)="onLayoutChange($event)"
(filterChange)="onFilterChange($event)"
[filterColumns]="[
'PRODUCT.NAME' | translate,
'PRODUCT.DISPLAY_NAME' | translate,
'PRODUCT.CLASSIFICATIONS' | translate
]"
(sortChange)="onSortChange($event)"
(sortDirectionChange)="onSortDirChange($event)"
[translations]="dataViewControlsTranslations"
>
</ocx-data-view-controls
></ng-template>
<ng-template let-product let-idx="rowIndex" pTemplate="listItem">
<div
[id]="'product_search_data_list_' + idx"
class="col-12 grid grid-nogutter align-items-center row-gap-1 listview-row p-1 hover:bg-gray-200 cursor-pointer"
[routerLink]="['./', product.name]"
>
<div class="col-12 md:col-2 lg:col-2 xl:col-2 text-center">
<div class="flex flex-column justify-content-center align-items-center gap-1 md:gap-2 h-full">
<app-image-container
[id]="'product_search_data_list_' + idx + '_image'"
[imageUrl]="getImageUrl(product)"
[title]="'LOGO.TOOLTIPS.' + (product.imageUrl ? 'IMAGE' : 'PLACEHOLDER') | translate"
[small]="true"
></app-image-container>
</div>
<div class="col-12 md:col-5 lg:col-5 xl:col-6">
<div class="flex flex-column justify-content-center gap-1 text-center md:text-left">
<div
[id]="'product_search_data_list_' + idx + '_product_display_name'"
class="font-bold"
[title]="'PRODUCT.DISPLAY_NAME' | translate"
>
{{ limitText(product.displayName, 100) }}
</div>
<div [id]="'product_search_data_list_' + idx + '_product_name'" [title]="'PRODUCT.NAME' | translate">
{{ limitText(product.name, 100) }}
</div>
</div>
<div class="col-12 md:col-5 lg:col-5 xl:col-6">
<div class="flex flex-column justify-content-center gap-1 text-center md:text-left">
<div
[id]="'product_search_data_list_' + idx + '_product_display_name'"
class="font-bold"
[title]="'PRODUCT.DISPLAY_NAME' | translate"
>
{{ limitText(product.displayName, 100) }}
</div>
<div [id]="'product_search_data_list_' + idx + '_product_name'" [title]="'PRODUCT.NAME' | translate">
{{ limitText(product.name, 100) }}
</div>
</div>
</div>
</ng-template>
<ng-template let-product let-idx="rowIndex" pTemplate="gridItem">
<div
[id]="'product_search_data_grid_' + idx"
class="col-12 sm:col-6 md:col-4 lg:col-4 xl:col-3 p-3"
[routerLink]="['./', product.name]"
>
<div class="card p-2 flex flex-column justify-content-center hover:bg-gray-200 cursor-pointer">
<div class="h-3rem md:h-5rem flex flex-column justify-content-center align-items-center text-center">
<app-image-container
[id]="'product_search_data_grid_' + idx + '_image'"
[imageUrl]="getImageUrl(product)"
[title]="'LOGO.TOOLTIPS.' + (product.imageUrl ? 'IMAGE' : 'PLACEHOLDER') | translate"
[small]="false"
></app-image-container>
</div>
</ng-template>
<ng-template let-product let-idx="rowIndex" pTemplate="gridItem">
<div
[id]="'product_search_data_grid_' + idx"
class="col-12 sm:col-6 md:col-4 lg:col-4 xl:col-3 p-3"
[routerLink]="['./', product.name]"
>
<div class="card p-2 flex flex-column justify-content-center hover:bg-gray-200 cursor-pointer">
<div class="h-3rem md:h-5rem flex flex-column justify-content-center align-items-center text-center">
<app-image-container
[id]="'product_search_data_grid_' + idx + '_image'"
[imageUrl]="getImageUrl(product)"
[title]="'LOGO.TOOLTIPS.' + (product.imageUrl ? 'IMAGE' : 'PLACEHOLDER') | translate"
[small]="false"
></app-image-container>
</div>
<div class="h-3rem flex flex-column justify-content-between gap-1 lg:gap-2 mt-0 mb-1 text-center">
<div
[id]="'product_search_data_grid_' + idx + '_product_display_name'"
class="font-bold text-xl"
[title]="('PRODUCT.DISPLAY_NAME' | translate) + ': ' + limitText(product.displayName, 100)"
>
{{ limitText(product.displayName, 20) }}
</div>
<div class="h-3rem flex flex-column justify-content-between gap-1 lg:gap-2 mt-0 mb-1 text-center">
<div
[id]="'product_search_data_grid_' + idx + '_product_display_name'"
class="font-bold text-xl"
[title]="('PRODUCT.DISPLAY_NAME' | translate) + ': ' + limitText(product.displayName, 100)"
>
{{ limitText(product.displayName, 20) }}
</div>
<div
[id]="'product_search_data_grid_' + idx + '_product_name'"
[title]="('PRODUCT.NAME' | translate) + ': ' + product.name"
>
{{ limitText(product.name, 25) }}
</div>
<div
[id]="'product_search_data_grid_' + idx + '_product_name'"
[title]="('PRODUCT.NAME' | translate) + ': ' + product.name"
>
{{ limitText(product.name, 25) }}
</div>
</div>
</div>
</ng-template>
</p-dataView>
</ng-container>
</div>
</ng-template>
</p-dataView>
</ocx-page-content>
</ocx-portal-page>
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { RouterTestingModule } from '@angular/router/testing'
import { Router } from '@angular/router'
import { of } from 'rxjs'
import { of, throwError } from 'rxjs'
import { DataViewModule } from 'primeng/dataview'
import { TranslateTestingModule } from 'ngx-translate-testing'
import { Product, ProductPageResult, ProductsAPIService } from 'src/app/shared/generated'

import { ProductSearchComponent } from './product-search.component'

Expand All @@ -14,7 +15,16 @@ describe('ProductSearchComponent', () => {
let fixture: ComponentFixture<ProductSearchComponent>
let router: Router

const product: Product = {
id: 'id',
name: 'name',
basePath: 'basePath',
displayName: 'displayName'
}
const translateServiceSpy = jasmine.createSpyObj('TranslateService', ['get'])
const apiProductServiceSpy = {
searchProducts: jasmine.createSpy('searchProducts').and.returnValue(of({ stream: [] }))
}

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
Expand All @@ -28,15 +38,21 @@ describe('ProductSearchComponent', () => {
en: require('src/assets/i18n/en.json')
}).withDefaultLanguage('en')
],
providers: [{ provide: ProductsAPIService, useValue: apiProductServiceSpy }],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents()
}))

beforeEach(() => {
beforeEach(async () => {
fixture = TestBed.createComponent(ProductSearchComponent)
component = fixture.componentInstance
router = TestBed.inject(Router)
fixture.detectChanges()
//fixture.detectChanges()
fixture.componentInstance.ngOnInit() // solved ExpressionChangedAfterItHasBeenCheckedError
})

afterEach(() => {
apiProductServiceSpy.searchProducts.calls.reset(), translateServiceSpy.get.calls.reset()
})

it('should create', () => {
Expand Down Expand Up @@ -93,13 +109,57 @@ describe('ProductSearchComponent', () => {
expect(component.sortOrder).toEqual(1)
})

it('should call loadProducts onSearch', () => {
translateServiceSpy.get.and.returnValue(of({ 'ACTIONS.CREATE.LABEL': 'Create' }))
spyOn(component, 'searchProducts')
it('should search products - successful found', (done) => {
apiProductServiceSpy.searchProducts.and.returnValue(of({ stream: [product] } as ProductPageResult))

component.onSearch()

component.products$.subscribe({
next: (result) => {
if (result.stream) {
expect(result.stream.length).toBe(1)
result.stream.forEach((product) => {
expect(product.id).toEqual('id')
})
}
done()
},
error: done.fail
})
})

it('should search products - successful not found', (done) => {
apiProductServiceSpy.searchProducts.and.returnValue(of({ stream: [] } as ProductPageResult))

component.onSearch()

component.products$.subscribe({
next: (result) => {
if (result.stream) {
expect(result.stream.length).toBe(0)
}
done()
},
error: done.fail
})
})

it('should search products - failed', (done) => {
const err = { status: 403 }
apiProductServiceSpy.searchProducts.and.returnValue(throwError(() => err))

component.onSearch()

expect(component.searchProducts).toHaveBeenCalled()
component.products$.subscribe({
next: (result) => {
if (result.stream) {
expect(result.stream.length).toBe(0)
expect(component.exceptionKey).toEqual('EXCEPTIONS.HTTP_STATUS_403.PRODUCTS')
}
done()
},
error: done.fail
})
})

it('should reset productSearchCriteriaGroup onSearchReset', () => {
Expand Down
Loading

0 comments on commit 4c7a7a1

Please sign in to comment.