I am writing a Selenium script to test a Chrome app that uses the Chrome.fileSystem.chooseEntry API to select a directory. When I do this manually, it works fine. But when I do this in a Selenium script, I get back this error:
Unchecked runtime.lastError while running fileSystem.chooseEntry: Invalid calling page. This function can't be called from a background page.
Any ideas on how to make Selenium and chooseEntry play nicely together?
I updated to the latest Chromedriver, but still no luck. I also looked at ChromeOptions, but didn't see anything that looked like it would be helpful. The interwebs doesn't seem to have much to say about Selenium and chooseEntry. I'm on version 51 of Chrome.
I'm down to thinking I'll need a special javascript entry point to set the path values for testing instead of using chooseEntry. But I would strongly prefer to not have a separate code execution path for my tests. Anybody have a cleaner solution?
EDIT: per commenter's request, here's the offending code:
chrome.fileSystem.chooseEntry({type:'openDirectory'},function(entry) {
chrome.fileSystem.getWritableEntry(entry,function(writeable_entry) {
console.log("got writeable entry");
});
}, function(e) { errorHandler(e); });
EDIT #2: I've gone with the special javascript entry point hack. In manual mode -- i.e., not running under Selenium -- I run code that executes chooseEntry, and then use the retainEntry API to get the entry id. I added an entry point in my javascript to take an entry id and call the restoreEntry API to turn it back into an entry. I also modified my code so if this entry object is set, then use that as the file instead of calling chooseEntry. Lastly, I modified my Selenium script to call the restoreEntry entry point before running the rest of the script.
This is not ideal, since now my test code execution path is somewhat different from my actual live-human-being-at-the-controls code execution path. But at least it lets me use Selenium scripts now. Of course, if anyone can think of a non-horrible way to solve this solution, I'd love to hear about it.
EDIT #3: Per #Xan's comment, corrected my terminology from "extension" to "Chrome App."
I can only offer this horrible hack. For Chrome Apps under OSX I created folder favorites and use Robot keyPress to navigate and select the 'favorite' folders needed for the App. The only possible redeeming factor is that it does mirror a valid/possible actual human interaction with the file interface.
private void selectOSXFolderFavorite(int favorite) {
// With an OSX file folder dialog open, Shift-Tab to favorites list
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_SHIFT);
// move to the top of favorites list
int i = 40;
while (i-- > 0) {
robot.keyPress(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_UP);
}
while (favorite-- > 0) {
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
}
// Send an enter key to Select the selected folder
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
}
Related
I am developing a react application with the bundler Webpack.
I would like to debug this application with a browser console (here i use chrome).
I have used source-maps and equivalent in my webpack config:
devtool = 'inline-source-map';
Now errors are displayed with the exact line of the original file.
The problem is that i want to access to live variables with the console.
So far I found two ways to display them:
1- Add a library in webpack.config.js
output: {
library: "lib"
},
export variable in the code export var foo = 34; and finally inside the browser console use lib.foo.
2- use breakpoint and access to variable set in the file
Is there another solution to access live variables?
Thanks
There are other solutions, but that means defining global variables and that should be avoided as it can have side effects in the code you're trying to debug, so you might run into problems that are not identical with and without exposing the variables, which makes your debugging experience very frustrating.
Using breakpoints is the best you can do for debugging purposes. The browser debuggers, especially the Chrome devtools, are extremely powerful and it's absolutely worth spending some time to get familiar with them.
Because pausing the app at every breakpoint you set for getting to a certain point can be tedious, you can use conditional breakpoints. One way is to use the debugger statement in your code, in that case you can guard it by any JavaScript you like, for instance this will only pause when the input to the function is 5:
function debug(input) {
if (input === 5) {
debugger;
}
// Other code
}
Another way is to add conditional breakpoints in the Chrome devtools. As you've configure source maps, you can set the breakpoints in the original source under Sources > top > webpack:// > .
To set a conditional breakpoint you simply right-click a line and choose Add conditional breakpoint... and enter the condition, e.g. input === 5. You can also Edit breakpoint... to change or add a condition to an existing breakpoint. For more information about breakpoints in Chrome see Pause Your Code With Breakpoints.
In the Sources tab you can also right click anywhere and Add folder to workspace so you can edit the sources directly and save the changes to disk (in older versions of Chrome it's a bit more complicated to add a folder to the workspace). To let Chrome know that the source maps of webpack correspond to your workspace, you can right-click any webpack source map and select Map to File System Resource... and you simply choose the correct file of the workspace. After that, all the sources of webpack should automatically be mapped to the correct files. Now you can set the breakpoints there and when you change something and save it (Ctrl + S or Cmd + S), webpack will recompile it. See also Set Up Persistence with DevTools Workspaces.
Sometimes setting a breakpoint might be too much effort for only getting values of variables. With just console.log you probably end up with a lot of different messages. To make it easier to find the messages you need, you can use console.group which lets you put messages inside a group, that can be expanded and collapsed. The groups can also be nested. Use console.groupCollapsed if you want the group to be collapsed initially.
I'm new to JavaScript environment and it's the one running on the system i'm newly at.
We're using GWT for JavaScript.
What is the best way to detect the connections between the back-end processes
and front-end actions? Eg. which back-end method is invoked when "that" button is pressed, tab is clicked,
window is opened, ... .
The only way I can think of is using the debugger and Eclipse search/call hierarchies facilities: keep putting breakpoints
in places where I anticipate will run-- until i hit the spot.
Is/n't there a more efficient way of doing this?
How do other developers do?
I'm a back-end developer.
In a previous system, I put a port monitor-- Fiddler,
saw the contents of the request the FE is sending and went from there.
I'm aware that this is a naive Q-- please bear with me.
TIA.
//======================
EDIT:
the best would be a
debugger-like tool showing the stack-trace, or even the
execution path in any way, telling the back-end methods that are running and/or spawning the threads.
is there such a tool?
The following takes for granted that you are using a decent IDE and that you have imported the GWT project into such IDE. There's some help at the end if this is not your case.
If you know which Java class contains the front-end logic, and the element you're interested in
Find the object representing the element (a Button, a ListBox, whatever) and look at the event handlers attached to it.
Something like this:
//...
#UiField
ListBox myDropDownList;
//...
myDropDownList.addChangeHandler(new ChangeHandler() {
#Override
public void onChange(ChangeEvent changeEvent) {
SomeService.someRPCmethod(... params, callback, ...);
}
});
The SomeService.someRPCmethod method implementation should contain all the backend calls.
If you know the Java class, but not which one of all the buttons is the one you're looking for
Most GWT apps make use of *.ui.xml files which are like a skeleton for the actual web page. This XML files reference the actual Java objects used in the Java class, and are usually named like the class they represent.
Locate the ui.xml file and look for something like this:
...
<g:ListBox ui:field="myDropDownList" styleName="cssClassName"/>
...
This should appear in your webpage like this:
<select class="cssClassName" ...>
<option ...>
The position inside the XML file, and the CSS class name, should help you pinpoint the element you're looking for. Once you find it, the ui:field attribute points to the Java object (try ctrl+clicking it in your IDE).
Now you just have to look at the handlers as explained before.
If you don't know the Java class which contains the front-end logic
To find the Java class for a given webpage, you can resort to the good ol' string search.
Locate a not-so-common string literal used in the web page. Not something like "Add" but more like "User registration".
Use your IDE to search the project's code base for that string. It should appear inside a .properties file, or a class with constants and literals, or maybe even hardcoded inside the front-end Java class.
Now just use your IDE to follow the references. It might be something like .properties file -> Constants interface -> .ui.xml file -> front-end Java class, or literals Java class -> front-end Java class.
If you don't have access to the front-end source code
You can try to use your Developer Tools / Fiddler to look for REST calls, which is how GWT implements RPC.
So the call to SomeService.someRPCmethod above might appear in Fiddler as a http:://yourwebpage/somepath/SomeService call with a bunch of GET/POST parameters, one of which should be someRPCmethod (the method's name). But this is not always the case.
If you're running GWT 2.6+ in SuperDev mode with Sources enabled, you can also try to debug the Javascript in the front-end until you reach the RPC calls. See abhinav3414's answer.
Last (or maybe first!) resource
Ask the front-end developers, they put the calls in there and can get you on track in minutes ;)
I had similar issue, so I installed an extension in my chrome.Below is the name of the extension. You can try once.
Visual Event 2.1
Know what event is bound on each dom element
There is one more approach, You can debug your code from front end. You can inspect element in your browser and then open Source tab.
Press ctrl + P to search the file in which you want to put the debug points.
Put debug points by clicking on the row number.
This way you need not to go to eclipse that often.
I would start by searching the code for the listeners of whatever events you are interested in and go from there. I work in EXT JS and I do this all the time.
Following all code paths through is the only guarantee unless all calls to the backend go through some known class.
Monitoring the network is also a good way to go.
This can be done in Chrome through the "Developer Tools" on the Network tab.
In GWT you have on the client side "import java.util.logging.Logger;" which output your debug info to the browsers console. On the server side you just use "System.out.println("debug");" for debugging which goes to the Apaches Tomcat log files. Which makes debugging on a live server a bit easier.
GWT uses RPC's for communication between the client and server. The data sent is serialized and can be a whole class if needed. The three folder for source in a module as 'client', 'server' and 'shared'.
For example a shared class used for sending data back and forth: (The blank constructor is required to serialise the class)
public class MySharedData implements Serializable {
private static final long serialVersionUID = 1987236748763652L; // used for serializing data
public List<String> lotsOfStrings = new ArrayList<String>(); // use most java vars
public int width, height;
public MySharedData() {} // 'need' a blank constructor
public MySharedData(MySharedData data) { //do stuff } // also can
}
On the server side it may look something like this:
public class MyServerRPCImpl extends RemoteServiceServlet implements MyServerRPC {
private static final long serialVersionUID = 4435555929902374350L;
public List<String> getStringList(int var, List<String> strs) {
// do stuff
System.out.println("debugging output"); // to tomcat log file
return stringList;
}
}
The client will use an Asynchronous callback with two methods, onSuccess() and onFailure() so you can handle call failures. To use this is something along the lines of:
public class MyGWTApp implements EntryPoint {
// the server RPC class
final MyServerRPCAsync server = GWT.create(MyServerRPC.class); // create RPC instance
final Logger log = Logger.getLogger("tag");
public void doSomething() {
MySharedData data = new MySharedData();
server.getStringList(data, new AsyncCallback<List<String>>() {
#Override
public void onFailure(Throwable caught) {
log.info("error"); // logging goes to the javascript console output
}
#Override
public void onSuccess(List<String> result) {
log.info("call worked");
}
};)
}
}
The above is my way of managing logging as my projects have to run straight from a Tomcat server. I also believe the server logging when run from Eclipse will go to Eclipse's console log, but I'm unsure on that. All server output and errors, including stack traces will be in the /var/log/tomcat/ folder on linux, or the equivalent on Windows. I can honestly say, I've yet not used breakpoints debugging with GWT.
Client and server code is in separate classes in their own folders within the project.
Just want to mention that sometimes debugger is used in situations where other tools can also help (not sure if this is the situation here - but bear with me just another two sentences):
(1) you can grep the relevant html asset , grep is a wonderful tool to learn large systems
(2) you can add log , in some cases you can switch to debug mode and see tons of log traces
Use Network tab in developer tools of your preferred browser you are using to test.
CHROME
Press F12 or alternatively choose from menu - tools > developer tools
FIREFOX
Press F12 or alternatively choose from menu - Developer > toggle tools
IE
Press F12
Well here's a problem.
I've got a website with large javascript backend. This backend talks to a server over a socket with a socket bridge using http://blog.deconcept.com/swfobject/
The socket "bridge" is a Flex/Flash .swf application/executable/plugin/thing for which the source is missing.
I've got to change it.
More facts:
file appExePluginThing.swf
appExePluginThing.swf Macromedia Flash data (compressed), version 9
I've used https://www.free-decompiler.com/flash/ to decompile the .swf file and I think I've sorted out what's the original code vs the libraries and things Flash/Flex built into it.
I've used FDT (the free version) to rebuild the decompiled code into MYappExePluginThing.swf so I can run it with the javascript code and see what happens.
I'm here because what happens isn't good. Basically, my javascript code (MYjavascript.js) gets to the point where it does
window.log("init()");
var so = new SWFObject("flash/MYappExePluginThing.swf"", socketObjectId, "0", "0", "9", "#FFFFFF");
window.log("init() created MYappExecPluginThing!!!");
so.addParam("allowScriptAccess", "always");
log("init() added Param!!");
so.write(elId);
log("init() wrote!");
IE9's console (yeah, you read that right) shows
init()
created MYappExecPluginThing!!!
init() added Param!!
init() wrote!
but none of the debugging i've got in MYappExePluginThing.as displays and nothing else happens.
I'm trying to figure out what I've screwed up/what's going on? Is MYappExePluginThing.as running? Is it waiting on something? Did it fail? Why aren't the log messages in MYappExePluginThing.as showing up?
The first most obvious thing is I'm using FDT which, I suspect, was not used to build the original. Is there some kind of magic "build javascript accessible swf thing" in FlashBuilder or some other IDE?
First noteworthy thing I find is:
file MYappExePluginThing.swf
MYappExePluginThing.swf Macromedia Flash data (compressed), version 14
I'm using Flex 4.6 which, for all I know, may have a completely different mechanism for allowing javascript communication than was used in appExePluginThing.swf
Does anyone know if that's true?
For example, when FDT runs this thing (I can compile but FDT does not create a .swf unless i run it) I get a warning in the following method:
private function init() : void
{
Log.log("console.log", "MYappExePluginThing init()");
//var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
try
{
ExternalInterface.addCallback("method1Callback",method1);
ExternalInterface.addCallback("method2Callback",method2);
ExternalInterface.call(initCallback);
}
catch(err:Error)
{
Log.log("console.log", "MYappExePluginThing init() ERROR err="+err);
}
}
I got a warning that Application.application was deprecated and I should change:
var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
to:
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
which I did but which had no effect on making the thing work.
(FYI Log.log() is something I added:
public class Log{
public static function log(dest:String, mssg:String):void{
if(ExternalInterface.available){
try{
ExternalInterface.call(dest, mssg);
}
catch(se:SecurityError){
}
catch(e:Error){
}
}
trace(mssg);
}
}
)
Additionally, in MYjavascript.js MYappExePluginThing_init looks like this:
this.MYappExePluginThing_init = function () {
log("MYjavascript.js - MYappExePluginThing_init:");
};
Its supposed to be executed when MYappExePluginThing finishes initializing itself.
Except its not. The message is NOT displaying on the console.
Unfortunately, I cannot find any references explaining how you allow javascript communication in Flex 4.6 so I can check if I've got this structured correctly.
Is it a built in kind of thing all Flex/Flash apps can do? Is my swf getting accessed? Is it having some kind of error? Is it unable to communicate back to my javascript?
Does anyone have any links to references?
If this was YOUR problem, what would you do next?
(Not a full solution but I ran out of room in the comment section.)
To answer your basic question, there's nothing special you should need to do to allow AS3-to-JS communication beyond what you've shown. However, you may have sandbox security issues on localhost; to avoid problems, set your SWFs as local-trusted (right-click Flash Player > Global Settings > Advanced > Trusted Location Settings). I'm guessing this not your problem, though, because you'd normally get a sandbox violation error.
More likely IMO is that something is broken due to decompilation and recompilation. SWFs aren't meant to do that, it's basically a hack made mostly possible due to SWF being an open format.
What I suggest is that you debug your running SWF. Using break-points and stepping through the code you should be able to narrow down where things are going wrong. You can also more easily see any errors your SWF is throwing.
Not really an answer, but an idea to get you started is to start logging everything on the Flash side to see where the breakage is.
Since you're using IE, I recommend getting the Debug flash player, installing it, then running Vizzy along side to show your traces.
Should give you a good idea of where the app is breaking down.
Vizzy
Debug Player
We have some QUnit javascript tests running in Visual Studio using the Chutzpah test adapter. Everything was working fine until we changed our api (the one being tested by the js files) recently, and added some validations over the UserAgent http header. When I tried to update the tests to change/mock the user agent I realized it was not directly possible even by overriding the default browser property.
After a few days of scavenging, I finally found what exactly is happening. Chutzpah is creating a phantomjs page object for the test files to run on. This is being done on a base javascript file (chutzpahRunner.js) located at the Chutzpah adapter installation path. These are the last lines on the file, that effectively start the tests:
...
// Allows local files to make ajax calls to remote urls
page.settings.localToRemoteUrlAccessEnabled = true; //(default false)
// Stops all security (for example you can access content in other domain IFrames)
page.settings.webSecurityEnabled = false; //(default true)
page.open(testFile, pageOpenHandler);
...
Phatomjs supports changing the user agent header by specifying it in the page settings object. If I edit this chutzpahRunner.js file in my machine, and manually set the user agent there, like this:
page.settings.userAgent = "MyCustomUserAgent";
My tests start to work again. The problem is that this is not in the project itself, and thus cannot be shared with the rest of the team.
Is it possible to change the properties of the phantomjs objects created by Chutzpah to run the tests? I'd like to either change them from inside my own tests, or from another script file I could embed on the pipeline.
Without a code change in Chutzpah it is not possible to set those properties on the PhantomJS object. Please file an issue at https://github.com/mmanela/chutzpah asking for this functionality and then fork/patch Chutzpah to add it (or wait for a developer on the project to hopefully get to this).
Update:
I pushed a fix for this issue. Once this is released you can use the following in a Chutzpah.json file:
{
"userAgent": "myUserAgent"
}
Say I have the following Node program, a machine that goes "Ping!":
var machine = require('fs').createWriteStream('machine.log', {
flags : 'a',
encoding : 'utf8',
mode : 0644
});
setInterval(function () {
var message = 'Ping!';
console.log(message);
machine.write(message + '\n');
}, 1000);
Every second, it will print a message to the console and also append it to a log file (which it will create at startup if needed). It all works great.
But now, if I delete the machine.log file while the process is running, it will continue humming along happily, but the writes will no longer succeed because the file is gone. But it looks like the writes fail silently, meaning that I would need to explicitly check for this condition. I've searched the Stream docs but can't seem to find an obvious event that is emitted when this type of thing occurs. The return value of write() is also not useful.
How can I detect when a file I'm writing to is deleted, so I can try to reopen or recreate the file? This is a CentOS box, if that's relevant.
The writes actually do not fail.
When you delete a file that is open in another program you are deleting a named link to that file's inode. The program that has it open still points to that inode. It will happily keep writing to it, actually writing to disk. Only now you don't have a way to look it at, because you deleted the named reference to it. (If there were other references, e.g. hard links, you would still be able to!).
That's why programs that expect their log files to "disappear" (b/c of logrotate, say) usually support a signal (usually SIGHUP and sometimes SIGUSR1) that tells them to close their file (at which point it is really gone, because now there are no links to it anywhere) and re-create it.
You should consider something like that as well.