4

I am trying to simulate a click on a React element using a Tampermonkey script. Unfortunately, since React has its own shadow DOM, the naive approaches using document.querySelector() don't work. I came across some solutions that require modification to the react components themselves, while some others try to leverage React test utils, neither of which are great in the Tampermonkey context.

To summarize my question: I have to click on a component "managed" using React. Is there any way to do this from Tampermonkey (which uses plain old javascript)?

Simulate click event on react element How to programmatically fill input elements built with React? https://reactjs.org/docs/test-utils.html

Is there a plain old javascript approach to firing a click event at a dynamically generated react element?

Code:

The selector for the element I want is #rubric_criterion_8 > div > table > tbody > tr:nth-child(5) > td.level-description, which works fine with document.querySelector(). But the click event does not work.

The relevant react component is below (from Chrome Dev Tools):

export class MarksPanel extends React.Component {
  static defaultProps = {
    marks: []
  };

  constructor(props) {
    super(props);
    this.state = {
      expanded: new Set(),
    }
  }

  componentDidMount() {
    if (!this.props.released_to_students) {
      // TODO: Convert this to pure React
      // Capture the mouse event to add "active-criterion" to the clicked element
      $(document).on('click', '.rubric_criterion, .flexible_criterion, .checkbox_criterion', (e) => {
        let criterion = $(e.target).closest('.rubric_criterion, .flexible_criterion, .checkbox_criterion');
        if (!criterion.hasClass('unassigned')) {
          e.preventDefault();
          activeCriterion(criterion);
        }
      });
    }

//more code...

It seems like if I can get access to the react component, then I can send the proper setState. But is this feasible from Tampermonkey?

information_interchange
  • 2,538
  • 6
  • 31
  • 49
  • Why do you not have access to the react component? Looks like you have the component there in your question, does setting an event listener in react not suit your needs? – Drew Reese Mar 02 '20 at 07:14
  • Did you try to simulate mouse down and mouse up? Make sure to put the right coordinates in also. I'm not sure how react evaluates the events, so you want to make them as real as possible. – Tomáš Zato Mar 02 '20 at 11:58
  • Thanks for the replies everyone. @DrewReese I have access to the react component via the react dev tools Chrome extension; I don't think that this is a programmatic way of accessing the component (I would need to inject/modify the react component on the client side, which I think would be needlessly painful) – information_interchange Mar 02 '20 at 20:54
  • @TomášZato-ReinstateMonica I tried the answer in https://stackoverflow.com/questions/40091000/simulate-click-event-on-react-element, which handles mouse-up/mouse-down events but it didn't work – information_interchange Mar 02 '20 at 20:58

1 Answers1

3

OK, I figured it out. As it turns out, you can interact with the React-generated elements (for the most part) via regular javascript. However, you need to wait for the elements to actually be generated! Hence, my original script worked, I just needed to delay execution of it until the document was ready, which I hacked together using a setTimeout, since I didn't want to add a jquery dependency to my Tampermonkey script.

Here is a minimal working example of the script:

function enter_marks(){

    console.log("script running");
    const set_mark = document.querySelector("#rubric_criterion_8 > div > table > tbody > tr:nth-child(5)").click()
    console.log("Mark set!")
    console.log("finished execution");
}

setTimeout(enter_marks,2000);
information_interchange
  • 2,538
  • 6
  • 31
  • 49