Skip to content

Commit

Permalink
feat: Add quick order cart form (#12836)
Browse files Browse the repository at this point in the history
feat: Add quick order cart form (#12696, #12697)
  • Loading branch information
dydome authored Jun 18, 2021
1 parent 1320441 commit fc8dd90
Show file tree
Hide file tree
Showing 14 changed files with 490 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
export const quickOrderCartForm = {
entriesWasAdded: '({{ quantity }}) {{ product }} has been added to the cart',
entryWasAdded: '{{ product }} has been added to the cart',
noResults: 'We could not find any products',
stockLevelReached: 'The maximum stock level has been reached',
title: 'Quick Order',
productCode: 'Product Code',
addToCart: 'Add To Cart',
product: 'Product',
products: 'Products',
};

export const quickOrderContainer = {
addProducts: 'Add Products/Skus',
emptyList: 'Empty list',
addToCart: 'Add to cart',
};

export const quickOrderForm = {
placeholder: 'Enter Product SKU',
};
Expand All @@ -14,13 +32,8 @@ export const quickOrderList = {
outOfStock: 'Out of Stock',
};

export const quickOrderContainer = {
addProducts: 'Add Products/Skus',
emptyList: 'Empty list',
addToCart: 'Add to cart',
};

export const quickOrder = {
quickOrderCartForm,
quickOrderContainer,
quickOrderForm,
quickOrderList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@ export const quickOrderTranslations: TranslationResources = {

// expose all translation chunk mapping for quickOrder feature
export const quickOrderTranslationChunksConfig: TranslationChunksConfig = {
quickOrder: ['quickOrderContainer', 'quickOrderForm', 'quickOrderList'],
quickOrder: [
'quickOrderCartForm',
'quickOrderContainer',
'quickOrderForm',
'quickOrderList',
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<ng-container *ngIf="cart$ | async as cart">
<div class="cx-cart-quick-form-title">
{{ 'quickOrderCartForm.title' | cxTranslate }}
</div>
<div class="form-group">
<form (ngSubmit)="applyQuickOrder()" [formGroup]="orderForm">
<div class="cx-cart-quick-form-container">
<input
class="form-control input-product-code"
formControlName="productCode"
placeholder="{{ 'quickOrderCartForm.productCode' | cxTranslate }}"
type="text"
/>
<input
[min]="min"
class="form-control input-quantity"
formControlName="quantity"
type="number"
/>
<button
[class.disabled]="cartIsLoading$ | async"
[disabled]="(cartIsLoading$ | async) || orderForm.invalid"
class="btn btn-block btn-action apply-coupon-button"
type="submit"
>
{{ 'quickOrderCartForm.addToCart' | cxTranslate }}
</button>
<cx-form-errors
[control]="orderForm.get('productCode')"
></cx-form-errors>
<cx-form-errors [control]="orderForm.get('quantity')"></cx-form-errors>
</div>
</form></div
></ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { StoreModule } from '@ngrx/store';
import {
ActiveCartService,
Cart,
CartAddEntryFailEvent,
CartAddEntrySuccessEvent,
EventService,
GlobalMessageService,
GlobalMessageType,
I18nTestingModule,
Translatable,
} from '@spartacus/core';
import { FormErrorsModule } from 'projects/storefrontlib/src/shared';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { CartQuickFormComponent } from './cart-quick-form.component';

const mockCart: Cart = {
code: '123456789',
description: 'testCartDescription',
name: 'testCartName',
};

const mockUserId = 'test-user';
const mockCartId = '123456789';

const mockCartAddEntryFailEvent: CartAddEntryFailEvent = {
cartCode: mockCartId,
cartId: mockCartId,
productCode: '123456789',
quantity: 1,
userId: mockUserId,
};
const mockCartAddEntrySuccessEvent: CartAddEntrySuccessEvent = {
cartCode: mockCartId,
cartId: mockCartId,
deliveryModeChanged: false,
entry: {
product: {
name: 'test-product',
},
},
productCode: '123456789',
quantity: 1,
quantityAdded: 1,
userId: mockUserId,
};

const cart$ = new BehaviorSubject<Cart>(mockCart);

class MockEventService implements Partial<EventService> {
get(): Observable<any> {
return of();
}
}

class MockGlobalMessageService implements Partial<GlobalMessageService> {
add(
_text: string | Translatable,
_type: GlobalMessageType,
_timeout?: number
): void {}
}

class MockActiveCartService implements Partial<ActiveCartService> {
getActive(): Observable<Cart> {
return cart$.asObservable();
}
getActiveCartId(): Observable<string> {
return of('123456789');
}
isStable(): Observable<boolean> {
return of(true);
}
addEntry(_productCode: string, _quantity: number): void {}
}

fdescribe('CartQuickFormComponent', () => {
let component: CartQuickFormComponent;
let fixture: ComponentFixture<CartQuickFormComponent>;
let activeCartService: ActiveCartService;
let eventService: EventService;
let globalMessageService: GlobalMessageService;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
FormErrorsModule,
I18nTestingModule,
ReactiveFormsModule,
StoreModule.forRoot({}),
],
declarations: [CartQuickFormComponent],
providers: [
{ provide: ActiveCartService, useClass: MockActiveCartService },
{
provide: EventService,
useClass: MockEventService,
},
{ provide: GlobalMessageService, useClass: MockGlobalMessageService },
],
}).compileComponents();

fixture = TestBed.createComponent(CartQuickFormComponent);
component = fixture.componentInstance;

activeCartService = TestBed.inject(ActiveCartService);
eventService = TestBed.inject(EventService);
globalMessageService = TestBed.inject(GlobalMessageService);

fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should create form on init', () => {
expect(component.orderForm.valid).toBeFalsy();
expect(component.orderForm.controls['productCode'].value).toBe('');
expect(component.orderForm.controls['quantity'].value).toBe(1);
});

it('should add entry on form submit', () => {
spyOn(activeCartService, 'addEntry').and.callThrough();

component.orderForm.controls['productCode'].setValue('test');
component.applyQuickOrder();

expect(activeCartService.addEntry).toHaveBeenCalledWith('test', 1);
});

it('should set quantity value to min when it is smaller than min value', () => {
component.min = 3;
component.orderForm.controls['quantity'].setValue(2);
fixture.detectChanges();

expect(component.orderForm.controls['quantity'].value).toEqual(3);
});

it('should show global confirmation message on add entry success event', () => {
spyOn(globalMessageService, 'add').and.callThrough();
spyOn(eventService, 'get').and.returnValue(
of(mockCartAddEntrySuccessEvent)
);

component.ngOnInit();

expect(globalMessageService.add).toHaveBeenCalledWith(
{
key: 'quickOrderCartForm.entryWasAdded',
params: {
product: mockCartAddEntrySuccessEvent.entry.product?.name,
quantity: mockCartAddEntrySuccessEvent.quantityAdded,
},
},
GlobalMessageType.MSG_TYPE_CONFIRMATION
);
});

it('should show global error message on add entry fail event', () => {
spyOn(globalMessageService, 'add').and.callThrough();
spyOn(eventService, 'get').and.returnValue(of(mockCartAddEntryFailEvent));

component.ngOnInit();

expect(globalMessageService.add).toHaveBeenCalledWith(
{
key: 'quickOrderCartForm.noResults',
},
GlobalMessageType.MSG_TYPE_ERROR
);
});
});
Loading

0 comments on commit fc8dd90

Please sign in to comment.