Unable to execute login feature on chrome browser using Behat + Drupal 8 - selenium

Just using Behat with drupal 8 and facing problem with login behat script to run. Below are the my code :
behat.yml
default:
suites:
default:
contexts:
- FeatureContext
- Drupal\DrupalExtension\Context\DrupalContext
- Drupal\DrupalExtension\Context\MinkContext
- Drupal\DrupalExtension\Context\MessageContext
- Drupal\DrupalExtension\Context\DrushContext
extensions:
Behat\MinkExtension:
goutte: ~
base_url: http://localhost:8080/drupal-dev/web
javascript_session: selenium2
browser_name: 'chrome'
selenium2: ~
Drupal\DrupalExtension:
blackbox: ~
api_driver: drupal
drupal:
drupal_root: web/
region_map:
navigation: ".navbar-header"
navigation_collapsible: "#navbar-collapse"
header: ".region-header"
highlighted: ".highlighted"
help: ".region-help"
content: ".region-content"
sidebar_first: ".region-sidebar-first"
sidebar_second: ".region-sidebar-second"
footer: ".footer"
login.feature
#javascript
Feature: login check
Scenario: user login is working
Given I am on "/user"
When I fill in "john" for "edit-name"
And I fill in "john for "edit-pass"
And I press "Log in"
Then I should see "Add content"
While i execute the vendor\bin\behat then it will open the chrome browser and redirect to user login page but failed from second step. See below error message :
#javascript
Feature: login check
Scenario: user login is working # features\bootstrap\login.feature:4
Given I am on "/user" # Drupal\DrupalExtension\Context\MinkContext::visit()
When I fill in "john" for "edit-name" # Drupal\DrupalExtension\Context\MinkContext::fillField()
Form field with id|name|label|value|placeholder "edit-name" not found. (Behat\Mink\Exception\ElementNotFoundException)
And I fill in "john" for "edit-pass" # Drupal\DrupalExtension\Context\MinkContext::fillField()
And I press "Log in" # Drupal\DrupalExtension\Context\MinkContext::pressButton()
Then I should see "Add content" # Drupal\DrupalExtension\Context\MinkContext::assertPageContainsText()
--- Failed scenarios:
features\bootstrap\login.feature:4
1 scenario (1 failed)
5 steps (1 passed, 1 failed, 3 skipped)
0m15.30s (17.82Mb)
And same feature file working fine and all steps passed if i replaced from #javasript to #api.

