Enzima: come accedere e impostare il valore <input>?


91

Sono confuso su come accedere al <input>valore durante l'utilizzo mount. Ecco cosa ho come 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 viene stampata undefined. Ma se modifico leggermente il codice, funziona:

  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();
  });

Tranne, ovviamente, la input.simulatelinea fallisce poiché sto usando renderora. Ho bisogno di entrambi per funzionare correttamente. Come lo risolvo?

MODIFICA :

Dovrei menzionare, <EditableText />non è un componente controllato. Ma quando passo defaultValuein <input />, sembra impostare il valore. Il secondo blocco di codice sopra stampa il valore e, allo stesso modo, se controllo l'elemento di input in Chrome e digito $0.valuenella console, mostra il valore previsto.

Risposte:


100

Penso che quello che vuoi è:

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

Ecco la mia fonte .

Non dovresti aver bisogno di usare render()ovunque per impostare il valore. E solo per tua informazione, stai usando due diversi render(). Quello nel tuo primo blocco di codice è da Enzyme, ed è un metodo sull'oggetto wraper mounte finddarti. Il secondo, sebbene non sia chiaro al 100%, è probabilmente quello di react-dom. Se stai usando Enzyme, usa shallowo mountcome appropriato e non ce n'è bisogno renderda react-dom.


Non input.render()è il react-domrendering. È questo: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam,

3
Inoltre, shallow()non funziona per qualche motivo .. l' focusevento innesca un metodo che cerca di fare riferimento this.refs.input, che fallisce. Ma quando ho scambiare shallowper mount, esso funziona come previsto. Principalmente .. (un altro problema con la simulazione del tasto ESC)
ffxsam

Avrei dovuto essere più chiaro. Intendevo il rendering che assomiglia render(<EditableText defaultValue="Hello" />). Penso che il tuo caso d'uso sia più specializzato di quanto pensassi; Vedo che si occupa della nota solo con l'impostazione del valore di input ma con lo stato attivo e "l'annullamento delle modifiche". Sarebbe fantastico se potessi creare un plunker .
Tyler Collier

Ciao, ho riscontrato un problema con i valori predefiniti come this.state = {inputNum: 10};, e il Ricevuto sarà sempre 1 anche se il Previsto è 100 come impostato in input.simulate('change', { target: { value: '100' } }). Qualcuno potrebbe aiutare per favore?
nambk

@nambk Sarebbe meglio fare una nuova domanda. Forse ha qualcosa a che fare con le virgolette intorno al file '100'. Non sono sicuro della discrepanza con 10 e 1.
Tyler Collier

44

Con Enzyme 3 , se è necessario modificare un valore di input ma non è necessario attivare la onChangefunzione, è sufficiente farlo (la nodeproprietà è stata rimossa ):

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

Puoi usare wrapper.find('input').simulate("change", { target: { value: "foo" }})per invoke onChangese hai un sostegno per quello (cioè, per i componenti controllati).


7
NOTE: can only be called on a wrapper instance that is also the root instance.- dai documenti su airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb

2
instance()può essere chiamato su qualsiasi child wrapper se è stato reso tramite mount.
Vladimir Chervanev

41

Fatto. (versione aggiornata / migliorata)

  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();
  });

Curioso come funziona per te. Stiamo usando PhantomJS e mount()non inseriamo componenti nel DOM. Quindi, non possono ricevere la concentrazione. Dobbiamo aggiungere un elemento DOM e utilizzare l' contextopzione permount()
Pre101

@ Pre101 In realtà ho iniziato a usare Jest invece di Enzyme. Altamente raccomandato!
ffxsam

1
@ffxsam: input.get (0) .value mostra sempre "undefined"
Siddharth_Vyas

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

16

Quindi molte opinioni diverse qui. L'unica cosa che ha funzionato per me era nessuna delle precedenti, stava usando input.props().value. Spero che aiuti.


1
Questa è l'unica risposta che mi ha permesso di interrogare il valore dell'ingresso.
mojave

1
Da notare, puoi anche usare: input.prop('value')se conosci il nome della tua prop key.
Sterling Bourne

4

Sto usando l'app create-react che viene fornita con jest per impostazione predefinita e l'enzima 2.7.0.

Questo ha funzionato per me:

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

Nessuno dei precedenti ha funzionato per me. Questo è ciò che ha funzionato per me su Enzyme ^ 3.1.1:

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

Ecco il resto del codice per il contesto:

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

Sto usando React con TypeScript e quanto segue ha funzionato per me

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

Impostazione diretta del valore

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

mi stava causando un avviso di compilazione.


1

Questo funziona per me usando l'enzima 2.4.1:

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

console.log(input.node.value);

4
Quando ho iniziato a usare Jest / enzyme, ho spesso console.logun oggetto e ho scavato nelle (sotto) proprietà per ottenere ciò di cui avevo bisogno. In questo modo, ho spesso finito per usare .nodein qualche forma, come hai fatto tu. Tuttavia, non ricordo di aver visto .nodeessere menzionato in nessuna documentazione ufficiale, suggerendo che potrebbe cambiare / interrompersi tra le versioni poiché non fa ufficialmente parte dell'API pubblicamente pubblicizzata. Inoltre, spesso sembrano esserci alternative. ad esempio input.node.value=== input.get(0).value. Quindi, .nodepotrebbe funzionare, e sospetto che a volte fornirà un buon trucco, ma usalo con cautela.
Andrew Willems,

Questo non è più un metodo pubblico.
Faissaloo

1

ecco il mio codice ..

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)

Ho aggiornato il mio DOM con componentname.update() E poi controllo la convalida del pulsante di invio (disabilita / abilita) con una lunghezza di 10 cifre.


1

Nel caso qualcuno stia lottando, ho scoperto che quanto segue funziona per me

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

Sembra che sia necessario definire prima cosa accade nell'evento di modifica e poi simularlo (invece di simulare l'evento di modifica con i dati)


Questo ha funzionato per me. Anche se ho dovuto mettere l'evento onChange in act ().
Pankaj

0

Nel mio caso stavo usando i callback ref,

  <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}}
                                                    >

Per ottenere il valore. Quindi l'enzima non cambierà il valore di this._username.

Quindi ho dovuto:

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

Per poter impostare il valore, chiamare change. E poi affermare.


0

Questo ha funzionato per me:

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

0

Ho risolto in modo molto semplice:

  1. Imposta il valore da props :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. Codice html :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Accedi all'attributo da wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

Saluti


0

Nessuna delle soluzioni sopra ha funzionato per me perché stavo usando Formik e avevo bisogno di contrassegnare il campo "toccato" insieme alla modifica del valore del campo. Il codice seguente ha funzionato per me.

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()non funziona per me in qualche modo, ho capito che funziona semplicemente accedendo a node.valuesenza bisogno di chiamare .simulate(); nel tuo caso:

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

Spero che questo aiuti per gli altri!


Genera `` Tentativo di accedere a ReactWrapper :: node, che in precedenza era una proprietà privata sulle istanze di Enzyme ReactWrapper, ma non è più e non dovrebbe essere invocato. Considera invece l'utilizzo del metodo getElement (). ``
Davi Lima

2
@DaviLima per la versione più recente di Enzyme, invece di .nodeusare .instance()o .getDOMNode(), dipende se hai usato il risultato come ReactElement o DOMComponent.
Jee Mok
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.