I’ve had to use Cypress at work, and I really don’t like it. I find the command chaining and assertion queuing to be very unintuitive. (“Do I chain this one or not? Maybe stick it in a callback? No idea!”)
It’s been a few months since I’ve touched it, so I’m struggling to give more specific criticisms.
I’ve had a really great time using Kent Dodd’s DOM Testing Library [1] for unit tests. The readability and writability of these tests has been fantastic. I wish I could use the exact same API for e2e tests. It looks like they actually do have a Cypress version of the Testing Library [2], but it seems to suffer from the same Cypress-isms that I was just complaining about.
Has anyone else had a similar experience? It seems like I’m in the minority opinion. Maybe I’m just bothered because I don’t understand Cypress well.
I spent a few weeks with it, and it was very frustrating.
The programming model is very odd. I found it next to impossible to share any code between tests, and most of the programming skills I've learned over the decades didn't seem to apply.
It is vastly superior to anything else we've seen in stability and polish. If I only could write reasonable code for it, things would be great...
I found their idea about defining commands very odd, but when we ignored these entirely and just went with the good old page pattern, the tests became very tame again. All the cypress-internals are done in small methods within page-objects, the tests contain only the abstract page-object-methods.
But yes, when we tried to run with the patterns they advertise, the tests became indeed hard to write and read; maybe we did it all wrong but it's at least consistent with the experience expressed by you and others in the thread here.
The one slight gotcha is if you go for the page object pattern the intuition is that each page object holds a reference to the cypress element that formed it so you can do new LoginForm(cy.get('#loginForm')) or similar which is a mistake because of the way cypress chaining works - it will result in only being able to use a single method once on the page object. Instead you need to query fresh again each time.
Which is fine when the page object is a login form, but a bit more comfortable complicated when it's notification 5 or something.
Good point, I'd gotten used to that and forgotten how it is kind of counterintuitive at first. Our base test helper object does this:
get root() {
// It is important here to run cy.get()
// each time this property is accessed.
// Lots of methods of this class chain
// off of `this.root` so it needs to be
// re-evaluated every time.
return cy.get(rootComponentCss);
}
find(selector: string, options?: any) {
return this.root.find(selector, options);
}
...so that component-specific test helper objects (subclasses) can just do something like:
get sendMissileAlertButton() {
this.root.find('.x-hawaii-missile-incoming');
}
That way, it looks up the target element every time it is used in a test.
I've compared a few thousand tests in each testing library from real companies and I've found Cypress to be with "as many defects as Selenium in real projects".
Most of the other open source tools (not to mention enterprise tools like Testim.io where I work) support the things that make Cypress "fast" like mocking network requests or automatically waiting for elements. I wrote an article about this somewhere I can dig it if you want.
If you have data showing differently I'd love to see it.
Did you ever need to mix cypress tests with anything else? Say for example I wanted to have cypress click through a frontend, and then make a separate backend call to verify something happened in the same test run. Is there a clean way to do that in a cypress context, or is playwright / puppeteer going to be a better fit?
What's your backend written in? I'm in a similar position where work is pushing cypress, but there is no library for cypress in our backend language, there is for playwright. I want to do something in the frontend, and check the backend, so it would be nice to use our existing backend language for both so we have access to our internal library. I was told we could write a bash script and have cypress exec. Of course we can do a script in any language, but suddenly I'm seeing a bash QA library emerging at my work. Does that sound absurd to anyone else?
What do you mean with "check the backend"? You can e.g. do assertions on HTTP-responses coming from the backend - is this what you head in mind?
If you want to test the backend on its own, I personally would recommend using a different framework than cypress (or a different framework than the one being used for frontend e2e testing in general). Otherwise you risk that people conflate these two things and start "testing the backend" in e2e-tests for the frontend, which are super slow.
Yeah, specifically that interfacing with the ui causes some side effects we would expect to happen (web hooks sent, reports generated, etc). I definitely wouldn't want to write all of our tests that way, because that sounds like a nightmare to maintain and run, but was considering a handful for covering a few major features. We do already have a very extensive backend integration test suite (http / rest interactions) that doesn't do anything with UIs, though.
Cypress is a recent addition for us, so this is more a curiousity than anything else. I've done similar fully e2e / functional tests with puppeteer in the past.
Our backend is in node / typescript, so it's theoretically possible to mix the two. I would be able to test what I need using REST APIs, though, so in theory the backend language doesn't really matter for me.
I haven't had much time to try anything yet, but cypress's override of promises and async / await makes me think it'll be a pain to try adding non-cypress-specific checks to a cypress test.
Ideally you should not combine Cypress Frontend end to end tests with backend testing.
You use Cypress to do something on the frontend, which triggers something on the backend and ideally that change is reflected on the frontend, you test that frontend change using Cypress.
For backend testing just directly call the backend API's and then check the database directly.
There is a difference between integration testing (Cypress UI click through UI) and backend unit testing.
We run integration tests with Cypress and then rspec or some other Rails testing platform for the backend.
Cypress uses fixtures so ideally you would not let it hit a backend API unless you don't care about reproducibility of the response. For example a PUT will augment the data on the backend so when you run the test again the backend data will probably give you a different response to assert and fail your expected.
Due to the limitations of Cypress you end up using them both.
Cypress for the simple tests, and for the more complex case, e.g. opening tabs, testing your SSO login paths, I frame widgets, you end up using Playwright. I spend quite a lot of time to even fork Cypress to add support for testing WebKit browsers. Probably was quicker to write a Cypress kind of solution for Puppeteer/Playwright
We have Cypress tests that call our database directly and get information out, call 3rd party APIs to get information back, and call our APIs we've specifically created ourselves to help Cypress tests. It's pretty flexible; I'm just not sure how much this flexibility might bite us in the future.
One thing I didn't see mentioned is to just have some extra routes in /tests/* that are only enabled for tests to call or return data from arbitrary back-end code.
cy.exec() lets you run general system commands iirc. Istr seeding a database with it before running tests, I think if that command fails with Nonzero, the test would fail.
What made it hard to reuse code? You can just import/export stuff like normal, unless you mean it was hard to find any logic that could be usefully extracted into a helper?
We have a lot of data in UI tables, so I wanted to write code that extracted the cell values to a ROWSxCOLUMNS matrix, that I could reuse in each test.
Did you try custom commands? I have some for more basic stuff like 'get data-value attribute for the element with data-name attribute of x' which I can use in any test.
That said, I find checking for specific values in the page against other page values to be really difficult so if you're doing that with the table... good luck!
if that functionality isn't already present in the UI, e.g. by selecting a filter or exporting, then perhaps it belongs in the domain of a scraper rather than a testing tool
I love Cypress overall, but wouldn't advocate using Cypress commands unless you are doing something weird.
Their examples show using Cypress commands for pedestrian things like "log in to app" but there is no need to get all Cypress-specific for things like that.
Instead, we typically write "test helper" objects for that, which are conceptually similar to the Page Objects pattern from the Selenium era. So like:
class GroupUiTester {
get groupChooser() {
return cy.get('#group-chooser-button');
}
}
Then, in your test, you can just be like:
tester.groupChooser.click();
That is kind of simplified, but even that would be useful if you had dozens of tests interacting with that group chooser element. (Especially since, unlike string-based "cy.get('.some-class.whatever')" it will all auto-complete in any decent editor.)
An example of "doing something weird" where we do use Cypress.Commands is like:
We do that because the local storage clearing breaks a third party lib we use for a few tests. But that is something you can't just do with the regular Cypress/DOM API, so it is a good candidate for using Cypress "commands".
we have extensive Page Objects which let us re use code everywhere. i’m not a huge fan of cypress commands because they pollute a public prototype and i don’t like modifiying those
Basically, I think all the code to locate UI elements and perform common interactions with them should be in re-usable utility code, so that the actual tests can focus on just testing what they test.
I don't think the Cypress docs probably do a great job emphasizing how easy this is (especially since they go out of their way to de-emphasize the 'page objects' pattern, but without offering much in the way of a replacement).
Yes, I'll echo my disagreement with the Cypress advice against the page object pattern - the advantage was always that the logic to get the element could be updated in a single place, and that applies as much whether that code is 3-5 lines of webdriver code or one line of cypress code.
Yeah, "no DOM in tests" is actually a pretty good mantra.
Code that is just inspecting the DOM to find elements, or to do stuff to them that is just working up to the state where you can actually test something, should be in some shared object/library, but that is as easy as:
import { Whatever } from '/foo/bar';
Having that kind of code outside of the test probably makes the introductory "test hello world" example more complicated, but I think it's definitely a good practice in the real world, and isn't documented well.
Last time I checked you couldn't even organize tests in different folders, I wonder if they finally fixed that. I always find it odd using test frameworks developed by a for profit company. They pick and choose what code to merge and bugs to fix based on their own priority, not what's best for the users.
This even model is sooo confusing, clumsy and error-prone that writing any non-trivial test is a challenge. Whole product uses async/await or Promises and suddenly you have to switch to this baroque model just to write a test. Reusing logic between production code and tests is pretty much impossible.
Dynamic pages etc. often confuse cypress. I'm actually not a frontend developer, so I don't have a lot of insight while exactly that is, but I just know that it has been a huge drag.
Other than that, it would be OKish. Being able to test the UI is great, but I would advice everyone not to base the whole testing strategy on it. It's just too heavy, slow and unreliable. It doesn't not scale even moderately with the product growing.
e2e testing is better done on API level, IMO. You'll want redesigns, changes of UX, and suddenly your changes will require updating tests, which otherwise (if done on the API level) would require no modifications.
It’s possible (and indeed uh ... recommended) to write frontend tests that are resilient to DOM changes by not depending on things that are not essential to the functionality being tested. Eg select a form field by its label, not by its position in the DOM, and use specific data attributes if there’s no better choice. Then when you gut the HTML for UI overhaul, if the functionality hasn’t changed, the cypress test doesn’t change, you just make sure you attach the attributes to the right new elements.
Of course if the functionality changed (like you split something up into 2 pages) yeah you need to update your UI tests cause you are testing a different experience now. But they are UI tests, so yeah. That’s appropriate.
I dunno. It sounds like you found other parts of it unwieldy as well, but the idea that the tests are inherently brittle is wrong. Time spent maintaining UI based testing is saved many times over when compared with the manual clicking around that it saves imo.
> Then when you gut the HTML for UI overhaul, if the functionality hasn’t changed,
How often website redesigns are only about html? Usually everything changes. New flows, new dialogs, new toolbars, new frameworks.
Often the web UI gets and Android UI and iOS UI siblings. Gets replaced altogether by a completely different UI, developed by a different team.
APIs change much less often, and can be shared between many UIs. You can also version them. How are you going to version a web UI? Like reddit with "turn back on classic look"? How long can you keep the old UI around just because you have 1000s tests around that use it.
> but the idea that the tests are inherently brittle is wrong
I don't think so. Tests are great calcifyiers (check my blogpost about it if you want). If you test though your UI, you're calcifying your UI. The more you test though it, the more you calcifying it. No way around it.
I’m not against testing APIs. But testing APIs does not tell you if your latest CSS change broke pointer events on your “add to cart” button, so you can no longer receive orders, etc.
If you are wholesale redesigning/rebuilding a whole site and all the workflows yes of course you need new tests. But also your users would get pretty impatient if entire ways of working are changing all the time in a way that makes testing a giant moving target.
The purpose of a UI test in my mind is to make sure that the core business things a user is supposed to be able to do, are doable. In the context of your blog posts, I think those things should be calcified.
Like, I want a test to fail if I remove a workflow that used to be there. I want a test to fail if a form field suddenly has no label. There should be those alerts when functionality that was previously understood to be correct has been changed. Lightweight UI tests with some easily re-approved screenshot diffs goes a long way.
The idea behind the code being async is that you don't know how long things will take, especially talking to a backend, or even sometimes DOM manipulations in dynamic pages like you mention.
Having said that, I find parts of it v confusing (although not the asyn stuff) especially around assertions - there seem to be multiple ways to do things and I'm never clear which is which.
As a sibling reply said, try to write cypress (or other similar product) tests not to rely too much on layout - I use html data attrivutes rather than text or Dom based selectors, so the tests can survive most redesigns, and if they don't, it's because the user journey has changed enough that we _should_ be changing the tests.
There are much simpler programming models to deal with long-running actions, like processes and threads. The essential point of async is to be thread-like, but with lower overhead; or in environments where you cannot use processes and threads - but there's no very convincing reason for testing to be it. And choosing to prioritize dealing with runtime overhead over dealing with coding complexity isn't an obvious win. Note that promises make sense for processes and threads too; the key question is whether you really block, or virtually block.
Nothing wrong with async code; but it's often sold as the "obvious" solution to, well, several things happening and some of them taking long - and it's just not that great a solution.
Would threads or processes be a great way of simulating how a user interacts with a web app though?
I tend to think of them clicking things and waiting for a response then moving on to the next thing when that happens (or failing the test when it doesn't) which seems to fit well with an async model.
Cypress _does_ do a lot of magic behind the scenes to stop you explicitly using async/await or promises in the code... Which occasionally bites it.
Especially when you have to use a .then to use values you pull from the Dom.
You can wait in a threaded model too, right? The only difference is that if you do so, you're blocking that thread. The pain comes when you mix the two models, because async often deals really poorly with blocking. In general, the differences between the two models when used cleanly are quite small. When most waits are no-ops, threads have significantly lower overhead; but when waits are common, especially if long-lived, async overhead is much lower.
In fact, if you want to minimize the chance of deadlocks, using threads or processes for every action is safest; although of course that means you may get issues with concurrent modification. But though that risk is serious, it's worth noting that async code doesn't actually solve it; after all, every await may mean a context switch, and thus if you have shared mutable state living across an await, all bets are still off. async-only code with exactly 1 thread only provides safety to the extent that modification is encapsulated and that the module within which the internal datastructures are updated does not use async. And that's not nothing; it's kind of as if a java object was synchronized on all methods. But it's also not reliable enough that you can just forget about concurrent modification, either.
But if all you want to do is automate a browser, those overheads are completely irrelevant, and this story about concurrent modification likely is too. You could use either model equally well. To be explicit: there's nothing about promises that means you need to use async. It's only once you start chaining a bunch of them that you enter async territory, but why would you ever do that in a threaded model when automating a browser? The browser is so heavy weight, just fork a bunch of processes already, and KISS: no need to worry about any of this, at all.
I am quite surprised. Our experience has been quite positive. We were able to do full coverage of our web app in less than a month without prior experience with cypress. This is what we learned from it: https://blog.servmask.com/8-tricks-i-learned-from-cypress/
To hop on the unhappy train, it's actually quite hard to get an internal mirror mirror working correctly because the platform for which the extra file it downloads is based on a query string, not the path. Argh.
I have been developing tests using Cypress for 6+ months.
I have used multiple other variations of test frameworks that were built on the Selenium WebDriver protocol. The official documentation [1] states that Cypress differs fundamentally and architecturally as compared to Selenium.
Admittedly I found Cypress web testing framework frustrating initially, and yes, I have performed many re-writes because Cypress documentation behind command chaining and assertion queuing to be not intuitive.
Thanks for my management's support, perseverance afforded me with the stubbornness with a purpose of checking out Cypress if it has a better DOM manipulation, how it operates directly in the browser, interactive test runner, and its API and configuration.
It required 3+ months of perseverance in getting the Cypress tests organized [2] for handling web testing core functionality of a commercial-grade corporate web site. My current layout required adding a lot of extensions to the core folders under /cypress: /support, /plugins & /config.
I am motivated in writing a series of posts on Medium, because I like Cypress. Is it perfect, no, some aspects are frustrating. In other words, I have not found a solution yet, but I will continue to use Cypress.
From the minimal amount of Cypress development experience, suggestions:
a) Switch everything to TypeScript
b) Declare Commands within Cypress namespace
c) Understand selectors
d) Add querying attributes, like 'data-cy', to expedite finding elements.
e) Wait for element to appear using 'cy.get(...).contains([ element attributes]).then(...)'
f) Avoid if at all possible using XPath for selectors.
g) Use 'cy.wait()' to wait for an alias to become available, and not for millisecond delays.
h) Use available eslint extensions for Cypress.
I will try to get a couple of posts on Medium as soon as possible. They may be helpful.
If you're willing to try something a bit different, we're working on a no-code approach to test automation that tries to avoid the pitfalls of code-based testing [1]. We're focused on building a E2E testing platform that (1) makes it as easy as possible to create tests and (2) makes tests easy to maintain. Easier said than done but that's our goal.
What are the benefits over selenium ide? It’s been years since I worked heavily on testing but I don’t recall there ever being a good record/playback testing tool. I’m intrigued.
Selenium IDE uses a Chrome or Firefox extension to record your actions, but they're rewriting it to be an Electron app. I'm not sure about the status of that rewrite though.
But the benefits we have vs. what you experienced with Selenium IDE is:
- Instead of using an extension to record your actions, there's nothing to install to use Reflect. We spin up an instrumented browser inside a virtual machine and screenshare that with you within our web app. It records your actions and translates those actions into a repeatable test automatically.
- Since we have complete control of the test environment, we can do cool things like make recording file uploads really easy or present a nice workflow for getting coverage of visual regressions via screenshot testing.
- Our recorder is more accurate :)
- For every test you run within Reflect, you get a video synced up to the steps in your test, along with console and network logs from the test run.
- Instead of emitting Selenium code that you then maintain like a normal code-based testing tool, we are completely no-code meaning that even updating a test is completely codeless. So for example if you need to make bigger changes to an existing test, we expose a way to re-record only the portions of the test you want to change, and keep the rest as-is.
It is visually appealing but sluggish and sucks at non-standard authentication to the point of not being usable.
Also no out of the box way to run more than one instance with incognito tabs to have communication to test multi-user bugs.
Perhaps radical, but I think it should support hooks with Playwright/Puppeteer that you can hand control back and forth to as a safety valve just like being able to shell out to the command line when your favorite programming language doesn't have a library for what you need.
The difference here is that the browser context needs to be passed - that means some janky handoff (which with crypto will be a PITA) or using the Playwright/Puppeter connector under the hood.
Same experience here, moved from cypress to testcafe after getting frustrated by cypress API.
It was some time ago so I may not remember correctly but I felt like cypress was not for people already fluent in javascript, a bit like jquery but pushed even further (you need to do everything the cypress way now, you can't even use variables or promises...).
No, page objects (AKA page models) are a recommended but optional pattern in TestCafe.
We use them on my team because they make the tests more readable and keep us from having copies of the same selectors in multiple places, but you can easily use TestCafe without them.
I really enjoyed the testing library when I used it. I recently came back to it and felt like they removed a lot of the documentation that I liked about the library. I'm not quite sure why they did, but it was very helpful to see their examples for integrating with common third party libraries.
it took a lot of time but i do like the cypress approach. there are weird things like how you can’t get the current time because all lines execute immediately and are evaluated later. but once you get your handle on .then and .wrap it is good. they should have picked a different name than .then because it’s not a promise but looks like one
For anyone new to Cypress, there are two things that I consider killer features:
1. It saves a snapshot of the DOM state before/after each test step. If you have a long acceptance test where it's deeply navigating through your app (i.e. visit "/admin", click on "Login", type "username", click "Submit"), using the GUI test runner will show each individual step in a side-panel. From there, you can hover over a step to see a snapshot of what the page looked like before that step was executed, and a snapshot of what it looked like after.
I had previously only used test runners where, when it would run the acceptance test, you would see a series of really quick flashes of the runner executing a bunch of steps faster than my eye could track, and then a big FAILED message. What failed? How did it fail? Cypress solves this problem by saving the DOM state and allowing me to traverse backwards through the state of the app until I find where things started to go wrong.
2. The cli test runner records a video of its test runs. Super useful in CI where you don't have access to the frontend. Cypress will record its run to an MP4 and you can investigate failures after-the-fact. This has solved a lot of "it works on my machine but not in CI" problems that seem to come up pretty often.
The other positive thing I have to say about Cypress is that I've actually found it more helpful as a development sidekick tool than as a test runner. Particularly when developing features on the front-end that require a lot of user interaction, many times it's easier for me to whip up a quick Cypress test that automates the user interaction (with assertions along the way to make sure the app is working) and then use the GUI Test Runner to do all my debugging.
It's not perfect and I definitely have some frustrations with it, but on the whole it's helped my productivity quite a bit.
They're still in restricted beta and only work on MacOS so far, but Replay [1] is really interesting in that regard, and would be fantastic to use for e2e tests: it not only saves a snapshot of the DOM, but of the entire execution environment. You can then replay it, add breakpoints, log statements and what not after the fact to investigate what broke.
Thanks you for bringing up Puppeteer and Playwright!!!!
when I saw this, I was thinking why use this unintuitive tool and coding style? when there is open source projects out there?
One minor point of differentiation, it looks like while this uses screenshots to capture each step (correct me if I'm wrong), Cypress captures the DOM structure. You can go back to any step an inspect the raw code on the page, which offers a bit more context when debugging.
Wow nice, that looks great. Documentation is confusing, and keeps complaining that localhost:6789 is not running. Wondering which step I missed after using the jest plugin and doing npx root-cause show and select the test via terminal
this 2 'killer features' could be implemented in your tests in a day or two. Also, you can use video recording features implemented in docker images like Zalenium
In all seriousness, if that's true you should do it and productize it. Based on the comments here it seems like many people prefer other browser scripting tools, so if you can replicate the novel features of Cypress in a better package, you could make money. Cypress raised almost $10M in their Series A.
I'm quite surprised to see the overwhelming negativity towards cypress here.
I recently started using it in a small project and I'm really enjoying myself. I mainly use cypress for high level UI testing and I mock my sever.
I found the server mock tool (route and route2) brilliant. I find the syntax for browser commands easy (visit, click, get). Using mocha with should and chai is fine.
Anyways, apart from some minor problems (you can't select a single test to run), I really love cypress. Compared to last time I used selenium, it's such a difference. Especially that cypress just seems to be one holistic package that works. Can't say the same for selenium.
I'm using it for a Vue project at work, and it's really easy to use. Had to get used to chaining the commands, and working around a few issues like when I needed to access something JS object (simply exposed the service object I needed globally when Cypress tests were executed, and then verified what I needed).
Used Selenium 1 and 2 in the past, and Cypress is definitely much easier. Can't say if the current Selenium is better though. But being able to reply the DOM states, and record videos, without needing to install other tools/libs is also very convenient.
I can see what people find annoying about cypress but to me, it's "cleverness" and tight browser integression provides such a much better experience than anything else I've used.
It is not perfect but I think they have the correct idea of how web e2e tests should work and I hope they will keep improving the experience as time goes on.
We wrote "cypress for playwright" recently in order to use it internally and decided to open source it.
Basically we took a bunch of Testim code for screenshots/console logs/network etc and made a package out of it at https://github.com/testimio/root-cause
It's amazing how much you can get done just combining open source tools together (like sauce's HAR viewer)!
I've seen a few people say this, but looking at the repository and documentation it seems more like an alternative to puppeteer for browser automation. I don't see anything in particular about testing?
Yes we can consider playwright as alternative to puppeteer . But it also got more features involved , I would say it is an upgraded version of puppeteer and it has also got Webkit support.
Wow, someone has submitted Cypress.io here - probably because we just crossed 25k stars on GitHub.
We at Cypress do read these comments, and we definitely understand both the positive and negative opinions. If you have never tried Cypress yourself - take a look at the first test page https://on.cypress.io/writing-your-first-test
Try it yourself, you might like the syntax and the developer experience. And if not - no worries, there are TestCafe, Puppeteer, Playwright, Selenium, Webdriver that might work better for you.
Like a couple other people I'm very surprised by the negativity around this tool. I was introduced to it when I started my current position a few months ago and I've found it everything BUT hard to use.
The method chaining feels good as long as you check the return type of the function your calling. Most of the time it returns the element you just asserted against. And when you're trying to drill down into deeper sections of the DOM you can speed up tests by calling .within from a higher level element to keep the search to a specific part of the tree.
The individual steps with their state available for viewing in the sidebar is great as others have mentioned. The test doesn't run at light speed, so locally you can actually VIEW what is happening. Plus when it does fail there's typically a long timeout (~40 seconds) before the test actually fails. So it's very noticeable when your test hits a snag.
Also helper functions are not hard at all, and we have a few useful ones we use in almost every section. I have more I could say, but I'm not going to write a huge raving post. Just wanted to try to post some positive contrarian perspective.
We used Cypress for a while at Notion but removed it due to high memory usage and crashes. Instead we use a very boring stack of mocha + selenium-webdriver + Chrome on Linux. That’s not my favorite either, because we have to paper over all of the crufty Webdriver/Selenium abstractions that feel like they were designed for Java.
I would much prefer to use Puppeteer or Playwright now that they’re starting to stabilize - for a while they both either didn’t support Firefox, or required custom builds of browsers.
Wow!! I pay for both Notion (it's good, thanks!) and Cypress, and have literally described Cypress this way: "Cypress is to Selenium as Notion is to Confluence"... :-O
So, I am very surprised (but interested) to hear your tale. It is literally the first time I have ever heard of somebody going back (I assume it is back?) to Selenium from Cypress.
When we used Selenium (until mid-2018) our tests were hard to write and hard to parallelize, so they took like an hour on a beefy machine. Now they take 5 minutes (across 16 medium-ish VMs, admittedly, but parallelized "for money, not for free" by the Cypress dash board service.
I'm curious to hear more about your experience moving off Cypress — did your test suites take longer to run? (Or did you perhaps move off of it before they introduced auto-parallelization?)
I'm really bad at marketing/getting the word out, and google took forever to approve the extension so I lost interest. I made it because I hate manually writing E2E tests like with Cypress.
Maybe if others show interest in it, I'll be motivated to resume the plans I had for it.
Like others in here you included "open source" in your phrasing, in a way that sounds to me as if Cypress wouldn't be open source. But it's rather MIT licensed, unless I've been fooled.
Following that up with a question, what's their business model, consulting? I didn't immediately find any upsells on their website.
Edit: finally found the pricing page, to but the core is still open source then?
It's all open source. What you pay for is their dashboard tool, which is a good, affordable product.
The dashboard also acts as an orchestrator for parallelization. I assume the orchestration is free up to the monthly free-limit, but if it falls back to single-threaded after that I don't know.
That looks like a massive productivity gain. Are there any other tools that build tests like that? Makes me feel like a caveman for writing them by hand.
The thing that strikes me as weird about Cypress is that, while the DX is quite nice, their core claim of being an end-to-end testing experience is, for the most part, not true. You can see that in how most events are simulated instead of native. As such, we're not really simulating user experience, and in fact the accuracy of testing doesn't seem to be meaningfully better than what's available in Karma.
DX is fantastic, of course, but I'd feel quite uncomfortable in committing to a commercial offering that I thought was being less than fully honest in what they were offering, just as a matter of trust.
It really is a great test runner on its own merits, though.
I'm not sure I agree with your first sentence. Simulated or not, the tests are accurate enough that you're going to be identifying real-world user experience failures the vast majority of the time. It won't be perfect, but then again neither is Selenium despite the difference in approach.
At my previous job, we had used Cypress for an internal React application but had to remove it due to incompatibility with our single sign on.
Each application either used the same OAuth solution that customers used or they used Okta which was more common for internal applications. It was a little unclear which was supposed to be used as some applications used the former and then it was common to have a "backend for frontend" that would solely deal with communicating between... ah, you know what, I don't even want to think about it.
Suffice it to say, the React application in question made use of the okta-react library which meant that the actual SSO dance was part of the Javascript bundle being shipped
That in itself isn't a problem but Cypress seems strongly designed around the idea that you never leave the domain. We got that to work but then when 2FA was mandated, we were kind of screwed.
We didn't have a TOTP seed to generate a passcode as part of the auth flow which is highly questionable of course but we also didn't have a solution to bypass the actual authentication step either, as it wasn't an API call to a backend (we controlled)
Anyway, we tried making a service account that has 2FA disabled only to discover that 2FA was mandated at a network level (unless you were on a specific subnet we later discovered) meaning we would just see some arbitrary "error 53"
Anyway, This isn't to say that Cypress is anyway at fault here but I have seered in my memory, from the tens of hours spend on this crap, the sight of threads where people would "How do I use this with Okta" and the developers essentially saying "Oh, yeah, you shouldn't be doing that".
Having said all that, while I remember finding Cypress pretty handy, I'm more fond of Testcafe myself :)
Ah also, I believe a lot of teams made use of a Zalenium... cluster? Bunch of instances anyway. I also recall a number of people having the above issue with no solutions
> That in itself isn't a problem but Cypress seems strongly designed around the idea that you never leave the domain.
Same here with PayPal or 3d-secure. I am actually baffled by the decision - what kind of applications did they thought was going to get tested - Todo apps?
Last I checked there was GH issue and they said that it will get addressed, I hope.
What they are also saying is that it is bad practice, you should send API requests from the tests that simulate the payment, for example. I find this BS, IMO the automation tests simulate user and user would not send API requests but click buttons on the screen.
In the particular case I mentioned above, it seemed the recommended avenue was to do sign in on the backend so you could mock it out.
Sounds fine on paper but in our case, we called out to multiple backends, with no unifying gateway that traffic reached them through as they were owned by different teams.
Realistically, that was a discipline issue rather than a technical issue of course but I do wonder how many organisations find tools like Cypress a non-starter due to their impure set up
I don't understand the difference between Selenium and Cypress. Is Cypress general control of the browser but just nicer somehow? Or is there a deeper disconnect in their designs/capabilities?
I go into the "in depth" bits of how each browser "clicks" in a few talks but basically:
- Cypress solves a much easier problem (no multiple tabs, no native actions no hovers etc).
- Cypress does everything in JavaScript and not with the debugger (like old versions of Selenium).
- Cypress is bidirectional (like puppeteer/playwright or selenium bidi).
- Cypress has very good dev tooling out of the box.
We've been using Cypress at work and we (well, at least I) have a love-hate relationship with it.
Coming from Capybara in Rails, it is a very noticeable improvement.
Unlike others here, we never really had issues with the chaining. We don't mess too much with custom commands. We just have a library of about 30-40 small helper functions, mostly to do simple steps to test UI elements from Material UI, React Select, etc.
So, for example, if we need to select something with React Select, it can get tricky. It is a multi-step process with Cypress to ensure the thing is actually rendered. But after we do that once, it is only a matter of making a `selectDropdownOption(tag: string, option: string)` helper function. We have dozens of tests that are just 3 or 4 lines of those helper functions.
One of the major drawbacks we have with Cypress, though, is about the data. Since Cypress just uses your `localhost`, it uses whatever DB you are connected. I really miss the Capybara/Rails integration of just spinning up a proper test DB, seeding it and then destroying it after the tests were done.
I bet there are ways to do this with Cypress, but it is just not as straightforward as it was in Rails.
Not sure what you mean by "just uses your localhost".
I recently set up Cypress for the app I'm working on, which is a legacy MEAN app that I've been modernizing (migrating to React+TS, etc).
It already had a set of Express server API "unit tests" that were really more like integration tests, using `supertest` to load the Express app and make calls to the real API endpoints. I updated it a few months back to use `mongodb-memory-server` to spin up a dynamic `mongod` instance solely for the test sequence.
When I set up Cypress, I was also able to use `mongodb-memory-server`. I configured the app to check for an environment variable indicating an E2E test environment, had it connect to the in-memory `mongod` instance, and used a Cypress task to seed the DB before every test. Seemed fairly straightforward, and is working pretty well.
My small team added Cypress to our large React project a few months ago and it’s been great. Took a bit of work for us to feel comfortable with it but it started catching bugs that justified the time investment in its first few weeks.
Cypress is very bad. What frustrated me most of all is that you can't use node.js, only 'browser javascript'. Also, absence of promises makes Cypress way behind its alternatives. Don't be fool, use TypeScript + Cucumber + puppeteer/ axios, or Java + Selenium/RestAssured, or any other appropriate tool with open source model and adequate code base, maintained by community
Cypress uses bluebird for their promise implementation which are A+ spec. [1]
Also (nearly) every command in Cypress is a promise which allows you to make them then-able. [2]
I don't agree with using Cucumber for anything. The way most teams implement Cucumber makes it such a pain to write a test. I do like the suggestion of puppeteer tho. If you haven't heard of playwright [3] I'd look into that. From the same creator as puppeteer but was hired to work on playwright full time. They have the advantage of being to test on gecko, chromium, and webkit browsers which is really nice because IME anything Apple becomes such a pain to setup to properly test.
It would be really nice if people built more on native promises and not bluebird. There was a time when bluebird was really great and useful but I think native promises are the better option now. (Source: I maintain bluebird and worked a bit with the V8 team on promises in Chrome as part of being a Node maintainer)
OP shared an opinion backing it with links to more information. What are your disagreements? Could you give a fundamented counter-opinion besides your snarky response?
Sorry but I can't provide more objective reasons why not use Cypress except that cypress is more about aggressive marketing and promotion, but not a useful tool for testing. I don't want to write node.js inside separate files, I want to use it without limitations, for manipulating with DOM and http.
I want to use normal async/await, as all adequate people do nowadays while using ES. Even when I wanted to make multipart-form-data request I found that it's not possible using Cypress. But it's quite a trivial common thing, I didn't want something unique, or am I?
I think you can use Node.js (through tasks) in cypress.
Agree with everything else though + the one time I opened an issue in their tracker (I asked a question about a crash in order to contribute!) they totally ignored me and then they opened a bunch of issues in projects I maintain and they use (not paying me, which is fair). Guess how much love I gave their issues?
Will instantly fail if you need to nav to a different domain at any point in your test .
Say you have happysite.com , but your using parentsite.com to authenticate, Cypress will explode instantly. If your test will ever leave your first domain, same thing.
Don't take shortcuts, use Puppeteer or it's successor Playwright
Can’t say we’ve experienced this at all. Part of our test involves navigating to a third party site (gocardless) to set up a direct debit. The test works fantastically well and is a pretty crucial part of our flow, so we’ve come to rely on it.
I agree with the sentiment but just want to mention Playwright isn't the "successor" of Puppeteer and both have pros and cons. Puppeteer is very much still in active development.
i’ve spent quite a bit of time in cypres this year. i’ve also invested tons of time into selenium and a lesser amount into puppeteer.
cypress is great. the video recordings are very useful. the paradigm of command driven actions is nice to see step by step.
but the more time you invest you find the rough edges: xvfb and parallelization, cypress runtime crashes (vastly improved since 5.x), a sometimes top opinionated stdlib with no alternatives (cy.get errors are always fatal), and a somewhat high cost pricing model.
i understand they need to run a business but i feel like the project is one custom scheduler away from losing its value prop. the cypress website itself is actually the worst part of the entire experience
you can’t do everything in cypress so we have a mix of it and puppeteer
cypress for most of the complex tests. puppeteer for more basic things you don’t need to debug / “should always work”. because the debugging experience is much poorer. but the tests are “free” to execute. i’ve only wasted time in selenium and don’t recommend it for any purpose
I've had a lot of success with selenium-webdriver and Jest as the test runner. Use it with Async/Await, write some custom framework around it for stuff like before/after image capture and upload to s3(or wherever), and Bob's your uncle. ffmpeg can also be used to record the xvfb apparently so I may have a play with adding video capture soon. Debugging in VsCode is nice.
It's a shame 4.0 has been in beta forever and people keep taking from the project and not giving back, and that async stacks got broke(but I created a proxy that creates a nested stack and preserves the original test code call site), but it works very well in general.
As someone who has recent been looking to learn either selenium or puppeteer, I'm surprised to not heard of this during my research into relevant tools. Would you mind helping me briefly weigh the pros and cons of each? Cheers.
Absolutely. Angular / React was very much an east coast / west coast thing for awhile, as one example.
Cypress was officed at ATDC at Georgia Tech (now downtown), so a lot of companies and startups in metro Atlanta adopted it and helped it take off. Further, any student from GT or SPSU trying to intern through ATDC (and probably ATV) would have been at least tangentially exposed to it, meaning these new grads / young devs got exposed early enough in their careers as to be impressionable, and more likely to adopt something new. It also helps to adopt a technology when you're three doors down from the devs.
I tried it in all honesty, even though I found the attitude of the founder not so nice, but it is acceptable for very bright people, which I am not. Unfortunately, I hit a bump very soon as it could not deal with the way my sut was doing login (with azure) and as far as I could see on SO for example, people were relying upon puppeteer scripts to work around that. cypress looks super smart and all, but it did not do it for me. I am a 20+ years test automater and I am having lots of fun using taiko.
I would also recommend checking out Testcafe or maybe some other alternatives (I read recently about a project called Playwright which at least “on paper” looks promising). I’ve used Testcafe on couple commercial projects (including one for a large and well known company) and it was a positive experience without any reservations I could remember.
Now it still makes me wonder, why do more people seem to prefer a less cross-browser solution that is constrained to one domain(!).
I like Cypress because it helps us easily validate when our backend teams introduce breaking API changes without notifying UI teams. Quality is often left to UI teams, when service teams need to step up and perform more due diligence of their own. Until then, Cypress is the tool for the job. Been using it for 6+ months. I'm not crazy about it, but I have no known superior alternatives, so I am grateful for this open source tech.
There are cheaper ways to validate APIs than Cypress and its class of tools. How about something of the likes of Postman (which is scriptable) or (oversimplified) a JavaScript file making calls combined with an assertion library?
If your goal isn't to test a frontend, Cypress seems inappropriate.
Front end teams shouldn't have to write tests for other team's services. This is more of an organizational concern. We do care about testing the front end, but it more often reveals back-end issues than regressions in UI code.
It sounded like these tests were only written to validate the backend. Great if that's not the case.
I agree that the backend team should test their own stuff. End to end testing is a poor substitute for that. There may be value, though, in having some (light?) validation of a dependency, ie. the frontend team validating that the backend is still there. I heard the latest SpringOneTour talk refer to this as "enemy testing". Maybe really bad for internal teams, but I can sympathize when the dependency is external and you don't know when to expect changes.
Cypress is great. We use it at Draftbit. e2e testing is straight forward. We test most of our platform with this (on top of some stronger unit tests). Love it
We have used Cypress for a few projects. It has been far easier to use than Cucumber and Selenium (although it has been a few years since I used those).
You might like the root cause open source which runs with playwright to capture test results automatically including screenshots, logs, stacktrace in a nice ui. https://github.com/testimio/root-cause
I just wanted to suggest https://github.com/seleniumbase/SeleniumBase if you are comfortable with using Python and Selenium. I opened various issues last year and the main developer is very welcoming and he fixes/improves the code very quickly.
With the shift of logic from the backend to the frontend (with the rise of clientside frameworks) it feels one thing that simply hasn’t matched the pace of transition is tooling for frontend testing.
It’s a tricky problem. We just started using Percy/Cypress at our company.
It all still makes you pull you pull your hair out. I’ve tried Selenium for E2E and RTL and others for integration and unit testing. As soon as you want to do anything remotely complex like testing an auth flow or a chained change of state you start running into issues. Mocking can be truly infernal. I tried to mock Firebase and I found myself thinking way too much about the internals of the Firebase SDK and their relationship with my own application to the point I didn’t know what I was testing anymore.
Compare this to testing the back-end where I can crank pages of tests like I’m the Beethoven of testing.
I love front-end dev but I cower at the thought of testing anything that’s not a pure data function or a very dumb presentational component.
One can still write tests that are flaky - some of the challenges that Selenium et al. experience are still present:
1. Selectors still need to be specific enough `.button` is great until you add another button.
2. Selectors can be _too_ specific in weird ways. Recently, I encountered a bug where reformatting my markup broke a test that detected if an element was present by checking for its contained text. Turns out the newlines that I inserted between the opening and closing tags were significant for the test. Thankfully, it's all JS, so one can appropriate work around.
3. For SPAs, it's harder to convey that a page/view load has completed. So, if I click a button and the entire viewport updates (potentially downloading a JS bundle in tandem), I either need to insert timeouts of arbitrary lengths, or explicitly call out to the the provided network API hooks. This can be annoying because now I not only need to worry about what I _can_ see when I navigate through my app, but also what I can't.
It's far better than what has come before, but it's not a silver bullet.
It depends what is the root cause of your "flakiness." Sometimes it's due to the browser not painting your elements in time because of various layout thrashing other times it could be because of data you're waiting on before you can render a table.
If your flakiness is due to items like layout thrashing, or triggering other HTML re-rendering like painting or compositing, IME you'll have issues with any test runner until you fix the problems of poor browser performance and layout thrashing
If your tests are flaky due to backend calls being inconsistent or taking a long time, Cypress allows you the ability to intercept network requests [1] and return "fixtures" of what you want the data to be. The benefit of this is you can go directly to any route for your web app then just stub the data you need immediately and test against that. The benefit of this approach if you can easily test negative scenarios and how your application behaves. Negative scenarios like failing response (500 error) or having a 200 response with missing data fields. This is useful when testing something like pagination because you can make the "3rd page" fail when you trigger that API call by forcing it to give you a 500 error (or something else). The downside of this approach is that you are no longer using real services that your app relies on, but you gain some confidence on testing multiple scenarios in an easy format rather than setting up proper chaos engineering scenarios/experiments.
Other testing libraries do allow you to intercept requests as well (I know playwright does this), but one of the selling points of cypress is that you have access to the same browser APIs that you have use when doing web development.
when we used Cypress, we found the framework itself to be flaky.
it has been months, and I can't remember the actual error we got intermittently, but I do remember it was something buried inside cypress (I think it was related to taking screenshots?) that caused our tests to just randomly fail sometimes.
Using Cypress in NX Angular CLI after having used Protractor previously. In comparison to Protractor it's an absolute god send and so much easier. The documentation for Cypress is pretty good IMO. I love that when you use should('be.visible') etc it'll continuously retry until the timeout as it makes your tests so much less flakey.
There's a couple of annoyances still:
- I hate that some things are wrapped in JQueryLike and then other times they're not.
- I still hate that there's async/await magic and wish we could stop it for e2e testing and just be explicit so I know what is or isn't going to be magic.
At my job I inherited a codebase which was completely both untested and undocumented aside from a general consensus from the backend guys on how it should behave. Cypress was instrumental in black boxing the behavior of the ui and then testing our refactors and changes against it. It has its worts. The chaining is not intuitive or consistent, the documentation never indicates fully return types or any types for that matter. Also you can only mock xhr requests and not the more modern fetch which is a bit hokey. You have to roll your own. But it’s free and offers a heck of a lot more in stability and features than what’s out there.
I’ve found Cypress generally better than other alternatives such as Selenium. The screenshot feature is nice and it seems to be a little less flakey, although E2E tests using a browser are always going to be more prone to flakiness than unit tests.
This last project we’ve actually been running true E2E tests by spinning up the backend in GH actions (looking for a branch with the same name or falling back to master), seeding it, and making snapshot-style assertions about the UI. It’s more complex and slower but tests a lot more code now that the backend is involved as well as the API layer. It has helped a lot in major refactors.
I've heard about cypress and testcafe both being better alternatives to selenium, but then when I looked into it they both seem pretty similar to selenium. Is there some killer feature making cypress better? Has anyone tried all three and can clarify the differences?
Basically the main difference is that Selenium executes outside the browser and controls the browser through the network. This has benefits like you can use any language. The likes of Cypress and TestCafe execute in browser. The main downside to this is you have to use JS or a compile to JS language however the argument is you have less latency and better access to the DOM making tests more quicker and more robust. Arguably JS is a language that is well suited to asynchronous event driven applications like e2e tests
I've used Cypress at work , it was really good experience in creation of test-scripts. Had a few hurdles in the start but achieved the tasks with the help of documentations available. Now we have configured E2e and code-coverage with it .
Would be awesome to have at least single test + run + output example in the README. At least as a screenshot, link to playground or something. I open website, see marketing, open github, see marketing.
Coming from a world of using puppeteer/playwright for testing in an actual browser with full access to dom/Network/console/perf stats etc, I don’t get cypress.
It operates at a higher level than puppeteer/playwright, and (at least in my personal and professional experience - others in the thread disagree) more reliably than selenium or libraries which wrap it.
I've used most of other front-end testing tool in the past (selenium, puppeteer, playwright) and none of them support drag and drop if I remember correctly.
cypress does not support popups. its a problem if you wish to test payment gateway or social login that opens in a new popup for login. so we could not use cypress..
Its sort of like selenium testing. It tests the frontend which ends up sending real requests to the backend so if the backend fails the frontend will too.
It’s been a few months since I’ve touched it, so I’m struggling to give more specific criticisms.
I’ve had a really great time using Kent Dodd’s DOM Testing Library [1] for unit tests. The readability and writability of these tests has been fantastic. I wish I could use the exact same API for e2e tests. It looks like they actually do have a Cypress version of the Testing Library [2], but it seems to suffer from the same Cypress-isms that I was just complaining about.
Has anyone else had a similar experience? It seems like I’m in the minority opinion. Maybe I’m just bothered because I don’t understand Cypress well.
[1]: https://testing-library.com/docs/dom-testing-library/intro
[2]: https://testing-library.com/docs/cypress-testing-library/int...