How do I query an image with a specific ID in Puppeteer? - puppeteer

I need a Page in Puppeteer to wait for a selector to appear - specifically an image with an ID attribute.
I am trying to wait for it to appear so that I can run a Jest assertion on it, and the tag only appears after a response is returned from pressing a button.
I've tried something like this:
await page.waitForSelector('img#testVideoText');
But that doesn't seem to work. How can I query a tag with an ID attribute?

Add some timeout or just add 0 as it disabling the timeout and waitForSelector function will runs forever.
await page.waitForSelector('img#testVideoText', {timeout : 0});

what do you mean by But that doesn't seem to work ... do you get an error or it just doesn't wait for element ? you need to be more specific and add your errors
sometimes element exists on the page , but its not visible
try this
await page.waitForSelector('img#testVideoText', {visible: true});

Related

Wait for form response after submitting with button.click()

I am using Puppeteer to submit a form and I can't figure out how to wait for the response because the normal approaches don't work.
Submitting must be done by invoking click() on the submit button rather than calling form.submit() which on this webpage results in an error that I can't control. Therefore, this does not work:
await page.$eval('#form', form => form.submit);
Submitting the form does not navigate to a new page, but rather modifies the HTML in place. I have also tried waitForNavigation with every waitUntil option, none works.
Are there any other approaches I can try? Thanks
Submitting the form does not navigate to a new page, but rather modifies the HTML in place.
In this case you can wait for a css selector via page.waitForSelector
For example if a success message is shown above your form after a successful submit, just wait for this css selector to appear in the dom:
await page.waitForSelector('form div.success');

Is it true that DIV elements cannot be clicked with selenium Web Driver?

Is it true that DIV elements cannot be clicked with selenium Web Driver?
For Instance, I'm unable to click on delete button in Gmail
Am trying to locate the elemnt using XPATH = //div[#aria-label='Delete']
here, class names and id's are dynamic which changes for every session. Imean, for every Login and Logout. I want my script to be Robust to run at any time.
You can by class name or ID, e.g. with class:
driver.findElement(By.className("class")).click();
Or by element name:
driver.findElement(By.ByTagName("div")).click();
Or find the parent or child a tag.
Have you tried using a different attribute ?
For e.g. you can use
//div[#data-tooltip='Delete']
or
//div[#data-tooltip='Delete']/div/div
It may derive because of gmail has async structure. You may wait to finish request after page load and after select action. If you can share code flow we can examine together.

Update the document.referrer via history.pushState()

I'm using pushStates in my ajax-app to navigate from one "page" to another. Now, I'd like to see from what page I was coming from. But document.referrer always returns "". Or, when I open my app from another page (where it is linked), I got the URL from that other page.
Shouldn't these lines...
history.pushState({}, "Some title", "/some/valid/url/1");
history.pushState({}, "Some title", "/some/valid/url/2");
...produce a referrer like this:
http://somedomain.com/some/valid/url/1
?
Or in other words: Is there any way to set the document.referrer accordingly, or at least reset it to ""?
Note: I'm looking for solutions without caching the previous URL in some variable. I need something that really changes the document.referrer, because I cannot change the scripts that rely on it.
Short Answer: use window.location instead of history.pushState
Longer Answer:
document.referrer according to MDN: "The value is an empty string if the user navigated to the page directly (not through a link, but, for example, via a bookmark)"
Directly manipulating the history state will not be treated as following a link. You can simulate a link click by update window.location (MDN) which will also update the history automatically.
For example, load a tab with https://github.com/kanaka/mal/. Then type the following one line at a time (otherwise they are all run in a single javascript execution context and only the last location update applies)
console.log(history.length) // 2
console.log(document.referrer) // ""
window.location = "/kanaka/mal/tree/master/ada"
console.log(history.length) // 3
console.log(document.referrer) // "https://github.com/kanaka/mal"
window.location = "/kanaka/mal/tree/master/python"
console.log(history.length) // 4
console.log(document.referrer) // "https://github.com/kanaka/mal/tree/master/ada"

How to handle popstate when url ceased to exist?

