Browse Source

Storybook test cases created

pull/4563/head
csehatt741 3 months ago
committed by Thomas Kaul
parent
commit
0863eb4874
  1. 23
      libs/ui/src/lib/symbol-autocomplete/mocks/httpClient.mock.ts
  2. 38
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html
  3. 108
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.stories.ts
  4. 49
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts

23
libs/ui/src/lib/symbol-autocomplete/mocks/httpClient.mock.ts

@ -0,0 +1,23 @@
import { LookupResponse } from '@ghostfolio/common/interfaces';
import { Observable } from 'rxjs';
export class HttpClientMock {
public constructor(
private readonly url: string,
private readonly mockData: LookupResponse
) {}
get<T>(url: string, options?: any): Observable<T> {
if (url === this.url && options) {
return new Observable<T>((subscriber) => {
subscriber.next(this.mockData as T);
subscriber.complete();
});
}
return new Observable<T>((subscriber) => {
subscriber.error(new Error(`No mock data for URL: ${url}`));
});
}
}

38
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html

@ -1,45 +1,15 @@
<input <input
*ngIf="!isAutocomplete"
autocapitalize="off" autocapitalize="off"
autocomplete="off" autocomplete="off"
matInput matInput
[formControl]="inputControl" [formControl]="control"
[matAutocomplete]="symbolAutocomplete" [matAutocomplete]="symbolAutocomplete"
/> />
<mat-select
*ngIf="isAutocomplete"
[displayWith]="displayFn"
[formControl]="selectControl"
(keydown)="onShowAutocomplete($event)"
(selectionChange)="onSelectUpdateSymbol($event)"
>
@for (lookupItem of defaultLookupItems; track lookupItem) {
<mat-option
class="line-height-1"
[disabled]="lookupItem.dataProviderInfo.isPremium"
[value]="lookupItem"
>
<span class="align-items-center d-flex line-height-1"
><span>{{ lookupItem.name }}</span>
@if (lookupItem.dataProviderInfo.isPremium) {
<gf-premium-indicator class="ml-1" [enableLink]="false" />
}
</span>
<small class="text-muted"
>{{ lookupItem.symbol | gfSymbol }} · {{ lookupItem.currency }}
@if (lookupItem.dataProviderInfo.name) {
· {{ lookupItem.dataProviderInfo.name }}
}
</small>
</mat-option>
}
</mat-select>
<mat-autocomplete <mat-autocomplete
#symbolAutocomplete #symbolAutocomplete="matAutocomplete"
[displayWith]="displayFn" [displayWith]="displayFn"
(optionSelected)="onAutocompleteUpdateSymbol($event)" (optionSelected)="onUpdateSymbol($event)"
> >
@if (!isLoading) { @if (!isLoading) {
@for (lookupItem of filteredLookupItems; track lookupItem) { @for (lookupItem of filteredLookupItems; track lookupItem) {
@ -65,7 +35,7 @@
</small> </small>
</mat-option> </mat-option>
} @empty { } @empty {
@if (inputControl.value?.length > 1) { @if (control.value?.length > 1) {
<mat-option class="line-height-1" disabled="true" i18n <mat-option class="line-height-1" disabled="true" i18n
>Oops! Could not find any assets.</mat-option >Oops! Could not find any assets.</mat-option
> >

108
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.stories.ts

@ -0,0 +1,108 @@
import { LookupItem } from '@ghostfolio/common/interfaces';
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { importProvidersFrom } from '@angular/core';
import {
FormControl,
FormsModule,
NgControl,
ReactiveFormsModule
} from '@angular/forms';
import { provideNoopAnimations } from '@angular/platform-browser/animations';
import { applicationConfig, Meta, StoryObj } from '@storybook/angular';
import { HttpClientMock } from './mocks/httpClient.mock';
import { GfSymbolAutocompleteComponent } from './symbol-autocomplete.component';
const FILTERED_OPTIONS: LookupItem[] = [
{
assetClass: 'COMMODITY',
assetSubClass: 'ETF',
currency: 'USD',
dataProviderInfo: { name: 'YAHOO', isPremium: false },
dataSource: null,
name: 'Test3',
symbol: 'TEST3'
},
{
assetClass: 'EQUITY',
assetSubClass: 'STOCK',
currency: 'USD',
dataProviderInfo: { name: 'YAHOO', isPremium: false },
dataSource: null,
name: 'Test4',
symbol: 'TEST4'
}
];
export default {
title: 'Symbol Autocomplete',
component: GfSymbolAutocompleteComponent,
decorators: [
applicationConfig({
providers: [
provideNoopAnimations(),
importProvidersFrom(CommonModule, FormsModule, ReactiveFormsModule),
{
provide: NgControl,
useValue: {
control: new FormControl(),
valueAccessor: null
}
},
{
provide: HttpClient,
useValue: new HttpClientMock('/api/v1/symbol/lookup', {
items: FILTERED_OPTIONS
})
}
]
})
],
parameters: {
mockData: [
{
url: '/api/v1/symbol/lookup',
method: 'GET',
status: 200,
response: {
items: FILTERED_OPTIONS
}
}
]
}
} as Meta<GfSymbolAutocompleteComponent>;
type Story = StoryObj<GfSymbolAutocompleteComponent>;
export const WithoutDefaults: Story = {
args: {
defaultLookupItems: []
}
};
export const WithDefaults: Story = {
args: {
defaultLookupItems: [
{
assetClass: 'COMMODITY',
assetSubClass: 'ETF',
currency: 'USD',
dataProviderInfo: { name: 'YAHOO', isPremium: false },
dataSource: null,
name: 'Test1',
symbol: 'TEST1'
},
{
assetClass: 'EQUITY',
assetSubClass: 'STOCK',
currency: 'USD',
dataProviderInfo: { name: 'YAHOO', isPremium: false },
dataSource: null,
name: 'Test2',
symbol: 'TEST2'
}
]
}
};

49
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts

@ -23,6 +23,7 @@ import {
ReactiveFormsModule ReactiveFormsModule
} from '@angular/forms'; } from '@angular/forms';
import { import {
MatAutocomplete,
MatAutocompleteModule, MatAutocompleteModule,
MatAutocompleteSelectedEvent MatAutocompleteSelectedEvent
} from '@angular/material/autocomplete'; } from '@angular/material/autocomplete';
@ -32,7 +33,6 @@ import {
} from '@angular/material/form-field'; } from '@angular/material/form-field';
import { MatInput, MatInputModule } from '@angular/material/input'; import { MatInput, MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectChange, MatSelectModule } from '@angular/material/select';
import { isString } from 'lodash'; import { isString } from 'lodash';
import { Subject, tap } from 'rxjs'; import { Subject, tap } from 'rxjs';
import { import {
@ -59,7 +59,6 @@ import { GfPremiumIndicatorComponent } from '../premium-indicator';
MatFormFieldModule, MatFormFieldModule,
MatInputModule, MatInputModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
MatSelectModule,
ReactiveFormsModule ReactiveFormsModule
], ],
providers: [ providers: [
@ -77,15 +76,13 @@ export class GfSymbolAutocompleteComponent
extends AbstractMatFormField<LookupItem> extends AbstractMatFormField<LookupItem>
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
@Input() public isLoading = false; public isLoading = false;
@Input() public isAutocomplete = false;
@Input() public defaultLookupItems: LookupItem[] = []; @Input() public defaultLookupItems: LookupItem[] = [];
@ViewChild(MatInput) private input: MatInput; @ViewChild(MatInput) private input: MatInput;
@ViewChild('symbolAutocomplete') public symbolAutocomplete: MatAutocomplete;
public selectControl = new FormControl(); public control = new FormControl();
public inputControl = new FormControl();
public filteredLookupItems: (LookupItem & { assetSubClassString: string })[] = public filteredLookupItems: (LookupItem & { assetSubClassString: string })[] =
[]; [];
@ -105,11 +102,21 @@ export class GfSymbolAutocompleteComponent
public ngOnInit() { public ngOnInit() {
if (this.disabled) { if (this.disabled) {
this.selectControl.disable(); this.control.disable();
this.inputControl.disable(); }
if (this.defaultLookupItems?.length) {
this.filteredLookupItems = this.defaultLookupItems.map((lookupItem) => {
return {
...lookupItem,
assetSubClassString: translate(lookupItem.assetSubClass)
};
});
this.changeDetectorRef.markForCheck();
} }
this.inputControl.valueChanges this.control.valueChanges
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => { .subscribe(() => {
if (super.value) { if (super.value) {
@ -117,7 +124,7 @@ export class GfSymbolAutocompleteComponent
} }
}); });
this.inputControl.valueChanges this.control.valueChanges
.pipe( .pipe(
filter((query) => { filter((query) => {
return isString(query) && query.length > 1; return isString(query) && query.length > 1;
@ -176,23 +183,7 @@ export class GfSymbolAutocompleteComponent
} }
} }
public onShowAutocomplete(event: KeyboardEvent) { public onUpdateSymbol(event: MatAutocompleteSelectedEvent) {
if (event.key.length === 1) {
this.inputControl.setValue(event.key);
this.isAutocomplete = true;
this.changeDetectorRef.markForCheck();
}
}
public onSelectUpdateSymbol(event: MatSelectChange) {
super.value = {
dataSource: event.source.value.dataSource,
symbol: event.source.value.symbol
} as LookupItem;
}
public onAutocompleteUpdateSymbol(event: MatAutocompleteSelectedEvent) {
super.value = { super.value = {
dataSource: event.option.value.dataSource, dataSource: event.option.value.dataSource,
symbol: event.option.value.symbol symbol: event.option.value.symbol
@ -200,7 +191,7 @@ export class GfSymbolAutocompleteComponent
} }
public set value(value: LookupItem) { public set value(value: LookupItem) {
this.inputControl.setValue(value); this.control.setValue(value);
super.value = value; super.value = value;
} }

Loading…
Cancel
Save