Cucumber, Java8: find usage of step defined by lambda expression - intellij-idea

Currently in our project's tests we switched from using annotated step definitions, e.g.:
public class Steps {
#Given("^Step name$")
void methodName() {
// do sth
}
}
to lambda expressions:
public class Steps implements En {
public Steps() {
Given("^Step name$", () ->
// do sth
);
}
}
When using Intellij Cucumber Java plugin it was easy to find the usage of some step, since it looked for usages of the annotated method (I presume).
Now however, we have to manually search for the regex passed as the argument.
My first question is: is there a neat way to do this with lambda expressions?
Moreover: when using Intellij's tool for version control and commiting files containing definitions of big numbers of steps, the code analysis tool goes on forever (I guess it is because of the constructor having to crank a lot of code).
So the second question is: since there is no possibility of the step library shrinking and step usage search is used very often wouldn't it be a good idea to switch back to Ye Olde Way i.e. using annotated methods?

Find usages for java-8 style step definitions do not yet work. One can vote and follow this request: IDEA-144648.

It is working here while using
IntelliJ IDEA 2018.1.5
'Cucumber for Java' plugin 181.5281.24
pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<version.cucumber>3.0.2</version.cucumber>
<!-- following versions were also checked -->
<!--<version.cucumber>2.4.0</version.cucumber>-->
<!--<version.cucumber>2.3.1</version.cucumber>-->
</properties>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java8</artifactId>
<version>${version.cucumber}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
</dependencies>
userdata.feature
Feature: demo for java8 glue classes
Scenario: user login on home page
Given user is on home page
When user navigate to login page
And user enters credentials to login
Then message displayed login successfully
glue/StepPojo.java
package glue;
import cucumber.api.PendingException;
import cucumber.api.java8.En;
public class StepPojo implements En {
public StepPojo() {
Given("^User is on Home Page$", () -> {
throw new PendingException();
});
When("^User Navigate to LogIn Page$", () -> {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
});
And("^User enters Credentials to LogIn$", () -> {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
});
Then("^Message displayed Login Successfully$", () -> {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
});
}
}
The class StepPojo.java was created by the Cucumber plugin by pressing ALT+ENTER while selecting a step in the feature file.
The feature file was shown before as
after the steps are defined as
[
when you hover with the mouse over a step while pressing down the CTRL key it looks as
when you click on a step while pressing down the CTRL key you jump to the respective method, e.g.
Given("^User is on Home Page$", () -> {
throw new PendingException();
});

Related

How should I run a background task that also updates the UI in an intellij settings plugin

I am adding some changes to an intelij plugin that integrates with vault I have settings page that implements Configurable that has a form for credentials and then a "Test Login" button. On button click I want to spawn an asynchronous background task to test the credentials and then update the UI with either success or failure.
Here is a screenshot of my settings
As far as I can tell the correct way to do this would be to use a background task but that requires a "project" which as far as I can tell you have to get from an AnAction and I don't really see how that would work in this context. Here are a few approaches I've played around with
This still blocks the UI and spits out a warning about the UI being blocked for too long
ApplicationManager.getApplication().executeOnPooledThread(() ->
ApplicationManager.getApplication().invokeLaterOnWriteThread(() -> {
// async work
// repaint
}, ModalityState.stateForComponent(myMainPanel)));
// I don't know how to get the project or if I even should here.
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Login"){
public void run(#NotNull ProgressIndicator progressIndicator) {
// async work
// repaint when done
}});
All of this is happening in my AppSettingsComponent button click addActionListener. Here is my complete source code on github
I had the same problem with the project instance required. But by looking at the Task.Backgroundable constructor you can pass a #Nullable project. So I just pass null and it works well for me.
ProgressManager.getInstance().run(new Task.Backgroundable(null, "Login") {
public void run(#NotNull ProgressIndicator progressIndicator) {
// your stuff
}
});

JavaFX + Kotlin coroutine without android OS, is it possible?

