Beginner's Guide to Testing With Ionic
In this post, we'll give a deep dive into Ionic and testing. After that, we're going to learn the difference between unit testing and end-to-end (E2E) testing in Angular apps. Next, we'll learn about Cypress and Jasmine, two frameworks for testing Angular apps. Finally, we'll learn to create a simple Ionic app using Angular. We'll then see how to test an Ionic application using Jasmine and Karma for unit testing and Cypress for E2E testing.
What Is Ionic?
Ionic is a completely open-source and free-to-use mobile app development platform. As mentioned earlier, it follows the principle of having one codebase for both major stores—iOS and Android. In that way, it's quite similar to React Native and Flutter, which are also used to create hybrid apps. But React Native and Flutter are limited in that each is attached to a platform. Additionally, React Native requires knowledge of React, while Flutter users must learn a completely new language, Dart.
Ionic has built-in web components for everything from input boxes to buttons. So, the learning curve is very low in comparison to React Native and Flutter. But Ionic also has the same performance issues as React Native and Flutter. Apps built with native languages like Kotlin and Java for Android or Swift and Objective-C for iOS are faster than these platforms. You can find a detailed comparison of native and cross-platform app development in this post.
Angular Unit Testing vs. E2E Testing
Two popular ways to test web apps or mobile apps are unit and E2E testing. Unit testing is always done by the developer. In most enterprise projects, multiple developers work on a project. This project is divided into small components, and each developer is responsible for their component. Through unit testing, we write test cases to check if our component is working properly.
E2E testing is generally done by testers. It can be performed manually or automated to check the functionality of the apps. Automation testing requires the unique IDs of each element. Scripts are created to interact with the elements like clicking on a button.
Angular comes with Jasmine built-in for unit testing. This means you don't have to install any third-party library. For E2E testing, Angular promotes Cypress, although it isn't a default E2E framework. Before Angular 12, Protractor was the default for E2E testing in Angular. We can use these same two frameworks to test our Angular app in Ionic. Let's learn a bit more about each.
Unit Testing Ionic Apps With Jasmine
Jasmine is a popular BDD unit testing tool. In addition to being the default unit testing tool in Angular, it's also the default in Ionic. To use Jasmine, we need to write all tests inside a describe block. It also has a beforeEach and afterEach function, which runs before and after all tests. So, before beforeEach, we can do the basic configuration for the app, which is required in each test. And in afterEach, we can do cleanup if required.
Tests are written inside the it function, in which we expect to check the result. Jasmine tests are pretty easy to write. The basic syntax for Jasmine tests is below:
E2E Testing Ionic Apps With Cypress
Cypress is a front-end E2E testing framework for web apps. It's different from Selenium in that it isn't an automation framework—a tester or developer needs to manually perform test cases in it. But like Selenium, Cypress tests target elements and checks their functionality. For example, you can target a button and perform a click operation.
Cypress's test syntax is quite similar to Jasmine's. We have the beforeEach, afterEach, and it statements. But then we use the powerful cy command to perform different tasks.
How Do You Test an Ionic Application?
To test our Ionic application, we're going to use Jasmine for unit testing and Cypress for E2E testing. Ionic was originally developed to work with Angular. Now, it works with React and Vue, too, but the ecosystem is still best with Angular. So, we're going to start by creating an Ionic app with Angular.
We need to install the Ionic CLI globally on our system. So, in the terminal, give the below command. Because I'm using a Mac, I also need to give sudo to install the package globally.
Now, we'll create a new Ionic app called testing-ionic with Angular. This will be a tabbed mobile app, with tabs created. Capacitor is the open-source library that Ionic uses to create hybrid apps. So, we require it as well.
Now our Ionic app will be created, and we'll also get instructions to start it:
- Go to your new project: cd ./testing-ionic.
- Run ionic serve within the app directory to see your app in the browser.
- Run ionic capacitor add to add a native iOS or Android project using Capacitor.
Per the instructions, we've changed the folder and started the Ionic app with the ionic serve command.
Our Ionic app will open in a browser on port 8100. And we'll see a nice tabbed mobile app.
Ionic and Angular apps come with Karma built-in. Karma helps run tests in the browser. We write the unit test in Jasmine, which is also installed by default. So, just run npm test from the terminal to see the unit tests.
Simple To-Do App
Now, we'll create a simple to-do app in Tab 1 of our tabbed app. So, open the tab1.page.ts file and add the below code in it. Here, we have a todoList array that contains the initial values as the object. Then, we have a randomValue() function, which gives us a random object from an array. The addNewItem() function is calling the randomValue() function and inserts a random object in todoList array.
Now, we'll add new code in our tab1.page.html file. It's similar to an Angular HTML file, but the difference is that we can't use any HTML elements. So, instead of the div and the button, we have to use Ionic components.
Here, in an ion-card, we're looping through the todoList with the ngFor directive. Then, we're showing the category, name, and due from each object. We also have an ion-fab-button. On click, it will fire the addNewItem() function.
Our app will now show all three initial items. We also have a button at the bottom.
On clicking the button, a random item will be added to our app.
Unit Testing With Jasmine
Our Ionic app already has unit testing set up with Jasmine. We just need to add test cases to it. We'll update the unit test for our tab1.page.ts file in the tab1.page.spec.ts file.
Here, we have the familiar describe function containing all of our code. In beforeEach(), we're using TestBed to create the Tab1Page. After that, the detectChanges() function is checking for any changes in the test.
We've added two new tests in it blocks. The first test is checking whether todoList is an array. The second test is calling the addNewItem() function and checking whether the array length is greater than three.
Since our test was already running because of the ng test command, we got the updated result. Both of our new tests ran successfully.
E2E Testing With Cypress
Our Ionic app, like the Angular app, doesn't have a default E2E testing framework. So, we'll add Cypress in our app with the below ng add command. And we also need to give Yes when asked if we'd like to proceed.
In the cypress.config.ts file, update the baseUrl to point to 8100. This is because our Ionic app runs on that port.
Now, from the terminal, run npx cypress open. It will open the browser. Here, click the Continue button.
In the next window, select E2E testing.
In a new window, we'll see the supported browsers, including Chrome and Firefox. Click the button Start E2E Testing in Chrome.
In the next window, click on the spec.cy.ts file to start our Cypress testing.
Our Cypress test failed because we've updated the default app.
Now, open the spec.cy.ts file inside the cypress > e2e folder. Here, we can see some basic Cypress code with a describe-it block. Cypress uses the cy command to do different things. The command visit('/') will take us home from the app. And the command contains will check if the item is in our mobile app. We've updated it from 'app is running' to Coding because our updated app has this item.
Now, our new Cypress test ran successfully in the browser.
Back to our spec.cy.ts file, we've added one more test in an it block. Here, we're first selecting the button and clicking on it. After that, we're checking whether we have a subtitle text as Work.
We've also added a beforeEach block, where we've moved the command cy. visit('/'). So, now this statement will run before both it statements. And we don't have to repeat it.
Our new Cypress test ran successfully in the browser.
What You've Learned
In this post, you learned about testing with the Ionic framework. First, we learned all about Ionic. After that, we discussed how Angular handles unit and E2E testing. You've also learned to create a simple mobile app with Ionic. After that, you learned to test an Ionic app with Jasmine and Cypress.
If you want to test your mobile apps easily, then try Waldo. You only need to provide the APK or IPA file. After that, you interact with the mobile app like a real user. Waldo automatically generates test cases and sends the result in an email to you.
Automated E2E tests for your mobile app
Learn more about our Automate product, or try our live testing tool Sessions today.