Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use .feature files in cypress with nrwl nx

I have an Angular project with an Nrwl Nx workspace. For my e2e test I use cypress with typescript. For this tests I would like to enable support for Feature files with Gherkin Syntax.

I added the "cypress-cucumber-preprocessor" to the project. This setup works fine when I write the bindings with js. But as soon as I try to setup the steps for typescript I get errors and I can't make it work.

Setup for js:

const { preprocessTypescript } = require('@nrwl/cypress/plugins/preprocessor');
const cucumber = require('cypress-cucumber-preprocessor').default;

module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config

  // Code Coverage
  on('task', require('@cypress/code-coverage/task'));

  // Preprocess Typescript
  on('file:preprocessor', preprocessTypescript(config));

  // Gherkin support
  on('file:preprocessor', cucumber());
};

Setup for ts:

const { preprocessTypescript } = require('@nrwl/cypress/plugins/preprocessor');
const cucumber = require('cypress-cucumber-preprocessor').default;
const browserify = require('@cypress/browserify-preprocessor');

module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config

  // Code Coverage
  on('task', require('@cypress/code-coverage/task'));

  // Preprocess Typescript
  on('file:preprocessor', preprocessTypescript(config));

  // Gherkin support
  const options = browserify.defaultOptions;
  options.browserifyOptions.plugin.unshift(['tsify']);
  on('file:preprocessor', cucumber());
};
{
  "name": "client-app",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "nx": "nx",
    "start": "ng serve",
    "start:browser": "ng serve -o --port 54055",
    "build": "ng build",
    "build:ssr": "ng run client-app:server:production",
    "test": "ng test",
    "lint": "nx workspace-lint && ng lint",
    "e2e": "ng e2e",
    "e2e:watch": "ng e2e --watch",
    "e2e:headless": "ng e2e --prod --headless",
    "affected:apps": "nx affected:apps",
    "affected:libs": "nx affected:libs",
    "affected:build": "nx affected:build",
    "affected:e2e": "nx affected:e2e",
    "affected:test": "nx affected:test",
    "affected:lint": "nx affected:lint",
    "affected:dep-graph": "nx affected:dep-graph",
    "affected": "nx affected",
    "format": "nx format:write",
    "format:write": "nx format:write",
    "format:check": "nx format:check",
    "update": "ng update @nrwl/workspace",
    "update:check": "ng update",
    "workspace-schematic": "nx workspace-schematic",
    "dep-graph": "nx dep-graph",
    "help": "nx help",
    "extract:clientApp": "ngx-translate-extract --input ./apps/client-app/src --output ./apps/client-app/src/assets/i18n/de.json ./apps/client-app/src/assets/i18n/en.json ./apps/client-app/src/assets/i18n/fr.json ./apps/client-app/src/assets/i18n/it.json --clean --sort",
    "extract:clientAppe2e": "ngx-translate-extract --input ./apps/client-app/src --output ./apps/client-app-e2e/src/fixtures/i18n/de.json ./apps/client-app-e2e/src/fixtures/i18n/en.json ./apps/client-app-e2e/src/fixtures/i18n/fr.json ./apps/client-app-e2e/src/fixtures/i18n/it.json --clean --sort"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^8.0.0",
    "@angular/cdk": "^8.1.1",
    "@angular/common": "^8.0.0",
    "@angular/compiler": "^8.0.0",
    "@angular/core": "^8.0.0",
    "@angular/flex-layout": "^8.0.0-beta.26",
    "@angular/forms": "^8.0.0",
    "@angular/material": "^8.1.1",
    "@angular/platform-browser": "^8.0.0",
    "@angular/platform-browser-dynamic": "^8.0.0",
    "@angular/platform-server": "^8.1.3",
    "@angular/pwa": "^0.801.2",
    "@angular/router": "^8.0.0",
    "@angular/service-worker": "^8.0.0",
    "@aspnet/signalr": "1.0.3",
    "@ngrx/effects": "^8.2.0",
    "@ngrx/entity": "^8.2.0",
    "@ngrx/router-store": "^8.2.0",
    "@ngrx/store": "^8.2.0",
    "@nguniversal/module-map-ngfactory-loader": "^8.1.1",
    "@ngx-translate/core": "^11.0.1",
    "@ngx-translate/http-loader": "^4.0.0",
    "@nrwl/angular": "8.4.0",
    "@types/file-saver": "^2.0.1",
    "applicationinsights-js": "^1.0.20",
    "aspnet-prerendering": "^3.0.1",
    "core-js": "^2.5.4",
    "file-saver": "^2.0.2",
    "hammerjs": "^2.0.8",
    "ngx-infinite-scroll": "^7.2.0",
    "rxjs": "~6.4.0",
    "zone.js": "^0.9.1"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^0.800.1",
    "@angular/cli": "8.1.1",
    "@angular/compiler-cli": "^8.0.0",
    "@angular/language-service": "^8.0.0",
    "@biesbjerg/ngx-translate-extract": "^2.3.4",
    "@cypress/code-coverage": "^1.8.0",
    "@ngrx/store-devtools": "^8.2.0",
    "@nrwl/cypress": "8.4.0",
    "@nrwl/jest": "8.4.0",
    "@nrwl/linter": "^8.4.1",
    "@nrwl/workspace": "8.4.0",
    "@types/applicationinsights-js": "^1.0.9",
    "@types/cypress-cucumber-preprocessor": "^1.12.0",
    "@types/jest": "24.0.9",
    "@types/node": "^12.6.8",
    "codelyzer": "~5.0.1",
    "cypress": "3.4.0",
    "cypress-cucumber-preprocessor": "^1.16.0",
    "dotenv": "6.2.0",
    "istanbul-lib-coverage": "^2.0.5",
    "jest": "24.1.0",
    "jest-preset-angular": "7.0.0",
    "ngrx-store-freeze": "^0.2.4",
    "nyc": "^14.1.1",
    "prettier": "1.16.4",
    "ts-jest": "24.0.0",
    "ts-node": "~7.0.0",
    "tsify": "^4.0.1",
    "tslint": "~5.11.0",
    "typescript": "~3.4.5"
  },
  "cypress-cucumber-preprocessor": {
    "nonGlobalStepDefinitions": true
  }
}