I have a runnable jar that has a UI made with javafx fxml and the class code in kotlin with some database operations done with spring jpa.
Everything works great, except that I would like to not block the main thread while doing the work. Coming from C# I saw that in kotlin you can use coroutine like async await.
import javafx.fxml.FXML
import javafx.scene.control.Button
import kotlinx.coroutines.*
class appGui{
#FXML
private var buttonExecute: Button? = null
#FXML
fun buttonExecuteClick() {
buttonExecute!!.isDisable = true
CoroutineScope(Dispatchers.Main).launch {
withContext(Dispatchers.IO){
work()
}
buttonExecute!!.isDisable = false
}
}
private suspend fun work() {
println("corotine starting...")
delay(5000);
//springMain.applyChanges()
println("corotine finished...")
}
}
So I have added the coroutine call, but I got an exception Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher
Looking at this exception, I found that you have to import the coroutines-android instead of the core, so I change my pom to it
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-android</artifactId>
<version>1.4.2</version>
</dependency>
which cause other exception ClassNotFoundException: android.os.Looper
Now I'm confused, is the coroutine intended to be used in android app? I'm running a jar on windows. Or do I need to go back to runnable task and do things like it was done in swing?
Thank to mipa (comment) for the tip.
just change the pom to import the javafx instead android.
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-javafx</artifactId>
<version>1.4.2</version>
</dependency>
simple and easy.
There is 3 main imports in the doc right now https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md
kotlinx-coroutines-android -- Dispatchers.Main context for Android applications.
kotlinx-coroutines-javafx -- Dispatchers.JavaFx context for JavaFX UI
applications.
kotlinx-coroutines-swing -- Dispatchers.Swing context for Swing UI applications.
I just need to use the right one

Map Plugin shows no service providers

I'm trying to render an empty Map in QML 5.7, in order to draw geolocated polylines. However, no plugins are available to supply the map data:
Map {
anchors.fill:parent
plugin: Plugin {
name: "osm"
Component.onCompleted: console.log('a',availableServiceProviders.length)
}
MapPolyline {
line.color: "#299FE7"; line.width: 3
path: parent.points
}
Timer {
running:true; interval:1000
onTriggered: console.log('b',parent.supportedMapTypes.length)
}
}
The above outputs:
qml: a 0
qml: b 0
Why don't I have any plugins available, and how can I get one to work?
You don't have a default provider because Qt does not enforce the usage of a specific one. Even more now that all of the available ones require a registration (and the acceptance of an agreement/ToS) to use their services.
The list of available plugins can be found here.
Following the links you can read about the specific setup for the usage of each one.
Adding a provider in QML is just a matter of declaring a Plugin type, something along the line of that:
Plugin {
name: <provider_name> // { "here" | "mapbox" | "osm" }
PluginParameter { name: <param_name>; value: <param_value> }
// other parameters
}
The very same task can be carried out in a C++/non-QML project via QGeoServiceProvider class.
Mind that the access to MapQuest changed few months ago, breaking the Open Street Map plugin. You now need credentials to access their service, e.g. read this comment. The relevant patch has been pushed and merged, as stated in the bug report page of last linked comment, and will be available in Qt 5.6.2 (and Qt 5.7.1) patch release.

Alfresco custom action permission

