mirror of
https://github.com/sartography/uva-covid19-testing-frontend.git
synced 2025-02-11 23:26:58 +00:00
Merge pull request #1 from sartography/bug/no-internet-connection
Caches sample records locally if frontend cannot connect to backend. Saves records and clears cache when connection is restored.
This commit is contained in:
commit
6f42797dd4
@ -21,14 +21,16 @@ import {AppComponent} from './app.component';
|
|||||||
import {CountComponent} from './count/count.component';
|
import {CountComponent} from './count/count.component';
|
||||||
import {FooterComponent} from './footer/footer.component';
|
import {FooterComponent} from './footer/footer.component';
|
||||||
import {HomeComponent} from './home/home.component';
|
import {HomeComponent} from './home/home.component';
|
||||||
|
import {LabelLayoutComponent} from './label-layout/label-layout.component';
|
||||||
import {LoadingComponent} from './loading/loading.component';
|
import {LoadingComponent} from './loading/loading.component';
|
||||||
import {NavbarComponent} from './navbar/navbar.component';
|
import {NavbarComponent} from './navbar/navbar.component';
|
||||||
|
import {PrintLayoutComponent} from './print-layout/print-layout.component';
|
||||||
import {PrintComponent} from './print/print.component';
|
import {PrintComponent} from './print/print.component';
|
||||||
import {SampleComponent} from './sample/sample.component';
|
import {SampleComponent} from './sample/sample.component';
|
||||||
import {ApiService} from './services/api.service';
|
import {ApiService} from './services/api.service';
|
||||||
|
import {CacheService} from './services/cache.service';
|
||||||
|
import {SettingsService} from './services/settings.service';
|
||||||
import {SettingsComponent} from './settings/settings.component';
|
import {SettingsComponent} from './settings/settings.component';
|
||||||
import { LabelLayoutComponent } from './label-layout/label-layout.component';
|
|
||||||
import { PrintLayoutComponent } from './print-layout/print-layout.component';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is used internal to get a string instance of the `<base href="" />` value from `index.html`.
|
* This function is used internal to get a string instance of the `<base href="" />` value from `index.html`.
|
||||||
@ -48,16 +50,16 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
LoadingComponent,
|
|
||||||
FooterComponent,
|
|
||||||
NavbarComponent,
|
|
||||||
HomeComponent,
|
|
||||||
SampleComponent,
|
|
||||||
CountComponent,
|
CountComponent,
|
||||||
SettingsComponent,
|
FooterComponent,
|
||||||
PrintComponent,
|
HomeComponent,
|
||||||
LabelLayoutComponent,
|
LabelLayoutComponent,
|
||||||
|
LoadingComponent,
|
||||||
|
NavbarComponent,
|
||||||
|
PrintComponent,
|
||||||
PrintLayoutComponent,
|
PrintLayoutComponent,
|
||||||
|
SampleComponent,
|
||||||
|
SettingsComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
@ -65,25 +67,26 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
|
|||||||
FormlyModule,
|
FormlyModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
MatProgressSpinnerModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatInputModule,
|
|
||||||
MatToolbarModule,
|
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatCardModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
QRCodeSVGModule,
|
MatIconModule,
|
||||||
AppRoutingModule,
|
MatInputModule,
|
||||||
MatOptionModule,
|
MatOptionModule,
|
||||||
|
MatProgressSpinnerModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
// <-- This line MUST be last (https://angular.io/guide/router#module-import-order-matters)
|
MatToolbarModule,
|
||||||
|
QRCodeSVGModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
AppRoutingModule, // <-- This line MUST be last (https://angular.io/guide/router#module-import-order-matters)
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: {appearance: 'outline'}},
|
|
||||||
ApiService,
|
ApiService,
|
||||||
|
CacheService,
|
||||||
|
SettingsService,
|
||||||
{provide: 'APP_ENVIRONMENT', useClass: ThisEnvironment},
|
{provide: 'APP_ENVIRONMENT', useClass: ThisEnvironment},
|
||||||
{provide: APP_BASE_HREF, useFactory: getBaseHref, deps: [PlatformLocation]},
|
{provide: APP_BASE_HREF, useFactory: getBaseHref, deps: [PlatformLocation]},
|
||||||
|
{provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: {appearance: 'outline'}},
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
entryComponents: []
|
entryComponents: []
|
||||||
|
@ -1,19 +1,35 @@
|
|||||||
|
import {APP_BASE_HREF} from '@angular/common';
|
||||||
|
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
|
||||||
import {async, ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
|
import {async, ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
|
||||||
|
import {ApiService} from '../services/api.service';
|
||||||
|
import {CacheService} from '../services/cache.service';
|
||||||
|
import {MockEnvironment} from '../testing/environment.mock';
|
||||||
|
|
||||||
import { HomeComponent } from './home.component';
|
import { HomeComponent } from './home.component';
|
||||||
|
|
||||||
describe('HomeComponent', () => {
|
describe('HomeComponent', () => {
|
||||||
let component: HomeComponent;
|
let component: HomeComponent;
|
||||||
let fixture: ComponentFixture<HomeComponent>;
|
let fixture: ComponentFixture<HomeComponent>;
|
||||||
|
let httpMock: HttpTestingController;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ HomeComponent ]
|
declarations: [ HomeComponent ],
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
ApiService,
|
||||||
|
CacheService,
|
||||||
|
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
|
||||||
|
{provide: APP_BASE_HREF, useValue: '/'},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
httpMock = TestBed.inject(HttpTestingController);
|
||||||
fixture = TestBed.createComponent(HomeComponent);
|
fixture = TestBed.createComponent(HomeComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {ApiService} from '../services/api.service';
|
||||||
|
import {CacheService} from '../services/cache.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@ -7,9 +9,33 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
})
|
})
|
||||||
export class HomeComponent implements OnInit {
|
export class HomeComponent implements OnInit {
|
||||||
|
|
||||||
constructor() { }
|
constructor(
|
||||||
|
private cacheService: CacheService,
|
||||||
|
private apiService: ApiService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
const cachedRecords = this.cacheService.getRecords();
|
||||||
|
let numSuccess = 0;
|
||||||
|
if (cachedRecords && cachedRecords.length > 0) {
|
||||||
|
cachedRecords.forEach(r => {
|
||||||
|
this.apiService.addSample(r).subscribe(() => {
|
||||||
|
numSuccess++;
|
||||||
|
console.log('cachedRecords', cachedRecords);
|
||||||
|
console.log('numSuccess', numSuccess);
|
||||||
|
|
||||||
|
if (numSuccess === cachedRecords.length) {
|
||||||
|
console.log('Cache cleared.');
|
||||||
|
this.cacheService.clearCache();
|
||||||
|
}
|
||||||
|
}, error => {
|
||||||
|
console.log('Cannot connect to server. Cache not cleared.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('No cached records to upload.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
<div *ngIf="showSpinner" class="loading" fxLayoutAlign="center center">
|
<div *ngIf="showSpinner"
|
||||||
{{message || ''}}
|
class="loading"
|
||||||
<mat-spinner [diameter]="diameter"></mat-spinner>
|
fxLayoutAlign="center center"
|
||||||
|
fxLayout="column"
|
||||||
|
fxLayoutGap="40px"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<mat-spinner [diameter]="diameter"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{message || ''}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span *ngIf="!showSpinner">{{message || '...'}}</span>
|
<span *ngIf="!showSpinner">{{message || '...'}}</span>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<mat-toolbar color="primary">
|
<mat-toolbar color="primary">
|
||||||
<mat-toolbar-row>
|
<mat-toolbar-row>
|
||||||
<button id="nav_logo" mat-button routerLink="/" class="logo">BeSAFE</button>
|
<button id="nav_logo" mat-button routerLink="/" class="logo">BeSAFE</button>
|
||||||
<button id="nav_location" mat-button routerLink="/settings">{{testingLocation ? testingLocation.name : 'No location found'}} ({{locationId}})</button>
|
<button id="nav_location" mat-button routerLink="/settings">{{locationId === '0000' ? 'Click here to set location' : 'Location: ' + locationId}}</button>
|
||||||
<span fxFlex></span>
|
<span fxFlex></span>
|
||||||
<button id="nav_home" mat-icon-button routerLink="/"><mat-icon>home</mat-icon></button>
|
<button id="nav_home" mat-icon-button routerLink="/"><mat-icon>home</mat-icon></button>
|
||||||
<button id="nav_settings" mat-icon-button routerLink="/settings"><mat-icon>settings</mat-icon></button>
|
<button id="nav_settings" mat-icon-button routerLink="/settings"><mat-icon>settings</mat-icon></button>
|
||||||
|
@ -9,14 +9,15 @@ import {TestingLocation} from '../models/testingLocation.interface';
|
|||||||
})
|
})
|
||||||
export class NavbarComponent implements OnInit {
|
export class NavbarComponent implements OnInit {
|
||||||
@Input() testingLocation: TestingLocation;
|
@Input() testingLocation: TestingLocation;
|
||||||
locationId: string;
|
|
||||||
|
|
||||||
constructor(private settingsService: SettingsService) {
|
constructor(private settingsService: SettingsService) {
|
||||||
const settings = this.settingsService.getSettings();
|
|
||||||
this.locationId = settings.locationId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get locationId(): string {
|
||||||
|
const settings = this.settingsService.getSettings();
|
||||||
|
return settings.locationId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,11 @@
|
|||||||
<h1>Print Labels</h1>
|
<h1>Print Labels</h1>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
|
|
||||||
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
|
<mat-card-content
|
||||||
|
fxLayout="column"
|
||||||
|
fxLayoutAlign="center center"
|
||||||
|
*ngIf="isSaved; else loadingMessage"
|
||||||
|
>
|
||||||
<app-print-layout
|
<app-print-layout
|
||||||
[barCode]="barCode"
|
[barCode]="barCode"
|
||||||
[initials]="initials"
|
[initials]="initials"
|
||||||
@ -46,3 +50,10 @@
|
|||||||
[dateCreated]="dateCreated"
|
[dateCreated]="dateCreated"
|
||||||
></app-print-layout>
|
></app-print-layout>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ng-template #loadingMessage>
|
||||||
|
<app-loading
|
||||||
|
message="Contacting the server..."
|
||||||
|
size="lg"
|
||||||
|
></app-loading>
|
||||||
|
</ng-template>
|
||||||
|
@ -1,8 +1,21 @@
|
|||||||
@import 'src/config';
|
@import 'src/config';
|
||||||
|
|
||||||
|
::ng-deep .loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen {
|
@media screen {
|
||||||
#media-print { display: none !important; }
|
#media-print { display: none !important; }
|
||||||
#media-screen { display: flex !important; }
|
#media-screen {
|
||||||
|
display: flex !important;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
@ -34,4 +47,3 @@
|
|||||||
background-color: $brand-gray-tint-2;
|
background-color: $brand-gray-tint-2;
|
||||||
height: 500px;
|
height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import {AppDefaults} from '../models/appDefaults.interface';
|
|||||||
import {LabelLayout} from '../models/labelLayout.interface';
|
import {LabelLayout} from '../models/labelLayout.interface';
|
||||||
import {Sample} from '../models/sample.interface';
|
import {Sample} from '../models/sample.interface';
|
||||||
import {ApiService} from '../services/api.service';
|
import {ApiService} from '../services/api.service';
|
||||||
|
import {CacheService} from '../services/cache.service';
|
||||||
import {SettingsService} from '../services/settings.service';
|
import {SettingsService} from '../services/settings.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -20,13 +21,14 @@ export class PrintComponent implements AfterViewInit {
|
|||||||
settings: AppDefaults;
|
settings: AppDefaults;
|
||||||
@ViewChild('saveAndPrintButton') saveAndPrintButton: MatButton;
|
@ViewChild('saveAndPrintButton') saveAndPrintButton: MatButton;
|
||||||
@ViewChild('doneButton') doneButton: MatButton;
|
@ViewChild('doneButton') doneButton: MatButton;
|
||||||
isSaved = false;
|
isSaved: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private changeDetector: ChangeDetectorRef,
|
private changeDetector: ChangeDetectorRef,
|
||||||
private settingsService: SettingsService
|
private settingsService: SettingsService,
|
||||||
|
private cacheService: CacheService,
|
||||||
) {
|
) {
|
||||||
this.dateCreated = new Date();
|
this.dateCreated = new Date();
|
||||||
this.route.queryParamMap.subscribe(queryParamMap => {
|
this.route.queryParamMap.subscribe(queryParamMap => {
|
||||||
@ -34,6 +36,11 @@ export class PrintComponent implements AfterViewInit {
|
|||||||
this.initials = queryParamMap.get('initials');
|
this.initials = queryParamMap.get('initials');
|
||||||
});
|
});
|
||||||
this.settings = this.settingsService.getSettings();
|
this.settings = this.settingsService.getSettings();
|
||||||
|
this.isSaved = false;
|
||||||
|
|
||||||
|
this.save(s => {
|
||||||
|
this.isSaved = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
@ -63,7 +70,7 @@ export class PrintComponent implements AfterViewInit {
|
|||||||
headEl.appendChild(styleEl);
|
headEl.appendChild(styleEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAndPrint() {
|
save(callback: (s: Sample) => void) {
|
||||||
const id = createQrCodeValue(
|
const id = createQrCodeValue(
|
||||||
this.barCode,
|
this.barCode,
|
||||||
this.initials,
|
this.initials,
|
||||||
@ -78,8 +85,22 @@ export class PrintComponent implements AfterViewInit {
|
|||||||
location: this.settings.locationId,
|
location: this.settings.locationId,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.api.addSample(newSample).subscribe(() => {
|
this.api.addSample(newSample).subscribe((result) => {
|
||||||
this.isSaved = true;
|
console.log('addSample subscribe callback');
|
||||||
|
callback(result);
|
||||||
|
}, err => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedRecords = this.cacheService.saveRecord(newSample);
|
||||||
|
console.log('cachedRecords', cachedRecords);
|
||||||
|
callback(newSample);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveAndPrint() {
|
||||||
|
this.save(s => {
|
||||||
window.print();
|
window.print();
|
||||||
this.doneButton.focus();
|
this.doneButton.focus();
|
||||||
this.changeDetector.detectChanges();
|
this.changeDetector.detectChanges();
|
||||||
|
@ -34,11 +34,11 @@ export class ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Add new sample */
|
/** Add new sample */
|
||||||
addSample(sample: Sample): Observable<Sample> {
|
addSample(sample: Sample): Observable<null> {
|
||||||
const url = this.apiRoot + this.endpoints.sample;
|
const url = this.apiRoot + this.endpoints.sample;
|
||||||
|
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
.post<Sample>(url, sample)
|
.post<null>(url, sample)
|
||||||
.pipe(catchError(err => this._handleError(err)));
|
.pipe(catchError(err => this._handleError(err)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
src/app/services/cache.service.spec.ts
Normal file
20
src/app/services/cache.service.spec.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
import {CacheService} from './cache.service';
|
||||||
|
|
||||||
|
describe('CacheService', () => {
|
||||||
|
let service: CacheService;
|
||||||
|
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
CacheService,
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
service = TestBed.inject(CacheService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
54
src/app/services/cache.service.ts
Normal file
54
src/app/services/cache.service.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import serializeJs from 'serialize-javascript';
|
||||||
|
import {Sample} from '../models/sample.interface';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CacheService {
|
||||||
|
// Default form field and data values
|
||||||
|
records: Sample[] = [];
|
||||||
|
|
||||||
|
// localStorage key
|
||||||
|
private localStorageKey = 'cachedRecords';
|
||||||
|
|
||||||
|
// Deserializes settings from local storage and returns AppDefaults instance
|
||||||
|
getStoredRecords(): Sample[] {
|
||||||
|
// tslint:disable-next-line:no-eval
|
||||||
|
return (eval(`(${localStorage.getItem(this.localStorageKey)})`) || []) as Sample[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if settings are found in local storage
|
||||||
|
hasStoredRecords(): boolean {
|
||||||
|
return this.getStoredRecords().length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns records from local storage, or [] if none have been saved yet.
|
||||||
|
getRecords(): Sample[] {
|
||||||
|
if (this.hasStoredRecords()) {
|
||||||
|
return this.getStoredRecords();
|
||||||
|
} else {
|
||||||
|
return this.saveRecords(this.records);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializes given record and adds it to cache in local storage
|
||||||
|
saveRecord(newRecord: Sample): Sample[] {
|
||||||
|
const records = this.getRecords();
|
||||||
|
records.push(newRecord);
|
||||||
|
return this.saveRecords(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializes multiple given records and stores them in local storage
|
||||||
|
saveRecords(newRecords: Sample[]): Sample[] {
|
||||||
|
localStorage.setItem(this.localStorageKey, serializeJs(newRecords));
|
||||||
|
return newRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears cached records.
|
||||||
|
clearCache(): Sample[] {
|
||||||
|
return this.saveRecords([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
20
src/app/services/settings.service.spec.ts
Normal file
20
src/app/services/settings.service.spec.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
import {SettingsService} from './settings.service';
|
||||||
|
|
||||||
|
describe('SettingsService', () => {
|
||||||
|
let service: SettingsService;
|
||||||
|
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
SettingsService,
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
service = TestBed.inject(SettingsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user