Enzim - Bagaimana cara mengakses dan mengatur nilai <input>?

90

Saya bingung tentang cara mengakses <input>nilai saat menggunakan mount. Inilah yang saya dapatkan sebagai ujian saya:

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

Konsol mencetak undefined. Tetapi jika saya sedikit memodifikasi kodenya, ini berfungsi:

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

Kecuali, tentu saja, input.simulatesaluran tersebut gagal karena saya sedang menggunakan rendersekarang. Saya membutuhkan keduanya untuk bekerja dengan baik. Bagaimana cara mengatasinya?

EDIT :

Saya harus menyebutkan, <EditableText />bukan merupakan komponen yang dikendalikan. Tetapi ketika saya masuk defaultValueke <input />, tampaknya mengatur nilainya. Blok kode kedua di atas tidak mencetak nilai, dan juga jika saya memeriksa elemen input di Chrome dan mengetik $0.valuedi konsol, itu menunjukkan nilai yang diharapkan.

ffxsam.dll
sumber

Jawaban:

99

Saya pikir yang Anda inginkan adalah:

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

Ini sumber saya .

Anda tidak perlu menggunakan di render()mana saja untuk menyetel nilainya. Dan hanya untuk diketahui, Anda menggunakan dua yang berbeda render(). Yang ada di blok kode pertama Anda adalah dari Enzim, dan merupakan metode pada objek pembungkus mountdan findmemberi Anda. Yang kedua, meskipun tidak 100% jelas, mungkin dari react-dom. Jika Anda menggunakan Enzim, cukup gunakan shallowatau yang mountsesuai dan tidak perlu renderdari react-dom.

Tyler Collier
sumber
The input.render()tidak react-domrender. Ini dia: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam
3
Selain itu, shallow()tidak berfungsi karena beberapa alasan .. focusperistiwa tersebut memicu metode yang mencoba mereferensikan this.refs.input, yang gagal. Tapi ketika saya swap keluar shallowuntuk mount, itu bekerja seperti yang diharapkan. Sebagian besar .. (satu masalah lagi dengan simulasi kunci ESC)
ffxsam
Saya seharusnya lebih jelas. Maksud saya render yang terlihat seperti itu render(<EditableText defaultValue="Hello" />). Saya pikir kasus penggunaan Anda lebih khusus daripada yang saya kira; Saya melihatnya berhubungan dengan catatan hanya dengan mengatur nilai input tetapi dengan fokus dan "membatalkan perubahan". Akan lebih bagus jika Anda bisa membuat plunker .
Tyler Collier
44

Dengan Enzim 3 , jika Anda perlu mengubah nilai input tetapi tidak perlu mengaktifkan onChangefungsi, Anda dapat melakukannya ( nodeproperti telah dihapus ):

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

Anda dapat menggunakan wrapper.find('input').simulate("change", { target: { value: "foo" }})untuk memanggil onChangejika Anda memiliki prop untuk itu (mis., Untuk komponen yang dikontrol).

bjudson.dll
sumber
7
NOTE: can only be called on a wrapper instance that is also the root instance.- dari dokumen di airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb
2
instance()bisa dipanggil di pembungkus anak mana pun jika dirender melalui mount.
Vladimir Chervanev
41

Mengerti. (versi yang diperbarui / ditingkatkan)

  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.dll
sumber
Penasaran bagaimana ini bekerja untuk Anda. Kami menggunakan PhantomJS dan mount()tidak memasukkan komponen ke DOM. Jadi, mereka tidak bisa menerima fokus. Kita harus menambahkan elemen DOM dan menggunakan contextopsi untukmount()
Pre101
@ Pre101 Saya sebenarnya mulai menggunakan Jest, bukan Enzim. Sangat dianjurkan!
ffxsam
1
@ffxsam: input.get (0) .value selalu menampilkan "undefined"
Siddharth_Vyas
3
@Siddharth_Vyas cobainput.prop('value')
Ersel Aker
16

Begitu banyak perbedaan pendapat di sini. Satu-satunya hal yang berhasil bagi saya adalah tidak satu pun di atas, itu digunakan input.props().value. Saya harap itu membantu.

Y2H
sumber
1
Ini adalah satu-satunya jawaban yang memungkinkan saya untuk menginterogasi nilai masukan.
mojave
1
Catatan, Anda juga dapat menggunakan: input.prop('value')jika Anda tahu nama kunci prop Anda.
Sterling Bourne
4

