Protractor - Cucumber - JS - Undefined Steps - javascript

I'm facing the next situation with Cucumber in Protractor (With Webstorm)
When I try to run the only feature that I have, it displays the next message (I have already defined the steps in a class)
Undefined. Implement with the following snippet:
Given('I open the url {string}', function (string) {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
...
1 scenario (1 undefined)
4 steps (4 undefined)
0m00.000s
Process finished with exit code 1
This is my config file (conf.js)
exports.config = {
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'https://www.afphabitat.cl/portalPrivado_FIXWeb/public/login.htm',
ignoreSynchronization: true,
getPageTimeout: 60000,
allScriptsTimeout: 50000,
defaultTimeoutInterval: 30000,
specs: ['features/*.feature'],
cucumberOpts: {
compiler: [],
require: ['step_defs/*.js'],
dryRun : false,
tags: ['#wip'],
monochrome: true,
strict: true,
plugin: "json",
format: 'json:reports/cucumber-report.json',
resultJsonOutputFile: 'reports/cucumber-report.json'
},
multiCapabilities:
[{
'browserName': 'chrome',
chromeOptions: {
binary: process.env.CHROME_BIN,
args: ['--no-sandbox', '--start-maximized']
}
},
{
'browserName': 'firefox',
args: ['--no-sandbox','--start-maximized']
}],
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
}
}
Next one is my step definition file (step_defs_Login.js)
import { Given, Then, When } from "cucumber";
import { browser, by, element, } from 'protractor';
Given('I open the url {string}', function (string) {
browser.get(string);
// callback();
});
When('proceed to enter my username as {string}', function (string1) {
let username = element(by.id('j_username_input')).clear();
username = element(by.id('j_username_input')).sendKeys(string1);
// callback();
});
When('proceed to enter my password as {string}', function (string2) {
let password = element(by.id('j_password')).clear();
password = element(by.id('j_password')).sendKeys(string2);
// callback();
});
Then('I have been logged in successfully', function () {
element(by.id('button')).click();
// callback();
});
Don't forget the JSON File (package.json)
{
"name": "package",
"version": "1.0.0",
"description": "First Protractor Cucumber project",
"main": "conf.js",
"scripts": {
"test": "cucumberjs"
},
"keywords": [
"TAE"
],
"author": "zzz",
"license": "ISC",
"devDependencies": {
"cucumber": "^5.1.0",
"selenium-webdriver": "^4.0.0-alpha.5"
},
"dependencies": {
"protractor": "latest"
}
}
I don't know if this is necessary or not, but this is my Hooks file (hooks.js)
let {defineSupportCode} = require('cucumber');
defineSupportCode (function ({After, Before}){
Before(function () {
// return this.driver.manage().window().maximize()
return this.browser.manage().window().maximize();
})
After(function () {
return this.driver.quit()
})
});
I have installed the next ones:
Protractor version 5.4.2
Node version 10.16.3
NPM 6.9.0
This is the project structure:
And this is the Run Configurations
Can anybody please help me with this???

Have you got the string you are passing in the feature file enclosed in "double quotes"?
I open the url "myUrl"

Try
require: ['../step_defs/*.js']
or
require: ['./step_defs/*.js']
In cucumberOpts object

Looks like you are using Webstrom to work on this cucumber framework. As I know, Webstrom will find the respective step definition for that step automatically. Coming to the issue,
1) Open your feature file and check that particular step is showing as implemented or not
2) Try to replace {string} with regular expression (.*) which will accept any type of data and check same step in feature file- step
Check both above cases

Related

Cypress environment variable undefined

