web-dev-qa-db-fra.com

Test React Sélectionnez le composant

https://github.com/JedWatson/react-select

Je voudrais utiliser le composant React-Select React, mais je dois ajouter des tests.

J'ai essayé plusieurs options que j'ai trouvées avec google, mais rien ne semble fonctionner. J'ai le code ci-dessous, mais il ne provoque pas d'événement de changement. J'ai pu ajouter un événement focus, qui ajoute la classe "is-focus", mais la classe "is-open" est toujours manquante.

J'ai utilisé: https://github.com/JedWatson/react-select/blob/master/test/Select-test.js comme référence

J'ai essayé d'utiliser un événement de changement uniquement sur le champ de saisie, mais cela n'a pas aidé non plus. J'ai remarqué qu'il y a onInputChange={this.change} pour la sélection.

Test

import Home from '../../src/components/home';
import { mount } from 'enzyme'

describe('Home', () => {

it("renders home", () => {

    const component = mount(<Home/>);

    // default class on .Select div
    // "Select foobar Select--single is-searchable"

    const select = component.find('.Select');

    // After focus event
    // "Select foobar Select--single is-searchable is-focussed"
    // missing is-open
    TestUtils.Simulate.focus(select.find('input'));

    //this is not working
    TestUtils.Simulate.keyDown(select.find('.Select-control'), { keyCode: 40, key: 'ArrowDown' });
    TestUtils.Simulate.keyDown(select.find('.Select-control'), { keyCode: 13, key: 'Enter' });

    // as per code below I expect the h2 to have the select value in it eg 'feaure'

});
});

Composant sous test

import React, { Component } from 'react';
import Select from 'react-select';

class Home extends Component {
constructor(props) {
    super(props);

    this.state = {
        message: "Please select option"};
    this.change = this.change.bind(this);
}

change(event) {

    if(event.value) {
        this.setState({message: event.label});
    }
}

render () {

    const options = [ {label: 'bug', value: 1} , {label: 'feature', value: 2 }, {label: 'documents', value: 3}, {label: 'discussion', value: 4}];

    return (
      <div className='content xs-full-height'>
          <div>
              <h2>{this.state.message}</h2>

              <Select
                  name="select"
                  value={this.state.message}
                  options={options}
                  onInputChange={this.change}
                  onChange={this.change}
              />

          </div>
        </div>
    );
}
}

export default Home;

Ligne de commande Pour exécuter le test, je fais:

>> npm run test

et dans package.js j'ai ce script:

"test": "mocha --compilers js:babel-core/register -w test/browser.js ./new",

Configuration du test

et browser.js est:

import 'babel-register';
import jsdom from 'jsdom';

const exposedProperties = ['window', 'navigator', 'document'];

global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
   if (typeof global[property] === 'undefined') {
       exposedProperties.Push(property);
       global[property] = document.defaultView[property];
   }
});

global.navigator = {
    userAgent: 'node.js'
};

J'ai également essayé d'utiliser des méthodes de test décrites ici: https://github.com/StephenGrider/ReduxSimpleStarter

Toute aide sera fortement appréciée

16
Llewellyn

De https://github.com/JedWatson/react-select/issues/1357

La seule solution que j'ai trouvée était de simuler une sélection à travers des événements de frappe:

wrapper.find('.Select-control').simulate('keyDown', { keyCode: 40 });
// you can use 'input' instead of '.Select-control'
wrapper.find('.Select-control').simulate('keyDown', { keyCode: 13 });
expect(size).to.eql('your first value in the list')
16
Keith

J'ai essayé les deux réponses énumérées ci-dessus, et toujours pas de chance.

Ce qui a fonctionné pour moi, c'est:

  1. Ajoutez classNamePrefix prop - c'est-à-dire list (comme mentionné dans les autres réponses):

    <Select
       classNamePrefix='list'
       options={[
         { label: 'one', value: 'one' },
         { label: 'two', value: 'two' }
    ]}/>
    
  2. sélectionnez l'indicateur de liste déroulante et simulez un mouseDown => liste déroulante ouverte:

    wrapper
      .find('.list__dropdown-indicator')
      .simulate('mouseDown', {
        button: 0 
      });
    
  3. s'attendre à ce que des choses se produisent, c'est-à-dire que dans mon cas, je vérifiais le nombre d'options déroulantes

    expect(wrapper.find('.list__option').length).toEqual(2);
    

    si vous avez le contrôle sur les accessoires envoyés, vous pouvez ajouter un accessoire menuIsOpen pour que le menu soit toujours ouvert (aka étape 2 dans la liste).

Pour sélectionner une valeur dans la liste déroulante, après avoir ouvert la liste déroulante:

