
Integration testing examines how components work together within the application. For the CartItem component, we use Cypress to perform end-to-end tests that simulate user interactions and verify the application’s behavior.
This is the third blog post in a trilogy related to vanilla JavaScript Web Components:
Since we are working with a Vanilla JavaScript project, we need to perform some basic setup for our testing environment using Cypress:
npm install cypress --save-dev commandpackage.json file:
"scripts": {
"cypress:open": "cypress open",
"cypress:run": "cypress run"
},
cypress.config.js file has been created and contains the following configuration:
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
.gitignore file:
# Cypress test artifacts
cypress/videos
cypress/screenshots
Integration testing examines how components work together within the application. Therefore, it’s essential to review the overall functionality to gain a clear understanding of the tests to perform.
In the following image, we can identify the different components of the ecommerce app. Remember, we have been focusing solely on the CartItem component:

Now that we have a better understanding of the app, we can easily comprehend the next functionality flowchart:

Each test begins with defining the constants values, finding the price text and the button of the first ProductItem in the Menu component and then clicking on it:
let itemPrice;
const taxRate = 0.0975;
beforeEach(() => {
cy.visit('/')
.get('[data-testid="menu"]').find('.price').first().invoke('text')
.then((text) => {
itemPrice= parseFloat(text.replace(/[^0-9.-]+/g, ""));
})
.get('[data-testid="menu"] button').first().click({ force: true })
})
The first test suite simulates adding an item to the cart and verifying that the item appears in the cart summary with the correct details:
describe('Add item to cart', () => {
it('should add an item to the cart', () => {
cy.get('[data-testid="menu"] button').first().should('have.class', 'in-cart')
.get('[data-testid="cart-summary"] li').should('have.length', 1)
})
it('should update totals when an item is added to the cart', () => {
cy.get('[data-testid="menu"]').find('.price').first().invoke('text')
.then((text) => {
itemPrice= parseFloat(text.replace(/[^0-9.-]+/g, ""));
})
.then(() => {
// Calculate expected tax and total
const expectedTax = itemPrice * taxRate;
const expectedTotal = itemPrice + expectedTax;
// Assert that the subtotal is equal to the item price
cy.get('[data-testid="subtotal"]').invoke('text')
.then((subTotalText) => {
const subTotal = parseFloat(subTotalText.replace(/[^0-9.-]+/g, ""));
expect(subTotal).to.equal(itemPrice);
})
// Calculate expected tax and total
cy.get('[data-testid="tax"]').invoke('text')
.then((taxText) => {
const displayedTax = parseFloat(taxText.replace(/[^0-9.-]+/g, ""));
expect(displayedTax).to.closeTo(expectedTax, 0.01);
})
// Retrieve and assert the displayed total value
cy.get('[data-testid="total"]').invoke('text')
.then((totalText) => {
const displayedTotal = parseFloat(totalText.replace(/[^0-9.-]+/g, ""));
expect(displayedTotal).to.closeTo(expectedTotal, 0.01);
})
})
})
})
The second test suite cover increasing and decreasing an item’s quantity within the Cart, verifying that the Cart updates to reflect these changes accurately:
describe('Update item in cart', () => {
it('should increase item quantity and cart total values', () => {
cy.get('.increase').click()
.then(() => {
const newQuantity = 2;
const expectedSubTotal = itemPrice * newQuantity;
const expectedTax = expectedSubTotal * taxRate;
const expectedTotal = expectedSubTotal + expectedTax;
// Assert that the subtotal is equal to the item price
cy.get('[data-testid="subtotal"]').invoke('text')
.then((subTotalText) => {
const subTotal = parseFloat(subTotalText.replace(/[^0-9.-]+/g, ""));
expect(subTotal).to.equal(expectedSubTotal);
})
// Calculate expected tax and total
cy.get('[data-testid="tax"]').invoke('text')
.then((taxText) => {
const displayedTax = parseFloat(taxText.replace(/[^0-9.-]+/g, ""));
expect(displayedTax).to.closeTo(expectedTax, 0.01);
})
// Retrieve and assert the displayed total value
cy.get('[data-testid="total"]').invoke('text')
.then((totalText) => {
const displayedTotal = parseFloat(totalText.replace(/[^0-9.-]+/g, ""));
expect(displayedTotal).to.closeTo(expectedTotal, 0.01);
})
})
})
it('should decrease item quantity and cart total values', () => {
cy.get('.decrease').click()
.then(() => {
const newQuantity = 0;
const expectedSubTotal = itemPrice * newQuantity;
const expectedTax = expectedSubTotal * taxRate;
const expectedTotal = expectedSubTotal + expectedTax;
// Assert that the subtotal is equal to the item price
cy.get('[data-testid="subtotal"]').invoke('text')
.then((subTotalText) => {
const subTotal = parseFloat(subTotalText.replace(/[^0-9.-]+/g, ""));
expect(subTotal).to.equal(expectedSubTotal);
})
// Calculate expected tax and total
cy.get('[data-testid="tax"]').invoke('text')
.then((taxText) => {
const displayedTax = parseFloat(taxText.replace(/[^0-9.-]+/g, ""));
expect(displayedTax).to.closeTo(expectedTax, 0.01);
})
// Retrieve and assert the displayed total value
cy.get('[data-testid="total"]').invoke('text')
.then((totalText) => {
const displayedTotal = parseFloat(totalText.replace(/[^0-9.-]+/g, ""));
expect(displayedTotal).to.closeTo(expectedTotal, 0.01);
})
})
})
})
The third test suite ensures that an item can be removed from the cart, and the Cart updates accordingly:
describe('Remove item from cart', () => {
it('should remove an item from the cart', () => {
cy.get('.decrease').click()
.get('.remove').click({ force: true })
.get('[data-testid="cart-summary"] li').should('have.length', 0)
.get('[data-testid="menu"] button').first().should('not.have.class', 'in-cart')
})
it('should update totals when an item is removed from the cart', () => {
cy.get('.decrease').click()
.get('.remove').click({ force: true })
.then(() => {
cy.get('[data-testid="subtotal"]').invoke('text')
.then((subTotalText) => {
const subTotal = parseFloat(subTotalText.replace(/[^0-9.-]+/g, ""));
expect(subTotal).to.equal(0);
})
})
})
})
That’s it!. We now have a complete integration test suite for our CartItem Web Component. The results can be seen running the cypress run --spec 'cypress/e2e/item-in-cart.cy.js' command in the terminal, where the spec path should be an absolute path or can be relative to the current working directory:

Testing the functionality of adding and removing multiple items in the Cart component is crucial for ensuring the smooth operation of the ecommerce application.
This kind of testing helps uncover potential issues related to item interactions, quantity adjustments, and total calculations, providing a comprehensive evaluation of the cart functionality.
For more details on the test suite for multiple cart items, visit the codebase in the following link: click here
These integration tests validate the CartItem component’s interaction with other parts of the application, ensuring a seamless user experience.
Through these three blog posts, we’ve explored the creation, unit testing, and integration testing of the CartItem web component, demonstrating the importance of each step in developing reliable and maintainable web applications.