And same feature file working fine and all steps passed if i replaced from #javasript to #api.
A common problem with Selenium is that the automated browser takes more time to render the page than the headless browser (in your case #api, #goutte in Symfony), so Behat returns an error when it tries to find elements in a DOM that is not yet rendered.
The solution is to add a wait() before trying to fill the field. You can even query the driver type in your context, and trigger the wait only if the type is Selenium.
You need to create your own Context file to add your methods.
Create "MyFeatureContext" (or whatever), make it inherit the MinkContext class, add it to the contexts in your behat.yml file (instead of the MinkContext since you inherit from it anyway), and add the following methods :
public function wait(int $ms)
{
if ($this->getDriver() instanceof Selenium2Driver) {
return $this->getSession()->wait($ms);
}
}
/**
* Fills in form field with specified id|name|label|value
* Example: When I fill in "username" with: "bwayne"
* Example: And I fill in "bwayne" for "username"
*
* #When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/
* #When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with:$/
* #When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/
*/
public function fillField($field, $value)
{
$this->wait(1000); # 1000ms or 1sec
parent::fillField($field, $value);
}
Note that the annotations are copied from MinkContext::fillField().

Thanks Olivier! Just resolved the issue via changing selenium server version from 3.1 to 2.53

Related

Handling Basic Authentication in Karate UI scenario

I have just started implementing karate UI (v0.9.5). Have already implemented api testing using karate and it works perfectly.
Following the HTTP basic auth strategy on this page - https://github.com/intuit/karate#http-basic-authentication-example the basic auth handling works for api tests. I set the HTTP headers once and run all api tests.
Now for the UI testing, the URL that I open brings up the basic auth pop-up as shown below:
So I thought that I could use the same strategy that I used for api tests to handle this. In the background section of my feature file, i call the feature file that does the authentication and sets headers as below:
The called feature file to set headers (admin-headers.feature). This feature file gets the token after admin user login is performed via karate-config.js. Then assigns the token along with the Base64 encoded basic auth to the headers calling headers.js. The Base64 user and password are being input as maven arguments and read via karate-config variables.
(/admin-headers.feature)
Feature: karate-config.js will perform one time login for admin and
set the session token for all subsequent requests
Background:
* def session = adminAuthInfo.authSession
* def basic_auth = call read('classpath:basic-auth.js') { username: '#(basicAuthUser)', password: '#(basicAuthPassword)' }
* configure headers = read('classpath:headers.js')
Scenario: One-time login for user and set the
session token in request header
The js code for returning Auth and Cookie to above feature file (/headers.js).
function() {
var session = karate.get('session');
var basic_auth = karate.get('basic_auth');
if(session){
return {
Authorization: basic_auth,
Cookie: "SESSION=" + session
};
} else {
return {};
}
}
My UI test feature file (/ui-test.feature):
Feature: Login test
Background:
# Authorise via api
* callonce read('classpath:common/headers/admin-headers.feature')
* configure driver = { type: 'chrome' }
Scenario: Test login
Given driver 'https://test.internal.mysite.com/names'
Running the above feature file still shows the auth pop-up.
I then tried to set the cookies while I am initialising the driver (which I think is probably not the right way?) as below:
Feature: Login test
Background:
# Authorise via api
* def login = callonce read('classpath:common/headers/admin-headers.feature')
* def uiCookie = { name: 'SESSION', value: '#(login.userAuthInfo.authSession)', domain: 'test.internal.mysite.com' }
* configure driver = { type: 'chrome', cookie: '#(uiCookie)' }
Scenario: Test login
Given driver 'https://test.internal.mysite.com/names'
The above also does not work. What is it that I am doing wrong here? the pop-up keeps coming up because the cookie is not set when the driver is initialised and then opens the specified url?
Help is much appreciated.
I think you raised a very good feature request, that configure driver should take cookies also, so that you can navigate to the page and set cookies in one-shot, and I opened a feature request: https://github.com/intuit/karate/issues/1053
So try this sequence, refer docs for cookie(): https://github.com/intuit/karate/tree/master/karate-core#cookieset
* driver 'about:blank'
* cookie(uiCookie)
* driver 'https://test.internal.mysite.com/names'
And now it should work !
Feature: Windows Authentication feature
Background:
* configure driver = { type: 'chrome' }
Scenario: Windows Authentication Valid Login test case
Given driver 'http://the-internet.herokuapp.com/basic_auth'
And delay(3000)
And screenshot()
* robot {}
* robot.input('admin' + Key.TAB)
* robot.input('admin')
* robot.click('Sign in')
And delay(3000)
And screenshot()
works fine with chrome, edge

How to login with HTTP basic authentication to ACCESS the website- Test Cafe with Gherkin and cucumber

All links, project name and company name has been modified and are not original.
We have a basic HTTP authentication popup that appears when we are accessing out test/staging environments.
I am wondering, how can I enter the login information into the popup login window or send an api request in advance to save the cookie?
Because otherwise, I can't run the automation on our test environment. When the test access the page, I see a white website showing "unauthorized" in small letters.
This is what the login prompt looks like when accessing the Test/Staging env
We are using following plugin: https://www.npmjs.com/package/gherkin-testcafe
What I am asking is very similar to this question: Testing http basic authentication with Cucumber and RSpec in Rails 3.2.3
I have tried adding a role and using TestCafe http-authentication.html
Here is what I have tested so far:
TestCafe trying to use role:
const { Role } = require('testcafe');
const regularAccUser = Role('https://website/login', async t => {
await t
.typeText('#login', 'username')
.typeText('#password', 'password')
.click('#sign-in');
});
Given("I am open Dealer's login page", async t => {
await t
.useRole(regularAccUser)
.navigateTo(`${url}/login`);
});
That gives me:
ERROR CompositeParserException: Parser errors:
(7:3): expected: #EOF, #Comment, #BackgroundLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Empty, got 'Correct action happens when user provide either wrong or correct login information'
at Function.Errors.CompositeParserException.create (/Users/dennis/Projects/src/company/project/node_modules/gherkin/lib/gherkin/errors.js:27:13)
at Parser.parse (/Users/dennis/Projects/src/company/project/node_modules/gherkin/lib/gherkin/parser.js:72:45)
at specFiles.forEach.specFile (/Users/dennis/Projects/src/company/project/node_modules/gherkin-testcafe/src/compiler.js:43:33)
at Array.forEach (<anonymous>)
at GherkinTestcafeCompiler.getTests (/Users/dennis/Projects/src/company/project/node_modules/gherkin-testcafe/src/compiler.js:42:20)
at getTests (/Users/dennis/Projects/src/company/project/node_modules/testcafe/src/runner/bootstrapper.js:79:47)
at Generator.next (<anonymous>)
at step (/Users/dennis/Projects/src/company/project/node_modules/babel-runtime/helpers/asyncToGenerator.js:17:30)
at /Users/dennis/Projects/src/company/project/node_modules/babel-runtime/helpers/asyncToGenerator.js:28:13
If I try using:
import {Role} from 'testcafe'
I get:
tests/ui/stepDefinitions/login/login.js:1
(function (exports, require, module, __filename, __dirname) { import { Role } from 'testcafe';
^
SyntaxError: Unexpected token {
Using TestCafe's HTTP Authentication:
Feature: Login with correct and wrong info functionallity
.page('website/login')
.httpAuth({
username: 'username',
password: 'password',
})
Correct action happens when user provide either wrong or correct login information
#loginFunc
Scenario: Should NOT be able to login without filling in any credentials
Given I am open Dealer's login page
When I am login in with "empty" and "empty"
Then I should NOT be able to press the login button
I am getting following:
Feature: Login with correct and wrong info functionallity
✖ Scenario: Should NOT be able to login without filling in any credentials
1) Cannot obtain information about the node because the specified selector does not match any node in the DOM tree.
  | Selector('button[data-qa="qa-login-submit-button"]')
 > | Selector('button[data-qa="qa-login-submit-button"]')
Browser: Chrome 72.0.3626 / Mac OS X 10.14.3
32 | }
33 |});
34 |
35 |Then("I should NOT be able to press the login button", async t => {
36 | await t
> 37 | .expect(submitButton.hasAttribute('disabled')).ok()
38 | .expect(h1.exists).eql(true);
39 |});
```
It is basically showing me a white screen and saying: "**unauthorized**" in small letters.
You don't need any post/get requests with the Basic HTTP. Instead, you can log in using the Role mechanism:
When you switch to a role for the first time, TestCafe internally creates a branch of this role for this particular test run. All cookies set by your further actions will be appended to this branch. This branch will be used whenever you switch back to this role from the same test run.

Karate API : Passing variables to other feature file is not working

I am calling login feature file from other feature file from where I am passing url, username and password but it is not working for me. I am not using Background key here and i do not want also.
#CallAnotherFeature
Feature: Call Login Feature
Scenario: Calling Login Test
* def config = { endPointURL: 'https://qa1.testurl.com/login',username: 'user123', password: 'password123' }
* def result= call read('Login.feature') config
* print result.response
* print 'Sign In-'+signIn
* print 'Sign In Reponse-'+signIn.response
Feature: Login Feature
Scenario: Test Login for different users
* print 'Starting Test','#(endPointURL)'
Given url '#(endPointURL)'
* print 'user name','#(username)'
* print 'Password ','#(password)'
#And form field username = '#(username)'
#And form field password = '#(password)'
And request { username: '#(username)', password: '#(password)'}
When method post
Then status 200
* print response
* match response.loginSuccess == true
In Login.feature I tried to pass username and password as form data also even though these did not work. Could someone tell me what mistake I am making here.
I am using latest karate version 0.9.0
I see a few issues in your scripts,
1. Call Login Feature
1.1) I don't see signIn variable initialized anywhere in this feature nor from your login feature but you are trying to print it.
1.2) = Should be placed properly ;)
* def result = call read('Login.feature') config
2. Login Feature
2.1) I think you misunderstood the concept of embedded expressions. only for templating it into a JSON you may use it. but for calling it you can simply use the variable name.
eg.
Given url endPointURL
And form field username = username
And request { username: '#(username)', password: '#(password)'}
NOT
Given url '#(endPointURL)'
And form field username = '#(username)'
I will be more clear for you if you read the karate documentation from here -> karate Doc and refer karate Demos

How to customize screen resolution with saucelabs (selenium, behat3.0 mink) capabilities

This is my behat.yml file :
firefox:
suites:
firefox:
contexts:
-FeatureContext
extensions:
Behat\MinkExtension:
javascript_session: selenium2
base_url: https://example.com
selenium2:
wd_host: username:pwd#ondemand.saucelabs.com/wd/hub
browser: firefox
capabilities: {'platform':'OS X 10.10', 'browser':'firefox', 'version':'42.0', "screen-resolution":"1280x1024"}
Which is giving error "
[Symfony\Component\Config\Definition\Exception\InvalidConfigurationException]
Unrecognized option "screen-resolution" under "testwork.mink.sessions.selenium2.selenium2.capabilities"
I have tried this
https://groups.google.com/forum/#!topic/behat/kApbLIiAkOg, but I am also getting exactly same error.
If I configure SauceLabsDriver then only I will get all (https://github.com/Behat/MinkExtension/blob/master/doc/index.rst#sessions) - special flavor of the Selenium2Driver
The above document is suggesting modify your behat.yml profile:
default:
extensions:
Behat\MinkExtension:
sessions:
my_session:
sauce_labs: ~
But no idea how to implementing this. Any idea? How to change behat.yml file with saucelabs to use all those customization parameters.
Although this is for behat 2, could you please try Resizing browser window size with behat2.
class FeatureContext extends MinkContext
{
/**
* #BeforeScenario
*/
public function resizeWindow()
{
$this->getSession()->resizeWindow(1440, 900, 'current');
}
}
Using resize with #BeforeScenario hook can be not optimal.
Another way is to use a scenario step
/**
* #Given /^I set browser window size to "([^"]*)" x "([^"]*)"$/
*/
public function iSetBrowserWindowSizeToX($width, $height) {
$this->getSession()->resizeWindow((int)$width, (int)$height, 'current');
}
And if needed to maximize it back
/**
* #Given /^I maximize browser window size$/
*/
public function iSetBrowserWindowSizeToX($width, $height) {
$this->getSession()->resizeWindow((int)$width, (int)$height, 'current');
}

Behat mink test multiple pages

I'm new to behat.
what I want to do is test a bunch of pages if they exist or not.
this is my example:
Scenario: Page "contact"
Given I am on "/contact"
Then I should see "contact"
in the footer you see a link called contact
so if there is some php error the it quits and I don't see the footer so behat fails.
but can I select multiple names like this:
Given I am on [/, /contact, /about-me] etc
You have many options but I'm just giving you two for now so for more, you can do your own research:
This is what many people would do:
Feature file:
Scenario: Checking pages and their content
Given I am on "/"
Then I should see "welcome home"
When I am on "/contact"
Then I should see "welcome to contact page"
When I am on "/about-me"
Then I should see "welcome to about me page"
When I am on "/whatever"
Then I should see "welcome to whatever page"
......
......
This is another option which verifies physical existence of the files:
Feature file:
Scenario: Checking pages and but not their content
Given I am on "/"
Then I should see "welcome home"
And the files below must exist in my project folder:
| file |
| /path/to/my/project/files/contact.tml |
| /path/to/my/project/files/about-me.tml |
| /path/to/my/project/files/whatever.tml |
In your FeatureContext file:
class FeatureContext extends MinkContext
{
/**
* #When /^the files below must exist in my project folder:$/
*/
public function theFilesBelowMustExistInMyProjectFoder(TableNode $table)
{
foreach ($table->getHash() as $file) {
if (file_exists($file) !== true) {
throw new Exception(sprintf('File "%s" not found', $file));
}
}
}
}