Skip to content

Trying to load and bootstrap Angular component dynamically inside Cypress

Notifications You must be signed in to change notification settings

bahmutov/cypress-angular-unit-test

Repository files navigation

cypress-angular-unit-test

npm version renovate-app badge cypress version ci status cypress-angular-unit-test

Installation

npm install -D cypress cypress-angular-unit-test

Add to your support file

// cypress/support/index.js
// core-js 3.*
require('core-js/es/reflect');
// core-js 2.*
require('core-js/es7/reflect');
require('cypress-angular-unit-test/support');

Webpack config

Create a new file webpack.config.ts in cypress/plugins folder. You can find the file content here :

Cypress >= v7

npm install -D @cypress/webpack-dev-server html-webpack-plugin

Enable component testing in cypress.json.

{
  "component": {
    "componentFolder": "src/app",
    "testFiles": "**/*cy-spec.ts"
  }
}

Configure cypress/plugins/index.js to transpile Angular code.

const webpackConfig = require('./webpack.config');
const { startDevServer } = require('@cypress/webpack-dev-server');

module.exports = (on, config) => {
  on('dev-server:start', (options) =>
    startDevServer({
      options,
      webpackConfig,
    }),
  );
  return config;
};

Run npx cypress open-ct

Cypress < v7

npm install -D @cypress/webpack-preprocessor

Enable experimental component testing mode in cypress.json and point at the spec files. Usually they are alongside your application files in src folder.

{
  "experimentalComponentTesting": true,
  "componentFolder": "src",
  "testFiles": "**/*cy-spec.*"
}

Configure cypress/plugins/index.js to transpile Angular code.

const wp = require('@cypress/webpack-preprocessor');
const webpackConfig = require('./webpack.config');
module.exports = (on, config) => {
  const options = {
    webpackConfig,
  };
  on('file:preprocessor', wp(options));
  return config;
};

Run npx cypress open

Use

import { mount } from 'cypress-angular-unit-test';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  it('shows the input', () => {
    // Init Angular stuff
    initEnv(AppComponent);
    // You can also :
    // initEnv({declarations: [AppComponent]});
    // initEnv({imports: [MyModule]});

    // component + any inputs object
    mount(AppComponent, { title: 'World' });
    // use any Cypress command afterwards
    cy.contains('Welcome to World!');
  });
});

Demo

Examples

Use case Description
Input Test inject @Input() value
Output Test catching @Output()
Bootstrap Bootstrap integration with style : setConfig({ stylesheet: 'https://...});
Add style Add custom style for testing : setConfig({ style: 'p {background-color: blue;}' });
HTML mount Mount a component with html, don't forget to call detectChanges() after
Image Snapshot Mount a component and visual asserting
Material Material integration
Prime NG PrimeNG integration
OnPush strategy Component with changeDetection: ChangeDetectionStrategy.OnPush need call detectChanges()
Directive Test directive with mountHtml
Pipe Test pipe with mountHtml
Stub service Stub a service with Observable
Only service Test a service without a component
Web Component Test a custom element with shadow dom
Assets assets folder accessible by Cypress
Async Async test with cy.tick
Routing Test routing link
Network Test with http calls
NGRX NGRX store

Code coverage

Integration test

  • Install ngx-build-plus to extends the Angular CLI's build process and instrument the code

npm i -D ngx-build-plus

  • Add webpack coverage config file coverage.webpack.js to cypress folder
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|ts)$/,
        loader: 'istanbul-instrumenter-loader',
        options: { esModules: true },
        enforce: 'post',
        include: require('path').join(__dirname, '..', 'src'),
        exclude: [
          /\.(e2e|spec)\.ts$/,
          /node_modules/,
          /(ngfactory|ngstyle)\.js/,
        ],
      },
    ],
  },
};
  • Update angular.json to use ngx-build with extra config
"serve": {
  "builder": "ngx-build-plus:dev-server",
  "options": {
    "browserTarget": "cypress-angular-coverage-example:build",
    "extraWebpackConfig": "./cypress/coverage.webpack.js"
  },
}
  • Instrument JS files with istanbul for code coverage reporting

npm i -D istanbul-instrumenter-loader

  • Add cypress code coverage plugin

npm install -D @cypress/code-coverage

  • Then add the code below to your supportFile and pluginsFile
// cypress/support/index.js
import '@cypress/code-coverage/support';
// cypress/plugins/index.js
module.exports = (on, config) => {
  require('@cypress/code-coverage/task')(on, config);
  return config;
};

source : https://github.com/skylock/cypress-angular-coverage-example

Unit test

  • Instrument JS files with istanbul for code coverage reporting

npm i -D istanbul-instrumenter-loader

  • In your cypress/plugins/cy-ts-preprocessor.ts add this rule
rules: [
  {
    test: /\.(js|ts)$/,
    loader: 'istanbul-instrumenter-loader',
    options: { esModules: true },
    enforce: 'post',
    include: path.join(__dirname, '../..', 'src'),
    exclude: [/\.(e2e|spec)\.ts$/, /node_modules/, /(ngfactory|ngstyle)\.js/],
  },
];

Report

You can find the HTML report at coverage/lcov-report/index.html

Working

I have successfully used this mounting approach to test components in other frameworks.

Debugging

You can turn on debugging log by setting environment variable :

// Unix
export DEBUG="cypress-angular-unit-test,cypress:webpack:stats"

// PowerShell
$env:DEBUG="cypress-angular-unit-test,cypress:webpack:stats"

Development

This project only transpiles the library, to see it in action:

  • Install dependencies npm i
  • Compile the library npm run build
  • Open Cypress with npx cypress open

Pick any component test spec file to run