Filip Hric, Author at Automated Visual Testing | Applitools https://applitools.com/blog/author/filiphric/ Applitools delivers the next generation of test automation powered by AI assisted computer vision technology known as Visual AI. Fri, 01 Dec 2023 18:15:16 +0000 en-US hourly 1 Using TypeScript for Test Automation https://applitools.com/blog/typescript-is-not-only-for-developers-anymore/ Wed, 18 Jan 2023 21:25:08 +0000 https://applitools.com/?p=46025 TypeScript is not only for developers anymore. If you are working as a tester in a web development team, chances are that you have heard about TypeScript. It’s been getting...

The post Using TypeScript for Test Automation appeared first on Automated Visual Testing | Applitools.

]]>
TypeScript logo

TypeScript is not only for developers anymore. If you are working as a tester in a web development team, chances are that you have heard about TypeScript. It’s been getting more and more attention over the past couple of years and has even surpassed JavaScript as the dominant language in a recent survey on state of software delivery made by CircleCI.

In my very un-scientific poll on LinkedIn, I asked fellow web application testers about the programming language of their choice. It seems that JavaScript is the most popular choice, winning over TypeScript and Java. But, in my opinion, testers should pay attention to the rising popularity of TypeScript and ideally start using it. In this article, I would like to take a closer look at many of TypeScript’s benefits for testing and automation.

What is TypeScript?

TypeScript is a programming language that is a superset of JavaScript. It adds many extra capabilities to JavaScript, improving the overall developer experience. As Basarat Ali Syed aptly puts it, TypeScript gives you the ability to use future JavaScript today. Besides that, TypeScript adds a type system into JavaScript, helping you write more stable and maintainable code. Let me give you an example of what that means.

Look at this plain JavaScript function:

const addition = (a, b) => {
 return a + b
}

This function takes two parameters and adds them up. It’s helpful if we need to sum two numbers. But what if we use this function in a way it was not intended? Or worse – what if we misunderstood how this function works?

addition(1, 2) // returns 3
addition('1', '2') // returns '12'

In the example above, our function will yield different results based on the type of input we provide it with. On the first line, we are passing two numbers, and our function will correctly add them up. On the second line, we are passing two strings, and since the input values are wrapped in quotation marks, the function will concatenate them instead of adding the numbers.

The function works as designed, but even if that’s the case, we may get into unexpected results. After all, this is why software testing is a thing.

But as developers work on more complex projects, on more complex problems, and with more complex data, risks increase. This is where TypeScript can become very helpful, since it can specify what kind of input the function expects. Let’s see how a similar function definition and function call would look like in TypeScript:

const addition = (a: number, b: number) => {
 return a + b
}


addition(1, 2) // returns 3
addition('1', '2') // shows an error

In the function definition, we specify the types for the parameters that this function expects. If we try to use our add() function incorrectly, the TypeScript compiler will complain about this and throw an error. So what is TypeScript compiler, you ask?

How TypeScript works

TypeScript cannot be read by the browser. In order to run TypeScript code, it needs to be compiled. In other words, everything you create using TypeScript will be converted to JavaScript at some point.

To run the compiler, we can open the terminal and run the following command:

tsc addition.ts

This command will point TypeScript compiler (tsc) to our addition.ts file. It will create a JavaScript file alongside the original TypeScript file. If there are any “type errors” in the file, we’ll get an error into our terminal.

But you don’t have to do this manually every time. There’s a good chance your code editor has a TypeScript compiler running in the background as you type your code. With VS Code, this functionality comes out of the box, which makes sense since both TypeScript and VS Code are developed and maintained by Microsoft. Having the compiler running in the background is incredibly useful, mostly because this allows us to immediately see errors such as the one shown in the last example. Whenever there is such an error, we get feedback and an explanation:

In this case, we are passing a string into a function that requires us to pass numbers. This information comes from a compiler that runs inside the editor (VS code in my case).

Additionally, some modern testing tools such as Playwright and Cypress run the compiler on the fly and convert your TypeScript code into browser-readable JavaScript for you.

How to use TypeScript as a tester

Now that you know what TypeScript is and how it works, it is time to answer the most important question: why? Is TypeScript even useful for someone who focuses on test automation?

My answer is yes, and I would like to demonstrate this in a few examples. I’ll also give you a couple of reasons why I think test automation engineers should start getting familiar with TypeScript.

Typed libraries

As test automation engineers, we often implement many different libraries for our work. There’s no tool that fits all the needs, and many times we deal with plugins, integrations, toolsets, extensions, and libraries. When you start, you need to get yourself familiar with the API of that tool, dig into the documentation, try it out, and understand different commands. It’s a process. And it can be exhausting to get through that first mile.

TypeScript can be helpful in speeding up that process. Libraries that contain type definitions can really get you up to speed with using them. When a library or a plugin contains type definitions, it means that functions in that library will have the same type of checking implemented as in the example I have given earlier.

This means that whenever you e.g. pass a wrong argument to a function, you will see an error in your editor. In the following example, I am passing a number into a cy.type() function that will only accept text:

Code autocompletion

Besides checking for correct arguments, TypeScript can help with giving autocomplete suggestions. This can act as a quick search tool, when you are looking for the right command or argument.

I have recently made a plugin for testing API with Cypress, and TypeScript autocompletion helps with passing different attributes such as url, method, or request body:

Handling imported data

Working with data can often get complicated. Especially when working with complex datasets in which you have to navigate through multiple levels of data structure. One mistake can make the whole test fail and cause a headache when trying to debug that problem.

When data is imported to a test, for example from a JSON file, the structure of that JSON file is imported to the test as well. This is something that the TypeScript compiler inside the editor does for us. Let’s take a look at a simple JSON file that will seed data into our test:

While creating our test, the editor will guide us through the fixture file and suggest possible keys that can be inferred from that file:

Notice how we not only get the key names, but also the type of the key. We can use this type inference for both seeding the data into our tests, as well as making assertions. The best part about this? The fixture file and test are now interconnected. Whenever we change our fixture file, the test file will be affected as well. If e.g. we decide to change the name property in our JSON file to title, TypeScript compiler will notice this error even before we decide to run our test.

Tightening source code with test code

Probably my strongest argument for using TypeScript is the connection between test code and source code. Being able to tie things together is a game changer. Whenever the source code changes, it can have a direct effect on tests, and with TypeScript, there’s a high chance it will show even before you run your tests on a pipeline.

Let’s say you have an API test. If your developers use TypeScript, chances are they have a TypeScript definition of the API structure. As a tester, you can import that structure into your test and use it e.g. for testing the API response:

import Board from "trelloapp/src/typings/board";


it('Returns proper response when creating new board', () => {
 cy.request<Board>('POST', '/api/boards', { name })
   .then(({ body }) => {
     expect(body.name).to.eq(name)
     expect(body.id).to.exist
   })
 })

Similarly to the previous example with fixture files, whenever something changes in our typings file, we will notice the change in the test file as well.

Checking errors on CLI

A really powerful feature of TypeScript is the ability to check all errors in the project. We can do this by typing following command in the terminal:

tsc --noEmit

The –noEmit flag means that the TypeScript compiler will not create JavaScript files, but it will check for any errors on our files. We can check all our files in the project, which means that even if we have worked on a single file, all the files will be checked for errors.

We can check the health of our tests even before they are run. Whenever we change files in our project, we can check if type checks are still passing. Even without opening any files.

This is sometimes referred to as “static testing”. It enables us to add an additional layer of checks that will help us make less mistakes in our code.

A great advantage of this is that it runs super fast, making it a good candidate for a pre-commit check.

In fact, setting up such a check is very easy and can be done in three simple steps:

First, install pre-commit package via npm using following command:

npm install pre-commit --save-dev

Then, create a lint script in package.json:

"scripts": {
 "lint": "tsc --noEmit"
}

As a final step, define lint as one of the pre-commit checks in package.json:

"pre-commit": [ "lint" ]

From now on, whenever we try to commit, our tsc –noEmit script will run. If it throws any errors, we will not be able to commit staged files.

Conclusion

TypeScript offers a variety of advantages. Static typing can improve the reliability and maintainability of the test code. It can help catch errors and issues earlier in the development process, saving time and effort spent on debugging. And there are many more that didn’t make it to this post.

