I want to trigger some code when page action or browser action popup gets closed. I tried listening to onunload and onbeforeunload events on <body> or window but they never fire.
It's a bug, but a chromium developer posted a workaround.
http://crbug.com/31262#c13
As looks like there is no straight forward solution, this is what I ended up doing if anyone interested.
Periodically ping background page from the popup, and if background page is not received ping within some time period, it triggers required action. Works like a time bomb :)
In background page:
var timeoutId = 0;
function popupPing() {
if(timeoutId != 0) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(function() {
popupClosed();
timeoutId = 0;
}, 1000);
}
function popupClosed() {
//...
}
In popup:
ping();
function ping() {
chrome.extension.getBackgroundPage().popupPing();
setTimeout(ping, 500);
}
(note that popup pings 2 times faster than "trigger" time in background page)
Related
I'm using Chrome Extension to scrape web sites and once in a while the Chrome Extension crashes. To reload the crashed extension, I have created another extension that reloads the crashed extension every X minutes.
It all worked fine until recently. The extension that I was using to restart the scraper did not restart the extension anymore while I haven't changed anything to it.
Here is a sample for the alarm:
chrome.alarms.get(alarmName, function(Alarm)
{
if (typeof Alarm === 'undefined')
{
console.log('is not defined');
chrome.alarms.create(alarmName,
{
periodInMinutes: 1
});
}
else
{
console.log('is defined');
}
});
and then the code to restart the extension:
chrome.alarms.onAlarm.addListener(async function( alarm )
{
var child = null;
chrome.management.getAll(function (info) {
for (var i=0; i < info.length; i++) {
if (info[i].name == 'MyScraper') {
child = info[i];
console.log(child);
chrome.management.setEnabled(child.id, true, function ()
{
console.log('Enabled '+Date.now());
});
break;
}
}
});
});
The code finds the extension correctly and display the child object, the content of this object is ok but once I try to reload it with setEnabled, the console outputs "Enable + time" but the scraping extension is not restarted. I don't get any error message.
The extension is running on a Raspberry Pi 4 with Chromium, it used to run on Windows before but I don't see why the code would not work anymore.
Any idea?
Thanks!
As I couldn't find a way to solve this through a Chrome Extension, I have installed xdotool and created a script that clicks on the reload button every 10 minutes. It's not super clean but at least it solves my issue.
Thanks
When I perform an action on my page, a spinner is displayed which disappears once the action is completed. I want to wait for the spinner to disappear so as to execute the assert statements.
I read the documentation which tells me how to wait for an element to appear but does not give info on how to wait for the element to disappear
I don't know how to implement this in Cucumber, Geb, Groovy project.
I'll edit/explain this in a bit, when i have more time:
In your page object:
static content = {
loadingSpinner(wait:3, required:false) { $("mat-spinner") }
//this wait:3 is redundant (i think) if we also give the waitFor() a timeout
//required:false allows our wait !displayed to pass even if the element isnt there
}
def "Handle the loader"() {
try {
waitFor(2) { loadingSpinner.isDisplayed() }
} catch (WaitTimeoutException wte) {
//do nothing, if spinner doesnt load then thats ok
//most likely the spinner has come and gone before we finished page load
//if this is not the case, up our waitFor timeout
return true;
}
waitFor(10) { !loadingSpinner.isDisplayed() }
}
As described in the documentation, the waitFor block uses Groovy Truth to know when it waited long enough. When you put a Navigator in it and the element is currently not present, it will wait for it to appear or until the maximum waiting time it elapsed.
So if want to wait for an element to disappear, you can simply put it in a waitFor like this:
// go to the page
waitFor(2) { $(".loadingspinner").displayed }
waitFor(10) { !$(".loadingspinner").displayed }
// do your assertions
In case the loading spinner already disappeared, waitFor will return immediately. In case it never disappears, it will throw a WaitTimeoutException after 10 seconds, which will make your test fail.
In my Xamarin iOS app, I have a static helper method that displays an alert dialog. This dialog box needs to automatically go away after a few seconds if the user has still not pressed OK button. Here is the simplified code snippet:
UIAlertController dlg = UIAlertController.Create(title, text,
UIAlertControllerStyle.Alert);
dlg.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null);
UIApplication.SharedApplication.KeyWindow.RootViewController.
PresentViewController(dlg, true, null);
Later, when the timer expires:
t.Elapsed += (s, e) => {
dlg.DismissViewController(true, null);
};
Although, the method DismissViewController is indeed getting invoked, the dialog does not disappear from the screen.
I even tried calling dlg.Dispose() but this didn't help either.
Can someone please help me understand what is it that I am missing? Regards.
The code in event Elapsed is not on the main Thread .
Invoke it on Main Thread.
t.Elapsed += (s, e) =>
{
InvokeOnMainThread(() => {
dlg.DismissViewController(true, null);
});
};
I have created a chrome extension which does something after its button is clicked.
However I dont want it be abused so I need the its code to be executed after some time.
How can I surround this code with a timeout in order to achieve this?
Thank you for reading me!
chrome.tabs.getSelected(null,function(tab) {
var Mp=tab.url.substring(0,23);
if(Mp=='https://www.example.com')
{
onWindowLoad();
chrome.extension.onMessage.addListener(function(request, sender) {
if (request.action == "getSource")
{
...Working here
}
});
}
else
{
message.innerHTML='<span style="color: #f00">This is not a valid page</span>';
}
});
function onWindowLoad()
{
var message = document.querySelector('#message');
chrome.tabs.executeScript(null, {file: "getPagesSource.js"});
}
I had to make a compromise so just after the getSelected I added the following line:
chrome.browserAction.disable(tab.Id);
It disables the action button thus it cant be clicked while the script sends the data to the server, as with this extension I grab the tab url in order to store it in my database.
After the ajax response and adding the following
if(xhr.readyState==4)
{
message.innerHTML=xhr.responseText;
chrome.browserAction.enable(tab.Id); /////<---THAT LINE
}
the button gets ready again to be clicked.
I couldnt find the way to add a specific delay in seconds, this way seems stupid but its working, as the response's delay from my server is enough for switching the 2 states of the action button.
With this, however another problem came up, which Ill write in different question.
I believe this is related to the asynchronous nature of chrome extensions.
This section of my code:
alert(tab.title);
chrome.tabs.executeScript(tab.id, {code:"document.title = 'test'"});
Works fine, but as soon as I remove the alert, it stops working. Is there anything I can do to remove the alert but still have the js injected?
EDIT: More Code
tabs is a global array of tab objects.
chrome.tabs.onSelectionChanged.addListener(function (tabId) {
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id == tabId) {
var tab = tabs[i];
while (i < tabs.length) {//length-1
tabs[i] = tabs[i+1];
i++;
}
tabs.pop();
alert(tab.title);//WHY IS THIS NEEDED
chrome.tabs.executeScript(tab.id, {code:"document.title = document.title.substring(1)"});
return;
}
}
});
I am very confused. Changing it the following solves the problem:
chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});
However, as soon as I change the delay to 50, the script doesn't get executed again. I would prefer not to have to have to make this delay. Does anyone know whats going on?
I know this is an old question, but if anyone is looking - wrap the chrome.tabs.executeScript method in a timeout.
setTimeout(function(){chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});},500);
It's certainly not ideal but it gets the job done.
Sounds like you have a race condition. My best guess would be to change the injected code to execute on onLoad.