Enzyme - Comment accéder et définir la valeur <input>?


90

Je ne sais pas comment accéder à la <input>valeur lors de l'utilisation mount. Voici ce que j'ai comme test:

  it('cancels changes when user presses esc', done => {
    const wrapper = mount(<EditableText defaultValue="Hello" />);
    const input = wrapper.find('input');

    console.log(input.render().attr('value'));
    input.simulate('focus');
    done();
  });

La console imprime undefined. Mais si je modifie légèrement le code, cela fonctionne:

  it('cancels changes when user presses esc', done => {
    const wrapper = render(<EditableText defaultValue="Hello" />);
    const input = wrapper.find('input');

    console.log(input.val());
    input.simulate('focus');
    done();
  });

Sauf, bien sûr, la input.simulateligne échoue depuis que je l'utilise rendermaintenant. J'ai besoin des deux pour fonctionner correctement. Comment puis-je réparer ça?

MODIFIER :

Je devrais mentionner, <EditableText />n'est pas un composant contrôlé. Mais quand je passe defaultValuedans <input />, il semble fixer la valeur. Le deuxième bloc de code ci-dessus imprime la valeur, et de même, si j'inspecte l'élément d'entrée dans Chrome et que je tape $0.valuedans la console, il affiche la valeur attendue.

Réponses:


99

Je pense que ce que tu veux c'est:

input.simulate('change', { target: { value: 'Hello' } })

Voici ma source .

Vous ne devriez pas avoir besoin d'utiliser render()n'importe où pour définir la valeur. Et juste pour info, vous utilisez deux différents render(). Celui de votre premier bloc de code provient d'Enzyme et est une méthode sur l'objet wraper mountet findvous donne. Le deuxième, bien qu'il ne soit pas clair à 100%, est probablement celui de react-dom. Si vous utilisez Enzyme, utilisez simplement shallowou mountselon le cas et il n'est pas nécessaire d'utiliser renderfrom react-dom.


Le input.render()n'est pas react-domrendu. C'est ceci: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam

3
De plus, shallow()cela ne fonctionne pas pour une raison quelconque ... l' focusévénement déclenche une méthode qui tente de référencer this.refs.input, qui échoue. Mais quand je change shallowpour mount, cela fonctionne comme prévu. Surtout .. (encore un problème avec la simulation de la touche ESC)
ffxsam

J'aurais dû être plus clair. Je voulais dire le rendu qui ressemble render(<EditableText defaultValue="Hello" />). Je pense que votre cas d'utilisation est plus spécialisé que je ne le pensais; Je vois qu'il traite simplement de la définition de la valeur d'entrée mais avec le focus et "l'annulation des modifications". Ce serait formidable si vous pouviez créer un plunker .
Tyler Collier

44

Avec Enzyme 3 , si vous avez besoin de changer une valeur d'entrée mais que vous n'avez pas besoin de déclencher la onChangefonction, vous pouvez simplement le faire (la nodepropriété a été supprimée ):

wrapper.find('input').instance().value = "foo";

