Enzyme - จะเข้าถึงและตั้งค่า <input> ได้อย่างไร?


91

ฉันสับสนเกี่ยวกับวิธีการเข้าถึงคุ้มค่าเมื่อใช้<input> mountนี่คือสิ่งที่ฉันได้รับจากการทดสอบของฉัน:

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

undefinedคอนโซลพิมพ์ออก แต่ถ้าฉันแก้ไขโค้ดเล็กน้อยมันใช้งานได้:

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

ยกเว้นแน่นอนว่าinput.simulateสายล้มเหลวตั้งแต่renderตอนนี้ฉันใช้งานอยู่ ฉันต้องการทั้งสองอย่างเพื่อให้ทำงานได้อย่างถูกต้อง ฉันจะแก้ไขปัญหานี้ได้อย่างไร

แก้ไข :

ฉันควรพูดถึง<EditableText />ไม่ใช่ส่วนประกอบที่ควบคุมได้ แต่พอผ่านdefaultValueเข้าไป<input />ดูเหมือนว่าจะตั้งค่า บล็อกโค้ดที่สองด้านบนจะพิมพ์ค่าออกมาและในทำนองเดียวกันหากฉันตรวจสอบองค์ประกอบอินพุตใน Chrome และพิมพ์$0.valueในคอนโซลก็จะแสดงค่าที่คาดไว้

คำตอบ:


100

ฉันคิดว่าสิ่งที่คุณต้องการคือ:

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

นี่คือที่มาของฉัน

คุณไม่จำเป็นต้องใช้render()ที่ใดก็ได้ในการตั้งค่า และเพียงแค่ FYI คุณกำลังใช้แตกต่างกันสองrender()'s หนึ่งในบล็อกรหัสแรกของคุณมาจาก Enzyme และเป็นวิธีการบนวัตถุห่อหุ้มmountและfindให้คุณ คนที่สองแม้ว่าจะไม่ 100% react-domชัดเจนอาจเป็นหนึ่งจาก หากคุณกำลังใช้เอนไซม์เพียงใช้shallowหรือmountตามความเหมาะสมและไม่มีความจำเป็นในการจากrenderreact-dom


input.render()ไม่ได้react-domทำให้ นี่คือ: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam

3
นอกจากนี้ยังใช้shallow()ไม่ได้ด้วยเหตุผลบางประการ .. focusเหตุการณ์เรียกใช้เมธอดที่พยายามอ้างอิงthis.refs.inputซึ่งล้มเหลว แต่เมื่อฉันเปลี่ยนไปshallowใช้mountงานได้ตามที่คาดไว้ ส่วนใหญ่ .. (อีกหนึ่งปัญหาในการจำลองคีย์ ESC)
ffxsam

ฉันควรจะชัดเจนมากกว่านี้ render(<EditableText defaultValue="Hello" />)ผมหมายถึงการแสดงผลที่มีลักษณะเหมือน ฉันคิดว่ากรณีการใช้งานของคุณมีความเชี่ยวชาญมากกว่าที่ฉันคิด ฉันเห็นว่ามันเกี่ยวข้องกับการตั้งค่าอินพุต แต่เน้นและ "ยกเลิกการเปลี่ยนแปลง" มันจะดีมากถ้าคุณสามารถสร้างนักกระโดดร่มได้
Tyler Collier

สวัสดีฉันพบปัญหาเกี่ยวกับค่าเริ่มต้นเช่นthis.state = {inputNum: 10};และสิ่งที่ได้รับจะเป็น 1 เสมอแม้ว่าคาดว่าจะเป็น 100 ตามที่ตั้งค่าไว้input.simulate('change', { target: { value: '100' } })ก็ตาม ใครช่วยได้บ้าง
nambk

@nambk ควรถามคำถามใหม่ บางทีมันอาจเกี่ยวข้องกับเครื่องหมายคำพูดรอบ ๆ'100'. ฉันไม่แน่ใจเกี่ยวกับความคลาดเคลื่อนของ 10 และ 1
Tyler Collier

44

ด้วยEnzyme 3หากคุณต้องการเปลี่ยนค่าอินพุต แต่ไม่จำเป็นต้องเริ่มการonChangeทำงานของฟังก์ชันคุณสามารถทำได้ ( nodeคุณสมบัติถูกลบออก ):

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

คุณสามารถใช้wrapper.find('input').simulate("change", { target: { value: "foo" }})เพื่อเรียกใช้onChangeหากคุณมีเสาสำหรับสิ่งนั้น (เช่นสำหรับส่วนประกอบที่ควบคุม)


7
NOTE: can only be called on a wrapper instance that is also the root instance.- จากเอกสารที่airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb

2
instance()สามารถถูกเรียกบนกระดาษห่อเด็ก ๆ mountถ้ามันถูกแสดงผลผ่านทาง
Vladimir Chervanev

41

เข้าใจแล้ว (รุ่นปรับปรุง / ปรับปรุง)

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

อยากรู้ว่าสิ่งนี้เหมาะกับคุณอย่างไร เรากำลังใช้ PhantomJS และmount()ไม่ได้ใส่ส่วนประกอบลงใน DOM ดังนั้นพวกเขาจึงไม่สามารถรับโฟกัสได้ เราต้องเพิ่มองค์ประกอบ DOM และใช้contextตัวเลือกสำหรับmount()
Pre101

@ Pre101 ฉันเริ่มใช้ Jest แทน Enzyme ขอแนะนำ!
ffxsam

1
@ffxsam: input.get (0) .value แสดง "ไม่ได้กำหนด" เสมอ
Siddharth_Vyas

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

16

มีความคิดเห็นที่แตกต่างกันมากมายที่นี่ input.props().valueสิ่งเดียวที่ทำงานสำหรับฉันคือไม่มีการข้างต้นก็คือการใช้ ฉันหวังว่าจะช่วยได้


1
นี่เป็นคำตอบเดียวที่ทำให้ฉันสามารถซักถามค่าของอินพุตได้
โมฮาวี

1
นอกจากนี้คุณยังสามารถใช้: input.prop('value')ถ้าคุณรู้ชื่อของคีย์เสาของคุณ
Sterling Bourne

4

ฉันใช้ create-react-app ซึ่งมาพร้อมกับ jest โดยค่าเริ่มต้นและ enzyme 2.7.0

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

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

ข้างต้นไม่ได้ผลสำหรับฉัน นี่คือสิ่งที่ได้ผลสำหรับฉันกับ Enzyme ^ 3.1.1:

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

นี่คือส่วนที่เหลือของโค้ดสำหรับบริบท:

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

ฉันใช้การตอบสนองกับ TypeScript และสิ่งต่อไปนี้ใช้ได้ผลสำหรับฉัน

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

การตั้งค่าโดยตรง

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

ทำให้ฉันต้องรวบรวมคำเตือน


1

สิ่งนี้ใช้ได้กับฉันโดยใช้เอนไซม์ 2.4.1:

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

console.log(input.node.value);

4
เมื่อฉันเริ่มใช้ Jest / enzyme ฉันมักจะconsole.logสร้างวัตถุและขุดผ่านคุณสมบัติ (ย่อย) เพื่อให้ได้สิ่งที่ฉันต้องการ การทำเช่นนั้นฉันมักจะใช้.nodeในรูปแบบบางอย่างเช่นคุณมี อย่างไรก็ตามฉันจำไม่ได้ว่าเห็น.nodeมีการกล่าวถึงในเอกสารอย่างเป็นทางการใด ๆ โดยบอกว่าอาจมีการเปลี่ยนแปลง / หยุดพักระหว่างการเผยแพร่เนื่องจากไม่ได้เป็นส่วนหนึ่งของ API ที่โฆษณาต่อสาธารณะอย่างเป็นทางการ นอกจากนี้มักจะมีทางเลือกอื่น เช่น===input.node.value input.get(0).valueดังนั้น.nodeอาจใช้งานได้และฉันสงสัยว่าบางครั้งอาจมีการแฮ็กที่ดี แต่ควรใช้ด้วยความระมัดระวัง
Andrew Willems

นี่ไม่ใช่วิธีสาธารณะอีกต่อไป
Faissaloo

1

นี่คือรหัสของฉัน ..

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)

ฉันอัปเดต DOM ด้วยcomponentname.update() แล้วตรวจสอบการตรวจสอบปุ่มส่ง (ปิด / เปิดใช้งาน) ด้วยความยาว 10 หลัก


1

ในกรณีที่ใครก็ตามกำลังดิ้นรนฉันพบว่าสิ่งต่อไปนี้ใช้ได้ผลกับฉัน

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

ดูเหมือนว่าคุณต้องกำหนดสิ่งที่เกิดขึ้นในเหตุการณ์การเปลี่ยนแปลงก่อนแล้วจึงจำลองเหตุการณ์นั้น (แทนที่จะจำลองเหตุการณ์การเปลี่ยนแปลงด้วยข้อมูล)


สิ่งนี้ได้ผลสำหรับฉัน แม้ว่าฉันจะต้องใส่เหตุการณ์ onChange ในการกระทำ ()
Pankaj

0

ในกรณีของฉันฉันใช้การโทรกลับอ้างอิง

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

เพื่อให้ได้ค่า ดังนั้นเอนไซม์จะไม่เปลี่ยนค่าของ this._username.

ดังนั้นฉันต้อง:

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

เพื่อให้สามารถตั้งค่าได้แล้วโทรเปลี่ยน แล้วยืนยัน



0

ฉันแก้ไขด้วยวิธีง่ายๆ:

  1. ตั้งค่าจากอุปกรณ์ประกอบฉาก :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. รหัส Html :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. เข้าถึงแอตทริบิวต์จากwrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

ไชโย


0

วิธีแก้ปัญหาข้างต้นไม่ได้ผลสำหรับฉันเพราะฉันใช้ Formik และฉันจำเป็นต้องทำเครื่องหมายฟิลด์ "สัมผัส" พร้อมกับการเปลี่ยนค่าฟิลด์ รหัสต่อไปนี้ใช้ได้ผลสำหรับฉัน

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()ไม่ทำงานสำหรับฉันอย่างใดผมได้รับมันทำงานที่มีเพียงการเข้าถึงnode.valueโดยไม่จำเป็นต้องโทร.simulate(); ในกรณีของคุณ:

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

หวังว่านี่จะช่วยให้คนอื่น ๆ !


พ่น `` พยายามเข้าถึง ReactWrapper :: node ซึ่งก่อนหน้านี้เป็นคุณสมบัติส่วนตัวบนอินสแตนซ์ Enzyme ReactWrapper แต่ไม่ได้ใช้งานอีกต่อไปและไม่ควรพึ่งพา ลองใช้เมธอด getElement () แทน ``
Davi Lima

2
@DaviLima สำหรับ Enzyme รุ่นใหม่กว่า.nodeคุณควรใช้.instance()หรือ.getDOMNode()ขึ้นอยู่กับว่าคุณใช้ผลลัพธ์เป็น ReactElement หรือ DOMComponent
เจ๊หมอก
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.