The Problem
I am attempting to run a Cucumber test using a Karma test runner in my Npm project using the karma-cucumber-js adapter. However, when running my test, I find the following error in my console:
START:
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
ReferenceError: Can't find variable: __adapter__
at features/Test.steps.js:80
For more context, I am in the middle of a platform migration. We had a complex system in place previously that essentially used karma 1.7.x, cucumber 1.2.x, karma-cucumber-js 0.3.3, and Node 0.8.x. I am trying to set up a simple npm project with the same exact versions (except now I'm using Node 8.x as I am not allowed to use 0.8.x). We have a suite of thousands of old tests that we'd like to minimize modifications for, and it would be easiest to get the karma-cucumber-js plugin working due to how tightly coupled our test system is with both karma and cucumber.
Things I've Tried
I played around with the dependent karma-cucumber-js source code a bit by tweaking the code in my package's node_modules directory as an attempt to better understand the issue at hand. I was able to bypass the issue above by modifying these lines in adapter.js to globalize the adapter variable in the window as follows:
var __adapter__;
(function (win) {
var adapter = new karma.CucumberAdapter(__karma__);
__adapter__ = adapter;
__karma__.start = adapter.getStart();
win.__adapter__ = __adapter__;
})(window);
Which lead to the next error:
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
ReferenceError: Can't find variable: Cucumber
at node_modules/karma-cucumber-js/src/adapter.js:242
Which I worked around by adding the following line of code to the top of that very file after 'use strict':
var Cucumber = require('../../cucumber/release/cucumber.js');
Which lead to this issue:
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
ReferenceError: Can't find variable: CucumberHTML
at node_modules/karma-cucumber-js/src/adapter.js:177
And the workaround was to manually require that file adapter.js as well:
var CucumberHTML = require('../../cucumber-html/src/main/resources/cucumber/formatter/formatter.js');
With this "hack" in place, the cucumber tests are now able to run successfully:
START:
PhantomJS 2.1.1 (Mac OS X 0.0.0) LOG: 'Found features: /base/features/Test.feature'
PhantomJS 2.1.1 (Mac OS X 0.0.0) LOG: 'Tags: '
Is it Friday yet?
Friday is Friday
✔ Given today is Friday
✔ When I ask whether it's Friday yet
✔ Then I should be told "TGIF"
Finished in 0.002 secs / 0.002 secs @ 19:36:12 GMT-0700 (PDT)
SUMMARY:
✔ 3 tests completed
The underlying issue seems to be that [these Typescript variables][4] declared at the end of the karma-cucumber-js packages are, for some reason, not available to use. Which I believe is due to a webpack wiring issue.
Some other things I've tried:
- Using other karma-cucumber adapters (there are 2 others), no luck.
- Playing around with karma/phantomjs/cucumber version combinations
- Using Firefox and Chrome in replacement of PhantomJS
My questions
- I need help understanding why this webpack setup is not working. How can I fix this?
- Are there any steps I'm missing or alternative approaches I should be taking to debug and resolve the issue at hand?
I've included some of the project code below, thank you for your time!
Project Code
package.json:
{
"name": "npm-pretty-much-local-example",
"version": "1.0.0",
"scripts": {
"wp": "webpack",
"wpd": "webpack --debug",
"test": "./node_modules/karma/bin/karma start"
},
"devDependencies": {
"@babel/core": "^7.7.2",
"@babel/preset-env": "^7.7.1",
"@babel/preset-react": "^7.7.0",
"babel-loader": "^8.0.0",
"@babel/preset-typescript": "^7.7.x",
"babel-generator": "^6.26.1",
"babel-core": "^6.26.3",
"cucumber": "^1.2.x",
"jquery": "^3.4.1",
"karma": "^1.7.x",
"karma-cucumber-js": "^0.3.3",
"karma-mocha-reporter": "^2.0.5",
"karma-phantomjs-launcher": "^1.0.x",
"karma-webpack": "^1.7.x",
"socket.io": "^1.4.x",
"webpack": "^3.7.1",
"setimmediate": "^1.0.5",
"karma-typescript-preprocessor": "^0.4.0"
},
"dependencies": {}
}
webpack.config.js:
const path = require('path');
module.exports = {
context: path.resolve('.'),
entry: './src/index.js',
output: {
filename: "./dist/output.js"
},
resolve: {
extensions: ['.js'],
modules: [
path.resolve('./src'),
path.resolve('./node_modules')
]
}
};
Test.feature:
@Test
Feature: Is it Friday yet?
Everybody wants to know when it's Friday
Scenario: Friday is Friday
Given today is Friday
When I ask whether it's Friday yet
Then I should be told "TGIF"
Test.steps.js:
function isItFriday(today) {
if (today === "Friday") {
return "TGIF";
} else {
return "Nope";
}
}
// TODO: why is this not defined, and how was __adapter__ defined in the first place?
__adapter__.addStepDefinitions(function (scenario) {
scenario.Given('today is {string}', function (givenDay) {
this.today = givenDay;
});
scenario.When('I ask whether it\'s Friday yet', function () {
this.actualAnswer = isItFriday(this.today);
});
scenario.Then('I should be told {string}', function (expectedAnswer) {
return this.actualAnswer === expectedAnswer;
});
});
src/index.js
var dummyVar = "";