Skip to content

Commit

Permalink
refactor: introduce product context (#403)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: refactoring the way product specific components retrieve data with context facade
  • Loading branch information
dhhyi committed Jan 29, 2021
1 parent eb21405 commit c767f90
Show file tree
Hide file tree
Showing 186 changed files with 3,468 additions and 3,232 deletions.
20 changes: 18 additions & 2 deletions e2e/cypress/integration/pages/checkout/cart.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,24 @@ export class CartPage {
return {
quantity: {
set: (num: number) =>
cy.get(this.tag).find('input[data-testing-id="quantity"]').eq(idx).clear().type(num.toString()).blur(),
get: () => cy.get(this.tag).find('input[data-testing-id="quantity"]').eq(idx).invoke('val'),
cy
.get(this.tag)
.find('input[data-testing-id="quantity"]:visible')
.eq(idx)
.click()
.wait(1000)
.clear()
.wait(1000)
.type(num.toString())
.wait(1000)
.blur(),
get: () =>
cy
.get(this.tag)
.find('input[data-testing-id="quantity"]:visible')
.eq(idx)
.invoke('val')
.then(v => +v),
},
remove: () => cy.get(this.tag).find('svg[data-icon="trash-alt"]').eq(idx).click(),
sku: cy.get(this.tag).find('.product-id').eq(idx),
Expand Down
6 changes: 6 additions & 0 deletions e2e/cypress/integration/pages/shopping/product-list.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export class ProductListModule {
return cy.get(this.contextSelector).find(`ish-product-item div[data-testing-sku="${sku}"]`);
}

setProductTileQuantity(sku: string, quantity: number) {
const input = cy.get(this.contextSelector).find(`[data-testing-sku="${sku}"]`).find('[data-testing-id="quantity"]');
input.clear();
input.type(quantity.toString());
}

gotoProductDetailPageBySku(sku: string, wait: () => unknown = waitLoadingEnd) {
this.productTile(sku).scrollIntoView().find('a.product-title').wait(500).click();
wait();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe('Basket Handling', () => {
page.header.miniCart.total.should('contain', _.product.price * 4);
});
at(CartPage, page => {
page.lineItem(0).quantity.get().should('equal', '4');
page.lineItem(0).quantity.get().should('equal', 4);
});
});

Expand Down Expand Up @@ -133,10 +133,10 @@ describe('Basket Handling', () => {
at(CartPage, page => {
page.lineItems.should('have.length', 1);
page.lineItem(0).quantity.set(2);
waitLoadingEnd();
waitLoadingEnd(2000);
page.subtotal.should('contain', _.product.price * 2);
page.lineItem(0).remove();
waitLoadingEnd();
waitLoadingEnd(2000);
page.header.miniCart.text.should('contain', '0 items');
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { ProductDetailPage } from '../../pages/shopping/product-detail.page';

const _ = {
retailSetSKU: '201807198',
retailSetParts: ['201807195', '201807197', '201807196', '201807199'],
retailSetParts: [
{ sku: '201807195', quantity: 1 },
{ sku: '201807197', quantity: 0 },
{ sku: '201807196', quantity: 1 },
{ sku: '201807199', quantity: 3 },
],
};

describe('Shopping User', () => {
Expand All @@ -13,12 +18,18 @@ describe('Shopping User', () => {
it('starting at product detail page of a retail set', () => {
at(ProductDetailPage, page => {
page.sku.should('have.text', _.retailSetSKU);
page.retailSetParts.visibleProductSKUs.should('deep.equal', _.retailSetParts);
page.retailSetParts.visibleProductSKUs.should(
'deep.equal',
_.retailSetParts.map(e => e.sku)
);
});
});

it('adding retail set to cart', () => {
at(ProductDetailPage, page => {
_.retailSetParts.forEach(part => {
page.retailSetParts.setProductTileQuantity(part.sku, part.quantity);
});
page.addProductToCart();
cy.wait(2000);
page.header.miniCart.goToCart();
Expand All @@ -27,10 +38,15 @@ describe('Shopping User', () => {

it('should see the product retail set as multiple items in cart', () => {
at(CartPage, page => {
page.lineItems.should('have.length', 4);
for (let idx = 0; idx < _.retailSetParts.length; idx++) {
page.lineItem(idx).sku.should('contain', _.retailSetParts[idx]);
}
const parts = _.retailSetParts.filter(p => !!p.quantity);
page.lineItems.should('have.length', parts.length);

let idx = 0;
parts.forEach(part => {
page.lineItem(idx).sku.should('contain', part.sku);
page.lineItem(idx).quantity.get().should('equal', part.quantity);
idx++;
});
});
});
});
3 changes: 3 additions & 0 deletions src/app/core/directives.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import { NgModule } from '@angular/core';
import { ClickOutsideDirective } from './directives/click-outside.directive';
import { IdentityProviderCapabilityDirective } from './directives/identity-provider-capability.directive';
import { IntersectionObserverDirective } from './directives/intersection-observer.directive';
import { ProductContextDirective } from './directives/product-context.directive';
import { ServerHtmlDirective } from './directives/server-html.directive';

@NgModule({
declarations: [
ClickOutsideDirective,
IdentityProviderCapabilityDirective,
IntersectionObserverDirective,
ProductContextDirective,
ServerHtmlDirective,
],
exports: [
ClickOutsideDirective,
IdentityProviderCapabilityDirective,
IntersectionObserverDirective,
ProductContextDirective,
ServerHtmlDirective,
],
})
Expand Down
72 changes: 72 additions & 0 deletions src/app/core/directives/product-context.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Directive, Input, OnChanges, OnInit, Optional, Output, SimpleChanges, SkipSelf } from '@angular/core';

import { ProductContextDisplayProperties, ProductContextFacade } from 'ish-core/facades/product-context.facade';
import { ProductCompletenessLevel, SkuQuantityType } from 'ish-core/models/product/product.model';

@Directive({
selector: '[ishProductContext]',
providers: [ProductContextFacade],
})
export class ProductContextDirective implements OnInit, OnChanges {
@Input() completeness: 'List' | 'Detail' = 'List';
@Input() propagateIndex: number;

@Output() skuChange = this.context.select('sku');
@Output() quantityChange = this.context.select('quantity');

constructor(
@SkipSelf() @Optional() private parentContext: ProductContextFacade,
private context: ProductContextFacade
) {
this.context.hold(this.context.$, () => this.propagate());
}

@Input()
set sku(sku: string) {
this.context.set('sku', () => sku);
}

@Input()
set quantity(quantity: number) {
this.context.set('quantity', () => quantity);
}

@Input()
set allowZeroQuantity(allowZeroQuantity: boolean) {
this.context.set('allowZeroQuantity', () => allowZeroQuantity);
}

@Input()
set parts(parts: SkuQuantityType[]) {
this.context.set('parts', () => parts);
}

@Input()
set configuration(config: Partial<ProductContextDisplayProperties>) {
this.context.config = config;
}

private propagate() {
if (this.propagateIndex !== undefined) {
if (!this.parentContext) {
throw new Error('cannot propagate without parent context');
}
this.parentContext.propagate(
this.propagateIndex,
this.context.get('propagateActive') ? this.context.get() : undefined
);
}
}

ngOnChanges(changes: SimpleChanges): void {
if (changes?.propagateActive) {
this.propagate();
}
}

ngOnInit() {
this.context.set('requiredCompletenessLevel', () =>
this.completeness === 'List' ? ProductCompletenessLevel.List : ProductCompletenessLevel.Detail
);
}
}
Loading

0 comments on commit c767f90

Please sign in to comment.