For study purposes i'm trying to automate message sending on Google Messages (https://messages.google.com/), only by using Javascript.
What i do is, i fill the textarea with message content and click on the send button, all using Javascript.
Filling the textarea is working with no problem, but the click on send button is not.
When navigating to Google Messages, on webmaster tools i can select the send button to get its HTML code :
<button _ngcontent-ng-c1078039276="" mat-button-ripple-uninitialized="" mat-icon-button="" data-e2e-send-text-button="" class="send-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base ng-star-inserted" aria-label="Send RCS message" mat-button-is-fab="false"><span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span><mws-icon _ngcontent-ng-c1078039276="" class="send-icon ng-star-inserted" _nghost-ng-c2331098597=""><svg viewBox="0 0 24 24" class="flip-in-rtl">
<path d="M2,3v18l20,-9L2,3zM4,14l9,-2 -9,-2L4,6.09L17.13,12 4,17.91L4,14z"></path>
</svg></mws-icon><!----><!----><!----><span class="mat-mdc-focus-indicator"></span><span class="mat-mdc-button-touch-target"></span></button>
So i'm using this code to select the button :
document.getElementsByClassName('send-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base ng-star-inserted')
This returns 2 elements. So to simulate the click , tried both [0] and [1] :
document.getElementsByClassName('send-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base ng-star-inserted')[1].click();
But nothing happens. It only works if i manually click on the button with the mouse. I also tried to use [0] instead of [1], but no lucky : the command runs but nothing happens.
What am i missing here ?
If you look at the event handler code, you'll see that they did some tests there. Obviously you won't know what exactly they're doing since it's obfuscated, but my guess is they're testing if the event come from click()
or real user action. Not only Google, but most websites do this to prevent exactly what you're trying, automated scripting.
The way you have searched for your buttons was correct:
console.log(document.getElementsByClassName('send-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base ng-star-inserted'));
<button _ngcontent-ng-c1078039276="" mat-button-ripple-uninitialized="" mat-icon-button="" data-e2e-send-text-button="" class="send-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base ng-star-inserted" aria-label="Send RCS message" mat-button-is-fab="false"><span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span><mws-icon _ngcontent-ng-c1078039276="" class="send-icon ng-star-inserted" _nghost-ng-c2331098597=""><svg viewBox="0 0 24 24" class="flip-in-rtl">
<path d="M2,3v18l20,-9L2,3zM4,14l9,-2 -9,-2L4,6.09L17.13,12 4,17.91L4,14z"></path>
</svg></mws-icon><!----><!----><!----><span class="mat-mdc-focus-indicator"></span><span class="mat-mdc-button-touch-target"></span></button>
Therefore it's safe to assume that clicking on element [0]
and [1]
of the element of those buttons was also correct. Javascript does not provide an easy way to detect whether the click was done programmatically as far as I know, but one can implement mechanisms that make some differentiation between programmatic clicks and nonprogrammatic clicks. Example:
let amIAUser = false;
function myClick(message) {
if (amIAUser) alert(message);
}
let message = "";
let btn = document.getElementsByClassName('send-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base ng-star-inserted')[0];
btn.addEventListener("mouseenter", function() {
amIAUser = true;
});
btn.addEventListener("mouseleave", function() {
amIAUser = false;
});
btn.addEventListener("click", function() {
myClick(message);
});
//first test: click on the button normally, the message being failure. We expect this message not to be shown
message = "failure";
btn.click();
//second test: this time we set amIAUser to true, the message to success, click and then set amIAUser to false again. Expectation: we should see an alert telling us about the success
amIAUser = true;
message = "success";
btn.click();
amIAUser = false;
//third test: this time we trigger mouseenter and then click on the button with the message being "another success". We expect that to be shown as well
message = "another success";
var evObj = document.createEvent( 'Events' );
evObj.initEvent( "mouseenter", true, false );
btn.dispatchEvent( evObj );
btn.click();
evObj = document.createEvent( 'Events' );
evObj.initEvent( "mouseleave", true, false );
btn.dispatchEvent( evObj );
message = "another failure";
btn.click();
<button _ngcontent-ng-c1078039276="" mat-button-ripple-uninitialized="" mat-icon-button="" data-e2e-send-text-button="" class="send-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base ng-star-inserted" aria-label="Send RCS message" mat-button-is-fab="false"><span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span><mws-icon _ngcontent-ng-c1078039276="" class="send-icon ng-star-inserted" _nghost-ng-c2331098597=""><svg viewBox="0 0 24 24" class="flip-in-rtl">
<path d="M2,3v18l20,-9L2,3zM4,14l9,-2 -9,-2L4,6.09L17.13,12 4,17.91L4,14z"></path>
</svg></mws-icon><!----><!----><!----><span class="mat-mdc-focus-indicator"></span><span class="mat-mdc-button-touch-target"></span>Some Text</button>
In the snippet above I'm using a flag to determine whether I think the click was triggered programmatically. In this simple example I will "believe" the click happened normally if a mouseenter preceded it over the element and I will not "believe" it to be a normally triggered event if there was no mouseenter event on the element at all, or a mouseleave event happened on it since the last mouseenter over the element.
So we see that we have a mechanism that makes it difficult for programmers to programmatically click on the button and trigger the same behavior as in normal clicks. Therefore, in the case of your button, you will need to get the script that runs, reverse-engineer the code and look for click
event handlers either manually (searching for words like onclick
, addEventListener
, click
) or more systematically trying to find handlers on an element, an issue discussed here: How to find event listeners on a DOM node in JavaScript or in debugging?
Narrow down the problem-space and find the exact function that you wanted to trigger. See how it differentiates between programmatic clicks and normal clicks, try to understand this differentiation.
Once you understand that, you will know exactly what you need to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With