JavaScript for automation in OSX Yosemite - javascript

Can we send a click event to a button inside a webview in Cocoa app using JavaScript?
I am trying to use the script editor under utilities (Yosemite) to record but unfortunately not able to record any events inside the webview.
I tried using the sample code under UI automation section provided in the Apple documentation with the testapp (cocoa app with webview) at https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/index.html.
TestApp = Application('TestApp')
TestApp.activate()
delay(1)
SystemEvents = Application('System Events')
TestApp = SystemEvents.processes['TestApp']
TestApp.document.getElementById('testid').click(); // stuck at this last line not sure if I can
//even call the document object in this way. Getting error undefined variable document.

You're trying to use browser/DOM Javascript to access native app UI elements. Although this environment uses Javascript like a browser does, the underlying object model is not the DOM you're used to seeing on a web page. That's why you're seeing that document is undefined.
As implied by the little snippet in the "UI Automation" section of the docs, you need to access the window and button objects. The exact path you'll use depends on your TestApp, of course, but it might look something like:
TestApp.windows[0].buttons[0].click()
(It is probably also possible to scrobble through these arrays by control ID using whose, or the like, but don't have experience with that.)

Related

How to tell if a web application is using ReactJs

I know there are tools like Wappalyzer & BuiltWith that give you information about which framework or library is used in a website. But I need some kind of proof regarding if ReactJs is really used in a website.
After some research I found out that commands like typeof React or window.React.version, but these commands don't work all the time.
Any ideas on how to check reactJs is used a web application?
try the below snippet, thanks for the examples for each site listed by rambabusaravanan. See the below link
if(!!window.React ||
!!document.querySelector('[data-reactroot], [data-reactid]'))
console.log('React.js');
if(!!window.angular ||
!!document.querySelector('.ng-binding, [ng-app], [data-ng-app], [ng-controller], [data-ng-controller], [ng-repeat], [data-ng-repeat]') ||
!!document.querySelector('script[src*="angular.js"], script[src*="angular.min.js"]'))
console.log('Angular.js');
if(!!window.Backbone) console.log('Backbone.js');
if(!!window.Ember) console.log('Ember.js');
if(!!window.Vue) console.log('Vue.js');
if(!!window.Meteor) console.log('Meteor.js');
if(!!window.Zepto) console.log('Zepto.js');
if(!!window.jQuery) console.log('jQuery.js');
you can find additional info here link
I had the same problem, and in my case, I found it better to rely on the React Developer Tools.
You can install it in Google Chrome, access the website you want to check, and open the Chrome DevTools.
If the website uses React, the React Developer Tools will include two tabs in the Chrome DevTools:
Otherwise, the React Developer Tools won't include the tabs:
There is an extension in Chrome named 'React Developer Tools' which allows you to inspect the React component hierarchies in the Chrome Developer Tools
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
There is also another extension named 'React-detector' as well :)
https://chrome.google.com/webstore/detail/react-detector/jaaklebbenondhkanegppccanebkdjlh
Other answers that involve checking for globals like globalThis.React will work fine if the website uses react via a dedicated script HTML element, but will otherwise face the problem that bundlers like webpack can wrap dependency code inside immediately-invoked-function-expressions or other mechanisms for encapsulating their details and preventing them from unnecessarily bleeding into the global scope. Such encapsulation is very often desirable.
One can try to get around this by testing if DOM elements have properties on them that get set in React contexts, such as _reactRootContainer. Like so:
Array.from(document.querySelectorAll('*'))
.some(e => e._reactRootContainer !== undefined)
A page can have tons of elements, so one can try to optimize based on an assumption that React code will call ReactDOM.createRoot and pass it an element queried via HTML id. Ie. instead of checking all DOM elements, only check those that have an id attribute. Like so:
Array.from(document.querySelectorAll('[id]'))
.some(e => e._reactRootContainer !== undefined)
Be aware that the id-filtering optimization will not always work because the id assumption will not always hold.
Important: Since this method relies on the react DOM already having been created, it should be careful not to be applied until one thinks the react DOM has been created. Once can try to apply techniques like the defer attribute on scripts, or using document.onload, or setTimeout, or a combination of them.
Note that wrapping the nodelist from the query to turn it into an array is probably sub-optimal performance-wise, but I feel that to try to optimize it might be micro-optimizing. A check for the presence of react should probably be saved to a variable and never performed again anyway.
This answer doesn't detect the React 18 CRA apps that I've tried it on.
I can't edit that answer (stack overflow says too many pending edits) but it should also have a check for window.__REACT_DEVTOOLS_GLOBAL_HOOK__.
After adding that check it looks like this:
if(!!window.React ||
!!window.__REACT_DEVTOOLS_GLOBAL_HOOK__ ||
!!document.querySelector('[data-reactroot], [data-reactid]'))
console.log('React.js');
if(!!document.querySelector('script[id=__NEXT_DATA__]'))
console.log('Next.js');
if(!!document.querySelector('[id=___gatsby]'))
console.log('Gatsby.js');
if(!!window.angular ||
!!document.querySelector('.ng-binding, [ng-app], [data-ng-app], [ng-controller], [data-ng-controller], [ng-repeat], [data-ng-repeat]') ||
!!document.querySelector('script[src*="angular.js"], script[src*="angular.min.js"]'))
console.log('Angular.js');
if (!!window.getAllAngularRootElements ||
!!window.ng?.coreTokens?.NgZone)
console.log('Angular 2+');
if(!!window.Backbone) console.log('Backbone.js');
if(!!window.Ember) console.log('Ember.js');
if(!!window.Vue) console.log('Vue.js');
if(!!window.Meteor) console.log('Meteor.js');
if(!!window.Zepto) console.log('Zepto.js');
if(!!window.jQuery) console.log('jQuery.js');