Vous pouvez utiliser wrapper.find('input').simulate("change", { target: { value: "foo" }})pour invoquer onChangesi vous avez un accessoire pour cela (c'est-à-dire pour les composants contrôlés).


7
NOTE: can only be called on a wrapper instance that is also the root instance.- extrait de la documentation sur airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb

2
instance()peut être appelé sur n'importe quel wrapper enfant s'il a été rendu via mount.
Vladimir Chervanev

41

Je l'ai. (version mise à jour / améliorée)

  it('cancels changes when user presses esc', done => {
    const wrapper = mount(<EditableText defaultValue="Hello" />);
    const input = wrapper.find('input');

    input.simulate('focus');
    input.simulate('change', { target: { value: 'Changed' } });
    input.simulate('keyDown', {
      which: 27,
      target: {
        blur() {
          // Needed since <EditableText /> calls target.blur()
          input.simulate('blur');
        },
      },
    });
    expect(input.get(0).value).to.equal('Hello');

    done();
  });

Curieux de savoir comment cela fonctionne pour vous. Nous utilisons PhantomJS et n'insérons mount()pas de composants dans le DOM. Donc, ils ne peuvent pas recevoir de concentration. Nous devons ajouter un élément DOM et utiliser l' contextoption pourmount()
Pre101

@ Pre101 J'ai en fait commencé à utiliser Jest au lieu d'Enzyme. Hautement recommandé!
ffxsam

1
@ffxsam: input.get (0) .value affiche toujours "undefined"
Siddharth_Vyas

3
@Siddharth_Vyas tryinput.prop('value')
Ersel Aker

16

Donc beaucoup d'opinions différentes ici. La seule chose qui a fonctionné pour moi n'était rien de ce qui précède, c'était l'utilisation input.props().value. J'espère que cela aide.


1
C'est la seule réponse qui m'a permis d'interroger la valeur de l'entrée.
mojave

1
À noter, vous pouvez également utiliser: input.prop('value')si vous connaissez le nom de votre clé prop.
Sterling Bourne

4

J'utilise create-react-app qui est livré avec jest par défaut et enzyme 2.7.0.

Cela a fonctionné pour moi:

const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input')[index]; // where index is the position of the input field of interest
input.node.value = 'Change';
input.simulate('change', input);
done();

3

Aucun de ces éléments n'a fonctionné pour moi. C'est ce qui a fonctionné pour moi sur Enzyme ^ 3.1.1:

input.instance().props.onChange(({ target: { value: '19:00' } }));

Voici le reste du code pour le contexte:

const fakeHandleChangeValues = jest.fn();
  const fakeErrors = {
    errors: [{
      timePeriod: opHoursData[0].timePeriod,
      values: [{
        errorIndex: 2,
        errorTime: '19:00',
      }],
    }],
    state: true,
  };
const wrapper = mount(<AccessibleUI
    handleChangeValues={fakeHandleChangeValues}
    opHoursData={opHoursData}
    translations={translationsForRendering}
  />);
const input = wrapper.find('#input-2').at(0);
input.instance().props.onChange(({ target: { value: '19:00' } }));
expect(wrapper.state().error).toEqual(fakeErrors);

3

J'utilise react avec TypeScript et ce qui suit a fonctionné pour moi

wrapper.find('input').getDOMNode<HTMLInputElement>().value = 'Hello';
wrapper.find('input').simulate('change');

Définition directe de la valeur

wrapper.find('input').instance().value = 'Hello'` 

me causait un avertissement de compilation.


1

Cela fonctionne pour moi en utilisant l'enzyme 2.4.1:

const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');

console.log(input.node.value);

4
Quand j'ai commencé à utiliser Jest / enzyme, je cherchais souvent console.logun objet et creusais des (sous-) propriétés pour obtenir ce dont j'avais besoin. Ce faisant, j'ai souvent fini par utiliser .nodesous une forme ou une autre, comme vous l'avez fait. Cependant, je ne me souviens pas avoir .nodeété mentionné dans la documentation officielle, suggérant que cela pourrait changer / rompre entre les versions car il ne fait pas officiellement partie de l'API annoncée publiquement. En outre, il semble souvent y avoir des alternatives. par exemple input.node.value=== input.get(0).value. Donc, cela .nodepourrait fonctionner, et je soupçonne que parfois cela fournira un bon hack, mais à utiliser avec prudence.
Andrew Willems

Ce n'est plus une méthode publique.
Faissaloo

1

voici mon code ..

const input = MobileNumberComponent.find('input')
// when
input.props().onChange({target: {
   id: 'mobile-no',
   value: '1234567900'
}});
MobileNumberComponent.update()
const Footer = (loginComponent.find('Footer'))
expect(Footer.find('Buttons').props().disabled).equals(false)

J'ai mis à jour mon DOM avec componentname.update() Et puis vérifier la validation du bouton d'envoi (désactiver / activer) avec une longueur de 10 chiffres.


0

Dans mon cas, j'utilisais des rappels de référence,

  <input id="usuario" className="form-control" placeholder="Usuario"
                                                       name="usuario" type="usuario"
                                                       onKeyUp={this._validateMail.bind(this)}
                                                       onChange={()=> this._validateMail()}
                                                       ref={(val) =>{ this._username = val}}
                                                    >

Pour obtenir la valeur. L'enzyme ne changera donc pas la valeur de this._username.

J'ai donc dû:

login.node._username.value = "mario@com.com";
    user.simulate('change');
    expect(login.state('mailValid')).toBe(true);

Pour pouvoir définir la valeur, appelez change. Et puis affirmer.


0

Cela a fonctionné pour moi:

let wrapped = mount(<Component />);
expect(wrapped.find("input").get(0).props.value).toEqual("something");

0

Au cas où quelqu'un aurait du mal, j'ai trouvé ce qui suit fonctionnant pour moi

const wrapper = mount(<NewTask {...props} />); // component under test
const textField = wrapper.find(TextField);

textField.props().onChange({ target: { value: 'New Task 2' } })
textField.simulate('change');
// wrapper.update() didn't work for me, need to find element again

console.log(wrapper.find(TextField).props()); // New Task 2

Il semble que vous deviez d'abord définir ce qui se passe dans l'événement de changement, puis le simuler (au lieu de simuler l'événement de changement avec des données)


0

J'ai résolu de manière très simple:

  1. Définissez la valeur des accessoires :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. Code HTML :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Accédez à l'attribut depuis wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

À votre santé


0

Aucune des solutions ci-dessus n'a fonctionné pour moi parce que j'utilisais Formik et que j'avais besoin de marquer le champ "touché" avec le changement de la valeur du champ. Le code suivant a fonctionné pour moi.

const emailField = orderPageWrapper.find('input[name="email"]')

emailField.simulate('focus')
emailField.simulate('change', { target: { value: 'test@example.com', name: 'email' } })
emailField.simulate('blur')


-1

.simulate()ne fonctionne pas pour moi d'une manière ou d'une autre, je l'ai fait fonctionner en accédant simplement au node.valuesans avoir besoin d'appeler .simulate(); dans ton cas:

const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input').at(0);

// Get the value
console.log(input.node.value); // Hello

// Set the value
input.node.value = 'new value';

// Get the value
console.log(input.node.value); // new value

J'espère que cela aidera les autres!


Lance `` Tentative d'accès à ReactWrapper :: node, qui était auparavant une propriété privée sur les instances Enzyme ReactWrapper, mais qui n'est plus et ne doit pas être invoquée. Pensez à utiliser la méthode getElement () à la place. ``
Davi Lima

2
@DaviLima pour la nouvelle version d'Enzyme, au lieu de .nodevous devriez utiliser .instance()ou .getDOMNode(), dépend si vous avez utilisé le résultat en tant que ReactElement ou DOMComponent.
Jee Mok
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.