Join the Stack Overflow Community
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I'm not really savvy in TypeScript and Angular2 and I've been trying to run the cucumber's features using steps that have been written in TypeScript. However, on executing the steps.ts files, I'm getting the following error:

[launcher] Running 1 instances of WebDriver
[launcher] Error: TypeError: step.Given is not a function
    at Object.module.exports (/Users/roalcantara/Documents/Tango/tango/test/features/step_definitions/signIn.steps.ts:13:8)
    at /Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/cli/support_code_loader.js:65:25
    at Array.forEach (native)
    at Object.wrapper (/Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/cli/support_code_loader.js:62:15)
    at Object.initializer (/Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/cli/support_code_loader.js:24:41)
    at Object.Library (/Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/support_code/library.js:118:25)
    at Object.getSupportCodeLibrary (/Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/cli/support_code_loader.js:10:58)
    at Object.getSupportCodeLibrary (/Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/cli/configuration.js:126:32)
    at Object.getSupportCodeLibrary (/Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/runtime.js:43:46)
    at Object.start (/Users/roalcantara/Documents/Tango/tango/node_modules/cucumber/lib/cucumber/runtime.js:12:37)
[launcher] Process exited with error code 100

It seems as if the cucumber definitions had not been compiled.

These are my (relevant) configurations:

My directory structure is:

/test/
|-/features/
|-xpto.feature
|--/step_definitions
|---xpto.step.ts

/package.json

{
  "name": "Tango",
  "version": "0.0.1",
  "private": true,
  "devDependencies": {
    "awesome-typescript-loader": "^0.17.0-rc.5",
    "chai": "^3.5.0",
    "chai-as-promised": "^5.3.0",
    "chalk": "^1.1.3",
    "codecov.io": "0.1.6",
    "cucumber": "^0.10.2",
    "cz-conventional-changelog": "^1.1.6",
    "del": "2.2.0",
    "es6-module-loader": "0.17.11",
    "gulp": "3.9.1",
    "gulp-autoprefixer": "^3.1.0",
    "gulp-inline-ng2-template": "^1.1.4",
    "gulp-load-plugins": "1.2.0",
    "gulp-sass": "2.2.0",
    "gulp-sourcemaps": "^1.6.0",
    "gulp-tslint": "^4.3.5",
    "gulp-typescript": "^2.12.1",
    "gulp-util": "^3.0.7",
    "gulp-watch": "4.3.5",
    "ionic-gulp-browserify-typescript": "^1.0.1",
    "ionic-gulp-fonts-copy": "^1.0.0",
    "ionic-gulp-html-copy": "^1.0.0",
    "ionic-gulp-sass-build": "^1.0.0",
    "ionic-gulp-scripts-copy": "^1.0.1",
    "jasmine-core": "2.4.1",
    "jasmine-spec-reporter": "^2.4.0",
    "karma": "0.13.22",
    "karma-chrome-launcher": "^0.2.3",
    "karma-coverage": "0.5.5",
    "karma-jasmine": "0.3.8",
    "karma-mocha-reporter": "^2.0.0",
    "karma-phantomjs-launcher": "1.0.0",
    "nconf": "^0.8.4",
    "phantomjs-prebuilt": "^2.1.7",
    "protractor": "^3.2.2",
    "protractor-cucumber-framework": "^0.5.0",
    "run-sequence": "1.1.5",
    "strip-sourcemap-loader": "0.0.1",
    "systemjs": "0.19.23",
    "traceur": "0.0.102",
    "ts-node": "0.5.5",
    "tslint": "^3.5.0",
    "tslint-eslint-rules": "1.0.1",
    "typescript": "^1.8.10",
    "typings": "^0.7.12"
  },
  "dependencies": {
    "angular2": "2.0.0-beta.13",
    "es6-promise": "3.0.2",
    "es6-shim": "^0.35.0",
    "ionic-angular": "2.0.0-beta.4",
    "ionic-native": "^1.1.0",
    "ionicons": "3.0.0-alpha.3",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.2",
    "zone.js": "^0.6.11"
  },
  "cordovaPlugins": [
    "cordova-plugin-device",
    "cordova-plugin-console",
    "cordova-plugin-whitelist",
    "cordova-plugin-inappbrowser",
    "cordova-plugin-splashscreen",
    "cordova-plugin-statusbar",
    "cordova-plugin-camera",
    "ionic-plugin-keyboard",
    "onesignal-cordova-plugin",
    "cordova-plugin-file",
    "cordova-plugin-crop"
  ],
  "cordovaPlatforms": [
    "ios",
    "android"
  ],
  "scripts": {
    "build": "gulp --gulpfile test/gulpfile.ts --cwd ./ ionic.build",
    "protractor": "./node_modules/protractor/bin/protractor protractor.conf.js",
    "e2e": "gulp --gulpfile test/gulpfile.ts --cwd ./ test.build.e2e && npm run protractor",
    "karma": "gulp --gulpfile test/gulpfile.ts --cwd ./ test.karma.debug",
    "postinstall": "typings install",
    "start": "ionic serve",
    "test": "gulp --gulpfile test/gulpfile.ts --cwd ./ test",
    "test.watch": "gulp --gulpfile test/gulpfile.ts --cwd ./ test.watch.build",
    "webdriver-update": "webdriver-manager update"
  }
}

