Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why .click() is not working on Google Messages?

Tags:

javascript

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 ?

like image 617
delphirules Avatar asked Oct 16 '25 09:10

delphirules


2 Answers

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.

like image 165
haolt Avatar answered Oct 18 '25 01:10

haolt


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.

  • first test: clicking on the button programmatically: failure, due to the flag never being set to true
  • second test: setting the flag programmatically to true, clicking and then setting it to false: success, due to the fact that the flag was true when the click occurred
  • third test: dispatching a mouseenter event over the element, which sets the flag to true, clicking and then dispatching a mouseleave event over it: success, because the mouseenter event has set the flag to true before the click and the mouseleave happened after the click
  • fourth test: clicking on the button when there did not happen a mouseevent since the last mouseleave over the button

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.

like image 25
Lajos Arpad Avatar answered Oct 18 '25 00:10

Lajos Arpad