Saya menggunakan create-react-app yang dilengkapi dengan lelucon secara default dan enzyme 2.7.0.

Ini berhasil untuk saya:

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
sumber
3

Semua hal di atas tidak berhasil untuk saya. Inilah yang berhasil untuk saya di Enzim ^ 3.1.1:

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

Berikut adalah kode lainnya untuk konteks:

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

sumber
3

Saya menggunakan react dengan TypeScript dan yang berikut ini berhasil untuk saya

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

Mengatur nilai secara langsung

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

menyebabkan saya peringatan kompilasi.

Joe King
sumber
1

Ini berfungsi untuk saya menggunakan enzyme 2.4.1:

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

console.log(input.node.value);
SunshinyDoyle
sumber
4
Ketika saya mulai menggunakan Jest / enzyme, saya sering console.logmenggunakan objek dan menggali (sub-) properti untuk mendapatkan apa yang saya butuhkan. Melakukannya, saya sering berakhir menggunakan .nodedalam beberapa bentuk, seperti yang Anda miliki. Namun, saya tidak ingat pernah melihat .nodedisebutkan dalam dokumentasi resmi mana pun, menyarankan itu dapat berubah / putus di antara rilis karena itu bukan bagian resmi dari API yang diiklankan secara publik. Juga, tampaknya sering ada alternatif. misalnya input.node.value=== input.get(0).value. Jadi, .nodemungkin berhasil, dan saya curiga terkadang ini akan memberikan peretasan yang baik, tetapi gunakan dengan hati-hati.
Andrew Willems
Ini bukan lagi metode publik.
Faissaloo
1

ini kode saya ..

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)

Saya telah memperbarui DOM saya dengan componentname.update() Dan kemudian memeriksa validasi tombol kirim (nonaktifkan / aktifkan) dengan panjang 10 digit.

Anupam Maurya
sumber
0

Dalam kasus saya, saya menggunakan 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}}
                                                    >

Untuk mendapatkan nilai. Jadi enzyme tidak akan merubah nilai this._username.

Jadi saya harus:

login.node._username.value = "[email protected]";
    user.simulate('change');
    expect(login.state('mailValid')).toBe(true);

Untuk dapat mengatur nilai maka panggil ubah. Dan kemudian tegaskan.

cabaji99.dll
sumber
0

Ini berhasil untuk saya:

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

Jika ada yang berjuang, saya menemukan yang berikut bekerja untuk saya

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

Tampaknya Anda perlu menentukan apa yang terjadi dalam peristiwa perubahan terlebih dahulu dan kemudian mensimulasikannya (alih-alih mensimulasikan peristiwa perubahan dengan data)

César Palacios
sumber
0

Saya memecahkannya dengan cara yang sangat sederhana:

  1. Tetapkan nilai dari alat peraga :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. Kode HTML :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Akses atribut dari wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

Bersulang

Daniel Santana
sumber
0

Tidak ada solusi di atas yang berhasil untuk saya karena saya menggunakan Formik dan saya perlu menandai bidang "tersentuh" ​​bersama dengan mengubah nilai bidang. Kode berikut berhasil untuk saya.

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

emailField.simulate('focus')
emailField.simulate('change', { target: { value: '[email protected]', name: 'email' } })
emailField.simulate('blur')
Farhan Haider
sumber
-1

.simulate()tidak bekerja untuk saya entah bagaimana, saya membuatnya bekerja dengan hanya mengakses node.valuetanpa perlu menelepon .simulate(); dalam kasus Anda:

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

Semoga ini bisa membantu orang lain!

Jee Mok
sumber
Melempar `` Mencoba mengakses ReactWrapper :: node, yang sebelumnya merupakan properti pribadi pada instance Enzyme ReactWrapper, tetapi tidak lagi dan tidak boleh diandalkan. Pertimbangkan untuk menggunakan metode getElement () sebagai gantinya. ``
Davi Lima
2
@DaviLima untuk versi Enzim yang lebih baru, alih-alih .nodeAnda harus menggunakan .instance()atau .getDOMNode(), tergantung apakah Anda menggunakan hasilnya sebagai ReactElement atau DOMComponent.
Jee Mok