Reputation: 606
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?
Upvotes: 2
Views: 2512
Reputation: 606
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.
Upvotes: 2
Reputation: 3565
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
Upvotes: 0