Chrome tabs query returning empty tab array - google-chrome-extension

I'm trying to port a Web Extension that I've gotten working in Firefox to chrome and I having some problems. I need to send a message form the background script to a content script. I was using a port when I first build it from Firefox, but I switched it to using chrome.tabs.query() because chrome kept finding an error. But now with query(), it still works fine in Firefox, but now chrome is saying that it can't find the current tab:
Error handling response: TypeError: Cannot read property 'id' of undefined
at chrome-extension://hhfioopideeaaehgbpehkmjjhghmaaha/DubedAniDL_background.js:169:11
It returns that the tab argument pass is length == 0. console.log(tabs):
[]
This is the function that Chrome is complaining about.
var browser = chrome; // I set this only for compatibility with chrome; not set in Firefox.
function sendToTab(thing) {
browser.tabs.query(
{active: true, currentWindow: true},
function(tabs) {
console.log(tabs);
browser.tabs.sendMessage(
tabs[0].id, // The inspector identifies an error on this line
thing
);
}
);
}
The same function works fine in Firefox and has no problem getting access to the tab. But it doesn't work in Chrome.
Update 2020-01-30
#wOxxOm:
Show the code that calls sendToTab
This is where sendToTab is called:
function logURL(requestDetails) {
var l = requestDetails.url;
if (l.includes(test_url)) {
if (logOn) { console.log(l); }
sendToTab({dl_url: l});
}
}
browser.webRequest.onBeforeRequest.addListener(
logURL,
{urls: ["<all_urls>"]}
);

Sounds like you're running this code while your active window is devtools, which is a known bug.
Another problem takes place in your code: it always accesses the focused (active) tab even though the request may have occurred in a backgrounded (inactive) tab.
Solution:
Use the tab id provided inside the listener function parameter as tabId property.
In your case it's requestDetails.tabId
If for whatever reason you really want the active tab, make sure a real window is active while this code runs or use the following workaround that succeeds even if devtools window is focused:
chrome.windows.getCurrent(w => {
chrome.tabs.query({active: true, windowId: w.id}, tabs => {
const tabId = tabs[0].id;
// use tabId here...
});
});

Related

Aurelia popup when refreshing the page not working