Since TypeScript is built on top of JavaScript, test automation engineers who are familiar with JavaScript will be able to easily pick up TypeScript. The knowledge and skills they have developed in JavaScript will transfer over. If you need the initial push, you can check out my new course on TypeScript in Cypress, where I explain the basics of TypeScript within Cypress, but most of the knowledge can be transferred to other tools as well. The best part? It’s absolutely free on Test Automation University.

The post Using TypeScript for Test Automation appeared first on Automated Visual Testing | Applitools.

]]>
What’s New in Cypress 12 https://applitools.com/blog/whats-new-in-cypress-12/ Tue, 10 Jan 2023 17:56:27 +0000 https://applitools.com/?p=45657 Right before the end of 2022, Cypress surprised us with their new major release: version 12. There wasn’t too much talk around it, but in terms of developer experience (DX),...

The post What’s New in Cypress 12 appeared first on Automated Visual Testing | Applitools.

]]>
Cypress 12 is here

Right before the end of 2022, Cypress surprised us with their new major release: version 12. There wasn’t too much talk around it, but in terms of developer experience (DX), it’s arguably one of their best releases of the year. It removes some of the biggest friction points, adds new features, and provides better stability for your tests. Let’s break down the most significant ones and talk about why they matter.

No more “detached from DOM” errors

If you are a daily Cypress user, chances are you have seen an error that said something like, “the element was detached from DOM”. This is often caused by the fact that the element you tried to select was re-rendered, disappeared, or detached some other way. With modern web applications, this is something that happens quite often. Cypress could deal with this reasonably well, but the API was not intuitive enough. In fact, I listed this as one of the most common mistakes in my talk earlier this year.

Let’s consider the example from my talk. In a test, we want to do the following:

  1. Open the search box.
  2. Type “abc” into the search box.
  3. Verify that the first result is an item with the text “abc”.

As we type into the search box, an HTTP request is sent with every keystroke. Every response from that HTTP request then triggers re-rendering of the results.

The test will look like this:

it('Searching for item with the text "abc"', () => {
 
 cy.visit('/')
 
 cy.realPress(['Meta', 'k'])
 
 cy.get('[data-cy=search-input]')
   .type('abc')
 
 cy.get('[data-cy=result-item]')
   .first()
   .should('contain.text', 'abc')
 
})

The main problem here is that we ignore the HTTP requests that re-render our results. Depending on the moment when we call cy.get() and cy.first() commands, we get different results. As the server responds with search results (different with each keystroke), our DOM is getting re-rendered, making our “abc” item shift from second position to first. This means that our cy.should() command might make an assertion on a different element than we expect.

Typically, we rely on Cypress’ built-in retry-ability to do the trick. The only problem is that the cy.should() command will retry itself and the previous command, but it will not climb up the command chain to the cy.get() command.

It is fairly easy to solve this problem in versions v11 and before, but the newest Cypress update has brought much more clarity to the whole flow. Instead of the cy.should() command retrying only itself and the previous command, it will retry the whole chain, including our cy.get() command from the example.

In order to keep retry-ability sensible, Cypress team has split commands into three categories:

  • assertions
  • actions
  • queries

These categories are reflected in Cypress documentation. The fundamental principle brought by version 12 is that a chain of queries is retried as a whole, instead of just the last and penultimate command. This is best demonstrated by an example comparing versions:

// Cypress v11:
cy.get('[data-cy=result-item]') // ❌ not retried
 .first() // retried
 .should('contain.text', 'abc') // retried
 
// Cypress v12:
cy.get('[data-cy=result-item]') // ✅ retried
 .first() // retried
 .should('contain.text', 'abc') // retried

cy.get() and cy.first() are commands that both fall into queries category, which means that they are going to get retried when cy.should() does not pass immediately. As always, Cypress is going to keep on retrying until the assertion passes or until a time limit runs up.

cy.session() and cy.origin() are out of beta

One of the biggest criticisms of Cypress.io has been the limited ability to visit multiple domains during a test. This is a huge blocker for many test automation engineers, especially if you need to use a third-party domain to authenticate into your application.

Cypress has advised to use programmatic login and to generally avoid trying to test applications you are not in control of. While these are good advice, it is much harder to execute them in real life, especially when you are in a hurry to get a good testing coverage. It is much easier (and more intuitive) to navigate your app like a real user and automate a flow similar to their behavior.

This is why it seems so odd that it took so long for Cypress to implement the ability to navigate through multiple domains. The reason for this is actually rooted in how Cypress is designed. Instead of calling browser actions the same way as tools like Playwright and Selenium do, Cypress inserts the test script right inside the browser and automates actions from within. There are two iframes, one for the script and one for the application under test. Because of this design, browser security rules limit how these iframes interact and navigate. Laying grounds for solving these limitations were actually present in earlier Cypress releases and have finally landed in full with version 12 release. If you want to read more about this, you should check out Cypress’ official blog on this topic – it’s an excellent read.

There are still some specifics on how to navigate to a third party domain in Cypress, best shown by an example:

it('Google SSO login', () => {
 
 cy.visit('/login') // primary app login page
 
 cy.getDataCy('google-button')
   .click() // clicking the button will redirect to another domain
 
 cy.origin('https://accounts.google.com', () => {
   cy.get('[type="email"]')
     .type(Cypress.env('email')) // google email
   cy.get('[type="button"]')
     .click()
   cy.get('[type="password"]')
     .type(Cypress.env('password')) // google password
   cy.get('[type="button"]')
     .click()
 })
 
 cy.location('pathname')
   .should('eq', '/success') // check that we have successfully
 
})

As you see, all the actions that belong to another domain are wrapped in the callback of cy.origin() command. This separates actions that happen on the third party domain.

The Cypress team actually developed this feature alongside another one that came out from beta, cy.session(). This command makes authenticating in your end-to-end tests much more effective. Instead of logging in before every test, you can log in just once, cache that login, and re-use it across all your specs. I recently wrote a walkthrough of this command on my blog and showed how you can use it instead of a classic page object.

This command is especially useful for the use case from the previous code example. Third-party login services usually have security measures in place that prevent bots or automated scripts from trying to login too often. If you attempt to login too many times, you might get hit with CAPTCHA or some other rate-limiting feature. This is definitely a risk when running tens or hundreds of tests.

it('Google SSO login', () => {
 
 cy.visit('/login') // primary app login page
 cy.getDataCy('google-button')
   .click() // clicking the button will redirect to another domain
 
 cy.session('google login', () => {
   cy.origin('https://accounts.google.com', () => {
     cy.get('[type="email"]')
       .type(Cypress.env('email')) // google email
     cy.get('[type="button"]')
       .click()
     cy.get('[type="password"]')
       .type(Cypress.env('password')) // google password
     cy.get('[type="button"]')
       .click()
   })
 })
 
 cy.location('pathname')
   .should('eq', '/success') // check that we have successfully
 
})

When running a test, Cypress will make a decision when it reaches the cy.session() command:

  • Is there a session called google login anywhere in the test suite?
    • If not, run the commands inside the callback and cache the cookies, local storage, and other browser data.
    • If yes, restore the cache assigned to a session called “google login.”

You can create multiple of these sessions and test your application using different accounts. This is useful if you want to test different account privileges or just see how the application behaves when seen by different accounts. Instead of going through the login sequence through UI or trying to log in programmatically, you can quickly restore the session and reuse it across all your tests.

This also means that you will reduce your login attempts to a minimum and prevent getting rate-limited on your third party login service.

Run all specs in GUI

Cypress GUI is a great companion for writing and debugging your tests. With the version 10 release, it has dropped support for the “Run all specs” button in the GUI. The community was not very happy about this change, so Cypress decided to bring it back.

The reason why it was removed in the first place is that it could bring some unexpected results. Simply put, this functionality would merge all your tests into one single file. This can get tricky especially if you use before(), beforeEach(), after() and afterEach() hooks in your tests. These would often get ordered and stacked in unexpected order. Take following example:

// file #1
describe('group 1', () => {
 it('test A', () => {
   // ...
 })
})
 
it('test B', () => {
 // ...
})
 
// file #2
before( () => {
 // ...
})
 
it('test C', () => {
 // ...
})

If this runs as a single file, the order of actions would go like this:

  • before() hook
  • test B
  • test C
  • test A

This is mainly caused by how Mocha framework executes blocks of code. If you properly wrap every test into describe() blocks, you would get much less surprises, but that’s not always what people do.

