web-dev-qa-db-fra.com

Comment remplir par programmation des éléments d'entrée construits avec React?

Je suis chargé de l'exploration du site Web construit avec React. J'essaie de remplir les champs de saisie et de soumettre le formulaire en utilisant des injections javascript à la page (soit Selenium ou Webview dans un mobile). Cela fonctionne comme un charme sur tous les autres sites + technologies mais React semble être une vraie douleur.

voici donc un exemple de code

var email = document.getElementById( 'email' );
email.value = '[email protected]';

I la valeur change sur l'élément d'entrée DOM, mais le React ne déclenche pas l'événement change.

J'ai essayé une multitude de façons différentes d'obtenir le React pour mettre à jour l'état.

var event = new Event('change', { bubbles: true });
email.dispatchEvent( event );

en vain

var event = new Event('input', { bubbles: true });
email.dispatchEvent( event );

ca ne fonctionne pas

email.onChange( event );

ca ne fonctionne pas

Je ne peux pas croire que l'interaction avec React a été rendue si difficile. J'apprécierais grandement toute aide.

Je vous remercie

17
Timo Kauranen

React écoute l'événement input des champs de texte.

Vous pouvez modifier la valeur et déclencher manuellement un événement d'entrée, et le gestionnaire onChange de react déclenchera:

class Form extends React.Component {
  constructor(props) {
    super(props)
    this.state = {value: ''}
  }
  
  handleChange(e) {
    this.setState({value: e.target.value})
    console.log('State updated to ', e.target.value);
  }
  
  render() {
    return (
      <div>
        <input
          id='textfield'
          value={this.state.value}
          onChange={this.handleChange.bind(this)}
        />
        <p>{this.state.value}</p>
      </div>      
    )
  }
}

ReactDOM.render(
  <Form />,
  document.getElementById('app')
)

document.getElementById('textfield').value = 'foo'
const event = new Event('input', { bubbles: true })
document.getElementById('textfield').dispatchEvent(event)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'></div>
10
Timo

Cette solution acceptée semble ne pas fonctionner dans React> 15.6 (y compris React 16) à la suite de modifications apportées à la déduplication des entrées et aux événements de modification).

Vous pouvez voir la discussion React ici: https://github.com/facebook/react/issues/10135

Et la solution de contournement suggérée ici: https://github.com/facebook/react/issues/10135#issuecomment-314441175

Reproduit ici pour plus de commodité:

Au lieu de

input.value = 'foo';
input.dispatchEvent(new Event('input', {bubbles: true}));

Vous utiliseriez

function setNativeValue(element, value) {
  const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
  const prototype = Object.getPrototypeOf(element);
  const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;

  if (valueSetter && valueSetter !== prototypeValueSetter) {
    prototypeValueSetter.call(element, value);
  } else {
    valueSetter.call(element, value);
  }
}

puis

setNativeValue(input, 'foo');
input.dispatchEvent(new Event('input', { bubbles: true }));
11
meriial