Skip to content

Instantly share code, notes, and snippets.

@aasumitro
Last active March 13, 2023 10:38
Show Gist options
  • Save aasumitro/9d21fcd52e199f3ad54e5202eedabb55 to your computer and use it in GitHub Desktop.
Save aasumitro/9d21fcd52e199f3ad54e5202eedabb55 to your computer and use it in GitHub Desktop.
ANGULAR
import {Injectable} from '@angular/core';
import {CONFIGS} from '../config';
import {RestService} from './rest.service';
@Injectable({providedIn: "root"})
export class AuthRestService {
private pathResourceURL = CONFIGS.api.rest.path;
constructor(private restService: RestService) {}
getValidateSession(): Promise<any> {
return new Promise((resolve, reject) => {
const path = this.pathResourceURL.auth.validateSession
this.restService
.getReq(path, null)
.then((res) => resolve(res))
.catch((err) => reject(err))
});
}
}
export const CONFIGS = {
api: {
rest: {
dev_url: "localhost:8000/api",
prod_url: "becoop.bakode.id/api",
version: "v1",
path: {
auth: {
validateSession: "auth/session",
validateCredential: "auth/credential",
validateAccess: "auth/access"
}
}
}
},
infra: {
sentry: {},
firebase: {}
}
}
// noinspection DuplicatedCode
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {TestBed} from '@angular/core/testing';
import {ProductUsecase} from './product.usecase';
import {RouterTestingModule} from '@angular/router/testing';
import {fakeResponseForSpecifiedUsecase, fakeResponseWithPayloadObject} from '../../_mocks/fake-data';
import {CONFIG} from '../../../../services/config.service';
import {ResponseStatus} from '../../enums/response.status';
describe('ProductUsecase', () => {
let httpTestingController: HttpTestingController;
let usecase: ProductUsecase;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
providers: [ProductUsecase]
});
httpTestingController = TestBed.inject(HttpTestingController);
usecase = TestBed.inject(ProductUsecase);
});
afterEach(() => {
httpTestingController.verify();
});
it('should be created', () => {
expect(usecase).toBeTruthy();
});
const testsCase = [
{
title: 'should call products$, expect success',
error: false,
mockData: fakeResponseForSpecifiedUsecase,
usecaseFunc: 'products$',
params: {},
pathUrl: CONFIG.URL.myPharma.v1.products,
reqMethod: 'GET',
},
{
title: 'should call products$, expect failed',
error: true,
errorData: () => new ErrorEvent('Network Error'),
usecaseFunc: 'products$',
params: {},
pathUrl: CONFIG.URL.myPharma.v1.products,
reqMethod: 'GET',
},
{
title: 'should call product$, expect success',
error: false,
mockData: fakeResponseForSpecifiedUsecase,
usecaseFunc: 'product$',
params: '12345',
pathUrl: CONFIG.URL.myPharma.v1.productDetail('12345'),
reqMethod: 'GET',
},
{
title: 'should call product$, expect failed',
error: true,
errorData: () => new ErrorEvent('Network Error'),
usecaseFunc: 'product$',
params: '12345',
pathUrl: CONFIG.URL.myPharma.v1.productDetail('12345'),
reqMethod: 'GET',
},
{
title: 'should call productReviews$, expect success',
error: false,
mockData: fakeResponseForSpecifiedUsecase,
usecaseFunc: 'productReviews$',
params: ['12345', {}],
pathUrl: CONFIG.URL.myPharma.v1.productReviews('12345'),
reqMethod: 'GET',
},
{
title: 'should call productReviews$, expect failed',
error: true,
errorData: () => new ErrorEvent('Network Error'),
usecaseFunc: 'productReviews$',
params: ['12345', {}],
pathUrl: CONFIG.URL.myPharma.v1.productReviews('12345'),
reqMethod: 'GET',
},
{
title: 'should call productReviewCount$, expect success',
error: false,
mockData: fakeResponseWithPayloadObject,
usecaseFunc: 'productReviewCount$',
params: '12345',
pathUrl: CONFIG.URL.myPharma.v1.productReviewCount('12345'),
reqMethod: 'GET',
},
{
title: 'should call productReviewCount$, expect failed',
error: true,
errorData: () => new ErrorEvent('Network Error'),
usecaseFunc: 'productReviewCount$',
params: '12345',
pathUrl: CONFIG.URL.myPharma.v1.productReviewCount('12345'),
reqMethod: 'GET',
},
{
title: 'should call productSearch$, expect success',
error: false,
mockData: fakeResponseForSpecifiedUsecase,
usecaseFunc: 'productSearch$',
params: {},
pathUrl: CONFIG.URL.myPharma.v1.searchProduct,
reqMethod: 'GET',
},
{
title: 'should call productSearch$, expect failed',
error: true,
errorData: () => new ErrorEvent('Network Error'),
usecaseFunc: 'productSearch$',
params: {},
pathUrl: CONFIG.URL.myPharma.v1.searchProduct,
reqMethod: 'GET',
},
{
title: 'should call performGiveReview, expect success',
error: false,
mockData: fakeResponseForSpecifiedUsecase,
usecaseFunc: 'performGiveReview',
params: [{}, '12345'],
pathUrl: CONFIG.URL.myPharma.v1.addReviewToProduct('12345'),
reqMethod: 'POST',
},
];
testsCase.forEach(test => {
it(test.title, done => {
switch (test.usecaseFunc) {
case'products$':
usecase.products$(test.params).subscribe(data => {
if (data.state !== ResponseStatus.loading) {
validateData(test, data, done);
}
});
break;
case'product$':
usecase.product$(test.params as string).subscribe(data => {
if (data.state !== ResponseStatus.loading) {
validateData(test, data, done);
}
});
break;
case'productReviews$':
usecase.productReviews$(test.params[0] as string, test.params[1]).subscribe(data => {
if (data.state !== ResponseStatus.loading) {
validateData(test, data, done);
}
});
break;
case'productSearch$':
usecase.productSearch$(test.params).subscribe(data => {
if (data.state !== ResponseStatus.loading) {
validateData(test, data, done);
}
});
break;
case'productReviewCount$':
usecase.productReviewCount$(test.params as string).subscribe(data => {
if (data.state !== ResponseStatus.loading) {
validateData(test, data, done);
}
});
break;
case 'performGiveReview':
usecase.performGiveReview(test.params[0], test.params[1]);
done();
break;
}
const url = `${CONFIG.apiEndpoint}${test.pathUrl}`;
const req = httpTestingController.expectOne(url);
expect(req.request.method).toEqual(test.reqMethod);
if (!test.error) { req.flush(test.mockData); }
if (test.error) { req.error(test.errorData()); }
});
});
const validateData = (test, data, done) => {
if (!test.error) {
expect(data.state).toEqual(ResponseStatus.success);
expect(data.error).toEqual(null);
expect(data.value).toBeDefined();
expect(data.value).toBeInstanceOf(Object);
if (data.value instanceof Array) {
expect(data.value.length).toBeGreaterThan(0);
}
done();
}
if (test.error) {
expect(data.state).toEqual(ResponseStatus.error);
expect(data.value).toEqual(null);
expect(data.error).toBeTruthy();
expect(data?.error?.message).toBeDefined();
done();
}
};
});
import {Injectable} from '@angular/core';
import {MyPharmaService} from '../../../../services/mypharma.service';
import {defer, from, Observable, of, throwError} from 'rxjs';
import {HttpRequestState} from '../../utils/http-request-state.util';
import {catchError, concatMap, delay, map, retryWhen, startWith} from 'rxjs/operators';
import {ResponseStatus} from '../../enums/response.status';
import {Product, ProductRating, ProductRatingCount} from '../models/product';
import {Paging} from '../models/paging';
@Injectable()
export class ProductUsecase
{
constructor(private myPharmaService: MyPharmaService) {}
products$(params: any): Observable<HttpRequestState<Product[]>> {
return (defer(() =>
from(this.myPharmaService.getProducts(params)).pipe(
retryWhen(errors => errors.pipe(
concatMap((error, index) => {
if (index >= 2) {
return throwError(error);
}
return of(error).pipe(delay(1000));
})
)),
).pipe(
map((data) => ({
state: ResponseStatus.success,
value: data?.payload?.products as Product[],
paging: data?.payload as Paging,
error: null
})),
catchError((error) => of({
state: ResponseStatus.error,
value: null,
error
})),
startWith({
state: ResponseStatus.loading,
value: null,
error: null
}),
)));
}
product$(productId: string): Observable<HttpRequestState<Product>> {
return defer(() =>
from(this.myPharmaService.getProductDetail(productId)).pipe(
retryWhen(errors => errors.pipe(
concatMap((error, index) => {
if (index >= 2) {
return throwError(error);
}
return of(error).pipe(delay(1000));
})
)),
).pipe(
map((data: any) => ({
state: ResponseStatus.success,
value: data?.payload?.product as Product,
error: null
})),
catchError((error) => of({
state: ResponseStatus.error,
value: null,
error
})),
startWith({
state: ResponseStatus.loading,
value: null,
error: null
}),
)
);
}
productReviews$(productId: string, params: any): Observable<HttpRequestState<ProductRating[]>> {
return defer(() =>
from(this.myPharmaService.getProductReviews(productId, params)).pipe(
retryWhen(errors => errors.pipe(
concatMap((error, index) => {
if (index >= 2) {
return throwError(error);
}
return of(error).pipe(delay(1000));
})
)),
).pipe(
map((data: any) => ({
state: ResponseStatus.success,
value: data?.payload?.productReviews as ProductRating[],
paging: data?.payload,
error: null
})),
catchError((error) => of({
state: ResponseStatus.error,
value: null,
error
})),
startWith({
state: ResponseStatus.loading,
value: null,
error: null
}),
)
);
}
productReviewCount$(productId: string): Observable<HttpRequestState<ProductRatingCount>> {
return defer(() =>
from(this.myPharmaService.getProductReviewCount(productId)).pipe(
retryWhen(errors => errors.pipe(
concatMap((error, index) => {
if (index >= 2) {
return throwError(error);
}
return of(error).pipe(delay(1000));
})
)),
).pipe(
map((data: any) => ({
state: ResponseStatus.success,
value: data?.payload as ProductRatingCount,
error: null
})),
catchError((error) => of({
state: ResponseStatus.error,
value: null,
error
})),
startWith({
state: ResponseStatus.loading,
value: null,
error: null
}),
)
);
}
productSearch$(params: any): Observable<HttpRequestState<Product[]>> {
return (defer(() =>
from(this.myPharmaService.searchProduct(params)).pipe(
retryWhen(errors => errors.pipe(
concatMap((error, index) => {
if (index >= 2) {
return throwError(error);
}
return of(error).pipe(delay(1000));
})
)),
).pipe(
map((data) => ({
state: ResponseStatus.success,
value: data?.payload?.searchResult as Product[],
paging: data?.payload as Paging,
error: null
})),
catchError((error) => of({
state: ResponseStatus.error,
value: null,
error
})),
startWith({
state: ResponseStatus.loading,
value: null,
error: null
}),
)));
}
performGiveReview = async (params: any, productId: string) =>
await this.myPharmaService.addProductReview(params, productId);
}
import {Injectable, isDevMode} from '@angular/core';
import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
import {Router} from '@angular/router';
import {CONFIGS} from '../config';
import {catchError, map} from 'rxjs';
@Injectable({providedIn: "root"})
export class RestService {
private AUTH_PATH = 'auth'
constructor(
public http: HttpClient,
private router: Router
) {}
async getReq(pathUrl: string, params: any) {
const headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
const url = `${this.getAPIUrl()}/${pathUrl}`;
return this.http.get<any>(url, {headers, params}).pipe(
map(response => response),
catchError(this.handleError),
);
}
async postReq(pathUrl: string, body: any) {
const headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
const url = `${this.getAPIUrl()}/${pathUrl}`;
return this.http.post<any>(url, body, { headers }).pipe(
map(response => response),
catchError(this.handleError)
);
}
private getAPIUrl(): String {
// noinspection HttpUrlsUsage
const url = isDevMode()
? `http://${CONFIGS.api.rest.dev_url}`
: `https://${CONFIGS.api.rest.prod_url}`;
return `${url}/${CONFIGS.api.rest.version}`;
}
private async handleError(error: HttpErrorResponse) {
if (error.status === 401) {
await this.router.navigateByUrl(
this.AUTH_PATH,
{ replaceUrl: true },
);
}
return Promise.reject(error);
}
}
@aasumitro
Copy link
Author

Screenshot 2023-03-13 at 18 35 41

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment