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
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')
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:
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' }
]}/>
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
});
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');
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');
});
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: ... })
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.
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.
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);
});
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'});