In cypress.json file i have the following code
{
"baseUrl": "test",
"ignoreTestFiles": [],
"viewportHeight": 768,
"viewportWidth": 1024,
"video": false,
"env": { "email": "test#email.com", "password": "password" }
}
When i am trying to access it by calling Cypress.env('password') it shows undefined in console log when printing it, what is the issues.
const password: string = Cypress.env('password')
describe("Login to the application", () => {
beforeEach(() => {
cy.visit("/");
});
it.only("user should login successfully", () => {
console.log(Cypress.env('email')). --- undefined
loginPage.login(email, password);
cy.url().should("include", "/wallet");
});
My mistake for not knowing or not checking the location of my cypress.json file, moved it to the top cypress folder and value is shown properly.
In my Projekt (Version 10.xx) the cypress.config.ts must be in the root path not in the cypress folder. You can generate the config with the UI, to get it on the right location:
Settings > Project settings > cypress.config.ts
UPDATE for CYPRESS V10.
Extending #Artjom Prozorov answer,
Now in the newer version the cypress.json naming convention is deprecated.
So, we have to use cypress.config.ts as file name for configuration.
sample of file content given below.
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
specPattern: "src/**/*.cy.{js,jsx,ts,tsx}",
baseUrl: "http://localhost:3001",
trashAssetsBeforeRuns: false,
viewportWidth:1920,
viewportHeight:1080,
slowTestThreshold: 1000,
// watchForFileChanges : false,
env: {
apiUrl : "http://localhost:3000",
commandDelay: 100,
password: 'here it is'
},
reporter: 'mochawesome',
reporterOptions: {
reportDir: 'cypress/reports',
overwrite: false,
html: true,
json: false
},
setupNodeEvents(on, config) {
config.env.sharedSecret =
process.env.NODE_ENV === 'development' ? 'itsDev' : 'itsLocal'
return config
}
},
component: {
devServer: {
framework: "create-react-app",
bundler: "webpack"
}
}
});
NOTE : this cypress.config.ts must be inside the cypress directory.

'Error: TypeError: ProtractorImageComparison is not a constructor' with the protractor-image-comparison v2.0.1

I'm trying to write some visual tests and running into the mentioned error with the protractor-image-comparison of version 2.0.1. Even though there is an update of the library I decided to stick to the older version since I experience some issues with the newest one as well.
My setup is:
//protractor.conf.js:
const { SpecReporter } = require('jasmine-spec-reporter');
const { join } = require('path');
const { ProtractorImageComparison } = require('protractor-image-comparison');
exports.config = {
allScriptsTimeout: 11000,
specs: ['./src/**/*-spec.ts'],
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [
// '--headless',
'--disable-gpu', '--window-size=1600,950', '--no-sandbox'],
},
},
SELENIUM_PROMISE_MANAGER: false,
directConnect: true,
framework: 'jasmine2',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {
},
},
onPrepare() {
require('ts-node').register({
project: join(__dirname, './tsconfig.e2e.json'),
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
browser.protractorImageComparison = new ProtractorImageComparison({
baselineFolder: join(__dirname, '/src/resources/baseline/'),
screenshotPath: join(__dirname, '/src/tmp/'),
formatImageName: '{tag}',
autoSaveBaseline: false
});
},
};
I came across this issue today and apparently from version 3.0.1 this package now functions as a plugin and not a class which needs to be instantiated.
I managed to get it working adding the following code to my conf.js:
plugins: [
{
inline: require('protractor-image-comparison'),
// package: 'protractor-image-comparison' //protractor is installed globally so it is checking for plugin globally also
options: {
baselineFolder: './testArtifacts/screen-compare/baselines/',
screenshotPath: './testArtifacts/screen-compare/screenshots/',
formatImageName: `{tag}-{logName}-{width}x{height}`,
savePerInstance: true,
},
},
],
Note: For me protractor was installed globally so I needed this workaround using inline instead of package to get it searching for the plugin module locally.

SyntaxError: Unexpected token { when trying to run protractor test

I'm trying to run a very simple set of protractor tests, however, when i run the "yarn e2e" command, i got the following error:
import { browser } from "protractor";
^
SyntaxError: Unexpected token {
The code in protractor-config.ts where the error occurs is:
import { browser } from "protractor";
exports.config = {
allScriptsTimeout: 20000,
specs: ['./spec/spec.ts'],
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 720000
},
capabilities: {
'browserName': 'chrome',
},
directConnect: true,
framework: 'jasmine',
SELENIUM_PROMISE_MANAGER: false,
onPrepare: function () {
browser.driver.manage().window().setSize(1280, 1024);
}
}
What i've tried:
Changing
import { browser } from "protractor";
to
const browser = require('protractor');
Changing "target": "es5" to es6 in my tsconfig.json
But non of this options made any difference!
Anyone has any idea on what can this be? Thanks a lot in advance.
Your protractor.config.js should contain :
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json' // if you have one
});
This part is the one telling protractor how to handle typescript. This part of code is from angular-cli, so I suggest you to create a new angular app from scratch with ng new myapp and compare the config (protractor is working by default)

Electron Updates with Gitlab

