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.

ffxsam
la source

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.

Tyler Collier
la source
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).

Bjudson
la source
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();
  });
ffxsam
la source
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.

Y2H
la source
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();
erika_dike
la source
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);

la source
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.

Joe King
la source
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);
SunshinyDoyle
la source
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.

Anupam Maurya
la source
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 = "[email protected]";
    user.simulate('change');
    expect(login.state('mailValid')).toBe(true);

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

cabaji99
la source
0

Cela a fonctionné pour moi:

let wrapped = mount(<Component />);
expect(wrapped.find("input").get(0).props.value).toEqual("something");
Mahmoud Abd AL Kareem
la source
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)

César Palacios
la source
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é

Daniel Santana
la source
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: '[email protected]', name: 'email' } })
emailField.simulate('blur')
Farhan Haider
la source
-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!

Jee Mok
la source
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