wrapper.find('.list__option').last().simulate('click', null);

alors vous pouvez tester soit:

expect(wrapper.find('.list__value-container').text()).toEqual('two');

ou

expect(wrapper.find('.list__single-value').text()).toEqual('two');
14
Sanda

Pour ajouter à ce que Keith a dit, l'utilisation de la méthode de simulation semble être le seul moyen d'exercer la fonctionnalité. Cependant, lorsque j'ai essayé cela dans ma solution, cela n'a pas fonctionné - j'utilise TypeScript, donc je ne sais pas si cela a un roulement, mais j'ai trouvé qu'il est également nécessaire de passer la propriété key lors de la simulation de la un événement:

wrapper.find('.Select-control').simulate('keyDown', { key: 'ArrowDown', keyCode: 40 });
wrapper.find('.Select-control').simulate('keyDown', { key: 'Enter', keyCode: 13 });

J'ai également constaté qu'en définissant la propriété classNamePrefix, il était beaucoup plus facile de faire un test simple pour me donner l'assurance que le composant répondait correctement aux événements simulés. Lors de la définition de ce préfixe, les parties utiles du composant sont décorées avec des noms de classe facilitant leur accès (vous pouvez identifier ces noms de classe utiles en inspectant les éléments dans les outils de développement Google). Un test Jest simple:

it('react-select will respond to events correctly', () => {
    const sut = Enzyme.mount(
    <Select 
        classNamePrefix="list" 
        options={[{ label: 'item 1', value: 1 }]}
    />);

    // The intereactive element uses the suffix __control **note there are two underscores** 
    sut.find('.list__control').first().simulate('keyDown', { key: 'ArrowDown', keyCode: 40 });
    sut.find('.list__control').first().simulate('keyDown', { key: 'Enter', keyCode: 13 });

    // the selected value uses the suffix __single-value **note there are two underscores** 
    expect(sut.find('.list__single-value').first().text()).toEqual('item 1');
});
3
Code Ranger

Pour la nouvelle version de react-select (2.x +), la méthode ci-dessus ne fonctionne pas car react-select utilise l'émotion. Ainsi, wrapper.find('.Select-control') ou wrapper.find('.list__option') ne fonctionne plus. react-select 2.x + encapsule le composant Select à l'intérieur d'un gestionnaire d'état mais vous pouvez accéder à la méthode onChange du composant Select. J'utilise le code suivant pour déclencher la sélection:

wrapper.find(Select).props().onChange({ value: ... })
2
Armin Primadi

Je veux juste ajouter, j'ai en fait e pour ajouter le prop classNamePrefix au composant Select sinon je n'ai pas eu de *__control classes à verrouiller.

1
Quinton Aiken

Si quelqu'un utilise une enzyme, cela a fonctionné pour moi:

  wrapper.find('Select').simulate('change', {
    target: { name: 'select', value: 1 },
  });

où "sélectionner" est le nom de l'attribut tel que défini ici:

  <Select
      name="select"
      ...

et "valeur" est la valeur de l'option souhaitée.

0
AnaPana

Pour ceux qui utilisent l'enzyme v3.11.0 et React-Select v3.0.8, cela a fonctionné pour moi

component.find('Select').simulate('keyDown', { key: 'ArrowDown', keyCode: 40 });

Voici mon Select. Je l'utilise avec redux-form

<Select
    {...input}
    styles={customStyles}
    options={props.options}
    formatGroupLabel={formatGroupLabel}
    placeholder="Custom Search..."
    isSearchable={true}
    onBlur={handleBlur}
/>

Échantillon des tests

it('should render dropdown on keyDown', () => {
    expect(component.find('MenuList').length).toEqual(1);
});

it('should render the correct amount of options', () => {
    expect(component.find('Option').length).toEqual(optionsLength);
});
0
Sasha

Utilisation de testing-library et v2.0

Essayer d'éviter d'utiliser quelque chose de très spécifique comme classNamePrefix ou de pirater le fonctionnement du composant en recherchant l'accessoire onChange ou autre.

const callback = jest.fn();
const { container, getByText} = render(<Select ... onChange={callback} />);

Maintenant, nous prétendons être un lecteur d'écran et nous concentrer, et appuyez sur la flèche vers le bas.

fireEvent.focus(container.querySelector('input'));
fireEvent.keyDown(container.querySelector('input'), { key: 'ArrowDown', code: 40 });

Et maintenant, cliquez sur la valeur souhaitée

fireEvent.click(getByText('Option Two'));

Et affirmez.

expect(callback).toHaveBeenCalledWith({ value: 'two', label: 'Option Two'});
0
Dmitriy Likhten