Is it possible to use the Electron built in auto updater with Gitlab tags?
I have seen that you can use Electron with GitHub releases, via electron-builder, but I am not sure the same can be said with Gitlab, as the use of Github tokens is required.
If there is no option to use Gitlab, are the only other options (a) a self hosted squirrel server, or (b) github releases?
You can use a generic host which is the easiest method, see:
https://gist.github.com/iffy/0ff845e8e3f59dbe7eaf2bf24443f104
You can edit updates.json/yml to point to the gitlab release, and it will be no worse than a generic server. It won't check the gitlab credentials, though.
You can use Amazon S3 or Bintray, see:
https://github.com/electron-userland/electron-builder/wiki/Publishing-Artifacts
Google Compute claims that they can be setup to be compatible with S3, so you could probably use them as well.
You may be able to use Gitlab releases the same as Github using the git+ssh syntax. Haven't tested that, but see Install npm module from gitlab private repository
My working example
.gitlab-ci
variables:
VERSION_ID: '1.0.$CI_PIPELINE_ID'
stages:
- build
build:
image: slauta93/electron-builder-win
stage: build
artifacts:
paths:
- $CI_PROJECT_DIR/dist/*.*
script:
- sed "s/0.0.0/${VERSION_ID}/g" package.json > _package.json && mv _package.json package.json
- npm install && npm run build
main.js
// Inital app
const electron = require("electron");
const updater = require("electron-updater");
const autoUpdater = updater.autoUpdater;
...
///////////////////
// Auto upadater //
///////////////////
autoUpdater.requestHeaders = { "PRIVATE-TOKEN": "Personal access Token" };
autoUpdater.autoDownload = true;
autoUpdater.setFeedURL({
provider: "generic",
url: "https://gitlab.com/_example_repo_/-/jobs/artifacts/master/raw/dist?job=build"
});
autoUpdater.on('checking-for-update', function () {
sendStatusToWindow('Checking for update...');
});
autoUpdater.on('update-available', function (info) {
sendStatusToWindow('Update available.');
});
autoUpdater.on('update-not-available', function (info) {
sendStatusToWindow('Update not available.');
});
autoUpdater.on('error', function (err) {
sendStatusToWindow('Error in auto-updater.');
});
autoUpdater.on('download-progress', function (progressObj) {
let log_message = "Download speed: " + progressObj.bytesPerSecond;
log_message = log_message + ' - Downloaded ' + parseInt(progressObj.percent) + '%';
log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')';
sendStatusToWindow(log_message);
});
autoUpdater.on('update-downloaded', function (info) {
sendStatusToWindow('Update downloaded; will install in 1 seconds');
});
autoUpdater.on('update-downloaded', function (info) {
setTimeout(function () {
autoUpdater.quitAndInstall();
}, 1000);
});
autoUpdater.checkForUpdates();
function sendStatusToWindow(message) {
console.log(message);
}
...
package.json
{
"name": "electron-updater-gitlab",
"version": "0.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"pack": "node_modules/.bin/electron-builder --dir",
"build": "node_modules/.bin/electron-builder --win",
"postinstall": "",
"install": "node-gyp install",
},
"build": {
"appId": "com.electron.app",
"publish": [
{
"provider": "generic",
"url": "https://gitlab.com"
}
],
"win": {
"target": [
"nsis"
],
"verifyUpdateCodeSignature": false
},
"mac": {
"category": "public.app-category.productivity",
"identity": "Mac Developer: username (XXXXXXXX)",
"target": [
"dmg"
]
},
"linux": {
"target": [
"AppImage"
]
}
},
"dependencies": {
"electron-updater": "^2.7.2"
},
"devDependencies": {
"electron": "1.6.11",
"electron-builder": "^19.16.2"
}
}
After considering the answers in this issue and others, I ended up using GitLab Pages to publish my build artifacts. This allowed me to make make the installer files freely available to everyone in my organization without opening up the repo to everyone.
.gitlab-ci.yml:
stages:
- test
- build
- deploy
test-app:
stage: test
image: node:lts-alpine
script:
- npm install
- npm run test:colors
electron-release-build:
only:
- master
stage: build
image: electronuserland/builder:wine
script:
- npm ci
- npm run package:publish
artifacts:
paths:
- electron-release/*.exe*
- electron-release/*.yml
expire_in: 1 month
pages:
stage: deploy
only:
- master
image: alpine:latest
dependencies:
- electron-release-build
script:
# Note that `public` already exists in this repo, and has an index.html to
# to act as a downloads page.
- cp electron-release/*.exe electron-release/*.blockmap electron-release/*.yml public
- EXE_FILENAME=$(find ./electron-release -maxdepth 1 -name "Maestro*.exe")
- EXE_BASENAME=$(basename "$EXE_FILENAME")
- sed -i "s/INSERT_FILE_NAME/${EXE_BASENAME}/g" ./public/index.html
artifacts:
paths:
- public
Relevant part of package.json:
{
"build": {
"asar": true,
"appId": "com.myapp.app",
"productName": "myapp",
"directories": {
"output": "electron-release"
},
"extraFiles": [
"build/icon.ico"
],
"detectUpdateChannel": false,
"publish": {
"provider": "generic",
"url": "https://myappgroup.pages.example.com/myapp"
},
"win": {
"target": "nsis",
"verifyUpdateCodeSignature": false,
"icon": "build/icon.ico"
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowElevation": true,
"allowToChangeInstallationDirectory": true
}
}
}
No changes were needed anywhere else.
This also simplified things a bit, since I don't think I could use the provider URL proposed in another answer due to permissions (https://gitlab.com/_example_repo_/-/jobs/artifacts/master/raw/dist?job=build 404s for me).

How can I use Jasmine with CucumberJS?

How can I use jasmine with cucumberjs ?
I tried this solution from https://stackoverflow.com/a/30763260/5453732
But I have always this error : TypeError: this.expect(...).toBe is not a function at World. (/myApp/tests/e2e/steps/main.step.js:33:79)
Line 39 :
this.expect(element(by.css('[data-el="' + field + '"]')).isPresent()).toBe(true);
app/modules/user/tests/e2e/user.feature
#user.feature
Feature: Login feature
As a user
I want authenticate my account
Scenario: Authentication success
Given I am on "#/" page
Given I check if "navbar-menu-user-module" is visible
Given I wait "3" seconds
/tests/e2e/steps/main.step.js
module.exports = function () {
this.World = require("../support/world.js").World;
this.path = '#/';
this.Given(/^I am on "?([^"]*)"? page$/, function (arg1, callback) {
browser.get(arg1);
callback();
});
this.Given(/^I wait "?([^"]*)"? seconds$/, function (arg1, callback) {
browser.sleep(3000);
callback();
});
this.Given(/^I check if "?([^"]*)"? is visible$/, function (field, callback) {
this.expect(element(by.css('[data-el="' + field + '"]')).isPresent()).toBe(true);
callback();
});
};
/tests/e2e/support/world.js
var World, chai, chaiAsPromised;
chai = require('chai');
chaiAsPromised = require('chai-as-promised');
World = function World(callback) {
chai.use(chaiAsPromised);
this.expect = chai.expect;
callback();
}
module.exports.World = World;
protractor.conf.js
/* protractor.conf.js */
exports.config = {
directConnect: true,
seleniumServerJar: 'node_modules/selenium-server/lib/runner/selenium-server-standalone-2.48.2.jar',
specs: [
'app/modules/user/tests/e2e/*.feature'
],
getPageTimeout: 30000,
capabilities: {
'browserName': 'chrome',
version: '',
platform: 'ANY'
},
onPrepare: function() {
var width = 1024, height = 800;
browser.get('#/');
browser.driver.manage().window().setSize(width, height);
},
framework: 'cucumber',
cucumberOpts: {
require: [
'tests/e2e/steps/main.step.js'
],
format: 'pretty', // or summary
keepAlive: false
},
onCleanUp: function() {}
};
and my html :
<a data-el="navbar-menu-user-module" href="./#/user">User Module</a>
package.json
{
"name": "myApp",
"version": "1.0.0",
"description": "myApp",
"dependencies": {
},
"devDependencies": {
"chai": "^3.3.0",
"chai-as-promised": "^5.1.0",
"jasmine-core": "~2.3.4",
...
"protractor": "^2.5.1",
"selenium-server": "^2.48.2",
"selenium-standalone": "^4.7.0",
"selenium-webdriver": "^2.48.0",
}
}
The key thing to remember is that CucumberJS and Jasmine are mutually exclusive. You can only use Jasmine's expect's in conjunction with the Jasmine framework. toBe() is a function that is provided by Jasmine's expect, which doesn't exist in your framework. That is why you are receiving the error you described.
Since you are using CucumberJS to structure your test you need to use a separate assertion library, the most popular one being Chai. You'll need to use a function provided by Chai for your assertion. In your case you'll probably want to use the equal() function. Also remember that Protractor's isPresent() function returns a promise, so you'll want to use the eventually chain provided by chai-as-promised. All together, the following assertion:
this.expect(element(by.css('[data-el="' + field + '"]')).isPresent()).toBe(true);
should be changed to:
this.expect(element(by.css('[data-el="' + field + '"]')).isPresent()).to.eventually.equal(true);
You can use our jasmine-expect library. We took out the expectation library from Jasmine and released it as a separate module.
https://www.npmjs.com/package/xolvio-jasmine-expect

Categories