I would like to be able to do two things with html5 popstate, I'm not using any plugins just these two methods:
Push State:
function contentLoaded(...) {
...
window.history.pushState({ pageUrl: url }, url, url);
...
}
Pop State:
$(window).bind("popstate", function (e) {
if (event.state) {
loadContent(event.state.pageUrl);
}
});
Now if I delete a record, I want to avoid popping a state which couldn't be loaded, just skip it and try popping the next one.
The second question would be: How can I avoid try popping from an empty stack (I have a back button inside my app, but I can get rid of it with an appropriate reason), but keeping clear if the content couldn't be loaded OR if there is no more items in the stack.
History is not meant to be changed afterwards. You should separate the push/popstate functionality from the content loading functionality; think the "router" or "navigator" pattern in typical client-side mvc framework. If a state has become invalid, the content loading code can "redirect" to another state (by calling pushState), just as you would do in regular server-side app.
Just to remind, a client-side application should work identically whether the state was internally popped or the page was actually loaded using the same url, i.e. the HTML5 history support must be transparent, or in other words, the url alone must contain all the information to construct a particular view (but in the case of popstate, we can cheat and reuse the existing state to speed up things).

Clear all fields in a form upon going back with browser back button

I need a way to clear all the fields within a form when a user uses the browser back button. Right now, the browser remembers all the last values and displays them when you go back.
More clarification on why I need this
I've a disabled input field whose value is auto-generated using an algorithm to make it unique within a certain group of data. Once I've submitted the form and data is entered into the database, user should not be able to use the same value again to submit the same form. Hence I've disabled the input field in the first place. But if the user uses the browser back button, the browser remembers the last value and the same value is retained in the input field. Hence the user can submit the form with the same value again.
What I don't understand is what exactly happens when you press the browser back button. It seem like the entire page is retrieved from cache without ever contacting the server if the page size is within the browser cache limit. How do I ensure that the page is loaded from the server regardless of browser setting when you press the browser back button?
Another way without JavaScript is to use <form autocomplete="off"> to prevent the browser from re-filling the form with the last values.
See also this question
Tested this only with a single <input type="text"> inside the form, but works fine in current Chrome and Firefox, unfortunately not in IE10.
Modern browsers implement something known as back-forward cache (BFCache). When you hit back/forward button the actual page is not reloaded (and the scripts are never re-run).
If you have to do something in case of user hitting back/forward keys - listen for BFCache pageshow and pagehide events:
window.addEventListener("pageshow", () => {
// update hidden input field
});
See more details for Gecko and WebKit implementations.
I came across this post while searching for a way to clear the entire form related to the BFCache (back/forward button cache) in Chrome.
In addition to what Sim supplied, my use case required that the details needed to be combined with Clear Form on Back Button?.
I found that the best way to do this is in allow the form to behave as it expects, and to trigger an event:
$(window).bind("pageshow", function() {
var form = $('form');
// let the browser natively reset defaults
form[0].reset();
});
If you are not handling the input events to generate an object in JavaScript, or something else for that matter, then you are done. However, if you are listening to the events, then at least in Chrome you need to trigger a change event yourself (or whatever event you care to handle, including a custom one):
form.find(':input').not(':button,:submit,:reset,:hidden').trigger('change');
That must be added after the reset to do any good.
If you need to compatible with older browsers as well "pageshow" option might not work. Following code worked for me.
$(window).load(function() {
$('form').get(0).reset(); //clear form data on page load
});
This is what worked for me.
$(window).bind("pageshow", function() {
$("#id").val('');
$("#another_id").val('');
});
I initially had this in the $(document).ready section of my jquery, which also worked. However, I heard that not all browsers fire $(document).ready on hitting back button, so I took it out. I don't know the pros and cons of this approach, but I have tested on multiple browsers and on multiple devices, and no issues with this solution were found.
Because I have some complicated forms with some fields that are pre-fill by JS, clearing all fields is not suitable for me. So I found this solution, it detects the page was accessed by hitting the back/forward button and then does a page reload to get everything back to its original state. I think it will be useful to someone:
window.onpageshow = function(event) {
if (event.persisted || performance.getEntriesByType("navigation")[0].type === 'back_forward') {
location.reload();
}
};
As indicated in other answers setting autocomplete to "off" does the trick, but in php, what worked for me looks like this...
$form['select_state'] = array(
'#type' => 'select',
'#attributes' => array('autocomplete' =>'off'),
'#options' => $options_state,
'#default_value' => 'none');