Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(product): add uri resolver #1472

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ import {
} from '@daffodil/product/state';
import { DaffProductFactory } from '@daffodil/product/testing';

import { DaffProductPageResolver } from './product-page.resolver';
import { DaffProductPageIdResolver } from './product-page-id.resolver';

describe('DaffProductPageResolver', () => {
describe('DaffProductPageIdResolver', () => {
const actions$: Observable<any> = null;
let resolver: DaffProductPageResolver;
let resolver: DaffProductPageIdResolver;
let store: Store<DaffProductReducersState>;
let ProductFactory: DaffProductFactory;
let stubProduct: DaffProduct;
Expand All @@ -57,7 +57,7 @@ describe('DaffProductPageResolver', () => {
],
});

resolver = TestBed.inject(DaffProductPageResolver);
resolver = TestBed.inject(DaffProductPageIdResolver);
ProductFactory = TestBed.inject(DaffProductFactory);
stubProduct = ProductFactory.create();
store = TestBed.inject(Store);
Expand All @@ -80,7 +80,7 @@ describe('DaffProductPageResolver', () => {
store.dispatch(new DaffProductPageLoadSuccess(stubProduct));
});

it('should resolve when DaffCartLoadFailure is dispatched', () => {
it('should resolve when DaffProductPageLoadFailure is dispatched', () => {
resolver.resolve(route.snapshot).subscribe(value => {
expect(value).toEqual(true);
});
Expand Down Expand Up @@ -115,7 +115,7 @@ describe('DaffProductPageResolver', () => {
],
});

resolver = TestBed.inject(DaffProductPageResolver);
resolver = TestBed.inject(DaffProductPageIdResolver);
ProductFactory = TestBed.inject(DaffProductFactory);
stubProduct = ProductFactory.create();
store = TestBed.inject(Store);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { isPlatformBrowser } from '@angular/common';
import {
Inject,
Injectable,
PLATFORM_ID,
} from '@angular/core';
import {
ActivatedRouteSnapshot,
Resolve,
} from '@angular/router';
import { ofType } from '@ngrx/effects';
import {
ActionsSubject,
Store,
} from '@ngrx/store';
import {
Observable,
of,
} from 'rxjs';
import {
mapTo,
take,
} from 'rxjs/operators';

import {
DaffProductPageLoad,
DaffProductPageActionTypes,
} from '../../actions/public_api';
import { DaffProductReducersState } from '../../reducers/public_api';

/**
* Resolves product data for product pages, and will only resolve the url after a product request succeeds or fails. This resolver expects a url
* of the form `some/url/{id}` where `{id}` is the product id.
*/
@Injectable({
providedIn: 'root',
})
export class DaffProductPageIdResolver implements Resolve<Observable<boolean>> {
constructor(
@Inject(PLATFORM_ID) private platformId: string,
private store: Store<DaffProductReducersState>,
private dispatcher: ActionsSubject,
) { }

resolve(route: ActivatedRouteSnapshot): Observable<boolean> {
this.store.dispatch(new DaffProductPageLoad(route.paramMap.get('id')));

return isPlatformBrowser(this.platformId) ? of(true) : this.dispatcher.pipe(
ofType(DaffProductPageActionTypes.ProductPageLoadSuccessAction, DaffProductPageActionTypes.ProductPageLoadFailureAction),
mapTo(true),
take(1),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {
ɵPLATFORM_BROWSER_ID,
ɵPLATFORM_SERVER_ID,
} from '@angular/common';
import { PLATFORM_ID } from '@angular/core';
import {
TestBed,
waitForAsync,
} from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { provideMockActions } from '@ngrx/effects/testing';
import {
StoreModule,
combineReducers,
Store,
} from '@ngrx/store';
import { fail } from 'assert';
import { Observable } from 'rxjs';

import { DaffProduct } from '@daffodil/product';
import {
DaffProductPageLoadByUrl,
DaffProductPageLoadSuccess,
DaffProductPageLoadFailure,
daffProductReducers,
DaffProductReducersState,
DAFF_PRODUCT_STORE_FEATURE_KEY,
} from '@daffodil/product/state';
import { DaffProductFactory } from '@daffodil/product/testing';

import { DaffProductPageUriResolver } from './product-page-uri.resolver';

describe('DaffProductPageUriResolver', () => {
const actions$: Observable<any> = null;
let resolver: DaffProductPageUriResolver;
let store: Store<DaffProductReducersState>;
let ProductFactory: DaffProductFactory;
let stubProduct: DaffProduct;
let route: ActivatedRoute;

describe('resolve - on the server', () => {

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({
[DAFF_PRODUCT_STORE_FEATURE_KEY]: combineReducers(daffProductReducers),
}),
],
providers: [
provideMockActions(() => actions$),
{
provide: ActivatedRoute,
useValue: { snapshot: { paramMap: { get: () => '123' }, toString: () => '123' }},
},
{ provide: PLATFORM_ID, useValue: ɵPLATFORM_SERVER_ID },
],
});

resolver = TestBed.inject(DaffProductPageUriResolver);
ProductFactory = TestBed.inject(DaffProductFactory);
stubProduct = ProductFactory.create();
store = TestBed.inject(Store);
route = TestBed.inject(ActivatedRoute);
}));

it('should dispatch a DaffProductPageLoadByUrl action with the correct product url', () => {
spyOn(store, 'dispatch');
resolver.resolve( route.snapshot );
expect(store.dispatch).toHaveBeenCalledWith(
new DaffProductPageLoadByUrl(route.snapshot.toString()),
);
});

it('should resolve when DaffProductPageLoadSuccess is dispatched', () => {
resolver.resolve(route.snapshot).subscribe(value => {
expect(value).toEqual(true);
});

store.dispatch(new DaffProductPageLoadSuccess(stubProduct));
});

it('should resolve when DaffProductPageLoadFailure is dispatched', () => {
resolver.resolve(route.snapshot).subscribe(value => {
expect(value).toEqual(true);
});

store.dispatch(new DaffProductPageLoadFailure(null));
});

it('should not resolve without a product load success or failure', () => {
resolver.resolve(route.snapshot).subscribe(() => {
fail();
});
expect(true).toBeTruthy();
});
});

describe('resolve - in the browser', () => {

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({
[DAFF_PRODUCT_STORE_FEATURE_KEY]: combineReducers(daffProductReducers),
}),
],
providers: [
provideMockActions(() => actions$),
{
provide: ActivatedRoute,
useValue: { snapshot: { paramMap: { get: () => '123' }, toString: () => '123' }},
},
{ provide: PLATFORM_ID, useValue: ɵPLATFORM_BROWSER_ID },
],
});

resolver = TestBed.inject(DaffProductPageUriResolver);
ProductFactory = TestBed.inject(DaffProductFactory);
stubProduct = ProductFactory.create();
store = TestBed.inject(Store);
route = TestBed.inject(ActivatedRoute);
}));

it('should dispatch a DaffProductPageLoadByUrl action with the correct product url', () => {
spyOn(store, 'dispatch');
resolver.resolve( route.snapshot );
expect(store.dispatch).toHaveBeenCalledWith(
new DaffProductPageLoadByUrl(route.snapshot.toString()),
);
});

it('should resolve without a product load success or failure', () => {
resolver.resolve(route.snapshot).subscribe((value) => {
expect(value).toBeTruthy();
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { isPlatformBrowser } from '@angular/common';
import {
Inject,
Injectable,
PLATFORM_ID,
} from '@angular/core';
import {
ActivatedRouteSnapshot,
Resolve,
} from '@angular/router';
import { ofType } from '@ngrx/effects';
import {
ActionsSubject,
Store,
} from '@ngrx/store';
import {
Observable,
of,
} from 'rxjs';
import {
mapTo,
take,
} from 'rxjs/operators';

import {
DaffProductPageLoadByUrl,
DaffProductPageActionTypes,
} from '../../actions/public_api';
import { DaffProductReducersState } from '../../reducers/public_api';

/**
* Resolves product data for product pages, and will only resolve the url
* after a product request succeeds or fails. This resolver will take a full
* a url of the form `some/url.html` and attempt to resolve a product from it.
*/
@Injectable({
providedIn: 'root',
})
export class DaffProductPageUriResolver implements Resolve<Observable<boolean>> {
constructor(
@Inject(PLATFORM_ID) private platformId: string,
private store: Store<DaffProductReducersState>,
private dispatcher: ActionsSubject,
) { }

resolve(route: ActivatedRouteSnapshot): Observable<boolean> {
this.store.dispatch(new DaffProductPageLoadByUrl(route.toString()));
damienwebdev marked this conversation as resolved.
Show resolved Hide resolved

return isPlatformBrowser(this.platformId) ? of(true) : this.dispatcher.pipe(
ofType(DaffProductPageActionTypes.ProductPageLoadSuccessAction, DaffProductPageActionTypes.ProductPageLoadFailureAction),
mapTo(true),
take(1),
);
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,11 @@
import { isPlatformBrowser } from '@angular/common';
import {
Inject,
Injectable,
PLATFORM_ID,
} from '@angular/core';
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
Resolve,
} from '@angular/router';
import { ofType } from '@ngrx/effects';
import {
ActionsSubject,
Store,
} from '@ngrx/store';
import {
Observable,
of,
} from 'rxjs';
import {
mapTo,
take,
} from 'rxjs/operators';
import { Observable } from 'rxjs';

import {
DaffProductPageActionTypes,
DaffProductPageLoad,
} from '../../actions/product-page.actions';
import { DaffProductReducersState } from '../../reducers/public_api';
import { DaffProductPageIdResolver } from '../product-page-id/product-page-id.resolver';

/**
* Resolves product data for product pages, and will only resolve the url after a product page request succeeds or fails. This resolver expects a url
Expand All @@ -37,18 +16,10 @@ import { DaffProductReducersState } from '../../reducers/public_api';
})
export class DaffProductPageResolver implements Resolve<Observable<boolean>> {
lderrickable marked this conversation as resolved.
Show resolved Hide resolved
constructor(
@Inject(PLATFORM_ID) private platformId: string,
private store: Store<DaffProductReducersState>,
private dispatcher: ActionsSubject,
) {}
private productPageIdResolver: DaffProductPageIdResolver,
) { }

resolve(route: ActivatedRouteSnapshot): Observable<boolean> {
this.store.dispatch(new DaffProductPageLoad(route.paramMap.get('id')));

return isPlatformBrowser(this.platformId) ? of(true) : this.dispatcher.pipe(
ofType(DaffProductPageActionTypes.ProductPageLoadSuccessAction, DaffProductPageActionTypes.ProductPageLoadFailureAction),
mapTo(true),
take(1),
);
return this.productPageIdResolver.resolve(route);
}
}
2 changes: 2 additions & 0 deletions libs/product/state/src/resolvers/public_api.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { DaffProductPageResolver } from './product-page/product-page.resolver';
export { DaffProductPageIdResolver } from './product-page-id/product-page-id.resolver';
export { DaffProductPageUriResolver } from './product-page-uri/product-page-uri.resolver';