As we know, we can put a pop up asking if we are sure about refreshing the page when we click the refresh button on the browser. Usually it is done by adding an event listener on onbeforeunload.
However, in my Aurelia application, I try to do that but it's not working.
let's say this is my app.js ( root ModelView )
export class App {
this.refreshClicked = () =>{ return "Are you sure you want to exit?"; };
attached(){
window.addEventListener("onbeforeunload", this.refreshClicked);
}
But it is not working, however, if we replace the return statement to console.log("clicked") I can see that the listener works without any problem.
Any help?
First of all, if you are adding event handler through window.addEventListener, you don't use on prefix in that case. So it's either:
attached() {
window.addEventListener('beforeunload', this.refreshClicked);
}
or an older, not recommended, syntax:
attached() {
window.onbeforeunload(this.refreshClicked);
}
Second, you'll need to set the returnValue property on Event object and also return the same string value to support more browsers. To learn more about this event (and various browser quirks), check out its MDN page.
Your refreshClicked should look like this:
this.refreshClicked = e => {
const confirmation = 'Are you sure you want to exit?';
e.returnValue = confirmation;
return confirmation;
};

selenium-webdriver npm wait

I have a simple script that performs a login using the selenium-webdriver npm module. The script works, but it is really slow and the wait timeout is giving very odd results (sometimes it seems to timeout immediately, and other times it waits far past the defined timeout).
Am I doing something wrong that would make the login very slow (running this through a selenium hub perhaps)? The site itself is very responsive.
Here is the script:
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().
usingServer('http://hubserver:4444/wd/hub').
withCapabilities(webdriver.Capabilities.firefox()).
build();
console.log('\n\nStarting login.');
console.log('\nConnecting to grid: http://hubserver:4444/wd/hub' );
// Load the login page and wait for the form to display
driver.get('https://testsite.com');
driver.wait(function() {
return driver.isElementPresent(webdriver.By.name('user'));
}, 3000, '\nFailed to load login page.');
// Enter the user name
driver.findElement(webdriver.By.name('user')).sendKeys('testuser').then(function() {
console.log("\nEntering user name");
});
// Enter the password
driver.findElement(webdriver.By.name('pass')).sendKeys('testpwd').then(function() {
console.log("\nEntering password");
});
// Click the login button
driver.findElement(webdriver.By.id('submit')).click().then(function() {
console.log("\nLogging in.");
});
// Wait for the home page to load
driver.wait(function() {
console.log("\nWaiting for page to load");
return driver.isElementPresent(webdriver.By.id('main'));
}, 3000, '\nFailed to load home page.');
driver.getCurrentUrl().then(function(url) {
console.log("\nPage loaded: " + url);
});
driver.quit();
Maybe you have it specified elsewhere, but in the code shown your driver.wait() has no amount of time specified.
Also, maybe I'm misunderstanding your code because I do this mainly in Python, but driver.wait(function(){}); looks weird to me. Is this really proper use of the JS bindings? Generally, you wait for the element to be found and then subsequently call a function that does something with the element. I can't write it in JS, but in pseudocode:
driver.wait(#element you're looking for)
# Handle exception if there is one
# Otherwise do something with element you're looking for
Also, I would think
driver.isElementPresent(webdriver.By.name('user'));
Should be
driver.isElementPresent(By.name('user'));

How to identify a tab is reloading, I mean actual page reload

How to identify a tab is reloading, I mean actual page reload?
I see chrome.tabs.onUpdated event, but for this event status is 'loading' even in case of AJAX calls from a webpage.
How can I detect a page is getting reloaded ?
You are right, looks like not possible to recognize AJAX and page reload calls. As workaround you could listen for onunload event for tab webpage. You probably need to check if tabid and url were not changed after that.
But do you really need to know if page reloaded?
It's an old question, but here is my solution that could be in help (without AIAX).
Since the method 'chrome.tabs.get()' return a promise, you can use the 'callback function' to check the current 'tab.status'.
Setting a boolean variable 'waitingForComplete = true', you will run your code, only when the tab will return at status = 'complete'.
background.js
var waitingForComplete = false;
chrome.tabs.onUpdated.addListener((tabId. changeInfo,tab) => {
if(changeInfo.status == 'complete'){
if(waitingForComplete){
waitingForComplete = false;
// runYourCode...
}
}
};
function checkTabStatusComplete(tabId){
chrome.tabs.get(tabId. function(tab){
if(tab.status == 'complete'){
// runYourCode...
} else {
waitingForComplete = true;
}
}
};

Chrome extension problem getting tab url

I'm not good at JS and I'm having some -I hope- stupid problem I'm not seeing on my code... if you guys could help me out, I'd really appreciate it.
My extension does some stuff with the current tab's URL. It worked ok using the onUpdate event on my background page, setting the tab's URL on a variable and then I used it on a pop-up.
The thing is that if the user starts, selecting different tabs, without updating the URLs my event won't be triggered again... so I'm now also listening to the onSelectionChanged event.
The thing is that there's no "tab" object within the onSelectionChanged event's parameters, so I cannot ask for the tab.url property.
I tried to use the chrome.tabs.getCurrent() method, but obviously I'm doing something wrong... and I reached the limit of my -very little- knowledge.
Here's the code, if you guys could take a look and point me in the right direction, I'll really appreciate it.
<script>
var tabURL = '';
var defaultURLRecognition = [ "test" ];
// Called when the url of a tab changes.
function checkForValidUrl(tabId, changeInfo, tab) {
//THIS IS WHAT'S NOT WORKING, I SUPPOSE
if (tab==undefined) {
chrome.tabs.getCurrent(function(tabAux) {
test = tabAux;
});
}
//
// If there's no URLRecognition value, I set the default one
if (localStorage["URLRecognition"]==undefined) {
localStorage["URLRecognition"] = defaultURLRecognition;
};
// Look for URLRecognition value within the tab's URL
if (tab.url.indexOf(localStorage["URLRecognition"]) > -1) {
// ... show the page action.
chrome.pageAction.show(tabId);
tabURL = tab.url;
}
};
// Listen for any changes to the URL of any tab.
chrome.tabs.onUpdated.addListener(checkForValidUrl);
// Listen for tab selection changes
chrome.tabs.onSelectionChanged.addListener(checkForValidUrl);
</script>
I would do something like this:
function checkForValidUrl(tab) {
//...
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
if(changeInfo.status == "loading") {
checkForValidUrl(tab);
}
});
chrome.tabs.onSelectionChanged.addListener(function(tabId, selectInfo){
chrome.tabs.getSelected(null, function(tab){
checkForValidUrl(tab);
});
});

window.onbeforeunload not working in chrome

This is the code which i used for window.onbeforeunload
<head>
<script>
window.onbeforeunload = func;
function func()
{
var request = new XMLHttpRequest();
request.open("POST", "exit.php", true);
request.onreadystatechange = stateChanged;
request.send(null);
}
function stateChanged()
{
if (request.readyState == 4 || request.readyState == "complete")
alert("Succes!");
}
</script>
</head>
this works with IE and Mozilla but does not work with Chrome..... please help......
thanks in advance.....
It seems that the only thing you can do with onbeforeunload in recent version of Chrome is to set the warning message.
window.onbeforeunload = function () {
return "Are you sure";
};
Will work. Other code in the function seems to be ignored by Chrome
UPDATE: As of Chrome V51, the returned string will be ignored and a default message shown instead.
Know I'm late to this, but was scratching my head why my custom beforeunload message wasn't working in Chrome and was reading this. So in case anyone else does the same, Chrome from Version 51 onwards no longer supports custom messages on beforeunload. Apparently it's because the feature has been misused by various scams. Instead you get a predefined Chrome message which may or may not suit your purposes. More details at:
https://developers.google.com/web/updates/2016/04/chrome-51-deprecations?hl=en#remove-custom-messages-in-onbeforeload-dialogs
Personally do not think the message they've chosen is a great one as it mentions leaving the site and one of the most common legitimate uses for onbeforeunload is for dirty flag processing/checking on a web form so it's not a great wording as a lot of the time the user will still be on your site, just have clicked the cancel or reload button by mistake.
You should try this:
window.onbeforeunload = function(e) {
e.returnValue = 'onbeforeunload';
return 'onbeforeunload';
};
This works on latest Chrome. We had the same issue the e.returnValue with value of onbeforeunload solved my problem.
Your code should be like this:
<head>
<script>
window.onbeforeunload = function(e) {
e.returnValue = 'onbeforeunload';
func();
return ''onbeforeunload'';
};
function func()
{
var request = new XMLHttpRequest();
request.open("POST", "exit.php", true);
request.onreadystatechange = stateChanged;
request.send(null);
}
function stateChanged()
{
if (request.readyState == 4 || request.readyState == "complete")
alert("Succes!");
}
</script>
</head>
Confirmed this behavior on chrome 21.0.1180.79
this seems to work with the same restritions as XSS, if you are refreshing the page or open a page on same domain+port the the script is executed, otherwise it will only be executed if you are returning a string (or similar) and a dialog will be shown asking the user if he wants to leans or stay in the page.
this is an incredible stupid thing to do, because onunload/onbeforeunload are not only used to ask/prevent page changes.
In my case i was using it too save some changes done during page edition and i dont want to prevent the user from changing the page (at least chrome should respect a returning true or change the page without the asking if the return is not a string), script running time restrictions would be enought.
This is specially annoying in chrome because onblur event is not sent to editing elements when unloading a page, chrome simply igores the curent page and jumps to another. So the only change of saving the changes was the unload process and it now can't be done without the STUPID question if the user wants to change it... of course he wants and I didnt want to prevent that...
hope chrome resolves this in a more elegant way soon.
Try this, it worked for me:
window.onbeforeunload = function(event) {
event.returnValue = "Write something clever here..";
};
Try this. I've tried it and it works. Interesting but the Succes message doesn`t need confirmation like the other message.
window.onbeforeunload = function()
{
if ( window.XMLHttpRequest )
{
console.log("before"); //alert("before");
var request = new XMLHttpRequest();
request.open("POST", "exit.php", true);
request.onreadystatechange = function () {
if ( request.readyState == 4 && request.status == 200 )
{
console.log("Succes!"); //alert("Succes!");
}
};
request.send();
}
}
None of the above worked for me. I was sending a message from the content script -> background script in the before unload event function. What did work was when I set persistent to true (in fact you can just remove the line altogether) in the manifest:
"background": {
"scripts": [
"background.js"
],
"persistent": true
},
The logic is explained at this SO question here.
Current versions of Chrome require setting the event's returnValue property. Simply returning a string from the event handler won't trigger the alert.
addEventListener('beforeunload', function(event) {
event.returnValue = 'You have unsaved changes.';
});
I'm running Chrome on MacOS High Sierra and have an Angular 6 project whithin I handle the window.beforeunload an window.onbeforeunload events. You can do that, it's worked for me :
handleUnload(event) {
// Chrome
event.returnValue = true;
}
It show me an error when I try to put a string in event.returnValue, it want a boolean.
Don't know if it allows custom messages to display on the browser.
<script type="text/javascript">
window.addEventListener("beforeunload", function(e) {
e.preventDefault(); // firefox
e.returnValue = ''; // Chrome
});
</script>

Resources