I have following error with this setup:

SyntaxError: 'import' and 'export' may appear only with 'sourceType: module'

like image 681
Alexander Wissmann Avatar asked Oct 14 '19 09:10

Alexander Wissmann


People also ask

What is NRWL Cypress?

Cypress is a test runner built for the modern web. It has a lot of great features: Time travel. Real-time reloads.

What is NRWL workspace?

The workspace plugin contains executors and generators that are useful for any Nx workspace. It should be present in every Nx workspace and other plugins build on it.

What is Cypress cucumber preprocessor?

The cypress-cucumber-preprocessor adds support for using feature files when testing with Cypress. You can follow the documentation below, or if you prefer to hack on a working example, take a look at https://github.com/TheBrainFamily/cypress-cucumber-example.


1 Answers

I've found an article written by Balázs Tápai: I'm in a Pickle - Configuring Gherkin with NX Workspaces. It was for some reason not totally complete but really helpful.

After several hours of sweating and crying, I could have a running example. Read the article and then follow the following steps:

Set up Gherkin

Add npm package

npm i -D cypress-cucumber-preprocessor

Please note that tsify is not required.

Add config file

At the root of the nx project, add a file named cypress-cucumber-preprocessor.config.js The cypress-cucumber-preprocessor property in package.json is redundant and should be removed if present.

const path = require("path");

const stepDefinitionsPath = path.resolve(process.cwd(), "./src/integration");
const outputFolder = path.resolve(process.cwd(), "../../cyreport/cucumber-json");

module.exports = {
  nonGlobalStepDefinitions: true,
  stepDefinitions: stepDefinitionsPath,
  commonPath: stepDefinitionsPath, // I added this line, not sure if necessary
  cucumberJson: {
    generate: true,
    outputFolder: outputFolder,
    filePrefix: "",
    fileSuffix: ".cucumber"
  }
};

Write the tests

In the folder integration of your e2e project:

Add simple.feature

Feature: Simple test

  Simple test feature

@focus
Scenario: I always pass
Given I pass
Then I see "the expected text"

Add simple.test.ts

import { assert } from 'console';
import { Given, Then } from 'cypress-cucumber-preprocessor/steps';

Given(/I pass/, () => {
  console.log('Congrats!');
});

Then('I see {string}', (text: string) => {
  console.log(text === 'the expected text');
});

Preprocessed Pickles

Verify that cypress.json looks like this:

{
  "fileServerFolder": ".",
  "fixturesFolder": "./src/fixtures",
  "integrationFolder": "./src/integration",
  "modifyObstructiveCode": false,
  "pluginsFile": "./src/plugins/index",
  "supportFile": "./src/support/index.ts",
  "video": true,
  "videosFolder": "../../dist/cypress/apps/sandbox-e2e/videos",
  "screenshotsFolder": "../../dist/cypress/apps/sandbox-e2e/screenshots",
  "chromeWebSecurity": false,
  "testFiles": "**/*.{feature,features}"
}

Rewrite plugins/index.js

This part is slightly different than the one in the article.

const { preprocessTypescript } = require('@nrwl/cypress/plugins/preprocessor');

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = (on, config) => {
  on('file:preprocessor', preprocessTypescript(config, customizeWebpackConfig));
  return config;
}

function customizeWebpackConfig(webPackConfig) {
  webPackConfig.node = {
    fs: "empty",
    child_process: "empty",
    readline: "empty",
  };

  pushFeature(webPackConfig);
  pushFeatures(webPackConfig);

  return webPackConfig;
}

function pushFeature(webPackConfig) {
  pushModuleRule(webPackConfig, /\.feature$/, 'cypress-cucumber-preprocessor/loader');
}

function pushFeatures(webPackConfig) {
  pushModuleRule(webPackConfig, /\.features$/, 'cypress-cucumber-preprocessor/lib/featuresLoader');
}

function pushModuleRule(webPackConfig, testRegex, loaderLib) {
  webPackConfig.module.rules.push({
   test: testRegex,
   use: [{ loader: loaderLib }]
  });
}

Code coverage? Html reporter!

I tried using @cypress/code-coverage but it does not work. So I removed it from the solution.

The article describe then how to add html report for Business Owner. It is straighforward (if you install for dev chalk and cucumber-html-reporter) thus was not not copied here.

like image 174
Francois Stock Avatar answered Oct 15 '22 14:10

Francois Stock