Skip to content

Commit

Permalink
feat: customer address update in the My Account section (#1315)
Browse files Browse the repository at this point in the history
Co-authored-by: Silke <s.grueber@intershop.de>
  • Loading branch information
DilaraGueler and SGrueber authored Nov 14, 2022
1 parent 80d5f9d commit a98d391
Show file tree
Hide file tree
Showing 14 changed files with 392 additions and 38 deletions.
87 changes: 87 additions & 0 deletions e2e/cypress/e2e/pages/account/addresses.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { fillFormField } from '../../framework';
import { Registration } from '../account/registration.page';
import { HeaderModule } from '../header.module';

export type AddressDetailsTypes = Partial<
Pick<Registration, 'countryCode' | 'companyName1' | 'firstName' | 'lastName' | 'addressLine1' | 'postalCode' | 'city'>
>;
export class AddressesPage {
readonly header = new HeaderModule();
readonly tag = 'ish-account-addresses';

get defaultAddress() {
return cy.get(this.tag).find('[data-testing-id="preferred-invoice-and-shipping-address"]');
}

get furtherAddress() {
return cy.get(this.tag).find('[data-testing-id="further-addresses"]');
}

get shippingAddress() {
return cy.get(this.tag).find('[data-testing-id="preferred-shipping-address"]');
}

get invoiceAddress() {
return cy.get(this.tag).find('[data-testing-id="preferred-invoice-address"]');
}

createAddress() {
cy.get('[data-testing-id="create-address-button"]').click();
}

fillForm(user: string, password: string) {
cy.get('input[data-testing-id="login"]').clear().type(user).blur();
cy.get('input[data-testing-id="password"]').clear().type(password).blur();
return this;
}

fillCreateAddressForm(address: AddressDetailsTypes) {
Object.keys(address).forEach(key => fillFormField('[data-testing-id="create-address-form"]', key, address[key]));
return this;
}

fillUpdateAddressForm(address: AddressDetailsTypes) {
Object.keys(address).forEach(key => fillFormField('[data-testing-id="update-address-form"]', key, address[key]));
return this;
}

cancel() {
cy.get('button').contains('Cancel').click();
}

saveAddress() {
cy.get('button').contains('Save Address').click();
}

selectShippingAddress() {
cy.get('select[placeholder="Change preferred shipping address"]').select(1);
}

selectInvoiceAddress() {
cy.get('select[placeholder="Change preferred invoice address"]').select(2);
}

updateAddress() {
cy.get('[data-testing-id="update-address-button"]').last().click();
}

submit() {
cy.intercept('PUT', '**/customers/**').as('customers');
cy.wait(500);

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

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

deleteAddress() {
cy.get('[data-testing-id="delete-address-icon"]').last().click();
cy.get('button').contains('Delete').click();
}

get successMessage() {
return {
message: cy.get('#toast-container').find('.toast-message'),
};
}
}
98 changes: 98 additions & 0 deletions e2e/cypress/e2e/specs/account/addresses-crud.b2b.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { at } from '../../framework';
import { createB2BUserViaREST } from '../../framework/b2b-user';
import { AddressDetailsTypes, AddressesPage } from '../../pages/account/addresses.page';
import { LoginPage } from '../../pages/account/login.page';
import { Registration, sensibleDefaults } from '../../pages/account/registration.page';

const _ = {
user: {
login: `testuser${new Date().getTime()}@test.intershop.de`,
...sensibleDefaults,
companyName1: 'Big Foods',
} as Registration,
address: {
countryCode: 'DE',
companyName1: 'Intershop',
firstName: 'Pablo',
lastName: 'Parked',
addressLine1: 'Marcher Str. 87',
city: 'Stuttgart',
postalCode: '12345',
} as AddressDetailsTypes,
furtherAddress: {
companyName1: 'Samsung',
firstName: 'Daniel',
lastName: 'Circus',
addressLine1: 'Berg Str. 83',
city: 'Heidelberg',
postalCode: '36890',
countryCode: 'DE',
} as AddressDetailsTypes,
newAddress: {
companyName1: 'Samsung DE',
firstName: 'Daniels',
lastName: 'Decorous',
addressLine1: 'HeidelBerg Str. 83',
city: 'Heidelberg',
postalCode: '36890',
countryCode: 'DE',
} as AddressDetailsTypes,
};

describe('Addresses Page Functionality', () => {
before(() => {
createB2BUserViaREST(_.user);
LoginPage.navigateTo('/account/addresses');
at(LoginPage, page => {
page.fillForm(_.user.login, _.user.password);
page.submit().its('response.statusCode').should('equal', 200);
});
at(AddressesPage, page => {
page.defaultAddress.should('exist');
});
});

it('should be able to create address and assign as shipping address', () => {
at(AddressesPage, page => {
page.createAddress();
cy.wait(500);
page.fillCreateAddressForm(_.address);
page.saveAddress();
page.furtherAddress.should('contain', _.address.addressLine1);
page.selectShippingAddress();
page.shippingAddress.should('contain', _.address.addressLine1);
});
});

it('should be able to create a further address and see changes', () => {
at(AddressesPage, page => {
page.createAddress();
page.fillCreateAddressForm(_.furtherAddress);
page.saveAddress();
page.furtherAddress.should('contain', _.furtherAddress.addressLine1);
});
});

it('should be able to assign the further address as default invoice address', () => {
at(AddressesPage, page => {
page.selectInvoiceAddress();
page.invoiceAddress.should('contain', _.furtherAddress.addressLine1);
});
});

it('should be able to update address details and see changes', () => {
at(AddressesPage, page => {
page.updateAddress();
page.fillUpdateAddressForm(_.newAddress).submit().its('response.statusCode').should('equal', 200);
page.successMessage.message.should('contain', 'updated');
page.furtherAddress.should('contain', `${_.newAddress.firstName} ${_.newAddress.lastName}`);
});
});

it('should be able to delete an address and see changes', () => {
at(AddressesPage, page => {
page.deleteAddress();
page.successMessage.message.should('contain', 'deleted');
});
});
});
5 changes: 5 additions & 0 deletions src/app/core/facades/account.facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MessagesPayloadType } from 'ish-core/store/core/messages';
import {
createCustomerAddress,
deleteCustomerAddress,
updateCustomerAddress,
getAddressesError,
getAddressesLoading,
getAllAddresses,
Expand Down Expand Up @@ -240,6 +241,10 @@ export class AccountFacade {
this.store.dispatch(deleteCustomerAddress({ addressId }));
}

updateCustomerAddress(address: Address) {
this.store.dispatch(updateCustomerAddress({ address }));
}

// DATA REQUESTS

dataRequestLoading$ = this.store.pipe(select(getDataRequestLoading));
Expand Down
2 changes: 2 additions & 0 deletions src/app/core/store/customer/addresses/addresses.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const createCustomerAddressSuccess = createAction(
payload<{ address: Address }>()
);

export const updateCustomerAddress = createAction('[Address] Update Customer Address', payload<{ address: Address }>());

export const updateCustomerAddressFail = createAction('[Address API] Update Customer Address Fail', httpError());

export const updateCustomerAddressSuccess = createAction(
Expand Down
44 changes: 44 additions & 0 deletions src/app/core/store/customer/addresses/addresses.effects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import {
deleteCustomerAddress,
deleteCustomerAddressFail,
deleteCustomerAddressSuccess,
updateCustomerAddress,
updateCustomerAddressFail,
updateCustomerAddressSuccess,
loadAddresses,
loadAddressesSuccess,
} from './addresses.actions';
Expand All @@ -37,6 +40,7 @@ describe('Addresses Effects', () => {

when(addressServiceMock.getCustomerAddresses()).thenReturn(of([{ urn: 'test' } as Address]));
when(addressServiceMock.createCustomerAddress(anyString(), anything())).thenReturn(of({ urn: 'test' } as Address));
when(addressServiceMock.updateCustomerAddress(anyString(), anything())).thenReturn(of({ urn: 'test' } as Address));
when(addressServiceMock.deleteCustomerAddress(anyString(), anything())).thenReturn(of('123'));

TestBed.configureTestingModule({
Expand Down Expand Up @@ -155,4 +159,44 @@ describe('Addresses Effects', () => {
expect(effects.deleteCustomerAddress$).toBeObservable(expected$);
});
});

describe('updateCustomerAddress$', () => {
it('should call the addressService for updateCustomerAddress', done => {
const address = { urn: '123' } as Address;
const action = updateCustomerAddress({ address });
actions$ = of(action);

effects.updateCustomerAddress$.subscribe(() => {
verify(addressServiceMock.updateCustomerAddress('-', anything())).once();
done();
});
});

it('should map to action of type updateCustomerSuccess', () => {
const address = { urn: '123' } as Address;
const action = updateCustomerAddress({ address });
const completion = updateCustomerAddressSuccess({ address });
const completion2 = displaySuccessMessage({
message: 'account.addresses.address_updated.message',
});
actions$ = hot('-a-', { a: action });
const expected$ = cold('-(cd)', { c: completion, d: completion2 });

expect(effects.updateCustomerAddress$).toBeObservable(expected$);
});

it('should map invalid request to action of type updateCustomerFail', () => {
when(addressServiceMock.updateCustomerAddress('-', anything())).thenReturn(
throwError(() => makeHttpError({ message: 'invalid' }))
);
const address = { urn: '123' } as Address;
const action = updateCustomerAddress({ address });
const error = makeHttpError({ message: 'invalid' });
const completion = updateCustomerAddressFail({ error });
actions$ = hot('-a-a-a', { a: action });
const expected$ = cold('-c-c-c', { c: completion });

expect(effects.updateCustomerAddress$).toBeObservable(expected$);
});
});
});
24 changes: 24 additions & 0 deletions src/app/core/store/customer/addresses/addresses.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import {
createCustomerAddress,
createCustomerAddressFail,
createCustomerAddressSuccess,
updateCustomerAddress,
updateCustomerAddressFail,
updateCustomerAddressSuccess,
deleteCustomerAddress,
deleteCustomerAddressFail,
deleteCustomerAddressSuccess,
Expand Down Expand Up @@ -59,6 +62,27 @@ export class AddressesEffects {
)
);

/**
* Updates a customer address.
*/
updateCustomerAddress$ = createEffect(() =>
this.actions$.pipe(
ofType(updateCustomerAddress),
mapToPayloadProperty('address'),
withLatestFrom(this.store.pipe(select(getLoggedInCustomer))),
filter(([address, customer]) => !!address || !!customer),
mergeMap(([address]) =>
this.addressService.updateCustomerAddress('-', address).pipe(
mergeMap(() => [
updateCustomerAddressSuccess({ address }),
displaySuccessMessage({ message: 'account.addresses.address_updated.message' }),
]),
mapErrorToAction(updateCustomerAddressFail)
)
)
)
);

/**
* Deletes a customer address.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/app/core/store/customer/addresses/addresses.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
loadAddresses,
loadAddressesFail,
loadAddressesSuccess,
updateCustomerAddress,
updateCustomerAddressFail,
updateCustomerAddressSuccess,
} from './addresses.actions';
Expand All @@ -43,6 +44,7 @@ export const addressesReducer = createReducer(
loadAddresses,
createCustomerAddress,
createBasketAddress,
updateCustomerAddress,
updateBasketAddress,
deleteCustomerAddress,
deleteBasketShippingAddress
Expand Down
Loading

0 comments on commit a98d391

Please sign in to comment.