Skip to content

Commit

Permalink
Edit quote details (quote draft page) (#17730)
Browse files Browse the repository at this point in the history
Closes CXSPA-4230
  • Loading branch information
Larisa-Staroverova authored Aug 15, 2023
1 parent 0e1a6b1 commit 6c8cda1
Show file tree
Hide file tree
Showing 17 changed files with 1,262 additions and 208 deletions.
7 changes: 6 additions & 1 deletion feature-libs/quote/assets/translations/en/quote.i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,18 @@ export const quote = {
allProducts: 'All Products',
},
details: {
information: 'Quote Information',
code: 'Quote ID',
name: 'Name',
created: 'Created',
lastUpdated: 'Last Updated',
estimatedTotal: 'Estimated Total',
total: 'Total',
description: 'Description',
expiryDate: 'Expiry Date',
estimateAndDate: 'Estimated & Date',
update: 'Update',
expirationTime: 'Expiry Date',
charactersLeft: 'characters left: {{count}}',
},
links: {
newCart: 'New Cart',
Expand Down
8 changes: 8 additions & 0 deletions feature-libs/quote/components/details/edit/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2023 SAP Spartacus team <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

export * from './quote-details-edit.component';
export * from './quote-details-edit.module';
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<div *ngIf="content" class="cx-card">
<!-- Card Body -->
<div class="card-body cx-card-body cx-card-edit">
<!-- Card title -->
<span class="cx-card-title">
{{ 'quote.details.information' | cxTranslate }}
</span>
<!-- Card Content -->
<div class="cx-card-container">
<!-- Card Label -->
<div class="cx-card-label-container">
<form [formGroup]="editForm">
<div class="cx-card-paragraph">
<div class="cx-card-paragraph-title">
{{ 'quote.details.name' | cxTranslate }}
</div>
<div class="form-group">
<input
class="form-control"
[maxLength]="content.charactersLimit"
type="text"
name="name"
formControlName="name"
/>
</div>
</div>
<div class="cx-card-paragraph">
<div class="cx-card-paragraph-title">
{{ 'quote.details.description' | cxTranslate }}
</div>
<div class="form-group">
<textarea
class="form-control"
[maxLength]="content.charactersLimit"
rows="4"
name="description"
formControlName="description"
></textarea>
<p *ngIf="content.charactersLimit" class="cx-info-text">
{{
'quote.details.charactersLeft'
| cxTranslate
: {
count: getCharactersLeft(
'description',
content.charactersLimit
)
}
}}
</p>
</div>
</div>
</form>
</div>
</div>
<!-- Edit Mode Actions -->
<div class="cx-card-button-container">
<button class="btn btn-tertiary" (click)="cancel()">
{{ 'common.cancel' | cxTranslate }}
</button>
<button class="btn btn-block btn-secondary" (click)="save()">
{{ 'common.save' | cxTranslate }}
</button>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
import { Component, DebugElement, Input } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { I18nTestingModule } from '@spartacus/core';
import { ICON_TYPE } from '@spartacus/storefront';
import { CommonQuoteTestUtilsService } from '../../testing/common-quote-test-utils.service';
import {
EditCard,
QuoteDetailsEditComponent,
} from './quote-details-edit.component';

const mockCard: EditCard = {
name: 'Quote name',
description: 'Here you could enter a long description for the current quote',
charactersLimit: 255,
};

@Component({
selector: 'cx-icon',
template: '',
})
class MockCxIconComponent {
@Input() type: ICON_TYPE;
}

describe('QuoteDetailsEditComponent', () => {
let fixture: ComponentFixture<QuoteDetailsEditComponent>;
let component: QuoteDetailsEditComponent;
let htmlElem: HTMLElement;
let debugElement: DebugElement;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [I18nTestingModule, ReactiveFormsModule],
declarations: [QuoteDetailsEditComponent, MockCxIconComponent],
}).compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(QuoteDetailsEditComponent);
htmlElem = fixture.nativeElement;
debugElement = fixture.debugElement;
component = fixture.componentInstance;
component.content = mockCard;
fixture.detectChanges();

spyOn(component.saveCard, 'emit').and.callThrough();
spyOn(component.cancelCard, 'emit').and.callThrough();
});

