我在TypeScript和Angular2中并不是很精明,而且我一直试图使用TypeScript编写的步骤来运行黄瓜的功能。但是,在执行steps.ts文件时,我收到以下错误:
[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
似乎黄瓜定义尚未编制。
这些是我的(相关)配置:
我的目录结构是:
/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;
}
};
一个step_definition的例子是:
/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);
});
};
有什么我错过的吗?
答案 0 :(得分:2)
真正的诀窍是修复出口申报,因此:
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);
});
};
之后,黄瓜开始相应地运行。
答案 1 :(得分:0)
在 protractor.conf.js 中,您可以从cucumberOpts中删除编译器选项
cucumberOpts: {
format: 'pretty',
require: [
'test/features/step_definitions/**/*.steps.ts'
],
//remove this compiler: 'ts:ts-node/register'
},
其次,您的 signUp.steps.ts 应如下所示:
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;
您还可以使用https://github.com/timjroberts/cucumber-js-tsflow编写更清晰的步骤定义
@see https://github.com/samvloeberghs/protractor-gherkin-cucumberjs-angular2进行全面实施。
干杯