Language switch in SAPUI5

I've got a language problem with my SAPUI5 controls.
If I execute e.g.:
sap.ui.getCore().getConfiguration().setLanguage("de");
My i18n files are loaded correctly and all labels are translated to German. But the controls are still in English.
The only way to get German controls is with the URL parameter:
sap-ui-language=DE
But I can't use a parameter in my case. Any idea?
Please note that sap.ui.getCore().setLanguage() explicitly states
The framework does not guarantee that already created, language dependent objects will be updated by this call. It therefore remains best practice for applications to switch the language early, e.g. before any language dependent objects are created. Applications that need to support more dynamic changes of the language should listen to the localizationChanged event and adapt all language dependent objects that they use (e.g. by rebuilding their UI).
Besides that, I fully support Nabi's answer (but I'm not allowed to vote it up).
I just would like to add that controls (like FilterBar) better should use the hook approach:
FilterBar.prototype.onlocalizationChanged = function(oEvent) {
// .. same bundle update code as in Nabi's proposal
}
Using the hook in controls avoids the need for adding attach + detach calls in init / exit and keeps the event registry small.
I can easily confirm the behavior you described by testing the Explored App Example. There, just open the console and hit sap.ui.getCore().getConfiguration().setLanguage("de");
I also checked the implementation of the FacetFilter and I would call this a bug in the Control implementation. It comes from how the texts are loaded inside the control. Just in case you are interested:
The message bundles all contain the correct translations for FACETFILTER_INFOBAR_NO_FILTERS (for en the translation comes from the "default" bundle):
messagebundle.properties
messagebundle_de.properties
The FacetFilter has a hidden aggregation called SummaryBar. The SummaryBar contains the text you see. Of course, this text comes from a bundle.
However, the bundle is initialized exactly once in init() by calling sap.ui.getCore().getLibraryResourceBundle("sap.m");. Here the API docs say:
If only one argument is given, it is assumed to be the libraryName.
The locale then falls back to the current session locale.
This means the bundle is cached and therefor changes to the localization (e.g. language) do not trigger the bundle to load a new translation file. Thus, we will always see the initial language no matter what we try (even rerendering() does not help).
A solution would be to fix the control by adding the following code right after the the bundle gets loaded inside the init:
sap.ui.getCore().attachLocalizationChanged(function(oEvent){
var oChanges = oEvent.getParameter("changes");
if (oChanges && oChanges.language){
this._bundle = sap.ui.getCore().getLibraryResourceBundle("sap.m", oChanges.language);
this.rerender();
}
}.bind(this));
You can try this out in the explored app linked above, it worked for me just fine...
I just opened an issue on github.

