23
loading...
This website collects cookies to deliver better user experience
window.external
property in the live environment), I kept putting it off.TestBed
for the majority of my unit tests, since TestBed has a high overhead and slows down my couple thousand test cases dramatically.Why Cypress?
You may have noticed that I mentioned Selenium to begin with, but this article is about Cypress. Going back to Corgibytes, this time to Integration Tests Can Be Fun!, I didn't really care for the idea of setting up a black box that was hard to understand to handle my higher level tests. Plus, I've heard good things about Cypress from other sources, and it looks like it is relatively easy to set up, compared to Selenium.
npm install -D cypress
. I'm sure this would work, but I am also aware that Angular has its own package addition process, and sure enough, double checking for an Angular-specific install path lead me to End-to-End testing with Cypress - Testing Angular, which gives the Angular CLI command ng add @cypress/schematic
instead.NOTE:
If, like me, the first thing you do after installing Cypress is run it with npm run cypress:open
, you may be confused by the immediate error message of "Warning: Cypress could not verify that this server is running." Don't worry about this for now if you're following the tutorials. Later in, they go over running your development server alongside Cypress for testing.
cy.visit()
, but the Angular CLI ng add
command we used earlier already set up a default localhost address that's different from the one mentioned in Cypress's tutorials... and matches the one available from ng serve
. If you have customized ng serve
, I don't know if this will hold true, but in my case the address Cypress was looking for is a match. (If you want to customize the localhost address, the Cypress tutorial goes over configuring this in Step 3 of Testing Your App.)contains()
assertions when you use ng add
to include Cypress in your project. In my case, since this is an existing project with actual content, neither passed. I'm not sure whether they're valid for the empty new app that Angular's CLI generates when creating a new application; I suspect they might be.data-cy="whatever"
tags to the important elements, and had Cypress check that the ones that should exist on page load, do; and the ones that should be hidden on page load, are.window.external
when the pages are live in the production environment.window.external
. There was an immediate hurdle involving Typescript and parsing the commands file: as soon as I copied the example namespace declaration from the comment at the top of commands.ts
and adapted it to name my custom command, I got Argument of type 'mockWindow' is not assignable to parameter of type 'keyof Chainable<any>'.ts(2345)
from my linter. I tried a few things and got other errors, then ended up following along with Adding Custom Commands to Cypress Typescript. I created an index.d.ts
file in ./support
to hold my modified namespace declaration, and added ./support
to the tsconfig.json
in the cypress
folder, which resolved the type errors.// index.d.ts
declare namespace Cypress {
interface Chainable {
mockExternal(): Chainable<Element>
}
}
Error: Webpack Compilation Error
./node_modules/@angular/router/fesm2015/router.mjs
Module not found: Error: Can't resolve '@angular/common' in 'C:\Users\adunster\Documents\repos\HtmlApp\node_modules\@angular\router\fesm2015'
resolve '@angular/common' in 'C:\Users\adunster\Documents\repos\HtmlApp\node_modules\@angular\router\fesm2015'
Parsed request is a module
using description file: C:\Users\adunster\Documents\repos\HtmlApp\node_modules\@angular\router\package.json (relative path: ./fesm2015)
Field 'browser' doesn't contain a valid alias configuration
resolve as module
// ...
window.external
was actually showing up in the browser.environment.ts
file (as opposed the development environment in general) in the future. For now, the code that assigns the .external
property in my Angular service changed from:function _external (): any {
return window.external
}
function _external (): any {
if (environment.production) {
return window.external
} else {
return new MockCEMRWindow().external
}
}
MockCEMRWindow.external
property to produce the results I need to test. It's not ideal, but for the moment it will do what I need it to do, and actually is something I'd meant to do for a while for manual testing in a browser window running the development environment. I'm sure I will want to dig further into cy.stub()
and cy.spy()
when I get the chance, too.package.json
. After completing code and testing on a feature or bug fix, the code gets merged into the fresh
branch, and then we run an npm script that will cause the production server to pull the fresh
branch, run the Karma/Jasmine unit tests, and then run build it if the tests don't fail. (It's similar for the non-production server we use for semi-live testing on real data, only usually on the current development branch instead of fresh
.)pushd
command since we are using UNC paths), so this will be an adventure for another week. But Cypress has some direction here in their Continuous Integration documentation if you're looking for where to head next.