it('should create and render component accordingly', () => {
expect(component).toBeTruthy();

CommonQuoteTestUtilsService.expectElementPresent(
expect,
htmlElem,
'.cx-card'
);

CommonQuoteTestUtilsService.expectElementPresent(
expect,
htmlElem,
'.cx-card-edit'
);

CommonQuoteTestUtilsService.expectElementToContainText(
expect,
htmlElem,
'.cx-card-title',
'quote.details.information'
);

CommonQuoteTestUtilsService.expectElementPresent(
expect,
htmlElem,
'.cx-card-container'
);

CommonQuoteTestUtilsService.expectElementPresent(
expect,
htmlElem,
'.cx-card-label-container'
);

CommonQuoteTestUtilsService.expectNumberOfElementsPresent(
expect,
htmlElem,
'.cx-card-paragraph',
2
);

CommonQuoteTestUtilsService.expectNumberOfElementsPresent(
expect,
htmlElem,
'.cx-card-paragraph-title',
2
);

CommonQuoteTestUtilsService.expectNumberOfElementsPresent(
expect,
htmlElem,
'.form-group',
2
);

CommonQuoteTestUtilsService.expectNumberOfElementsPresent(
expect,
htmlElem,
'input',
1
);

CommonQuoteTestUtilsService.expectNumberOfElementsPresent(
expect,
htmlElem,
'textarea',
1
);

CommonQuoteTestUtilsService.expectElementToContainText(
expect,
htmlElem,
'.cx-card-paragraph-title',
'quote.details.description',
1
);

CommonQuoteTestUtilsService.expectElementToContainText(
expect,
htmlElem,
'.cx-info-text',
'quote.details.charactersLeft count:194'
);

CommonQuoteTestUtilsService.expectElementPresent(
expect,
htmlElem,
'.cx-card-button-container'
);

CommonQuoteTestUtilsService.expectElementToContainText(
expect,
htmlElem,
'button.btn-tertiary',
'common.cancel'
);

CommonQuoteTestUtilsService.expectElementToContainText(
expect,
htmlElem,
'button.btn-secondary',
'common.save'
);
});

describe('handle action events', () => {
it('should emit cancel event', () => {
const cancelButton = CommonQuoteTestUtilsService.getNativeElement(
debugElement,
'button.btn-tertiary'
);
cancelButton.click();
expect(component.cancelCard.emit).toHaveBeenCalled();
});

it('should emit edit event for disabling edit mode', () => {
const saveButton = CommonQuoteTestUtilsService.getNativeElement(
debugElement,
'button.btn-secondary'
);
saveButton.click();
expect(component.saveCard.emit).toHaveBeenCalled();
});

it('should emit edit event with an edited name and disabling edit mode', () => {
const newTextForTitle1: any = 'New title for name';
component.editForm.get('name')?.setValue(newTextForTitle1);
component.editForm.get('name')?.markAsDirty();
fixture.detectChanges();
const saveButton = CommonQuoteTestUtilsService.getNativeElement(
debugElement,
'button.btn-secondary'
);
saveButton.click();
expect(component.saveCard.emit).toHaveBeenCalled();
let arg: any = (component.saveCard.emit as any).calls.mostRecent()
.args[0];
expect(arg.name).toEqual(newTextForTitle1);
});

it('should emit edit event with an edited name, description and disabling edit mode', () => {
const newTextForTitle1: any = 'New title for name';
const newTextForTitle2: any = 'Here could be found a long description';
component.editForm.get('name')?.setValue(newTextForTitle1);
component.editForm.get('name')?.markAsDirty();
component.editForm.get('description')?.setValue(newTextForTitle2);
component.editForm.get('description')?.markAsDirty();
fixture.detectChanges();
const saveButton = CommonQuoteTestUtilsService.getNativeElement(
debugElement,
'button.btn-secondary'
);
saveButton.click();
expect(component.saveCard.emit).toHaveBeenCalled();
let arg: any = (component.saveCard.emit as any).calls.mostRecent()
.args[0];
expect(arg.name).toEqual(newTextForTitle1);
expect(arg.description).toEqual(newTextForTitle2);
});
});

describe('getCharactersLeft', () => {
function setValue(formControlName: string, value: any): void {
component.editForm.get(formControlName)?.setValue(value);
component.editForm.get(formControlName)?.markAsTouched();
fixture.detectChanges();
}

it('should calculate left characters', () => {
const formControlName = 'description';
setValue(formControlName, 'New title for name');

if (component.content.charactersLimit) {
let charactersLeft =
component.content.charactersLimit -
component.editForm.get(formControlName)?.value?.length;
expect(
component['getCharactersLeft'](
formControlName,
component.content.charactersLimit
)
).toBe(charactersLeft);

charactersLeft =
component.content.charactersLimit -
component.editForm.get(formControlName)?.value?.length;
expect(
component['getCharactersLeft'](
formControlName,
component.content.charactersLimit
)
).toBe(charactersLeft);

setValue(formControlName, '');

charactersLeft =
component.content.charactersLimit -
component.editForm.get(formControlName)?.value?.length;
expect(
component['getCharactersLeft'](
formControlName,
component.content.charactersLimit
)
).toBe(charactersLeft);
}
});
});
});
Loading

0 comments on commit 6c8cda1

Please sign in to comment.