Skip to content

Commit

Permalink
feat: manage multiple personal wishlists (#34, #129)
Browse files Browse the repository at this point in the history
* feat: wishlist feature added
* smaller improvements after review
* refactor: set wishlist breadcrumb in effect
* changes after review
* refactor: use upsert
* refactor: suppress warning of missing wishlist feature
* feat: select preferred wishlist in wishlist-link when available
* ui improvements for wishlist items
* i18n: unified wording in English and adapted localizations

Co-authored-by: cbratsch <57700960+cbratsch@users.noreply.github.com>
Co-authored-by: Danilo Hoffmann <dhhyi@aol.com>
Co-authored-by: MWallnisch <42213577+MWallnisch@users.noreply.github.com>
  • Loading branch information
4 people committed Feb 28, 2020
1 parent 0062272 commit 199f25b
Show file tree
Hide file tree
Showing 104 changed files with 4,339 additions and 83 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Expand Up @@ -150,6 +150,7 @@ jobs:
'checkout/*b2c*',
'shopping/*b2c*',
'system/*b2c*',
'extras/*b2c*',
# TODO: include remaining in a general way
# '!(shopping|account|checkout)*/*b2c*'
# '@(cms|contact)*/*b2c*'
Expand Down
2 changes: 1 addition & 1 deletion e2e/cypress/integration/framework/index.ts
Expand Up @@ -16,7 +16,7 @@ function onPage<T extends Page>(page: new () => T) {
}

export function at<T extends Page>(type: new () => T, callback?: (page: T) => void) {
onPage(type).should('be.hidden');
onPage(type).should('exist');
waitLoadingEnd();
if (callback) {
callback(currentPage as T);
Expand Down
34 changes: 34 additions & 0 deletions e2e/cypress/integration/pages/account/add-to-wishlist.module.ts
@@ -0,0 +1,34 @@
export class AddToWishlistModule {
constructor(private contextSelector: string = 'ish-product-listing') {}

addProductToWishlistFromPage(title: string = '', modal: boolean = false) {
if (modal) {
cy.get(`[data-testing-id="${title}"]`).click();
cy.get('[class="modal-footer"] button.btn-primary').click();
}
this.closeAddProductToWishlistModal('link');
}

addProductToWishlistFromList(product: string, title: string, modal: boolean = true) {
if (modal) {
cy.get(this.contextSelector)
.find(`ish-product-item div[data-testing-sku="${product}"] button.add-to-wishlist`)
.click();
cy.get(`[data-testing-id="${title}"]`).click();
cy.get('[class="modal-footer"] button.btn-primary').click();
this.closeAddProductToWishlistModal('link');
} else {
cy.get(this.contextSelector)
.find(`ish-product-item div[data-testing-sku="${product}"] button.add-to-wishlist`)
.click();
this.closeAddProductToWishlistModal('link');
}
}

private closeAddProductToWishlistModal(mode: 'link' | 'x') {
cy.wait(500);
mode === 'link'
? cy.get('[data-testing-id="wishlist-success-link"] a').click()
: cy.get('[class="modal-header"] button').click();
}
}
6 changes: 3 additions & 3 deletions e2e/cypress/integration/pages/account/login.page.ts
Expand Up @@ -28,13 +28,13 @@ export class LoginPage {

submit() {
cy.server()
.route('GET', '**/customers/**')
.as('customers');
.route('GET', /.*\/customers\/-.*/)
.as('currentCustomer');
cy.wait(500);

cy.get('button[name="login"]').click();

return cy.wait('@customers');
return cy.wait('@currentCustomer');
}

get errorText() {
Expand Down
4 changes: 4 additions & 0 deletions e2e/cypress/integration/pages/account/my-account.page.ts
Expand Up @@ -32,4 +32,8 @@ export class MyAccountPage {
navigateToAddresses() {
cy.get('a[data-testing-id="addresses-link"]').click();
}

navigateToWishlists() {
cy.get('a[data-testing-id="wishlists-link"]').click();
}
}
Expand Up @@ -12,14 +12,14 @@ export class ProfileEditPasswordPage {

submit() {
cy.server()
.route('PUT', '**/customers/**')
.as('customers');
.route('PUT', '**/password')
.as('passwordChange');
cy.wait(500);

cy.get(this.tag)
.find('button[type="submit"]')
.click();

return cy.wait('@customers');
return cy.wait('@passwordChange');
}
}
80 changes: 80 additions & 0 deletions e2e/cypress/integration/pages/account/wishlists-details.page.ts
@@ -0,0 +1,80 @@
import { HeaderModule } from '../header.module';

export class WishlistsDetailsPage {
readonly tag = 'ish-account-wishlist-detail-page';

readonly header = new HeaderModule();

static navigateToOverviewPage() {
cy.get('[href="/account/wishlists"]')
.first()
.click();
}

get listItem() {
return cy.get('ish-account-wishlist-detail-line-item');
}

get listItemLink() {
return cy.get('ish-account-wishlist-detail-line-item').find('a[data-testing-id="wishlist-product-link"]');
}

get wishlistTitle() {
return cy
.get('ish-account-wishlist-detail-page')
.find('h1')
.invoke('text');
}

get wishlistPreferredTextElement() {
return cy.get('[data-testing-id="preferred-wishlist-text"]');
}

getWishlistItemById(id: string) {
return cy
.get('span')
.contains(id)
.closest('ish-account-wishlist-detail-line-item')
.parent();
}

editWishlistDetails(name: string, preferred: boolean) {
cy.get('[data-testing-id="wishlist-details-edit"]').click();
cy.get('ngb-modal-window')
.find('[data-testing-id="title"]')
.clear()
.type(name);
cy.get('[data-testing-id="preferred"]').uncheck();
if (preferred) {
cy.get('[data-testing-id="preferred"]').check();
}
cy.get('[data-testing-id="wishlist-dialog-submit"]').click();
}

deleteWishlist(id: string) {
this.getWishlistItemById(id)
.find('[data-testing-id="delete-wishlist"]')
.click();
}

moveProductToWishlist(productId: string, listName: string) {
this.getWishlistItemById(productId)
.find('[data-testing-id="move-wishlist"]')
.click();
cy.get(`[data-testing-id="${listName}"]`).check();
cy.get('ngb-modal-window')
.find('button[class="btn btn-primary"]')
.click();
cy.get('[data-testing-id="wishlist-success-link"] a').click();
}

addProductToBasket(productId: string, quantity: number) {
this.getWishlistItemById(productId)
.find('[data-testing-id="quantity"]')
.clear()
.type(quantity.toString());
this.getWishlistItemById(productId)
.find('[data-testing-id="addToCartButton"]')
.click();
}
}
49 changes: 49 additions & 0 deletions e2e/cypress/integration/pages/account/wishlists-overview.page.ts
@@ -0,0 +1,49 @@
import { HeaderModule } from '../header.module';

export class WishlistsOverviewPage {
readonly tag = 'ish-account-wishlist-page';

readonly header = new HeaderModule();

static navigateTo() {
cy.visit('/account/wishlists');
}

addWishlist(name: string, preferred: boolean) {
cy.get('a[data-testing-id="add-wishlist"').click();
cy.get('[data-testing-id="wishlist-dialog-name"]')
.find('[data-testing-id="title"]')
.clear()
.type(name);
if (preferred) {
cy.get('[data-testing-id="wishlist-dialog-preferred"]')
.find('[data-testing-id="preferred"]')
.check();
}
cy.get('[data-testing-id="wishlist-dialog-submit"]').click();
}

deleteWishlistById(id: string) {
this.wishlistsArray
.find('a')
.contains(id)
.closest('[data-testing-id="wishlist-list-item-container"]')
.find('[data-testing-id="delete-wishlist"]')
.click();
cy.get('[data-testing-id="confirm"]').click();
}

goToWishlistDetailLink(name: string) {
cy.get('a')
.contains(name)
.click();
}

get wishlistsArray() {
return cy.get('[data-testing-id="wishlist-list-item"]');
}

get wishlistsTitlesArray() {
return this.wishlistsArray.find('[data-testing-id="wishlist-list-title"]').invoke('text');
}
}
8 changes: 8 additions & 0 deletions e2e/cypress/integration/pages/checkout/cart.page.ts
@@ -1,9 +1,11 @@
import { AddToWishlistModule } from '../account/add-to-wishlist.module';
import { HeaderModule } from '../header.module';

export class CartPage {
readonly tag = 'ish-shopping-basket';

readonly header = new HeaderModule();
readonly addToWishlist = new AddToWishlistModule();

private saveQuoteRequestButton = () => cy.get('[id="createQuote"]');

Expand All @@ -19,10 +21,16 @@ export class CartPage {
this.saveQuoteRequestButton().click();
}

private addToWishlistButton = () => cy.get('ish-shopping-basket').find('[data-testing-id="addToWishlistButton"]');

get lineItems() {
return cy.get(this.tag).find('div.pli-description');
}

addProductToWishlist() {
this.addToWishlistButton().click();
}

lineItem(idx: number) {
return {
quantity: {
Expand Down
11 changes: 11 additions & 0 deletions e2e/cypress/integration/pages/shopping/product-detail.page.ts
@@ -1,3 +1,4 @@
import { AddToWishlistModule } from '../account/add-to-wishlist.module';
import { BreadcrumbModule } from '../breadcrumb.module';
import { HeaderModule } from '../header.module';

Expand All @@ -13,6 +14,8 @@ export class ProductDetailPage {
readonly retailSetParts = new ProductListModule('ish-retail-set-parts');
readonly variations = new ProductListModule('ish-product-master-variations');

readonly addToWishlist = new AddToWishlistModule();

static navigateTo(sku: string, categoryUniqueId?: string) {
if (categoryUniqueId) {
cy.visit(`/category/${categoryUniqueId}/product/${sku}`);
Expand All @@ -25,6 +28,10 @@ export class ProductDetailPage {
private addToCompareButton() {
return cy.get('ish-product-detail').find('ish-product-detail-actions [data-testing-id*="compare"] .share-label');
}
private addToWishlistButton() {
return cy.get('ish-product-detail').find('ish-product-detail-actions [data-testing-id*="wishlist"] .share-label');
}

private addToQuoteRequestButton = () => cy.get('ish-product-detail').find('[data-testing-id="addToQuoteButton"]');
private quantityInput = () => cy.get('ish-product-detail').find('[data-testing-id="quantity"]');

Expand Down Expand Up @@ -66,6 +73,10 @@ export class ProductDetailPage {
this.addToQuoteRequestButton().click();
}

addProductToWishlist() {
this.addToWishlistButton().click();
}

setQuantity(quantity: number) {
this.quantityInput().clear();
this.quantityInput().type(quantity.toString());
Expand Down
2 changes: 2 additions & 0 deletions e2e/cypress/integration/pages/shopping/product-list.module.ts
@@ -1,6 +1,8 @@
import { waitLoadingEnd } from '../../framework';
import { AddToWishlistModule } from '../account/add-to-wishlist.module';

export class ProductListModule {
readonly addToWishlist = new AddToWishlistModule();
constructor(private contextSelector: string) {}

get visibleProducts() {
Expand Down

0 comments on commit 199f25b

Please sign in to comment.