Behat3 redirect within custom step - behat

I am trying to redirect to a url from within a custom step. That was doable on behat 2.x via:
return new Step\Then("my/url/page");
Unfortunately you can not call external steps from within your custom steps in behat 3.0!
How can I perform a redirect in my custom step?

Step chaining was removed from Behat 3 as it's considered a bad practice.
As explained by everzet:
Use the code tools like abstraction, compositions and inheritance together with a simple method calls :) Chained steps was an anti-pattern. It was hard to debug and maintain them. And in most cases, what could be done with 2-3 chained steps could be done with 1-2 method calls.
And here:
Because as soon as you start doing that you:
Can not refactor your contexts
Can not clearly see what the code actually does
Can not easily reword your features
And if you think that using inline steps is easier:
return array(
new Step\Given(‘I am on the homepage’),
new Step\When(‘I follow ”Login”’),
new Step\When(‘I fill ”Username” with “‘ . $username . '"’),
new Step\When(‘I fill ”Password” with “‘ . $password . '"’),
new Step\When(‘I click “Login"’),
);
It is not:
$session = $this->getSession();
$page = $session->getPage();
$session->visit($this->locateUrl(‘/‘));
$page->clickLink(‘Login’);
$page->fillField(‘Username’, $username);
$page->fillField(‘Password’, $password);
$page->pressButton(‘Login’);
Also see https://github.com/Behat/Behat/issues/546
There's an extension for Behat 3 with step chaining implementation, but it is broken and it's unlikely it'll be ever officially supported: https://github.com/Behat/ChainedStepsExtension
Solution
To solve your problem you can extend the Behat\MinkExtension\Context\RawMinkContext and use it to access the session:
$this->getSession()->visitPath('my/url/page');
You could also look at the page object extension.

Related

API call inside a JavaScript function present in a feature file

I tried my best but could not find information on calling an API inside the Javascript function when dealing with automation in Karate. Now, I might get suggestions to call the API outside the function and then do operations inside the function. However, my use case is such that I have to call the API inside the function only. Is there a way to do this?
One approach is to create a Java file and then write the code in java. However, I specifically want to know if there is any way to call an API inside a JS function in a FEATURE FILE itself.
First, these kinds of "clever" tests are not recommended, please read this to understand why: https://stackoverflow.com/a/54126724/143475
If you still want to do this, read on.
First - most of the time, this kind of need can be achieved by doing a call to a second feature file:
* if (condition) karate.call('first.feature')
Finally, this is an experimental and un-documented feature in Karate, but there is a JS API to perform HTTP requests:
* eval
"""
var http = karate.http('https://httpbin.org');
http.path('anything');
var response = http.get().body;
karate.log('response:', response);
"""
It is a "fluent API" so you can do everything in one-line:
var body = karate.http('https://httpbin.org/get').get().body;
If you need details, read the source-code of the HttpRequestBuilder and Response classes in the Karate project.

Get Karate request data using another util service

One of the param for my API is security related and linked to the environment on which the test would run , essentially it will be dynamic.
Since this is security related, I have an internal rest API that provides this data.
I want to understand what is the effective way of getting this data in Karate feature?
I have tried two different ways:
1. Defined a java util and invoke the java type and def variable for holding the data
Defined a Util method as part of karate-config.js
In karate-config.js
function getSomeData(someValue) {
return Java.type('xyz.abc.util.MyUtil');
}
In the feature file
defined a JS
* def dataFromJS = read('classpath:com/xyz/util/js_that_invokes_rest.js')
I want to understand if there is a pattern of how this should be done or if there is an explicit support in Karate for doing this?
I have an internal rest API
Well. Did you just forget that Karate is all about making REST requests !? :)
Please create a re-usable feature, make that REST call, define the variables that you need and now you can call it from other features.
Please refer to the documentation: https://github.com/intuit/karate#calling-other-feature-files

LibGit2Sharp: how to Task-Async

Hi I have begun to use the package for some very simple tasks, mainly cloning a Git-Wiki repo and subsequently pulling the changes from the server when needed.
Now I can not see any methods corresponding to the Task-Async (TAP) pattern. Also in the documentation I could not find anything concerning.
Could you please give me some direction how to wrap the LibGit2Sharp methods into a TAP construct? Link to documentation (if I missed something) or just telling me which callback to hook up to the TaskCompletionSource object would be nice.
It also doesn't really help that I am a newbie with Git, and normally I only do basic branching, merging, pushing with it.
For cloning I use:
Repository.Clone(#"https://MyName#bitbucket.org/MyRepo/MyProject.git/wiki", "repo");
For pulling I use:
using (var repo = new Repository("repo"))
{
// Credential information to fetch
LibGit2Sharp.PullOptions options = new LibGit2Sharp.PullOptions();
options.FetchOptions = new FetchOptions();
var signature = new LibGit2Sharp.Signature(new Identity("myname", "mymail#google.com"), DateTimeOffset.Now);
Commands.Pull(repo, signature, options);
}
Thanks in advance
First of all, you should never try sync over async or async over sync. See this article.
If you're thinking of using Task.Run, don't. That will just trade on thread pool thread for another with the added cost of 2 context switches.
But you should reconsider your whole approach to this. You don't need to clone the repository just to get the contents of a file. Each version of a file, has a unique URL. You can even get the URL of a file for a specific branch.

How can I set different driver for one step in behat?

In default I run tests with goutte. How can I set different driver for one step? For example to take screenshot after failed step I need selenium driver. And I don't know which step will fail.
Have a look at the Mink docs, specifically the managing sessions chapter to learn how to change the default driver. If you're not familiar with Behat hooks it's also good to catch up with Hooking into the Test Process docs.
Here's an example of how you could access mink and change the default session. Once this method is executed, all the following operations on the session object will be perform through the selected driver.
use Behat\Behat\Hook\Scope\BeforeStepScope;
use Behat\Behat\Hook\Scope\AfterStepScope;
class MyContext extends RawMinkContext
{
/**
* #BeforeStep
*/
public function before(BeforeStepScope $scope)
{
// note that this will be called before EVERY step
// add logic here if you want to perform it before SOME steps
// You can't really know if your step will fail though ;)
$mink = $this->getMink();
$mink->setDefaultSessionName('selenium');
}
public function after(AfterStepScope $scope)
{
// here you can inspect $scope to see if your step failed
}
}
This is not a complete solution, but should point you into the right direction if you really want to pursue it.
However, I strongly discourage you from doing so.
If your step failed it was already executed. To make a screenshot you would need to execute the step again with a different driver. The state of the app would be most likely different at this point. You'd also need to fight with differences between the drivers, try to share the cookie etc. It's just not worth the effort.
Instead, simply dump an html. You can always display it in a browser.

Intern:Leadfoot - testing drag-n-drop

I have a webapp that uses dojo widgets and drag-n-drop functionalities and I'm using Intern in order to test it. Now I want to test the drag-n-drop mechanism, and for this I hoped to use the Leadfoot's helper, DragAndDrop.js
As seen in the script's example, here my code:
return new DragAndDrop(remote)
.findByXpath(source)
.dragFrom()
.end()
.findByXpath(target)
.dragTo()
I have the return statement because this code is part of a promise chain.
However, it seems to be not working and I do not get any kind of errors|exceptions, neither in the browser neither in selenium neither on intern side. Honestly, I have no idea where to start from.
Any suggestion? May I provide further information?
Have you tried
return remote.findByXpath(target)
.then(function(targetNode){
return remote.findByXpath(source)
.moveMouseTo(1,1)
.pressMouseButton().sleep(500)
.moveMouseTo(targetNode).sleep(500)
.releaseMouseButton();
});
Note: sleep isn't necessary, I put it here so that you can see clearer the actions