Guide to Testing Angular Apps with Cypress

    Jan 8, 20259 min read150 viewsUpdated:Jan 8, 2025
    Guide to Testing Angular Apps with Cypress

    We develop high-quality websites using advanced technologies like React, Angular, and other modern frameworks. For testing purposes, customers often prefer unit testing or end-to-end (E2E) testing as end-to-end tests assess the fitness of the web page, objects, and application as a whole.

    In this angular unit testing tutorial, we'll walk you through setting up Cypress, a powerful internal end-to-end testing framework for Angular applications built using JavaScript that operates directly within the browser. We will also demonstrate how to create a test script and execute some basic unit test cases therefore you can consider it a cypress automation tutorial too.

    Introduction to Cypress and Angular Testing

    Testing is a vital aspect of modern web development that guarantees that applications are generated reliably, consistently, and without major bugs. If you are an Angular developer then useful testing tools can help you a lot in building high-qualified apps.

    Also, Angular testing is a core feature in every new project you set up with the Angular CLI. This is where Cypress comes into play — a powerful and efficient end-to-end testing framework created to make testing smooth and intuitive.

    What is Cypress?

    Cypress is a newer JavaScript end-to-end (E2E) unit testing framework. Cypress is designed for Unit / Integration Testing at the Front end. This is a popular unit test suite and framework for Angular applications due to their simplicity given tests, quick processing, and rich feature sets.

    Key features of Cypress include:

    • Fast Test Execution: Tests run directly in the browser, offering rapid feedback.

    • Real-Time Reloading: Automatically reloads tests as you make changes.

    • Powerful Debugging Tools: Provides detailed error messages and interactive debugging capabilities.

    • Built-in Waiting Mechanism: Cypress automatically waits meaning it handles asynchronous operations without requiring explicit waits.

    How Cypress Fits into the Angular Testing Environment

    Angular provides robust tools for unit testing out of the box, such as Jasmine and Karma. However, when it comes to simulating real-world scenarios and validating the application from a user’s perspective, Cypress excels. It complements Angular’s native testing tools by allowing developers to perform:

    1. UI Testing: Validate user interactions, visual layouts, and overall user experience.

    2. End-to-End Testing: Test the entire workflow of the application, from the front end to the back end.

    3. Integration Testing: Ensure various components and modules work together seamlessly.

    Why Testing is Crucial in Angular Development

    Angular framework is a dynamic framework that allows the development of scalable and performant applications. However, the Angular projects get very complicated and may contain potential bugs without proper testing. And this is why testing becomes an indispensable part of the process of developing, in order to:

    1. Verify that components function as expected.

    2. Ensure smooth integration between modules and services.

    3. Provide confidence during updates or refactoring.

    4. Improve code quality and maintainability over time.

    Setting Up Cypress for Angular Testing

    Now next step is to install Cypress which is simple to set up, especially in an Angular application, and its user-friendly makes it easier to write and execute tests by devs of the Angular app at any level. In the first test case and coming sections, we will explore how to set up Cypress in an Angular project and write simple test cases to show you how it works.

    To start testing and using Cypress, you must install Node.js and create a new project of Angular then install Cypress as a development dependency using Angular CLI's below command prompt.

    ng add @cypress/schematic
    cypress-angular

    The above command will produce the basic required cypress configuration file, with some files, and create one sepc.ts file as a sample cypress testing configuration file.

    cypress-configuration-file

    To check the Cypress test cases run the below command

    npm run cypress:open

    The above command will help open a browser window in Chrome to check the cypress test cases like the below screen.

    cypress-test-case

    Update your cypress.config.js file (if needed) to customize the base URL, timeout settings, or environment variables. For Angular applications, ensure the base URL matches your app’s running instance:

    module-export

    Writing and Running Cypress Tests

    One of the best practices and most dev-friendly tools to write and run end-to-end (e2e) tests is “Cypress.” Plus, its syntax is easy to write, and you can test your web application directly in the browser as you go — with an added bonus: it even works with Angular web apps! We will guide you through the steps of both writing tests and running these Cypress tests.

    cypress tests are a test file written in JavaScript and placed under the cypress/e2e directory. You can create a new test file under the cypress/e2e/ directory for Cypress tests.

    Here’s a Cypress test example for an Angular app’s login functionality:

    File Name: login.cy.js

    describe('Login Functionality', () => {
      it('should display the login page', () => {
        // Visit the login page
        cy.visit('/login');
    
        // Check if the login form is visible
        cy.get('form#login-form').should('be.visible');
      });
    
      it('should log in with valid credentials', () => {
        // Visit the login page
        cy.visit('/login');
    
        // Enter username and password
        cy.get('input[name="username"]').type('testuser');
        cy.get('input[name="password"]').type('password123');
    
        // Submit the form
        cy.get('button[type="submit"]').click();
    
        // Assert that the user is redirected to the dashboard
        cy.url().should('include', '/dashboard');
      });
    });

    Running Cypress Tests

    Once you’ve written test run your tests, you can run tests on them in two modes:

    Interactive Mode
    Launch Cypress in an interactive GUI environment with a npx cypress open command:

    npx cypress open

    From here, select the test file you want to run. The test scenario will execute in a browser, allowing you to watch each step.

    Headless Mode
    For continuous integration (CI) or automated testing environments, run Cypress tests in the terminal:

    npx cypress run

    This will execute all test files in the cypress/e2e folder and provide a summary of results.

    Key Cypress Commands to Know

    • cy.visit(): Navigate to a specific URL.

    • cy.get(): Selects an element using a CSS selector.

    • cy.type(): Simulates typing into input fields.

    • cy.click(): Simulates a click action on a button or link.

    • cy.should(): Asserts that an element meets a specific condition.

    • cy.url(): Validates the current URL.

    Best Practices for Writing Cypress Tests

    1. Keep Tests Atomic: Write small, focused tests that cover one functionality at a time.

    2. Use Descriptive Test Names: Clearly describe the test’s purpose for better readability.

    3. Mock APIs When Necessary: Use fixtures to simulate backend responses and avoid flaky tests.

    4. Leverage Custom Commands: Create reusable commands in the cypress/support/commands.js file for repetitive actions.

    Testing is No More a Hassle For Your Angular Project.
    The Angular application development done by us includes Cypress for modern component testing and robust unit testing with Jasmine or Jest, ensuring a reliable and maintainable codebase.Cypress Test Automation Fundamentals

    Cypress is an end-to-end testing framework that allows for easy automation unit tests through the use of easy commands along with well-designed debugging. Key concepts and best practices that form the foundation of using Cypress test automation effectively

    Build Test Scenarios

    Cypress tests are centered around test cases, with each scenario being an ordered set of steps executed to mimic real user actions or flows.

    Start by defining clear objectives for each scenario to ensure comprehensive test coverage.

    Use Cypress’s description and its blocks to organize and structure tests logically.

    describe('User Login', () => {
      it('should allow a valid user to log in', () => {
        // Test steps go here
      });
    });

    Automate Interactions Using Cypress Commands

    Cypress provides an extensive set of built-in commands to mimic user interactions, such as clicking buttons, entering text, and navigating between pages.

    Examples of commonly used commands:

    • cy.visit() to load a URL.

    • cy.get() to select elements using CSS selectors.

    • cy.type() to simulate typing into an input field.

    • cy.click() to mimic clicking buttons or links.

      cy.visit('/login');
      cy.get('input[name="username"]').type('testuser');
      cy.get('button[type="submit"]').click();

    Verify Test Results with Assertions

    Cypress uses Chai assertions to validate outcomes during tests, ensuring the application behaves as expected.

    Assertions can check various properties, such as element visibility, URL correctness, or content changes.

    Assertions in Cypress use a chainable syntax, making tests more readable.

    Examples of common assertions:

    • should('be.visible') to check if an element is visible.

    • should('include.text', 'Welcome') to validate text content.

    • should('have.attr', 'href', '/dashboard') to confirm an attribute’s value.

      cy.get('h1').should('contain.text', 'Welcome Back');
      cy.url().should('include', '/dashboard');

    Parameterize Tests with Test Data

    Using dynamic test data enhances test coverage by allowing the same test to run with multiple input sets.

    Leverage fixtures or data-driven approaches to supply different inputs for testing various scenarios.

    Store test data in cypress/fixtures as JSON files for easy access.

    cy.fixture('users.json').then((users) => {
      cy.get('input[name="username"]').type(users.validUser.username);
      cy.get('input[name="password"]').type(users.validUser.password);
    });

    Use Cypress._.each() to iterate over multiple data sets and execute the same test with varying inputs.

    Debugging and Real-Time Feedback

    Take advantage of Cypress’s real-time reloading and built-in debugging tools to quickly identify and fix issues. It automatically reloads the test runner when changes to test files are made.

    Use commands like cy.debug() or .then() for step-by-step debugging during test execution.

    The Cypress Test Runner provides a visual representation of test progress, making it easy to track failures.

    Tips for Better Test Results

    • Modularize Tests: Break down large scenarios into smaller, reusable test cases.

    • Avoid Flaky Tests: Use Cypress’s built-in waiting mechanisms instead of arbitrary delays like cy.wait().

    • Handle Dynamic Elements: Use cy.contains() or custom selectors for elements with dynamic IDs or text.

    • Leverage Custom Commands: Create custom reusable commands for repetitive actions to streamline test scripts.

    Testing Angular Components and Services

    Wondering how to check if each component and service is working separately? You love developing an Angular Application with test cases. Not only does Cypress shine in the arena of end-to-end (E2E) testing, but it is also equipped with robust features for component and service testing.

    Let’s see how they can be used to test an Angular component and test the execution of its services, individually and together, using Cypress.

    1. Testing Angular Components in Isolation

    Cypress features component testing which allows the developer to use the component testing of the Angular application without being dependent on the entire application.

    Cypress lets you mount components and acts on them like a user would to ensure that they work as expected. When you have complex UI elements and you need to be sure that they behave correctly.

    Example: Testing an Angular Button Component

    describe('Button Component', () => {
      it('should emit a click event when clicked', () => {
        cy.mount(ButtonComponent); // Mount the Angular component
        cy.get('button').click(); // Simulate user click
        cy.get('@buttonClick').should('have.been.called'); // Assert event was triggered
      });
    });

    By isolating components, you can focus on testing individual functionality, such as input fields, buttons, or modal dialogs, without worrying about external dependencies.

    2. Testing Angular Services with Cypress

    For example — By Testing Angular services — You can ensure your backend logic and business rules are working as expected. It is easy to mock service dependencies and check whether services behave in Cypress.

    Mocking to simulate API calls or other services that component or service relies on This allows you to be able to test your services in an isolated environment without external influences (such as network requests) affecting the outcome.

    Example: Mocking Angular Service Dependencies

    describe('UserService', () => {
      it('should return user data when getUser() is called', () => {
        const mockData = { id: 1, name: 'John Doe' };
        
        cy.intercept('GET', '/api/user/1', { body: mockData }).as('getUser'); // Mock the API call
        cy.mount(UserComponent); // Mount component that calls the service
        cy.wait('@getUser'); // Wait for the mocked API response
        cy.get('.user-name').should('contain.text', 'John Doe'); // Assert UI updates
      });
    });

    In this case, Cypress intercepts the API call and returns mock data, allowing you to test the service logic and the component that consumes the service, without hitting a real backend.

    3. Testing Angular Components and Services Together

    Testing Angular components and services together is similar to what happens in the real world, where components interact with services and to visualize output data.

    This end-to-end type of test allows you to validate that your application behaves as a user expects by ensuring that the respective integration works between components and services.

    Example: Testing Component and Service Integration

    describe('User Profile', () => {
      it('should display user data fetched from the service', () => {
        const mockData = { id: 1, name: 'John Doe' };
        
        cy.intercept('GET', '/api/user/1', { body: mockData }).as('getUser');
        cy.mount(UserProfileComponent); // Mount the full component that uses the service
        cy.wait('@getUser'); // Wait for the service to be called
        cy.get('.user-name').should('contain.text', 'John Doe'); // Assert that the component displays data correctly
      });
    });

    In this example, the component requests data from the service, and Cypress ensures that the component correctly displays the fetched data. This kind of integration test is essential for validating the functionality of an entire feature.

    Best Practices for Component and Service Testing with Cypress

    Mocking External Dependencies: Use cy.intercept() to mock API calls and external services to avoid unnecessary network requests and control the test data.

    Isolate Test Cases: Keep component tests focused on a single unit of functionality, and service tests on specific business logic. Combine them for integration testing to ensure everything works together.

    Use Stubs and Spies: Utilize Cypress commands like cy.spy() and cy.stub() to monitor function calls or mock service methods, which helps you assert specific behaviors without needing real data.

    Advanced Cypress Testing Techniques

    Once you become a pro at this test scenario with Cypress, move on to more complex test cases to ensure your application test runs (with ease) under a variety of conditions.

    So, these techniques allow them to go beyond testing the most basic functionality of your application and into the realm of testing more complex workflows, testing performance, scalability network latency, security, and even accessibility.

    So let’s see how you can leverage your test strategies with the help of Cypress.

    1. Testing Complex Scenarios with Multiple Components

    When building modern applications, components often work together to form complex workflows. Cypress enables you to simulate real-world interactions where multiple components interact with each other.

    Testing these interactions ensures that user interaction with your application behaves as expected across different parts of the UI and integrates correctly with backend services.

    • Test Multiple Components Together: Cypress allows you to mount and test multiple components that interact with each other. For example, if you have a form submission flow that involves multiple components (e.g., a form, a modal, and a confirmation message), you can test the entire process.

      Example: Testing a Form Submission Flow

      describe('Form Submission Flow', () => {
        it('should fill in the form, submit it, and show a success message', () => {
          cy.mount(FormComponent); // Mount the main component with multiple child components
          cy.get('input[name="email"]').type('test@example.com');
          cy.get('button[type="submit"]').click(); // Submit the form
          cy.get('.success-message').should('be.visible').and('contain.text', 'Form submitted successfully');
        });
      });
    • Test Application Workflows: Cypress can simulate full user workflows, from logging in to submitting forms, viewing dashboards, or navigating through different pages. This ensures that users can perform end-to-end tasks without any issues.

      Example: Testing a User Checkout Flow

      describe('User Checkout', () => {
        it('should allow a user to add items to the cart and complete checkout', () => {
          cy.visit('/shop');
          cy.get('.product').first().click();
          cy.get('.add-to-cart').click();
          cy.visit('/cart');
          cy.get('.checkout-button').click();
          cy.url().should('include', '/checkout');
          cy.get('.order-summary').should('exist');
        });
      });

    2. Cypress Performance and Scalability Testing

    Cypress is a tool that focuses more on functional testing but you can test some portions of your application performance and or scalability using the Cypress framework. Cypress might not be the tool for full-blown performance testing (for that very first test, you might want to use something like Lighthouse or WebPageTest), but you can at least check load times, API response times, and general UX under simulated load.

    Measure Load Time: Use cy.window() to measure how long it takes for critical elements to load. This is particularly useful for monitoring the performance of your application’s UI components.

    Simulate Scalability: While Cypress can’t simulate a large number of concurrent users, you can simulate multiple actions on the same page to ensure your app can handle heavy interactions. Use Cypress's built-in commands like cy.intercept() to mock large data sets or traffic.

    3. Security Testing with Cypress

    Security testing is essential to ensure your application is resistant to threats like XSS (cross-site scripting) and CSRF (cross-site request forgery). Cypress can be used to validate common security issues by simulating attacks or testing specific security mechanisms.

    Test for Vulnerabilities: While Cypress doesn't offer a dedicated security testing library, you can test for things like form input sanitization and authentication vulnerabilities by entering malicious data or invalid requests.

    Test for CSRF: Ensure that your application correctly handles CSRF protection by testing the handling of custom headers or tokens that prevent cross-site requests.

    4. Accessibility Testing with Cypress

    With the rise of inclusive design, accessibility testing has become an integral part of ensuring that your application is usable by people with disabilities. Cypress has integrations with tools like cypress-axe, which allow you to perform accessibility audits directly in your tests.

    Automate Accessibility Checks: By using cypress-axe (a Cypress plugin), you can automatically check your application for common accessibility issues, such as missing alt attributes, improper use of ARIA roles, and color contrast violations.

    Manual Accessibility Tests: Beyond automated checks, you can use Cypress to simulate keyboard navigation, screen reader interactions, and other manual accessibility tests to ensure users can navigate your application effectively.

    Conclusion

    Cypress is a powerful and functional testing framework that works especially well with Angular applications. It provides an ever-expanding array of tools that make end-to-end testing simple and fast to determine whether all the parts of an application function together as expected.

    It offers real-time debugging capabilities, intuitive assertions, and an interactive test runner that gives developers control over maintaining quality code that can be relied upon to deliver efficient user experiences.

    By following best practices and leveraging Cypress’s capabilities, developers can confidently ensure that their applications meet the specified requirements and function correctly in multiple tests across different scenarios. From component and service testing to complex workflows and integration scenarios, Cypress simplifies the testing process, making it faster and more efficient.

    For any Angular development team, Cypress is not just a test automation tool—it's an essential part of the development workflow, providing a robust and streamlined way given test and to ensure application quality, improve user experience, and catch issues early in the application code development cycle.

    24

    Related articles

    This website uses cookies to analyze website traffic and optimize your website experience. By continuing, you agree to our use of cookies as described in our Privacy Policy.