Showing posts with label Cypress. Show all posts
Showing posts with label Cypress. Show all posts

Monday, January 24, 2022

App breaks out of Cypress test run frame

Cypress is a end-to-end testing framework which is fast, easy and reliable testing for anything that runs in a browser.
Cypress version: 8.3.0

When using Cypress with ReactJS, you may run into a scenario where the tests run the first time, but subsequent tests break out of the Cypress tests run frame; and just shows your app, or your apps loading indicator.  So your tests stop.  

While clearing the Cypress cache fixes the tests for the next run, there should be a better solution.

In the developers tools, if you enable preserve logs for the console and network, you may see a redirect to `__`

Some searching for `cypress redirects to __` will lead you to

'Cypress test runner redirects to __ suddenly'

which suggests adding 
`
Cypress.on('window:before:load', (win) => {
      Object.defineProperty(win, 'self', {
            get: () => {
                return window.top
            }
        })
});
`

To add to your Cypress config,
assuming in `cypress.json` you have your support dir set to 
"supportFile": "[app-product]/support",

add the suggestion to a file
support/callbacks/fix_iframe_redirects.js

and in the support/index.js,
reference the file
import './callbacks/fix_iframe_redirects';

You may have to force refresh the Cypress browser, or clear the Cypress cache once more.

Additional config to check for:
While this seems to be the default, if you happen to be using an ejected Webpack config, also check that `navigateFallbackWhitelist` is set to check for `__`.  

...
new SWPrecacheWebpackPlugin({
...
navigateFallback: publicUrl + "/index.html",
navigateFallbackWhitelist: [/^(?!\/__).*/]
});


You may also encounter the generic error:
TypeError: Cannot set property name of  which has only a getter

Unfortunately, it seems that you can either delete the Cypress cache each time, or disable Chrome web security
tests/cypress/cypress.json
    "chromeWebSecurity": false,
With these changes, your Cypress tests should stay framed and run as expected.


-End of Document-
Thanks for reading 


Friday, January 15, 2021

Cypress configuration and organization

Cypress is a next generation front end testing tool built for the modern web.

Instead of using an external listener, such as Selenium, which can be 'flaky' at times waiting for responses, Cypress has been built to run in the browser so it can more accurately monitor and react to requests.  More information can be found at Cypress.io 

The following will install Cypress, give some configuration and organization recommendations, and show how to persist sessions.  Writing the tests is up to you! (Write your first test)



Install

In the base of your application, make a tests directory, and a cypress directory, as you may have or end up using other test suites

> mkdir tests/cypress

> cd tests/cypress


Simple npm install

> npm install cypress --save-dev


run Cypress

> npx cypress open


Official docs Install Cypress



Organization

While the install of Cypress creates an example skeleton directory 

test/cypress/cypress

It is recommended to create your own directory 'just in case' a npm update decides to do 'something' with those skeleton directories.


create an app or unique name under 

tests/cypress/[app_abbrev]

You can copy from 

tests/cypress/cypress

or create the directories:

  • integration 

where you write and run tests  

  • fixtures 

static data for testing

  • plugins 

enable you to modify or extend Cypress

  • screenshots 

if taken, storage

  • support

loaded automatically before your test files ie global tests configuration

    • commands

additional grouping of common executed test steps

    • callbacks

additional grouping of callbacks which can modify the behaviors of tests



Configuration

Under 

tests/cypress

create three config files,

cypress.json

cypress.env.json

cypress.env.json.example


cypress.json contains global configuration related to Cypress

Add your [app_abbrev] location to the config:

{

    "fixturesFolder": "[app_abbrev]/fixtures",

    "integrationFolder": "[app_abbrev]/integration",

    "pluginsFile": "[app_abbrev]/plugins",

    "screenshotsFolder": "[app_abbrev]/screenshots",

    "supportFile": "[app_abbrev]/support"

}


cypress.env.json contains environment dependent configuration, such as user names for logins

You should create and maintain a 

cypress.env.json.example 

with the available config options too

An example config:

{

    "web_base_url": "http://app.dev.localhost:8088/",

    "login_username": "yourtestuser@dev.localhost",

    "login_password": "randchars"

}


Note, while Cypress does have a baseUrl config option that can be added to cypress.json, doing so does not allow the url to change per environment/developer/tester.  If you are using a defined centralized test environment, or defined containers, then this should not be an issue.  But to allow the url the app uses during testing to vary between environment/developer/tester, you can add and use your own base url by adding it to cypress.env.json

So instead of 

Cypress.config().baseUrl

You would use

Cypress.env("web_base_url")



Support

The index.js in support is called on every run of a test.  

This is where you can add global tests configuration and behaviors

Note, for easier maintenance, try to keep functionality to one file.


Update

tests/cypress/[app_abbrev]/support/index.js

to contain

import './commands/login_ui';


import './callbacks/stop_on_failure';

import './callbacks/preserve_session';


Support Commands

An example of a common executed test step may be to log in to your app.


Login UI

support/commands/login_ui.js

Create and add the minimal steps to log into your app, which may look similar to:

// https://on.cypress.io/custom-commands

Cypress.Commands.add("login_ui", (email, password) => {

    // minimal info to login via ui

    cy.visit(Cypress.env("web_base_url"));

    cy.url().should("include", "[app_abbrev]");


    let el = cy.get('#login_form [name="username"]');

    el.type(Cypress.env("login_username"));


    el = cy.get('#login_form [name="password"]');

    el.type(Cypress.env("login_password"));


    el = cy.get('#login_submit');

    el.click();

});


Note, instead of using your apps ui to log in for every test, you should create a token or api access to expedite the test


Now you can call the command using one consistent statement


describe("Select that Awesome Thing Test", () => {

    describe("Can Login", () => {

        it("Can login", () => {

            cy.login_ui(Cypress.env("login_username"), Cypress.env("login_password"));

        });

    });

});


Support Callbacks/Behaviors


Stop on Failure:

support/callbacks/stop_on_failure.js

When on step of a test fails, it will often cause the next steps to fail.  

So fail early so the problem can be found quicker.

Create and add

// after each test

// stop test after first failure

afterEach(function () {

    if (this.currentTest.state === 'failed') {

        Cypress.runner.stop()

    }

});


Preserve Sessions:

support/callbacks/preserve_session.js

All tests are supposed to be isolated, so Cypress will often clean up your cookies.

While it would be nice if the cleanup happens after the first test, or the last test in a suite, the clean up will happen after a few tests, which can log you out of your app and make it seem like your app or the test are broken.

To persists your session, which is often stored in a session cookie, create and add:

// once before all tests

// preserve session cookie so don't get 'randomly' logged out after several specs

before(function () {

    Cypress.Cookies.defaults({

        preserve: ['your_sessionid_name']

    });

});



Package.json

While you can run Cypress via

> npx cypress open


You can also add a more common alias to your package.json

  "scripts": {

    "test": "npx cypress open"

  },

And run Cypress via

> npm run test



.gitignore
Update your .gitignore
/tests/cypress/node_modules
/tests/cypress/cypress
/tests/cypress/cypress.env.json


Hopefully the above information helps you setup and use Cypress in a more enjoyable and useful fashion.



-End of Document-

Thanks for reading