On the other hand, running all specs can be really useful when developing an application. I use this feature to get immediate feedback on changes I make in my code when I work on my cypress plugin for testing API. Whenever I make a change, all my tests re-run and I can see all the bugs that I’ve introduced. ?

Running all specs is now behind an experimental flag, so you need to set experimentalRunAllSpecs to true in your cypress.config.js configuration file.

Test isolation

It is always a good idea to keep your tests isolated. If your tests depend on one another, it may create a domino effect. First test will make all the subsequent tests fail as well. Things get even more hairy when you bring parallelisation into the equation.

You could say that Cypress is an opinionated testing framework, but my personal take on this is that this is a good opinion to have. The way Cypress enforces test isolation with this update is simple. In between every test, Cypress will navigate from your application to a blank page. So in addition to all the cleaning up Cypress did before (clearing cookies, local storage), it will now make sure to “restart” the tested application as well.

In practice the test execution would look something like this:

it('test A', () => {
 cy.visit('https://staging.myapp.com')
 // ...
 // your test doing stuff
})
 
// navigates to about:blank
 
it('test B', () => {
 cy.get('#myElement') // nope, will fail, we are at about:blank
})

This behavior is configurable, so if you need some time to adjust to this change, you can set testIsolation to false in your configuration.

Removing of deprecated commands and APIs

Some of the APIs and commands reached end of life with the latest Cypress release. For example, cy.route() and cy.server() have been replaced by the much more powerful cy.intercept() command that was introduced back in version 6.

The more impactful change was the deprecation of Cypress.Cookies.default() and Cypress.Cookies.preserveOnce() APIs that were used for handling the behavior of clearing up and preserving cookies. With the introduction of cy.session(), these APIs didn’t fit well into the system. The migration from these commands to cy.session() might not seem as straightforward, but it is quite simple when you look at it.

For example, instead of using Cypress.Cookies.preserveOnce() function to prevent deletion of certain cookies you can use cy.session() like this:

beforeEach(() => {
 cy.session('importantCookies', () => {
   cy.setCookie('authentication', 'top_secret');
 })
});
 
it('test A', () => {
 cy.visit('/');
});
 
it('test B', () => {
 cy.visit('/');
});

Also, instead of using Cypress.Cookies.defaults() to set up default cookies for your tests, you can go to your cypress/support/e2e.js support file and set up a global beforeEach() hook that will do the same as shown in the previous example.

Besides these there were a couple of bug fixes and smaller tweaks which can all be viewed in Cypress changelog. Overall, I think that the v12 release of Cypress is one of the unsung heroes. Rewriting of query commands and availability of cy.session() and cy.origin() commands may not seem like a big deal on paper, but it will make the experience much smoother than it was before.

New command queries might require some rewriting in your tests. But I would advise you to upgrade as soon as possible, as this update will bring much more stability to your tests. I’d also advise to rethink your test suite and integrate cy.session() to your tests as it might not only handle your login actions more elegantly but shave off minutes of your test run.

If you want to learn more about Cypress, you can come visit my blog, subscribe to my YouTube channel, or connect with me on Twitter or LinkedIn.

The post What’s New in Cypress 12 appeared first on Automated Visual Testing | Applitools.

]]>
Component testing in Cypress: What is it and why it’s important https://applitools.com/blog/component-testing-in-cypress-what-is-it-and-why-its-important/ Thu, 15 Dec 2022 00:01:53 +0000 https://applitools.com/?p=44890 Cypress released the first alpha version of component testing back in version 4.5.0. It caught the attention of many, but if you are like me, you didn’t understand the buzz....

The post Component testing in Cypress: What is it and why it’s important appeared first on Automated Visual Testing | Applitools.

]]>
Cypress welcome page

Cypress released the first alpha version of component testing back in version 4.5.0. It caught the attention of many, but if you are like me, you didn’t understand the buzz. It’s completely okay, as component testing was always more of a domain of developers than testers. But testers can take an interest in component testing, too. Now that Cypress’ component testing features have reached General Availability (GA) in version 11, I decided to dive into this topic and find out why component testing is important. The more I played with it, the more I understood the appeal. In this blog post, I’d like to share my perspective with you.

What is a component?

Components are like Lego blocks. In the same way as toy castles, cars, and other creations can be built from Lego blocks, Web applications are built from components. Like Lego blocks, components come in different shapes and sizes and can serve different purposes. Some are used just once, some are reused all the time.

Each component has certain visual and functional properties. Like a Lego block, a component can be a common one that is used all the time and changed just slightly, or it can be a unique one that serves a specific function.

I want to show you how this works on a simple Vue.js application. Let‘s take a look at a simple Vue component that might look something like this:

<template>
 <button class=".green-button">{{ buttonText }}</button>
</template>
<script setup lang="ts">
defineProps({
 buttonText: {
   type: String,
   default: "Hello world"
 }
});
</script>

This component consists of two parts. One is the <template> part that contains a dynamic HTML markup. The second part is the <script> part that contains a TypeScript function that defines the properties that we want to render in the <template>. There is a buttonText string property that will be rendered inside the <button> element.

This is an example of a reusable component. I can use the button element all across my application, but I might want to render different texts for the button. Whenever I want to use this component, I call it like this:

<MyButton buttonText="Click me!" />

The button will render differently based on what property is passed into it. Here are some examples:

Buttons displayed with emojis and different text

Why test a component?

If you need to make sure that this button looks good with an emoji, special character, or normal text, what do you do? You could choose an end-to-end approach by clicking through the app to find and validate all the buttons, but this is not going to be very effective. It will be slow and cumbersome.

Enter component testing.

Instead of opening the whole application, with component testing, you can just mount the component in isolation. This means that you can save time loading just the parts you are interested in and test much faster. Or you test different properties of the same component and see how they render. This can be really helpful for situations where small changes affect a big portion of the app.

Imagine you are a developer who wants to refactor a component. While you are doing so, you can get immediate feedback on anything that might be broken. In other words, it’s easier to simply render a component with an emoji than to hunt through your app looking for it.This is why component testing is growing in popularity and why it is becoming one of the major trends in front-end testing. We can already see different implementations of component testing in tools like Jest, Storybook, WebdriverIO, Playwright, and Cypress.

Buttons don’t seem like much, though…

You are right. This example is way too simple to show the value of component testing.

Instead of a button, imagine a login form that validates a multitude of different inputs. How do you test that the form throws correct errors?

You could write an end-to-end test that will load the login screen, enter valid (or invalid) credentials, validate error messages, log in, log out, etc.

Or, instead, you could open the login form component only and try different inputs without the need of logging in or loading the rest of the login page. Loading a single component is way faster than loading the whole application. Testing a component in isolation can provide a lot of value, especially in cases like these.

What makes component testing with Cypress great

The main difference between Cypress and other tools is that it runs its component tests in a real browser. Besides that, you have all the power of the Cypress API at hand for your component tests as well. You can click, type, make assertions, and intercept network calls. You can spy on functions or stub them. This enables you to get to some really hard-to-reach places in your app and test them. You can mock your data or the component state, avoiding difficult data management or app setup.

Setting up component testing in Cypress

Starting with Cypress v10, setting up component testing is very straightforward.Once you open Cypress GUI using the npx cypress open command, you will be welcomed by this screen:

Cypress welcome page

The component testing option will take you through a simple setup wizard that will help you set up everything according to your application’s needs. As opposed to end-to-end testing, component testing is actually framework-specific. While the principles are pretty much the same for all frameworks, the loaders differ slightly – each one of them needs a separate set of tools. The setup wizard will take you through the steps to set up everything.

Framework and bundler

On the very next screen, Cypress asks you to choose a framework and a bundler. It even tries to detect the ones used in your app automatically. If you are building web applications for living, you are probably familiar with the different choices.

Cypress project setup page

As a tester, I needed to become familiar with these terms, especially with the “bundler”. The bundler is an essential part in building a modern web application. It converts the code you write into something a browser can read. As mentioned earlier, components split our application into small “Lego blocks”. These are often .vue files, .jsx files, or something similar. But these will not work in browsers by themselves. The bundler makes them into a bunch of .html, .js, and .css files that browsers can read.

When running a component test, Cypress will use the bundler to convert your component file into something a browser can read using the same bundler as your application does.

Cypress component testing project

Based on the inputs, the installation wizard will set up our project. Looking at the cypress.config.ts file, you can see that the configuration is actually pretty concise:

export default defineConfig({
 component: {
   devServer: {
     framework: "vue",
     bundler: "vite",
   },
 },
});

By default, Cypress will take options set in vite.config.ts file in our project, so anything we have set up for our app will instantly become available to Cypress tests as well.

cy.mount()

Besides resolving our configuration, Cypress will create a couple of helper files, one of the most important being component.ts located in the cypress/support folder.

import { mount } from 'cypress/vue'
 
// Augment the Cypress namespace to include type definitions for
// your custom command.
// Alternatively, can be defined in cypress/support/component.d.ts
// with a <reference path="./component" /> at the top of your spec.
declare global {
 namespace Cypress {
   interface Chainable {
     mount: typeof mount
   }
 }
}
 
Cypress.Commands.add('mount', mount)
 
// Example use:
// cy.mount(MyComponent)

This file will contain the mounting function for the framework you use. Cypress supports React, Angular, Svelte, Vue, and even frameworks like Next.js and Nuxt. As of Cypress version 11, most of these are out of beta.

How Cypress is built

Cypress’ architecture is unique when compared to other testing tools. With Playwright or Selenium, the goal is to automate a browser in order to perform some actions. With Cypress, you are essentially building an app to test your app.

When you are developing an application, your files get bundled and opened inside a browser. Imagine your standard npm run dev mode.

With Cypress, pretty much the same principle is applied. Your test files get bundled and opened in a browser. With component testing, instead of opening the app for your end-to-end test, you’ll mount your component. Pretty cool, if you ask me.

Creating a first component test

Once you set up your component testing configuration and your cy.mount() command, you are ready to start testing! So, let’s take a look at how this can be done.

With end-to-end testing, we usually have a dedicated folder where all our tests are. But with component testing, it is better to place your tests right next to your components.

Component testing folder in Cypress

When you create your first test, put a standard naming convention in place. In fact, Cypress will encourage you to do so with its default configuration, as it will look for any .cy.js or .cy.ts files. Basically, the .cy addition identifies the file as a Cypress test

You can, however, change this to .spec.ts in your configuration file:

component: {
 devServer: {
   framework: 'vue',
   bundler: 'vite',
 },
 setupNodeEvents(on, config) { },
 specPattern: 'src/**/*.spec.ts',
}

Mounting the component

Let’s now try to test our button component from before. Component testing in Cypress feels very familiar with end-to-end testing. It uses the same it() and describe() blocks from Mocha, but instead of calling cy.visit(), you will use cy.mount() to mount your component into the browser.

import SaveButton from './SaveButton.vue'
 
it('display save button', () => {
 
 cy.mount(SaveButton)
 
})

Notice that whenever we want to mount a component, we need to import it into our test file. When we run this test in Cypress, it will successfully mount our component.

A Cypress test on the Hello world button

You’d be right to raise your eyebrows, as this is not exactly what you would expect. Our component is missing CSS styles! In many cases, components rely on some other resource. It can be a module, package, state manager, or CSS as in this case. This means that in order to make our component test work, it is often the case that we need to import a bunch of stuff.

CSS is something that probably all your components will need, so you might want to import that to your component.ts configuration file. This is a place to set a global configuration for mounting all of our components.

import { mount } from 'cypress/vue'
import '@/index.css';
 
declare global {
 namespace Cypress {
   interface Chainable {
     mount: typeof mount
   }
 }
}
 
Cypress.Commands.add('mount', mount)

Passing properties

Let’s now try something else with our component. You may remember that we were defining a buttonText property that would then render text in our button. We can pass our own properties to the button right within the test by giving our cy.mount() function a props object with given properties:

import SaveButton from './SaveButton.vue'
 
it('SaveButton component', () => {
 
 cy.mount(SaveButton, {
   props: {
     buttonText: 'Hello world'
   }
 })
 
})

Easy, right? We are now ready to test different versions of the button that may appear in our application. And since we are in a Cypress test, we can use Cypress commands, too. For example, we can check that the buttonText property is actually rendered in our button:

import SaveButton from './SaveButton.vue'
 
it('SaveButton component', () => {
 
 const buttonText = 'Hello world'
 
 cy.mount(SaveButton, {
   props: {
     buttonText
   }
 })
 
 cy.get('button').should('have.text', buttonText)
 
})

Component testing and its importance

Component testing enables you to look at the individual components of your application and ensures that they are working as expected. It helps testers and developers identify and fix issues with individual components before they become bigger problems affecting the whole application.

While component testing still falls mainly in the developers’ area of expertise, understanding this type of testing is beneficial for testers as well. Most notably, learning how web applications are built improves intuition for finding serious bugs.

To learn more about component testing in Cypress, check out the Getting Started with Component Testing in Cypress on-demand webinar. Head over to the Applitools design team solution page to learn how Applitools speeds up component testing with AI.

The post Component testing in Cypress: What is it and why it’s important appeared first on Automated Visual Testing | Applitools.

]]>
Cypress vs Playwright: Let the Code Speak Recap https://applitools.com/blog/cypress-vs-playwright/ Mon, 18 Jul 2022 15:00:00 +0000 https://applitools.com/?p=40437 Wondering how to decide between Cypress and Playwright for test automation? Check out this head to head battle and see who comes out on top.

The post Cypress vs Playwright: Let the Code Speak Recap appeared first on Automated Visual Testing | Applitools.

]]>

Wondering how to decide between Cypress and Playwright for your test automation? Check out the results of our head to head battle of Cypress vs Playwright and see who comes out on top.

On the 26th of May Applitools hosted another “Let the Code Speak!” event. This time it was focused on two rising stars in web test automation – Cypress and Playwright. Both of these tools have huge fan bases and users that have reasons to either love or doubt these tools. The event had more than 500 attendees that decided on the ultimate winner. To determine the best framework, I (Filip Hric) and Andrew Knight a.k.a Automation Panda shared short code snippet solutions on various different testing problems in front of an online audience. Right after each example, the audience got to vote for the better solution in each of the 10 rounds.

Why Compare Playwright vs Cypress?

Cypress and Playwright both brought some novelties to the world of web test automation. These often work well with modern web apps that are full of dynamic content, often fetched from the server by REST API. For cases like these, automatic waiting is a must. But while these tools carry some similarities, they also differ in many aspects. These stem from the basic architecture of these tools, choice of supported languages, syntax they use, and more.

There is no silver bullet in test automation. All these differences can make a tool super useful, or inefficient, based on the project you are working on. It is comparisons like these that aim to help you decide, and have a little fun along the way. 

If you missed the event, there’s no need to worry. The whole recording is available online, and if you want to check out the code snippets that were used, I recommend you to take a look into the GitHub repository that we have created for this event.

Cypress vs Playwright Head to Head – Top 10 Features Compared

Round 1: How to Interact with Elements

We started off with the basics, interacting with a simple login form. The goal was to compare the most simple flow, and the one you usually start your test automation with. 

At first sight these two code samples don’t look too different from one another. But the crowd decided that the Cypress syntax was slightly more concise and voted 61% in its favor.

Round 2: How to Test iframes

Although iframes are not as common as they used to be, they can still present a challenge to QA engineers. In fact, they need an additional plugin in Cypress, which was probably why it lost this round. Playwright has native API to switch to any given iframe that takes away the extra leg work of installing a plugin.

Round 3: How Cypress and Playwright Handle Waiting and Retrying

With the nature of modern apps, waiting for changes is essential. Single page applications re-render their content all the time. This is something testing tools need to account for nowadays. Built in waiting and retrying capabilities prove to give the edge to modern testing tools like Cypress and Playwright. 

Taking a look at the code, this could be anyone’s win, but this round went to Cypress with a 53% of audience vote.

Round 4: How to Test Native Browser Alerts in Cypress vs Playwright

Given the different design of each tool, it was interesting to see how each of them deal with native browser events. Playwright communicates with the browser using a websocket server, while Cypress is injected inside the browser and automates the app from there. Handling native browser events might be more complicated then and it has proven to be the case in this round. While Playwright showed a consistent solution for alerts and prompts, Cypress had its own solution for all three cases, which caused a sweeping 91% victory by Playwright in this round.

Round 5: Navigation to New Windows

In the next example, we attempted to automate a page that opens a new window. The design of each of the tools proved to be a deciding factor once again. While Playwright has an API to handle a newly opened tab, Cypress reaches for a hack solution that removes the target attribute from a link and prevents opening of a new window entirely. While I argued that this is actually a good enough solution, testers in the audience did not agree and out-voted Cypress 80:20 in favor of Playwright.

Round 6: Handling API Requests

Being able to handle API requests is an automation superpower. You can use them to setup your application, seed data, or even log in. Or you can decide to create a whole API test suite! Both Cypress and Playwright handle API requests really well. In Playwright, you create a new context and fire API request from that context. Cypress uses its existing command chain syntax to both fire a request and to test it. Two thirds of the audience liked the Cypress solution better and gave it their vote.

Round 7: Using the Page Objects Pattern

Although page objects are generally not considered the best option for Cypress, it is still a popular pattern. They provide necessary abstraction and help make the code more readable. There are many different ways to approach page objects. The voting was really close here. During the live event it actually seemed like Playwright won this one, after the show we found out that this round ended up with a tie. 

Round #8 – Cypress and Playwright Language Support

The variety of languages that testers use nowadays is pretty big. That’s why Playwright’s wider support of languages seems like a clear winner in this round. Cypress however tries to cater to the developer’s workflow, where the support of JavaScript and TypeScript is good enough. However, this may feel like a pain point to testers that come from different language backgrounds and are not used to writing their code in these languages. It seemed that the audience agreed that wider languages support is better and voted 77% in favor of Playwright.

Round 9: Browser Support in Cypress and Playwright

Although Chrome is the most popular browser and has become dominant in most countries, browser support is still important when testing web applications. Both tools have good support for various browsers, although Cypress currently lacks support for Safari or WebKit. Maybe this helped the audience decide on the final round win of Playwright.

Round 10: Speed and Overall Performance

Last round of the event was all about the speed. Everyone likes their tests to run fast, so they can get the feedback about the state of their application as soon as possible. Playwright was a clear winner this time, as its execution time was 4x faster than Cypress. Some latest improvements on Cypress’ side have definitely helped, but Playwright is still king in terms of speed.

And the (real) winner of Cypress vs Playwright is…

The whole code battle ended up in 7:3 favor of Playwright. After the event, we met for a little aftershow, discussed the examples in more depth and answered some questions. This was a great way to provide some more context to the examples and discuss things that had not been said.

I really liked a take from someone on Twitter who said that the real winners were the testers and QA engineers that get to pick between these awesome tools. I personally hope that more Cypress users have tried Playwright after the event and vice versa.

This event was definitely fun, and while it’s interesting to compare code snippets and different abilities of the tools, we are well aware that these do not tell the whole story. A tester’s daily life is full of debugging, maintenance, complicated test design decisions, considering risks and effectiveness of automation… Merely looking at small pieces of code will not tell us how well these tools perform in real life. We’d love to take a look into these aspects as well, so we are planning a rematch with a slightly different format. Save the date of September 8th for the battle and stay tuned to this page for more info on the rematch. We’ll see who’s the winner next time! ?

The post Cypress vs Playwright: Let the Code Speak Recap appeared first on Automated Visual Testing | Applitools.

]]>
What’s New in Cypress 10 https://applitools.com/blog/whats-new-cypress-10/ Wed, 01 Jun 2022 19:05:21 +0000 https://applitools.com/?p=38967 Cypress 10 is here with powerful new features, headlined by new component testing functionality and a completely redesigned UI.

The post What’s New in Cypress 10 appeared first on Automated Visual Testing | Applitools.

]]>

Just a few hours ago Cypress officially debuted their biggest release ever. Cypress version 10 has some powerful new features, headlined by new component testing functionality and a completely redesigned UI. There’s a lot to unpack, so let’s take a look together.

Component Testing

While component testing was present in previous versions of Cypress as an experimental feature, with Cypress 10 it is getting much more of a spotlight. This will make a lot of developers happy. Being able to render components in a real browser, debug them using Chrome DevTools and access different states is a real game changer.

With this feature Cypress is entering into a competition with tools like Jest or Storybook, which are very popular with developers.

The welcome screen of Cypress with options for E2E and Component Testing.

The best part about this is that instead of testing your components with the terminal (where you can’t really see them) you are testing your components inside a browser. You can interact with them too, which adds up to an amazing developer experience.

The main difference between end-to-end testing and component testing is that instead of using cy.visit() to open your application, you use cy.mount() to render out your React, Vue, Angular or other component and test it in isolation.

Key differences between end-to-end tests and component tests, including the need to use via cy.visit() for e2e and cy.mount() for component tests.

If you are just getting started with component testing, Cypress has got you covered. They have included a really nice setup wizard to help you setup your project for component testing. This will help you install the dependencies you’ll need and set up your cypres.config.js configuration file for you.

Project Structure

With previous versions, you might have been used to seeing these items in every Cypress project:

A screenshot of a Cypress project directory with folders for e2e, fixtures, plugins and support, as well as cypress.json and package.json files.

This is no longer the case for Cypress 10. Your configuration will now be stored in cypress.config.js instead of the cypress.json file. This is a pretty familiar pattern used with different web development tools.

Your plugins/index.js file is now part of this file as well. With this function you can tap into different node events that happen during a Cypress test run (like auto-opening dev tools when browser opens, or dynamically resolving configuration) or trigger node scripts right from your test.

A screenshot of a new Cypress 10 project directory with folders for e2e, fixtures and support, as well as cypress.config.js and package.json files.

Naming Conventions

With component testing brought into the game, developers and testers need to distinguish between different types of tests and be able to keep the whole project clean and easy to navigate. That’s why Cypress now recommends naming your end-to-end tests as test.cy.js and your component tests as test.spec.js. This is of course just a recommendation, and you can specify any pattern using specPattern option in the cypress.config.js file.

Besides this naming convention, the oddly named integration folder where the test files are will now become the e2e folder. support/index.js will now become support/e2e.js. Of course, all of these can be configured in the cypress.config.js file and there’s no need to follow these conventions if your project uses another.

Migration Assistant

Feeling overwhelmed by all the changes? No need to be! The Cypress team has prepared a migration assistant that will make sure the transition of your project is seamless. In three easy steps you can change the names and folder of your e2e tests:

rename the support/index.js file:

and most importantly, migrate your cypress.json to a cypress.config.js file.

Deprecations

With the new version, Cypress users will say goodbye to some of the features that were not widely used. Most notably, Cypress’ test recorder called Cypress Studio will no longer be present in v10. This was communicated in a recent blogpost in Cypress which communicates some of the reasoning behind the decision. There’s also an open discussion for those who might miss this feature. 

If you still need a record and replay tool for your Cypress testing, you can use the brand new functionality of DevTools Recorder. Since v100 it can generate Cypress code that you can import in your tests. We took a look at this with Mike Cataldo in our recent podcast. For more about it you can also check out this post to learn how to get started with the DevTools Recorder, or this webinar on automating tests using DevTools Recorder with Google’s Jecelyn Yeen.

Cypress is also pushing towards using cy.session(), which is a great command for caching your browser state and avoiding having to log in before every test. This solution will soon become the preferred way of handling cookies, local storage and session storage, making APIs like Cypress.Cookies() obsolete. This deprecation was in fact announced in version 9.7.0. The good news is that using cy.session() pairs greatly with Cypress’ recently released 3rd party domain support. To avoid doing 3rd party login multiple times, you can cache it with cy.session() and limit the number of login actions that could otherwise cause rate-limiting.

Going Forward

Cypress 10 was a version long in the making. While there are many changes that might feel like just visual changes there’s more to this update than meets the eye. The Cypress team has also made many changes “under the hood” which prepare ground for some long awaited features such as native iframe support, or WebKit support. While working with iframes is possible now, it requires some workarounds and does not provide the same debugging features as rest you’ll get for the rest of your site. With WebKit support, you’ll be able to test against a Safari-like browser, which is widely used, especially with Apple users. Since Cypress is open source, you can check out the progress on these features on their roadmap, where you can find links to the open issues.

Learn More and Get Started with Cypress 10

If you are interested in exploring what’s new with the latest versions of Cypress, join me live on YouTube, where Mike Cataldo and I will discuss the updates and explore what’s new in Cypress 10 together. We start the stream on June 1st, but you can check out the recording after the stream ends as well.

You can download the latest version of Cypress directly from their website or by running npm install cypress in your terminal, starting today. Of course, if you’re using Applitools for visual testing, it’s compatible with all versions of Cypress, including v10. Learn more about how to get started with Cypress and Applitools, or if you’re new to Applitools you can sign up for a free account today.

The post What’s New in Cypress 10 appeared first on Automated Visual Testing | Applitools.

]]>
What’s New in Cypress 9 https://applitools.com/blog/whats-new-cypress-9/ Fri, 19 Nov 2021 17:06:13 +0000 https://applitools.com/?p=32773 Cypress 9 has some breaking changes and new features that are worth talking about.

The post What’s New in Cypress 9 appeared first on Automated Visual Testing | Applitools.

]]>

Cypress 9.0.0

Last week, Cypress came out with their 3rd major release this year. Version 9.0.0 does not bring many radical changes, but as is usual with Cypress, it lays ground for upcoming features. But there are couple of breaking changes and new features that are worth talking about, so let’s dive into them.

Breaking Changes in Cy.Contains

This is one of my favourite commands in Cypress. It enables you to select elements using its text, which is just great for test readability. You can also filter what kind of element with a given text you want to search for.

View the code on Gist.

Prior to Cypress v9, .contains() would target any element that is inside the <body> tag. In some frameworks, this would lead to situations where Cypress would select a <style> or <script> tag as well, if it would contain given text. Normally this would lead to unexpected results, so in version 9, any <script> or <style> tags are ignored by cy.contains() querying. If you still want to check content of these tags, you can do so using cy.get() command.

View the code on Gist.

Custom Commands

Custom command are great. they are one of the best way to abstract your code in Cypress and expand your command library. They allow you to wrap existing commands and create command sequences, create custom logic or even autocomplete your selectors.

Since the existing command library is already pretty big, it is easy to create your own command and accidentally hit an existing command name. This can lead to confusing situations. Cypress team has added a guard, that will throw an error in case this happens.

You may see this error: “Please use Cypress.Commands.overwrite() if you would like to overwrite an existing command”

No worries though, the existing Cypress.Commands.overwrite() API remains intact. You can still rewrite existing commands, or add functionality. How about improving the existing cy.log() command and add numbers to your logs? Check out my article!

File Encoding

With commands like cy.writeFile() and cy.readFile() you can write and read files from your filesystem. In addition to existing encodings, you can now write and read your files and fixtures as binary, using a null argument.

To read about different encodings, visit Cypress documentation.

Other New Updates in Cypress 9

There are also a couple of minor improvements that may help you with testing your application. Cypress has improved the way it handles sticky headers. With its latest update, it will try to make sure that an element is not covered by sticky header – a situation one might run into. in various cases.

document.referrer is now correctly taken from the application under test, instead of being added by Cypress. This is especially helpful for application that rely on this attribute in situations where a given app is embedded inside an iframe.

Cypress has also done minor improvements on TypeScript for custom commands. With v9, argument types are inferred from type definition, which prevents adding improper arguments or their accidental rewriting.

With its latest release, Cypress also drops support of 32-bit version of Windows as this is not widely used anymore.

Curious How Cypress Works with Applitools?

You can easily add automated visual testing to your Cypress tests using Applitools – it’s fully compatible with the latest version. Check out this blog post for an example or feel free to dive right into our tutorials.


Get Started Today

Want to try Applitools Eyes for yourself? You can get started today at the link below – the account is free forever.


The post What’s New in Cypress 9 appeared first on Automated Visual Testing | Applitools.

]]>
How to Test a Mobile Web App in Cypress https://applitools.com/blog/how-to-test-mobile-web-app-cypress/ Mon, 08 Nov 2021 19:00:32 +0000 https://applitools.com/?p=32376 Cypress is sometimes known as a tool for testing anything that runs in a browser. Here's how you can do mobile testing on the browser with mobile web apps.

The post How to Test a Mobile Web App in Cypress appeared first on Automated Visual Testing | Applitools.

]]>

Before we start, we need to clear up some areas that tend to confuse people when it comes to mobile testing. If you’d like to test a mobile application built for iOS or Android, Cypress will not be efficient and you should probably reach for a tool like Appium (although there are some interesting examples by Gleb Bahmutov for React Native). Cypress is best known as a tool for testing anything that runs in a browser. So in order to use Cypress for your mobile testing, your app needs to be able to run in a browser. That brings forward a question: “What’s the difference between desktop and mobile web app?”

To answer this question, it’s best to look at the application in test from a perspective of a developer. As someone who creates a web application, you might want to consider a couple of traits that make the mobile app different from a desktop one:

  • screen size
  • touch interface
  • any other information about the device

Let’s go through them one by one and see how we can write a Cypress test that would ensure our application works as expected. If you want to follow along, you can clone my repository with the application and attached Cypress tests. The simple example application shows different messages based on viewport width, presence of touch interface or user agent.

Testing the Viewport Size

We might want to test a responsive CSS on different screen widths to see if the application renders correctly. This can be easily done by using the cy.viewport() command. You can specify width and height of the viewport, or choose from one of the predefined devices:

View the code on Gist.

Using these commands will trigger visibility of a “it’s getting pretty narrow here” message:

<the text displays ‘it’s getting pretty narrow here’ on a narrow viewport.

CSS responsiveness can hide or show different content, like buttons or modals. A nice trick to test this is to run your existing tests with different resolution. To do that, pass a --config flag to your CLI command:

npx cypress run --config viewportWidth=320 viewportHeight=480

You can also set the viewport width and viewport height in cypress.json or programmatically via Cypress plugin API. I write about this on my personal blog in a slightly different context, but it still might be helpful in this case.

Depending on your application, you might want to consider testing responsiveness of your application by visual tests using a tool like Applitools. Functional tests might have a tendency to become too verbose if their sole purpose is to check for elements appearing/disappearing on different viewports.

Testing for Touch Devices

Your application might react differently or render slightly different content based on whether it is opened on a touch screen device or not. Manually you can test this with Chrome DevTools:

displays whether we’re viewing the page on a computer that is a touch device, or one that is not.

Notice how we can have a touch device, that is actually not a mobile. This is a nice case to consider when testing your app.

In Chrome DevTools, we are simply switching a mode of our browser. It’s like changing a setting to enable viewing our app as if it was opened on a touch device.

With Cypress we can do something very similar. There is an ontouchstart property which is present on a mobile browser. This is usually a very good clue for a web application to “know” that it is being opened on a touch device. In Cypress, we can add this property manually, and make our application “think” it is being opened on a touch device:

View the code on Gist.

With the onBeforeLoad function, we tap into the window object and add the property manually, essentially creating a similar situation as we did in DevTools, when we toggled the “touch” option:

displays whether we’re viewing the page on a computer that is a touch device, or one that is not, in Cypress.

To go even further with testing a touch interface I recommend using Dmitryi Kovalenko’s cypress-real-events plugin that fires events using Chrome devtools protocol. Your Cypress API will now get augmented with cy.realTouch() and cy.realSwipe() commands, which will help you test touch events.

Testing with User Agent

Some applications use information from user agent to determine whether an app is being viewed on mobile device. There are some neat plugins out there that are commonly used in web applications to help with that.

Although User Agent might sound like a super complicated thing, it is actually just a string that holds information about the device that is opening a web application. Cypress allows you to change this information directly in the cypress.json file. The following setup will set the user agent to the exact same value as on an iPhone:

View the code on Gist.

However, you might not want to change the user agent for all of your tests. Instead of adding the user agent string to cypress.json you can again tap into the onBeforeLoad event and change the viewport on your browser window directly:

View the code on Gist.

The reason why we are not changing win.navigator.userAgent directly via the assignment operator (=) is that this property is not directly configurable, so we need to use the defineProperty method. Opening our application in this way will, however, cause our application to render a message that it is being viewed on mobile device:

shows that we are viewing this page on a mobile

Conclusion

You cannot test native mobile apps with Cypress, but you can get pretty close with mobile web apps. Combining these three methods will help you narrowing the gap between desktop and mobile testing. To understand what makes an app behave differently, it is nice to look into your app as a developer at least for a little while.

If you enjoyed this blogpost, make sure to head over to my personal blog for some more Cypress tips.

The post How to Test a Mobile Web App in Cypress appeared first on Automated Visual Testing | Applitools.

]]>
Getting Started with Cypress Studio for Test Automation https://applitools.com/blog/getting-started-cypress-studio/ Thu, 29 Apr 2021 22:50:00 +0000 https://applitools.com/?p=28731 With version 6.3.0, Cypress released a feature called “Cypress Studio.” It allows you to create a test script simply by opening the Cypress window and interacting with your app. If...

The post Getting Started with Cypress Studio for Test Automation appeared first on Automated Visual Testing | Applitools.

]]>

With version 6.3.0, Cypress released a feature called “Cypress Studio.” It allows you to create a test script simply by opening the Cypress window and interacting with your app. If you are familiar with record & replay testing tools, you’ll probably get yourself familiar with the tool pretty quickly. So let’s see what Cypress Studio offers and what makes it different from other record & replay tools.

Getting started

Cypress Studio is still in experimental mode, so to enable it, you need to edit your cypress.json file. Just add "experimentalStudio": true and you are good to go.

To start working with Cypress Studio, create your first test file, and open it. You should now see a Cypress Studio icon in your test runner. At first, you might not even notice it, because the icon only appears when you hover over the test name.

The icon for Cypress Studio appears when you hover over the test name

Once you click the icon, the test runner will enter a “recording mode” and you can start interacting with your app. It will record clicks, typing, un/checking checkboxes and selecting options from a <select> element. If you accidentally do an unintended action, you can remove it.

The Cypress Studio test recorder in action

Once you are happy with the flow you have created, you can save your commands right inside your test file. The flow you created is bounded by comments in the file, so you can clearly differ between what was generated and your own code.

The code created is bounded by comments indicating it was generated with Cypress Studio

Using Cypress Studio

First experience is really satisfying. You can see commands pop inside the test runner timeline. Being able to remove commands or accidental clicks is really neat and gives you a great control over the final script. Cypress Studio even seems to handle a situation when the application does an autofocus on an input and the user starts typing immediately. This is really nice, because this means that even if a user is not fully aware of this, it will still get added to the command chain.

Whenever you save your commands, your test is re-run. This gives you immediate feedback on your test flow. I have often found that my test is not really “repeatable” and I need to dive inside the code to handle this. That’s not always what I want, so to prevent automatic re-running of my test, I set "watchForFileChanges" to false in the cypress.json file.

One thing to keep in mind is that Cypress Studio does not record any assertions. Although you might be creating a great automation flow, you need to add some assertions to make your test really test something.

Cypress Studio builds on top of a Selector playground. This is another handy tool that helps you find the right selector in your application. It’s a great alternative to finding proper selectors via elements panel in Chrome developer tools.

What’s cool about Selector playground is that it has an API through which you can set up selector preference. The default preference can be found in docs, but if you wish to set up your own, you can do so by setting it up in your support/index.js file. For example, if you want to prefer using classes over any of the element attributes, you can set it up like this:

Setting a preference in Selector Playground

Who is Cypress Studio for?

To be completely honest, I wasn’t too excited when this feature was released. Trying to record my test flows will never be enough to generate a fully working test automation script. With a generated script you are just scratching the surface of what is happening in your app. There’s tons of network communication to be looked at and changes to be asserted.

But then I realized this was probably not built for someone who can already easily navigate themselves through Cypress or any other automation tool. It is actually a great learning tool for all those brave souls that want to start with test automation. And that’s where Cypress Studio becomes really empowering.

For years now, I held the opinion that Cypress is one of the greatest tools when it comes to starting with test automation. It has a really simple syntax and although you need to gather some JavaScript experience, you can get that thrill of your first running test very early on in your learning journey.

But even learning the basics of JavaScript might be too much in those beginnings. Especially when you are still learning what the web is made of. I started my first test automation efforts in Selenium IDE and there was a lot to figure out even with such a simple tool. Record and replay tools are great for getting that first time experience. Whenever you generate code, your natural next step is to examine how that code actually works. That can provide valuable insight.

E.g. you learn that for a normal user, typing into an input just a simple action. But for test automation script, it actually means:

  1. selecting the element with proper selector
  2. clearing the input
  3. typing in the text
  4. pressing an enter key

Not only that, but running a test multiple times introduces the problem of handling data that has been created, finding where the test should start and when should it end. This is just a fraction of things one needs to learn and it’s easy to forget these, once you’ve already passed a long way in your learning journey.

Cypress is a fairly new player in the test automation world and it seems to have gained a lot of love, and understandably, also some critique. Although the approach to testing might not sit well with everybody, there’s one area where the Cypress team pretty much nailed it. And that’s developer experience. With tools like Selector Playground and Cypress Studio, the Cypress team made sure that they open doors for everybody. At the time, when many make their first attempts in the tech world it makes perfect sense. Being one of those that started just a couple of years ago I really appreciate the effort to make test automation more accessible.

If you’ve enjoyed this post, visit my personal blog at filiphric.com, where I publish a new Cypress-related post every week.

The post Getting Started with Cypress Studio for Test Automation appeared first on Automated Visual Testing | Applitools.

]]>
Page objects vs. App actions in Cypress https://applitools.com/blog/page-objects-app-actions-cypress/ Thu, 04 Feb 2021 01:45:44 +0000 https://applitools.com/?p=26641 The truth is, that using POM does no harm in Cypress and can be really helpful. But I like that Gleb has made a strong argument for other options. Because using them unleashes some Cypress superpowers. In this post, I’d like to explore and describe both of these options

The post Page objects vs. App actions in Cypress appeared first on Automated Visual Testing | Applitools.

]]>

If you started using Cypress in recent years, chances are that you heard about “app actions” being preferred over using page objects. In fact, if you google “Cypress page objects” the first article you’ll see is Gleb Bahmutov’s blog titled:

Stop using Page Objects and Start using App Actions

I see this statement confusing some people, making them think that using Page Object Model (POM) is some sort of anti-pattern in Cypress. The truth is, that using POM does no harm in Cypress and can be really helpful. But I like that Gleb has made a strong argument for other options. Because using them unleashes some Cypress superpowers. In this post, I’d like to explore and describe both of these options.

Page objects

Gil Tayar has made an excellent demonstration of how to use page objects in Cypress. If you are new to this concept or haven’t yet used page objects in Cypress, I suggest you watch that video. In fact, go watch the full course on Test Automation University. It’s free! To sum things up for this article, let me just give you a very quick TL;DR version of how to create page objects.

For demonstration, you can take a look at my Trello clone app. Make sure you check out the page-objects-app-actions branch.

Let’s say we want to work with the login/signup part of our app. Normally this is the part where many of our test efforts start. To create a page object, create a separate .js or .ts file where all your functions for a particular component will be stored.

I will create a login.ts file that will look like this:

View the code on Gist.

I am creating a Login class, which contains two functions. One will open my login window, and the other clicks a link to the signup page. So basically, I’m grouping sequences of Cypress commands into these functions. These help me divide my test code into smaller chunks that I can later reuse.

Paraphrasing Gleb from Cypress again –

It’s all JavaScript, you can do whatever you want.

And he’s right. I can add actions, assertions, or pass arguments into these functions. Let’s see what these two functions do in our application (I slowed the video down a little so it’s clear to see):

In my test, I want to open the login modal window, and then click on the „Sign up here“ text. This is what our test code looks like, using functions from our page object:

Notice how our functions are chained together. This is because in each of our page object functions I’m using 

return this;

This way, each of our functions returns to the original context and will be chained off our Login class.

Now, whenever I want to create a flow that includes clicking on a “Log in” button, I can use a function from my page object. Since I have this action abstracted in page object, in theory, I can now write tests for login, signup, reset password, logout, and many other user stories.

Also, whenever something in our login flow would change, I can just edit my page object and that change translates everywhere. This helps avoid situations when I need to rewrite multiple tests because of a single change in the tested app.

Page objects are also a great way to get your app into the desired state that you want to test functionally or with visual tests.

These are some main reasons why testers abstract their UI actions into page objects. So why wouldn’t you use them in Cypress?

Why don’t just stick with page objects?

The main reason for choosing a different approach is to take advantage of how Cypress is built. Cypress runs inside the browser, which is the main difference compared to Selenium-based test automation. That means that Cypress can actually get access to a lot of what’s happening inside of our application.