/typings.json

{
  "dependencies": {},
  "devDependencies": {},
  "ambientDependencies": {
    "angular-protractor": "registry:dt/angular-protractor#1.5.0+20160317120654",
    "bluebird": "registry:dt/bluebird#2.0.0+20160319051630",
    "chalk": "registry:dt/chalk#0.4.0+20160317120654",
    "cucumber": "registry:dt/cucumber#0.0.0+20160316171810",
    "del": "registry:dt/del#2.2.0+20160317120654",
    "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
    "express": "registry:dt/express#4.0.0+20160317120654",
    "express-serve-static-core": "registry:dt/express-serve-static-core#0.0.0+20160322035842",
    "glob": "registry:dt/glob#5.0.10+20160317120654",
    "gulp": "registry:dt/gulp#3.8.0+20160316155526",
    "gulp-load-plugins": "registry:dt/gulp-load-plugins#0.0.0+20160316155526",
    "gulp-typescript": "registry:dt/gulp-typescript#0.0.0+20160317120654",
    "gulp-util": "registry:dt/gulp-util#3.0.0+20141016163602",
    "jasmine": "registry:dt/jasmine#2.2.0+20160412134438",
    "karma": "registry:dt/karma#0.13.9+20160316155526",
    "log4js": "registry:dt/log4js#0.0.0+20160316155526",
    "mime": "registry:dt/mime#0.0.0+20160316155526",
    "minimatch": "registry:dt/minimatch#2.0.8+20160317120654",
    "node": "registry:dt/node#4.0.0+20160412142033",
    "orchestrator": "registry:dt/orchestrator#0.0.0+20160316155526",
    "q": "registry:dt/q#0.0.0+20160323171452",
    "run-sequence": "registry:dt/run-sequence#0.0.0+20160316155526",
    "selenium-webdriver": "registry:dt/selenium-webdriver#2.44.0+20160317120654",
    "serve-static": "registry:dt/serve-static#1.7.1+20160104095738",
    "through2": "registry:dt/through2#2.0.0+20160317120654",
    "vinyl": "registry:dt/vinyl#1.1.0+20160316155526"
  }
}

/protractor.conf.js:

// @AngularClass
require('ts-node/register');
var helpers = require('./helpers');

exports.config = {
  /**
   * Angular 2 configuration
   *
   * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching
   * `rootEl`
   *
   */
  useAllAngular2AppRoots: true,

  /* LOCALHOST CONFIG */
  seleniumServerJar: "node_modules/protractor/selenium/selenium-server-standalone-2.52.0.jar",
  baseUrl: 'http://localhost:8100',

  exclude: [],

  allScriptsTimeout: 110000,

  framework: 'custom',
  frameworkPath: require.resolve('protractor-cucumber-framework'),
  specs: [
    helpers.root('test/features/**/*.feature')
  ],
  cucumberOpts: {
    format: 'pretty',
    require: [
      'test/features/step_definitions/**/*.steps.ts'
    ],
    compiler: 'ts:ts-node/register'
  },

  directConnect: true,

  capabilities: {
    'browserName': 'chrome'
  },

  onPrepare: function() {
    browser.ignoreSynchronization = false;
  }
};

And an example of one step_definition is:

/test/features/step_definitions/signUp.steps.ts

import cucumber = require('cucumber')
import {SignUpPage} from '../pages/signUp.page';
import {SignInPage} from '../pages/signIn.page';

let chai = require('chai').use(require('chai-as-promised'));
let expect = chai.expect;