Print out webview

How can we print out what an webview contains? i tried something like :
view.page().currentFrame().toPlainText()
but it didn't work
PS: my webview contains an evaluation of a javascript function , so i suppose toHtml() won't do the job any suggestion?
QtWebKit will display javascript-generated webpages exactly the same as it will display any other webpage (though you can disable js through QWebSettings). I assume then, that you want the webpage to generate elements based on requests from the C++ application.
If that's the case, you want QWebFrame::evaluateJavaScript (as previously stated in this previous question: Qt4: How to call JavaScript functions in a page from C++ via QtWebkit?).
More generally, you might find this useful.

Calling a function in a JavaScript file with Selenium IDE

So, I'm running these Selenium IDE tests against a site I'm working on. Everything about the tests themselves is running fine, except I would like to do a bit of clean-up once I'm done. In my MVC3 Razor based site, I have a JavaScript file with a function that gets a JsonResult from a Controller of mine. That Controller handles the database clean-up that Selenium IDE otherwise couldn't handle.
However, I'm having a hard time finding any sort of documentation on how to do this. I know I can do JavaScript{ myJavascriptGoesHere } as one of the Values for a line in the test, but I can't seem to find a way to tell it to go find my clean-up function.
Is it even possible for Selenium IDE to do this sort of thing?
If it comes down to it, I can just make a separate View to handle the clean-up, but I'd really like to avoid that if possible.
Thanks!
If you want to execute your own JavaScript function that exists in your test page from Selenium IDE, you need to make sure you access it via the window object. If you look at the reference for storeEval for instance, it says:
Note that, by default, the snippet will run in the context of the
"selenium" object itself, so this will refer to the Selenium object.
Use window to refer to the window of your application, e.g.
window.document.getElementById('foo')
So if you have your own function e.g. myFunc(). You need to refer to it as window.myFunc().
This can be very handy for exercising client-side validation without actually submitting the form, e.g. if you want to test a variety of invalid and valid form field values.
If you use runScript, that should already run in the window's context.
This works for me.
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
string title = (string)js.ExecuteScript("myJavascriptGoesHere");
Make sure your javascript works first before using it here!
Actually to access your page javascript space, you need to get the real window of your page : this.browserbot.getUserWindow()
See this statement to get the jQuery entry point in your page (if it has jQuery of course ^^ )
https://stackoverflow.com/a/54887281/2143734

Using third-party JS libraries in Mozilla Add-On SDK

I'm starting a new project (Firefox add-on) and I'd like to try using behavior-driven development. I particularly like the Jasmine BDD library. However, I can't find a good way how to use a framework such as Jasmine in the Add-On SDK.
One problem is that Jasmine needs setTimeout (and similar) functions to be specified on the global object, whereas Add-On SDK exports those using "timers" module. But let's say I tweak Jasmine to get those object from "timers" (or add the the methods exported by timers to the global object).
The bigger problem is that I don't know how to actually run the tests. There is a test directory generated by the SDK, however, there's no window or document object there to allow me to see the output (and I'd really like to see the fancy HTML output). I guess I could create a content script that would modify the page, but then I can't access (test) the background script.
Have you ever faced this before? Is there any recommended way how to deal with that?
Thanks!
Tomas
You can use the Add-on SDK windows API to open a new window to run your tests in. You should be able to load the Jasmine script(s) with the subscript loader and set window and document to whatever you want in the scope of that subscript:
var windows = require("windows").browserWindows;
windows.open({
url: "about:blank",
onOpen: function(window) {
var script;
var scriptLoader = Cc["#mozilla.org/moz/jssubscript-loader;1"].
getService(Ci.mozIJSSubScriptLoader);
scriptLoader.loadSubScript(subscriptSpec, script);
script["window"] = window;
script["document"] = window.document;
// ... run your tests here by calling script.someFunc() ...
}
});
Update: Further research shows that the browserWindows are actually special wrappers that don't give you access to the content window. You might try getting a window/document from a hidden frame. That's the only way I can see to get access to an HTML document from privileged code.

Categories

Resources