For example, we can call the exact same function that gets called when we click on the “log in” button. In other words, we can open our login modal window without actually doing the click. That way, we can skip interacting with UI through our page objects, and just start our app in any state we want. This enables us to avoid doing UI actions that are not actually a part of our test.

In our app, let’s say we want to do a visual test for our signup view. In order to create such a test, we need to:

  1. Click “log in” button
  2. Click “sign up here” link
  3. Do our visual test

Notice, that steps 1 and 2 are not actually part of what we want to achieve. We are here just for the state that we want to test visually. Furthermore, I imagine this is an example of a very simple flow. There may be some hard-to-reach places in your app that require you to do multiple steps. So how about we just:

  1. Set our app to the desired state
  2. Do our visual test?

This is what app actions actually do. Instead of clicking, typing, and interacting with our app, we will set it up the way we want.

Before we write our first app action, let’s examine how our app actually works.

Looking into the app

Our app is built with Vue.js. If you are not familiar with it, I suggest you check it out. It provides a great developer experience. For some reason, Vue was the easiest to learn for me as a tester out of the most popular frameworks. But if you are working with Angular or React, principles are pretty much the same.

Vue.js comes with some amazing developer tools. These enable you to change the state of your app right from devtools. Look at how I’m able to toggle the visibility of our login element with these tools:

You can see that I have an attribute called showLoginModule that can be set to true or false. With Cypress, we are going to change the state of our app in a very similar way.

To do that, we need to first expose our app to our window context. This may sound like a challenge, but in our Vue app is just done by adding the last line in this piece of code:

View the code on Gist.

Whenever we now open our dev tools and type window.app into our console, we will see our attributes, app functions, and much more information about our app. In fact, if we decide to type 

window.app.showLoginModule = true 

into our console, our login modal window will open. Go ahead and try that!

Creating an app action

Now, we can do the exact same thing using Cypress, like this:

And just like that, our login modal is open! We have made our first app action. In other words, we have set our app to the desired state. Let’s go one step further and get to our signup page. Now, instead of simply setting our attribute to the desired state, we will call a function that changes the state for us.

To save us some time, I have created a helper custom command in our app, that will select one of our components:

  • root
  • Navbar
  • Login
  • board-collection
  • board

These are the same components you can see in Vue.js dev tools. You can use the command simply by calling 

cy.component('Login')

This command will return our component with all its data and functions:

Notice that this component contains a logSignSwitch() function. If you look into the code, you’ll see that this is a function responsible for switching between “login” and “signup” view in our modal window.

We will now call this function from within our test using the following code:

This will now open our app in desired state, which is our signup screen.

Why bother though?

This is a legitimate question. Seems like the setup is more complicated than setting up page objects. However, one does not rule the other. You can combine both approaches and use the one that is more appropriate for your test. It is however good to design your tests in a way that will shorten them by starting it at a desired point.

App actions can also be quite fast. During my comparison of these two tests, I got to finish my tests in 0.34 seconds for page objects and 0.18 seconds for app actions. Although both are pretty fast, things can really make a difference when running thousands of tests.

App actions also skip the part where e.g. your inputs need to become interactive, our your buttons need to become clickable. There are no incomplete input fields or misclicks because we are skipping this kind of interaction altogether.

Of course, we cannot write an end-to-end test without interacting with our application directly. For these parts, abstracting common actions make absolute sense. But for the parts of our app that are already tested, we can save some time and skip a few steps.

I find app actions especially useful for setting up your app for a visual test. You may save yourself a few headaches by skipping UI interaction and jumping straight into your desired state.

If you liked this blog, be sure to check out my page at filiphric.com, I write a Cypress tip every week and do all kinds of fun stuff ?

The post Page objects vs. App actions in Cypress appeared first on Automated Visual Testing | Applitools.

]]>
8 Cypress Plugins You Should Know https://applitools.com/blog/cypress-plugins/ Mon, 23 Nov 2020 17:00:25 +0000 https://applitools.com/?p=24810 Cypress benefits greatly from being part of the JavaScript and Node.js ecosystem. There are tons of plugins which you can just install via npm and use them within your tests. They expand functionality, add new commands, add missing features and so much more.

The post 8 Cypress Plugins You Should Know appeared first on Automated Visual Testing | Applitools.

]]>

Cypress is a top choice for many developers that create modern web applications written in popular JavaScript frameworks. It is a tool that greatly fits into developer workflow, but has found love among test automation engineers and QAs too.

Cypress benefits greatly from being part of the JavaScript and Node.js ecosystem. There are tons of plugins which you can just install via npm and use them within your tests. They expand functionality, add new commands, add missing features and so much more.

Installing a Cypress plugin

Most Cypress plugins can be installed in 3 steps:

  1. open terminal and type `npm install <name of your plugin>`
  2. in your cypress project, go to support/index.js file and import/require your plugin
  3. go to plugins/index.js file and include your plugin inside module.exports function

Some of the plugins only require you to do step #2 or step #3. The installation is often very well documented by the authors, so even if you are new to Cypress, you’ll have good guidance.

There are tons of options, and it’s easy to get lost In the vast universe of Cypress plugins. In this post I’d like to share my pick for the very best.

Add drag and drop functionality

There is no .drag()  function in Cypress, but the Cypress Drag Drop plugin will add it for you. These come in super handy if you have a list that you can reorder by drag and dropping. You can simply select an element and then drag it onto another like this:

drag

Upload files

Similarly to the previous, the Cypress File Upload plugin adds missing functionality. With cypress-file-upload, you can take any file input element and upload a file within your tests. What’s really cool about this one, is that it plays well with Cypress fixtures. Just add the name of your file that is located in the fixtures folder as an argument and voila!

attach

Testing emails with Mailosaur

Have you ever tested “forgot password” functionality? These flows can be a real challenge since you need to access an email inbox. With Mailosaur service, you have an inbox created for you. You can access it by using this awesome Cypress Mailosaur plugin. It will allow you to search or delete your emails and so much more. When searching for a message, this plugin will return your email parsed as a JSON with data such as links, recipients or email subject.

Library of awesome commands

Cypress is all JavaScript. You can expand it any way you like, create your own logic and do whatever JavaScript enables you to do. With custom commands, you can create your own set of commands that fit in your project. Or you can choose to import an existing command set like the one offered by the Testing Library plugin.

Testing Library is an awesome project that contains utilities for better testing, suitable for many different frameworks, and it has its Cypress module too. You’ll be able to select elements based on their placeholder, label, role attribute and even more.

Docs in your terminal

The documentation of Cypress project is a masterpiece. It is basically a tutorial on how to use Cypress that will get you from A to Z. I open Cypress docs many times during the day.

With TypeScript and intellisense I can access the documentation right as I type. With the Cy Search plugin, I’m getting something little extra. I am able to search Cypress docs from the command line. I just type the keyword and pick the article I want to open. Fun fact: I helped improve this plugin ?

2020 11 12 23.06.23

Choose a spec to run headlessly

While we are still in the terminal, I’ve got another plugin tip for you. If you want to run a single test in your Cypress project in headless mode, you can just type `cypress run –spec <path to your spec>` but that gets tedious when you have multiple projects or you want to run multiple files at once. This can be easily solved by the Cyrun plugin, which enables you to pick a single spec or run a whole folder in Cypress headless mode.

Skip a test

There are some tests that you may want to run only on localhost. Or only in a certain browser. Or only in headless mode.

Rather than adding conditional statements that may pollute your test code, you can use the Cypress Skip Test plugin. It allows you to run a test or set of tests based on various conditions. You can choose to skip a test or decide to only run it if a condition is met. Out of the box you can decide based on stuff like operating system, browser or url, but you can basically choose any condition you like.

Sponsored by Applitools – Check out the Applitools Cypress SDK Tutorial

Visit Tutorial

Bonus plugin: Come to the dark side

Big fan of dark mode? There’s one for Cypress too, Cypress Dark! It even has a spooky Halloween theme that laughs at you when your test fails. How rude! ?

There are of course a ton of great plugins and I suggest you explore them. You‘ll definitely find the one that helps you write your tests faster or makes the process more comfortable. If you liked this article, come visit my blog where I share Cypress tips on a weekly basis.

Cover photo by James Orr on Unsplash

The post 8 Cypress Plugins You Should Know appeared first on Automated Visual Testing | Applitools.

]]>