export = () => {

  type Callback = cucumber.CallbackStepDefinition;
  let step = <cucumber.StepDefinitions>this;
  let index = new SignInPage();
  let page = new SignUpPage();

  step.Given(/^I am not authenticated$/, (callback:Callback) => {
    index.openApp();
    callback();
  });

  step.When(/^I go to register$/, (callback:Callback) => {
    index.signUp();
    callback();
  });

  step.When(/^I fill 'name' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setName(value);
    callback();
  });

  step.When(/^I fill 'email' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setEmail(value);
    callback();
  });

  step.When(/^I fill 'password' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setPassword(value);
    callback();
  });

  step.When(/^I fill 'passwordConfirmation' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setPasswordConfirmation(value);
    callback();
  });

  step.When(/^I press 'Sign up'$/, (callback:Callback) => {
    page.submit();
    callback();
  });

  step.Then(/^the register form is validated '(.*)'$/, (valid:string, callback:Callback) => {
    let isValid = (valid === 'true');
    expect(page.formIsValid()).to.become(isValid).and.notify(callback);
  });
};

Is there anything that I've missed?

share|improve this question

In your protractor.conf.js you can remove the compiler option from your cucumberOpts

  cucumberOpts: {
    format: 'pretty',
    require: [
      'test/features/step_definitions/**/*.steps.ts'
    ],
    //remove this compiler: 'ts:ts-node/register'
  },

Second, your signUp.steps.ts should look something like this:

let chai = require('chai').use(require('chai-as-promised'));
let expect = chai.expect;

import {SignUpPage} from '../pages/signUp.page';
import {SignInPage} from '../pages/signIn.page';

import Callback = cucumber.CallbackStepDefinition;

//1. create a class first
class SignupSteps{

  private index:SignInPage = new SignInPage();
  private page:SignUpPage = new SignUpPage();

  this.Given(/^I am not authenticated$/, (callback:Callback) => {
    index.openApp();
    callback();
  });

  this.When(/^I go to register$/, (callback:Callback) => {
    index.signUp();
    callback();
  });

  this.When(/^I fill 'name' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setName(value);
    callback();
  });

  this.When(/^I fill 'email' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setEmail(value);
    callback();
  });

  this.When(/^I fill 'password' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setPassword(value);
    callback();
  });

  this.When(/^I fill 'passwordConfirmation' with '([^"]*)'$/, (value:string, callback:Callback) => {
    page.setPasswordConfirmation(value);
    callback();
  });

  this.When(/^I press 'Sign up'$/, (callback:Callback) => {
    page.submit();
    callback();
  });

  this.Then(/^the register form is validated '(.*)'$/, (valid:string, callback:Callback) => {
    let isValid = (valid === 'true');
    expect(page.formIsValid()).to.become(isValid).and.notify(callback);
  });
}

//2. this is really key, expose the class
export = SignupSteps;

You could also use https://github.com/timjroberts/cucumber-js-tsflow for writing cleaner step definitions

@see https://github.com/samvloeberghs/protractor-gherkin-cucumberjs-angular2 for a full implementation.

Cheers

share|improve this answer
up vote 0 down vote accepted

What really did the trick was fix the export declaration, as such:

import {CallbackStepDefinition} from 'cucumber';
import {SignUpPage} from '../pages/signUp.page';
import {SignInPage} from '../pages/signIn.page';

let chai = require('chai').use(require('chai-as-promised'));
let expect = chai.expect;

export = function() {

  let index = new SignInPage();
  let page = new SignUpPage();

  this.When(/^I go to register$/, (callback:CallbackStepDefinition) => {
    index.signUp();
    callback();
  });

  this.When(/^I set 'name' with '([^"]*)'$/, (name:string, callback:CallbackStepDefinition) => {
    page.setName(name);
    callback();
  });

  this.When(/^I set 'email' with '([^"]*)'$/, (email:string, callback:CallbackStepDefinition) => {
    page.setEmail(email);
    callback();
  });

  this.When(/^I set 'password' with '([^"]*)'$/, (password:string, callback:CallbackStepDefinition) => {
    page.setPassword(password);
    callback();
  });

  this.When(/^I set 'passwordConfirmation' with '([^"]*)'$/, (value:string, callback:CallbackStepDefinition) => {
    page.setPasswordConfirmation(value);
    callback();
  });

  this.When(/^I press 'Sign up'$/, (callback:CallbackStepDefinition) => {
    page.submit();
    callback();
  });

  this.Then(/^the register form is validated '(.*)'$/, (valid:string, callback:CallbackStepDefinition) => {
    let isValid = (valid === 'true');
    expect(page.formIsValid()).to.become(isValid).and.notify(callback);
  });
};

After that, the cucumber started running accordingly.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.