Search code examples
javascriptreactjstampermonkeyreact-testing-libraryclient-side-scripting

How to simulate click in react app using tampermonkey?


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?


Solution

  • 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);