I have done a custom action. I can see the action in documentary library but i canot see it on faceted search result page.
<action id="custom-action" type="javascript" label="actions.custom.action">
<param name="function">onCustomActionlick</param>
</action>
So I went in the aikau-1.0.8.1.jar\META-INF\js\aikau\1.0.8.1\alfresco\renderers\_ActionsMixin.js file.
I see that we do a test to determine if action is allowed in this file :
if (this.filterActions === false || AlfArray.arrayContains(this.allowedActions, action.id))
On firebug i see that my costum action is not in the allowedActions object. My question is why ?
I think that actions wich have not permission are always allowed to all users. Am I right ?
What can i do to allow this action et make it visible on faceted search result page?
Thank you in advance.
You need to write an extension module which is described here: https://forums.alfresco.com/comment/159331#comment-159331.
In the JavaScript code you need to get the widget id of MERGED_ACTIONS and add your customAction to the array of allowdActions and define it in CustomActions.
This is the Aikau code from the link, probably it has been updated in the newer Alfresco version. So you need to extend this within your extension module.
You can probably just use org\alfresco\share\pages\faceted-search as your <sourcePackageRoot> in the module.
widgets: [{
id: "MERGED_ACTIONS",
name: "alfresco/renderers/Actions",
config: {
filterActions: true,
mergeActions: true,
allowedActions: ["folder-manage-rules", "folder-download", "folder-view-details", "CUSTOM3"],
customActions: [{
id: "CUSTOM3",
label: "Custom Action 3",
icon: "document-delete",
index: "10",
publishTopic: "DELETE_ACTION_TOPIC",
type: "javascript"
}],
widgetsForActions: [{
name: "alfresco/renderers/actions/ManageAspects"
}]
}
}]
The Document Library (at least up until Alfresco Share 5.1) is built with YUI, whereas the search page is built using Aikau. At the time of writing there is not yet parity of action handling between the search page and the Document Library, and the process of adding actions is very different.
In order to get your custom action to display in the faceted search page you'll need to do a couple of things:
Extend the search page to update the configuration for the "alfresco/search/AlfSearchResult" (it has the id "FCTSRCH_SEARCH_RESULT") to add your custom actions to the "additionalDocumentAndFolderActions" array (see http://dev.alfresco.com/resource/docs/aikau-jsdoc/AlfSearchResult.html)
Your custom action will publish a topic, so you need to create a new service to subscribe to that topic to perform the action. You will need to further extend the faceted search page so that your service is included on the page.
I'm paraphrasing from our latest blog the method we've used for this.
Our use case was we had existing actions in the document library view we didn't want to have to recreate, with standard configuration xml.
The first step is to create a Share Extension Module to add a Javascript controller in web-extensions/site-data/extensions/example.xml:
<extension>
<modules>
<module>
<id>Example Service</id>
<version>1.0</version>
<auto-deploy>true</auto-deploy>
<customizations>
<customization>
<targetPackageRoot>org.alfresco.share.pages.faceted-search</targetPackageRoot>
<sourcePackageRoot>com.parashift.example</sourcePackageRoot>
</customization>
</customizations>
</module>
</modules>
</extension>
This will load some extra javascript, allowing you to adjust the widget config.
Create a file in web-extension/site-webscripts/com/parashift/example/faceted-search.get.js (or whatever package name you've used in sourcePackageRoot), add in a file called faceted-search.get.js with the following contents:
var searchResultPage = widgetUtils.findObject(model.jsonModel.widgets, "id", "FCTSRCH_SEARCH_RESULT");
if(searchResultPage != null) {
searchResultPage.config = {
enableContextMenu : false,
mergeActions : true,
additionalDocumentAndFolderActions : ["example-action"]
}
}
model.jsonModel.widgets.push({
id: "EXAMPLE_LISTENER",
name: "parashift/action/example"
});
This will:
Add example-action to the list of actions in the search results. This should already be a configured action in some share-config.xml file.
Add a new listener widget for you to listen to when the action button is clicked.
Add a file for your listener widget: META-INF/parashift/action/example.js
define(["dojo/_base/declare",
"dijit/_WidgetBase",
"alfresco/core/Core"
],
function(declare, _Widget, Core) {
return declare([_Widget, Core], {
postCreate: function () {
this.alfSubscribe("ALF_SINGLE_DOCUMENT_ACTION_REQUEST", lang.hitch(this, this._onPayloadReceive));
},
_onPayloadReceive: function (payload) {
if(payload.action.id == "example-action") {
this.alfLog("log", "Received action, handling accordingly");
.......
}
}
});
});
This code will listen for ALF_SINGLE_DOCUMENT_ACTION_REQUEST and execute the _onPayloadReceive function. In this function we filter to the example-action and execute any custom code.
The payload variable will include document and action objects. Using Debug Logging you can see what their shape is.
This is roughly equivalent to the old YUI method:
YAHOO.Bubbling.fire("registerAction", {
actionName: "onExampleAction",
fn: function(file) {
console.log("Received action, handling accordingly");
....
}
});

Handle redirects and implicit at assertions

The website I want to test has a landing page which asks you to chose a language. You can skip this question by adding an extra parameter in the url. I want to test this behaviour with Geb and Spock as testing framework.
So I have the landing page with language selection:
class LanguageSelectionPage extends Page {
static url = "http://localhost:8080/registration/"
static at = { $("form#languageForm") }
}
The second page where it redirects to:
class InsertCardReaderPage extends Page {
static at = { welcomeTitle1 }
static content = {
welcomeTitle1(wait: true, cache: false) { $("#eidWelcomeTitle1") }
welcomeTitle2(wait: true, cache: false) { $("#eidWelcomeTitle2") }
}
}
(I've removed some methods from the pasted code)
So this is my test:
given:
to LanguageSelectionPage, "09";
expect:
at InsertCardReaderPage;
The "09" is an extra parameter in the url, when this one is available you will be immediatly redirected by the server (http redirect, so the page does change) to the InsertCardReaderPage. Now, my problem is that the to statement performs an implicit assertion on the at closure. This one fails because you have been redirected away from the page already.
Is there a way to conditionally disable this implicit assertion in this case? Or any other proposal how to setup the pages? I'm pretty new to Geband can't find any documentation that seems to help me in this case.
Use via instead of to
given:
via LanguageSelectionPage, "09";
expect:
at InsertCardReaderPage;
Geb Manual