We use Selenium WebDriver and Java for our framework. We need to add waitForAngular() method. At first I found source code of Protractor:
var waitForAngular = function(rootSelector, callback) {
var el = document.querySelector(rootSelector);
try {
if (window.getAngularTestability) {
window.getAngularTestability(el).whenStable(callback);
return;
}
if (!window.angular) {
throw new Error('window.angular is undefined. This could be either ' +
'because this is a non-angular page or because your test involves ' +
'client-side navigation, which can interfere with Protractor\'s ' +
'bootstrapping. See http://git.io/v4gXM for details');
}
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
if (!angular.element(el).injector()) {
throw new Error('root element (' + rootSelector + ') has no injector.' +
' this may mean it is not inside ng-app.');
}
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (err) {
callback(err.message);
}
};
var rootSelector = arguments[0];
var callback = arguments[1];
waitForAngular(rootSelector, callback);
I injected it in my framework, using JavaScriptExecutor driver:
public void waitForAngular() {
this.jsExecutor.executeAsyncScript(
waitForAngularJSScript, rootElement);
}
As rootElement I tried to use "body", "[ng-app]". But it doesn't work. I have exception
Error: ng:test
Testability Not Found
no injector found for element argument to getTestability
Link to description of exception
in the:
angular.getTestability(el).whenStable(callback);
I'm not strong in Angular, so maybe you could helpe me where I can find resolving.
Related
i have implemented a webview in my android app and trying to highlight or to mark element when user click in the layout.
The webview is initialized as following :
myWebView.getSettings().setJavaScriptEnabled(true);
//myWebView.getSettings().setGeolocationEnabled(true);
//myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
myWebView.getSettings().setBuiltInZoomControls(true);
myWebView.getSettings().setDomStorageEnabled(true);
myWebView.setWebViewClient(new WebViewController());
Trying to mark the element which is clicked by user for example like in this screenshot :
Selection with dot
I'm getting all the page divs via jsoup :
doc = Jsoup.connect(url).get();
final Elements alldivs = doc.select("div");
ArrayList<String> list = new ArrayList<String>();
for (org.jsoup.nodes.Element e : alldivs) {
if (!e.id().equals(""))
list.add(e.id());
}
But how to mark the selection as the photo above, and after that select marked content from div id.
How can make some thing like this ?
I'm using this javascript into webview to hightlight the selection but how to get the clicked element programmatically like : id of selected div or other values
public class MyWebViewClient extends WebViewClient {
#Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript: "
+ "Object.prototype.each = function (fn, bind) {\n" +
" console.log(bind);\n" +
" for (var i = 0; i < this.length; i++) {\n" +
" if (i in this) {\n" +
" fn.call(bind, this[i], i, this);\n" +
" }\n" +
" }\n" +
" };\n" +
"\n" +
" var _addListener = document.addEventListener || document.attachEvent,\n" +
" _eventClick = window.addEventListener ? 'click' : 'onclick';\n" +
"\n" +
" var elements = document.getElementsByTagName(\"div\");\n" +
"\n" +
" elements.each(function (el) {\n" +
" _addListener.call(el, _eventClick, function () {\n" +
// todo process the clicked div element
" el.style.cssText = \"border-color: black;border-style: dashed;\"\n" +
" }, false);\n" +
" })");
}
}
If I understand correctly, you want to get some information from the HTML component into the native side.
According to this answer, it is not possible to pass arbitrary objects to Java, but at least you can pass the HTML code of the clicked node and then parse it natively.
This code based on yours does exactly that.
MainActivity.java: I guess this is pretty self-explanatory. The only thing I did different from you is to get the Javascript code from a separate file, so it's easier to maintain.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WebView myWebView = findViewById(R.id.webView);
final WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
myWebView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
final String injectedJs = "javascript:(function(){" + injectedJs() + "})()";
myWebView.loadUrl(injectedJs);
}
});
myWebView.addJavascriptInterface(
new Object() {
#JavascriptInterface
public void onClick(String param) {
Toast.makeText(MainActivity.this, param, Toast.LENGTH_LONG).show();
}
},
"appHost"
);
myWebView.loadUrl("https://google.com");
}
// Javascript code to inject on the Web page
private String injectedJs() {
BufferedReader stream = null;
StringBuilder jsBuilder = new StringBuilder();
try {
stream = new BufferedReader(new InputStreamReader(getAssets().open("js.js")));
String line;
while ((line = stream.readLine()) != null) {
jsBuilder.append(line.trim());
}
return jsBuilder.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "";
}
}
js.js: The base of this part is your code. Keep in mind that since injectedJs() removes all line markers, every statement needs to finish, including comments, hence the /*...*/ instead of //
/* Keep track of the last clicked element so we can un-highlight it */
var lastSelectedItem = null;
var showHighlighted = function(/* HTML element */view, /*boolean */highlighted) {
if (view) {
view.style.cssText = highlighted? 'border-color: black;border-style: dashed;' : '';
}
};
/* This new method, _addEventListener and _eventClick are the same as yours */
Object.prototype.each = function (fn, bind) {
for (var i = 0; i < this.length; i++) {
if (i in this) {
fn.call(bind, this[i], i, this);
}
}
};
var _addListener = document.addEventListener || document.attachEvent,
_eventClick = window.addEventListener ? 'click' : 'onclick';
/* I changed the element selection criteria, but you can change it back easily.
I am adding event listeners all the leaf elements in the DOM. */
var elements = document.body.getElementsByTagName('*');
elements.each(function (el) {
if (el.children.length == 0) {
_addListener.call(el, _eventClick, function () {
/* First, deal with the previously selected item*/
showHighlighted(lastSelectedItem, false);
if (lastSelectedItem !== null) {
appHost.onClick(lastSelectedItem.outerHTML);
}
/* Update the selected item reference */
lastSelectedItem = el;
/* Finally, deal with the previously selected item*/
showHighlighted(lastSelectedItem, true);
appHost.onClick(el.outerHTML);
}, false);
}
});
consider the web view as a view of a web page. You need to configure the element inside that web view to send a request that would fire an intent in your android application, which is possible, but it would not work for multiple users unless you know the user in that web view and authenticate the users... the point is , it is very complicated if you want to send that request from web to the logical part of your app. Even if you can do it, it is not optimal and i discourage it.
On the other hand, what you can do if you insist on using web views is to complete the rest of your logical operations on the web view. Don't go back from the web view to the app java logic.
Normally web views are used to show something rather than to make actions on the app. (the action might be used on the same web view)
I hope you do get , I've tried to explain as much as possible.
First, I want to say thanks to everyone that took their time to help me figure this out because I was searching for more than a week for a solution to my problem. Here it is:
My goal is to start a custom workflow in Alfresco Community 5.2 and to set some custom properties in the first task trough a web script using only the Public Java API. My class is extending AbstractWebScript. Currently I have success with starting the workflow and setting properties like bpm:workflowDescription, but I'm not able to set my custom properties in the tasks.
Here is the code:
public class StartWorkflow extends AbstractWebScript {
/**
* The Alfresco Service Registry that gives access to all public content services in Alfresco.
*/
private ServiceRegistry serviceRegistry;
public void setServiceRegistry(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
#Override
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
// Create JSON object for the response
JSONObject obj = new JSONObject();
try {
// Check if parameter defName is present in the request
String wfDefFromReq = req.getParameter("defName");
if (wfDefFromReq == null) {
obj.put("resultCode", "1 (Error)");
obj.put("errorMessage", "Parameter defName not found.");
return;
}
// Get the WFL Service
WorkflowService workflowService = serviceRegistry.getWorkflowService();
// Build WFL Definition name
String wfDefName = "activiti$" + wfDefFromReq;
// Get WorkflowDefinition object
WorkflowDefinition wfDef = workflowService.getDefinitionByName(wfDefName);
// Check if such WorkflowDefinition exists
if (wfDef == null) {
obj.put("resultCode", "1 (Error)");
obj.put("errorMessage", "No workflow definition found for defName = " + wfDefName);
return;
}
// Get parameters from the request
Content reqContent = req.getContent();
if (reqContent == null) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Missing request body.");
}
String content;
content = reqContent.getContent();
if (content.isEmpty()) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Content is empty");
}
JSONTokener jsonTokener = new JSONTokener(content);
JSONObject json = new JSONObject(jsonTokener);
// Set the workflow description
Map<QName, Serializable> params = new HashMap();
params.put(WorkflowModel.PROP_WORKFLOW_DESCRIPTION, "Workflow started from JAVA API");
// Start the workflow
WorkflowPath wfPath = workflowService.startWorkflow(wfDef.getId(), params);
// Get params from the POST request
Map<QName, Serializable> reqParams = new HashMap();
Iterator<String> i = json.keys();
while (i.hasNext()) {
String paramName = i.next();
QName qName = QName.createQName(paramName);
String value = json.getString(qName.getLocalName());
reqParams.put(qName, value);
}
// Try to update the task properties
// Get the next active task which contains the properties to update
WorkflowTask wfTask = workflowService.getTasksForWorkflowPath(wfPath.getId()).get(0);
// Update properties
WorkflowTask updatedTask = workflowService.updateTask(wfTask.getId(), reqParams, null, null);
obj.put("resultCode", "0 (Success)");
obj.put("workflowId", wfPath.getId());
} catch (JSONException e) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
e.getLocalizedMessage());
} catch (IOException ioe) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
"Error when parsing the request.",
ioe);
} finally {
// build a JSON string and send it back
String jsonString = obj.toString();
res.getWriter().write(jsonString);
}
}
}
Here is how I call the webscript:
curl -v -uadmin:admin -X POST -d #postParams.json localhost:8080/alfresco/s/workflow/startJava?defName=nameOfTheWFLDefinition -H "Content-Type:application/json"
In postParams.json file I have the required pairs for property/value which I need to update:
{
"cmprop:propOne" : "Value 1",
"cmprop:propTwo" : "Value 2",
"cmprop:propThree" : "Value 3"
}
The workflow is started, bpm:workflowDescription is set correctly, but the properties in the task are not visible to be set.
I made a JS script which I call when the workflow is started:
execution.setVariable('bpm_workflowDescription', 'Some String ' + execution.getVariable('cmprop:propOne'));
And actually the value for cmprop:propOne is used and the description is properly updated - which means that those properties are updated somewhere (on execution level maybe?) but I cannot figure out why they are not visible when I open the task.
I had success with starting the workflow and updating the properties using the JavaScript API with:
if (wfdef) {
// Get the params
wfparams = {};
if (jsonRequest) {
for ( var prop in jsonRequest) {
wfparams[prop] = jsonRequest[prop];
}
}
wfpackage = workflow.createPackage();
wfpath = wfdef.startWorkflow(wfpackage, wfparams);
The problem is that I only want to use the public Java API, please help.
Thanks!
Do you set your variables locally in your tasks? From what I see, it seems that you define your variables at the execution level, but not at the state level. If you take a look at the ootb adhoc.bpmn20.xml file (https://github.com/Activiti/Activiti-Designer/blob/master/org.activiti.designer.eclipse/src/main/resources/templates/adhoc.bpmn20.xml), you can notice an event listener that sets the variable locally:
<extensionElements>
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string>
if (typeof bpm_workflowDueDate != 'undefined') task.setVariableLocal('bpm_dueDate', bpm_workflowDueDate);
if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;
</activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
Usually, I just try to import all tasks for my custom model prefix. So for you, it should look like that:
import java.util.Set;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.apache.log4j.Logger;
public class ImportVariables extends AbstractTaskListener {
private Logger logger = Logger.getLogger(ImportVariables.class);
#Override
public void notify(DelegateTask task) {
logger.debug("Inside ImportVariables.notify()");
logger.debug("Task ID:" + task.getId());
logger.debug("Task name:" + task.getName());
logger.debug("Task proc ID:" + task.getProcessInstanceId());
logger.debug("Task def key:" + task.getTaskDefinitionKey());
DelegateExecution execution = task.getExecution();
Set<String> executionVariables = execution.getVariableNamesLocal();
for (String variableName : executionVariables) {
// If the variable starts by "cmprop_"
if (variableName.startsWith("cmprop_")) {
// Publish it at the task level
task.setVariableLocal(variableName, execution.getVariableLocal(variableName));
}
}
}
}
Cordova Web View sendjavascript is deprecated and it not working for me.
My java code is:
public static void sendJavascript(JSONObject _json) {
String _d = "javascript:" + gECB + "(" + _json.toString() + ")";
Log.v(TAG, "sendJavascript: " + _d);
Log.i(TAG,_d);
if (gECB != null && gWebView != null) {
gWebView.sendJavascript(_d);//deprecated method
}
}
My java script code :
document.addEventListener("deviceready", function(){
window.plugins.pushNotification.register(successHandler, errorHandler, {
ecb : 'onNotificationGCM',
senderID : 'xxxxxxxxxxxxx'
});
// Method to handle device registration for Android.
var onNotificationGCM = function(e) {
if('registered' === e.event) {
// Successfully registered device.
alert(e.regid);
}
else if('error' === e.event) {
// Failed to register device.
alert(e.msg);
}
else if('message' === e.event) {
//mesage recived
alert(e.payload.message);
}
};
// result contains any message sent from the plugin call
function successHandler (result) {
alert('gcm result = ' + result);
}
// result contains any error description text returned from the plugin call
function errorHandler (error) {
alert('error = ' + error);
}
});
Deprecated details :https://apache.googlesource.com/cordova-android/+/3.6.1/framework/src/org/apache/cordova/CordovaWebView.java
Please help me?
This should work for you:
gWebView.loadUrl("javascript:myJavaScriptFuntion();");
Is it possible to implement unit test against such url mapping?
"500" (controller: 'error', action: 'handle', exception: MyCustomException)
I've tried to write such unit test
#TestFor(UrlMappings)
#Mock(ErrorController)
class UrlMappingsTest {
void test() {
assertForwardUrlMapping(500, controller: "error", action: "handle", exception: MyCustomException)
}
}
but got junit.framework.AssertionFailedError: url '500' did not match any mappings
If I remove exception: MyCustomException from UrlMapping.groovy and from unit test it works. But I cannot do it.
I know it has been almost 2 years but I too faced this problem yesterday, although using Grails 2.4.4, so I'll post a solution here in case anyone bumps into this.
As if it was not enough that you have to write tests, it is even more disturbing when writing tests takes 1000% more time than writing the actual code! :)
Anyway, the problem is that UrlMappingsUnitTestMixin does not handle this scenario.
There is an official bug reported here:
https://github.com/grails/grails-core/issues/10226 and a fix has been pushed just last month.
If you want to avail from the fix in Grails 2.4.4 you can create a mixin UrlMappingsUnitTestMixinBugFix and then use it in UrlMappingsTest.
UrlMappingsUnitTestMixin.groovy
package com.example.util.test
import grails.util.Holders
import junit.framework.AssertionFailedError
import org.codehaus.groovy.grails.commons.ControllerArtefactHandler
import org.codehaus.groovy.grails.commons.GrailsControllerClass
import org.codehaus.groovy.grails.web.mapping.UrlMappingsHolder
import static junit.framework.Assert.assertEquals
/**
* Methods below are copied from {#link grails.test.mixin.web.UrlMappingsUnitTestMixin}
*
* <p>This method is here because the {#link grails.test.mixin.web.UrlMappingsUnitTestMixin} in Grails 2.4.4 has a bug and this code fixes it.
* <p>Link to the bug: here.
*
* <p>To use this class just write UrlMappingsTest as per Grails guidelines and add a static code block to the Test:
* <p>
* <code>
* static {
* UrlMappingsTest.mixin(UrlMappingsUnitTestMixinBugFix)
* }
* </code>
*/
class UrlMappingsUnitTestMixinBugFix {
void assertForwardUrlMapping(assertions, url) {
assertForwardUrlMapping(assertions, url, null)
}
void assertForwardUrlMapping(assertions, url, paramAssertions) {
def assertionKeys = ["controller", "action", "view"]
final String KEY_EXCEPTION = 'exception'
UrlMappingsHolder mappingsHolder = Holders.applicationContext.getBean("grailsUrlMappingsHolder", UrlMappingsHolder)
if (assertions.action && !assertions.controller) {
throw new AssertionFailedError("Cannot assert action for url mapping without asserting controller")
}
if (assertions.controller) assertController(assertions.controller, url)
if (assertions.action) assertAction(assertions.controller, assertions.action, url)
if (assertions.view) assertView(assertions.controller, assertions.view, url)
def mappingInfos
if (url instanceof Integer) {
mappingInfos = []
// -------- START FIX --------
// -------- OLD CODE (below) --------
// def mapping = mappingsHolder.matchStatusCode(url)
// if (mapping) mappingInfos << mapping
// -------- FIXED CODE (below) --------
def mapping
if (assertions."$KEY_EXCEPTION") {
mapping = mappingsHolder.matchStatusCode(url, assertions."$KEY_EXCEPTION" as Throwable)
} else {
mapping = mappingsHolder.matchStatusCode(url)
}
if (mapping) mappingInfos << mapping
// -------- END FIX --------
} else {
mappingInfos = mappingsHolder.matchAll(url)
}
if (mappingInfos.size() == 0) throw new AssertionFailedError("url '$url' did not match any mappings")
def mappingMatched = mappingInfos.any { mapping ->
mapping.configure(webRequest)
for (key in assertionKeys) {
if (assertions.containsKey(key)) {
def expected = assertions[key]
def actual = mapping."${key}Name"
switch (key) {
case "controller":
if (actual && !getControllerClass(actual)) return false
break
case "view":
if (actual[0] == "/") actual = actual.substring(1)
if (expected[0] == "/") expected = expected.substring(1)
break
case "action":
if (key == "action" && actual == null) {
final controllerClass = getControllerClass(assertions.controller)
actual = controllerClass?.defaultAction
}
break
}
assertEquals("Url mapping $key assertion for '$url' failed", expected, actual)
}
}
if (paramAssertions) {
def params = [:]
paramAssertions.delegate = params
paramAssertions.resolveStrategy = Closure.DELEGATE_ONLY
paramAssertions.call()
params.each { name, value ->
assertEquals("Url mapping '$name' parameter assertion for '$url' failed", value, mapping.params[name])
}
}
return true
}
if (!mappingMatched) throw new IllegalArgumentException("url '$url' did not match any mappings")
}
private GrailsControllerClass getControllerClass(controller) {
return grailsApplication.getArtefactByLogicalPropertyName(ControllerArtefactHandler.TYPE, controller)
}
}
UrlMappingsTest.groovy
import com.example.controller.ErrorController
import com.example.util.test.UrlMappingsUnitTestMixinBugFix
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
#TestFor(UrlMappings)
#Mock(ErrorController)
class UrlMappingsTest {
static {
UrlMappingsTest.mixin(UrlMappingsUnitTestMixinBugFix)
}
void test() {
assertForwardUrlMapping(500, controller: "error", action: "handle", exception: MyCustomException)
}
}
I am new to Java and I want to call my saved pipeline using GATE JAVA API through Eclipse
I am not sure how I could do this although I know how to create new documents etc
FeatureMap params = Factory.newFeatureMap();
params.put(Document.DOCUMENT_URL_PARAMETER_NAME, new URL("http://www.gate.ac.uk"));
params.put(Document.DOCUMENT_ENCODING_PARAMETER_NAME, "UTF-8");
// document features
FeatureMap feats = Factory.newFeatureMap();
feats.put("date", new Date());
Factory.createResource("gate.corpora.DocumentImpl", params, feats, "This is home");
//End Solution 2
// obtain a map of all named annotation sets
Document doc = Factory.newDocument("Document text");
Map <String, AnnotationSet> namedASes = doc.getNamedAnnotationSets();
System.out.println("No. of named Annotation Sets:" + namedASes.size());
// no of annotations each set contains
for (String setName : namedASes.keySet()) {
// annotation set
AnnotationSet aSet = namedASes.get(setName);
// no of annotations
System.out.println("No. of Annotations for " +setName + ":" + aSet.size());
There is a good example of GATE usage from java. Probably it does exactly what you want. BatchProcessApp.java.
In particular:
loading pipeline is done with lines
// load the saved application
CorpusController application =
(CorpusController)PersistenceManager.loadObjectFromFile(gappFile);
pipeli executed with
// run the application
application.execute();
Code is informative, clear and could be easy changed for your particular needs. The oxygen of open source project :)
Something like this could be used(do not forget to init GATE: set GATE home and etc):
private void getProcessedText(String textToProcess) {
Document gateDocument = null;
try {
// you can use your method from above to build document
gateDocument = createGATEDocument(textToProcess);
corpusController.getCorpus().add(gateDocument);
corpusController.execute();
// put here your annotations processing
} catch (Throwable ex) {
ex.printStackTrace();
} finally {
if (corpusController.getCorpus() != null) {
corpusController.getCorpus().remove(gateDocument);
}
if (gateDocument != null) {
Factory.deleteResource(gateDocument);
}
}
}
private CorpusController initPersistentGateResources() {
try {
Corpus corpus = Factory.newCorpus("New Corpus");
corpusController = (CorpusController) PersistenceManager.loadObjectFromFile(new File("PATH-TO-YOUR-GAPP-FILE"));
corpusController.setCorpus(corpus);
} catch (Exception ex) {
ex.printStackTrace();
}
return corpusController;
}