Enzym - Wie kann man auf den <input> -Wert zugreifen und ihn einstellen?

90

Ich bin verwirrt darüber, wie ich <input>bei der Verwendung auf Werte zugreifen soll mount. Folgendes habe ich als 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();
  });

Die Konsole wird ausgedruckt undefined. Aber wenn ich den Code leicht ändere, funktioniert es:

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

Außer natürlich, dass die input.simulateLeitung ausfällt, da ich sie renderjetzt benutze . Ich brauche beides, um richtig zu arbeiten. Wie behebe ich das?

EDIT :

Ich sollte erwähnen, <EditableText />ist keine kontrollierte Komponente. Aber wenn ich gehe defaultValuein <input />, so scheint es , um den Wert einzustellen. Der zweite Codeblock oben druckt den Wert aus. Wenn ich das Eingabeelement in Chrome überprüfe und $0.valuedie Konsole eingebe, wird der erwartete Wert angezeigt.

ffxsam
quelle

Antworten:

99

Ich denke, was Sie wollen, ist:

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

Hier ist meine Quelle .

Sie sollten render()nirgendwo etwas verwenden müssen, um den Wert festzulegen. Und nur zu Ihrer Information, Sie verwenden zwei verschiedene render(). Der in Ihrem ersten Codeblock stammt von Enzyme und ist eine Methode für das Wraper-Objekt mountund findgibt Ihnen. Der zweite, obwohl nicht 100% klar, ist wahrscheinlich der von react-dom. Wenn Sie Enzyme verwenden, verwenden Sie einfach shallowoder mountnach Bedarf, und es besteht keine Notwendigkeit für renderfrom react-dom.

Tyler Collier
quelle
Das input.render()wird nicht react-domgerendert. Es ist dies: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam
3
Funktioniert auch shallow()aus irgendeinem Grund nicht. Das focusEreignis löst eine Methode aus, die versucht zu referenzieren this.refs.input, was jedoch fehlschlägt. Aber wenn ich die Swap shallowfür mount, es funktioniert wie erwartet. Meistens .. (ein weiteres Problem mit der Simulation von ESC-Schlüssel)
ffxsam
Ich hätte klarer sein sollen. Ich meinte den Render, der aussieht render(<EditableText defaultValue="Hello" />). Ich denke, Ihr Anwendungsfall ist spezialisierter als ich dachte; Ich sehe, es geht nur darum, den Eingabewert einzustellen, aber um den Fokus und "Änderungen abzubrechen". Es wäre großartig, wenn Sie einen Plunker erstellen könnten .
Tyler Collier
43

Wenn Sie mit Enzym 3 einen Eingabewert ändern müssen, aber die onChangeFunktion nicht auslösen müssen, können Sie dies einfach tun ( nodeEigenschaft wurde entfernt ):

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

Sie können verwenden, wrapper.find('input').simulate("change", { target: { value: "foo" }})um aufzurufen, onChangewenn Sie eine Requisite dafür haben (dh für gesteuerte Komponenten).

bjudson
quelle
7
NOTE: can only be called on a wrapper instance that is also the root instance.- Aus den Dokumenten unter airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
Davidjb
2
instance()kann auf jedem untergeordneten Wrapper aufgerufen werden, wenn er über gerendert wurde mount.
Vladimir Chervanev
39

Ich habs. (aktualisierte / verbesserte Version)

  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
quelle
Neugierig, wie das bei Ihnen funktioniert. Wir verwenden PhantomJS und mount()fügen keine Komponenten in das DOM ein. Sie können also keinen Fokus erhalten. Wir müssen ein DOM-Element hinzufügen und die contextOption fürmount()
Pre101
@ Pre101 Ich habe tatsächlich angefangen, Jest anstelle von Enzyme zu verwenden. Sehr empfehlenswert!
ffxsam
1
@ffxsam: input.get (0) .value zeigt immer "undefined" an
Siddharth_Vyas
3
@ Siddharth_Vyas versucheninput.prop('value')
Ersel Aker
15

Also viele verschiedene Meinungen hier. Das einzige, was für mich funktionierte, war keines der oben genannten, es wurde verwendet input.props().value. Ich hoffe das hilft.

Y2H
quelle
1
Dies ist die einzige Antwort, mit der ich den Wert der Eingabe abfragen konnte.
Mojave
1
Zu beachten ist auch, input.prop('value')dass Sie Folgendes verwenden können: Wenn Sie den Namen Ihres Requisitenschlüssels kennen.
Sterling Bourne
1
Das hat bei mir
funktioniert
4

Ich benutze die Create-React-App, die standardmäßig mit Scherz und Enzym 2.7.0 geliefert wird.

Das hat bei mir funktioniert:

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

Keines der oben genannten hat bei mir funktioniert. Dies hat bei Enzyme ^ 3.1.1 für mich funktioniert:

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

Hier ist der Rest des Codes für den Kontext:

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

quelle
3

Ich verwende Reagieren mit TypeScript und das Folgende hat für mich funktioniert

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

Wert direkt einstellen

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

verursachte mir eine Kompilierungswarnung.

Joe King
quelle
1

Dies funktioniert bei mir mit Enzym 2.4.1:

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

console.log(input.node.value);
SunshinyDoyle
quelle
4
Als ich anfing, Jest / Enzym zu verwenden, habe ich oft console.logein Objekt verwendet und (Unter-) Eigenschaften durchforstet, um das zu bekommen, was ich brauchte. Dabei habe ich oft .nodein irgendeiner Form verwendet, wie Sie es getan haben. Ich kann mich jedoch nicht erinnern, .nodedass dies in einer der offiziellen Dokumentationen erwähnt wurde, was darauf hindeutet, dass es zwischen den Releases geändert / unterbrochen werden könnte, da es nicht offiziell Teil der öffentlich beworbenen API ist. Auch scheint es oft Alternativen zu geben. zB input.node.value=== input.get(0).value. So .nodefunktionieren könnte, und ich vermute , dass manchmal wird es ein gutes Hack bieten, aber mit Vorsicht verwenden.
Andrew Willems
Dies ist keine öffentliche Methode mehr.
Faissaloo
1

Hier ist mein Code ..

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)

Ich habe mein DOM mit aktualisiert componentname.update() und dann die Überprüfung der Senden-Schaltfläche (Deaktivieren / Aktivieren) mit einer Länge von 10 Stellen überprüft.

Anupam Maurya
quelle
0

In meinem Fall habe ich ref Rückrufe verwendet,

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

Um den Wert zu erhalten. Das Enzym ändert also nicht den Wert von this._username.

Also musste ich:

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

Um den Wert einstellen zu können, rufen Sie change auf. Und dann behaupten.

cabaji99
quelle
0

Das hat bei mir funktioniert:

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

Für den Fall, dass jemand Probleme hat, habe ich Folgendes für mich gefunden

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

Es scheint, dass Sie zuerst definieren müssen, was im Änderungsereignis passiert, und es dann simulieren müssen (anstatt das Änderungsereignis mit Daten zu simulieren).

César Palacios
quelle
0

Ich habe auf sehr einfache Weise gelöst:

  1. Stellen Sie den Wert von Requisiten ein :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. HTML-Code :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Besuchen Sie das Attribut aus wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

Prost

Daniel Santana
quelle
-1

.simulate()funktioniert bei mir irgendwie nicht, ich habe es geschafft, nur auf das zuzugreifen, node.valueohne anrufen zu müssen .simulate(); in deinem Fall:

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

Hoffe das hilft für andere!

Jee Mok
quelle
Wirft `` `Es wurde versucht, auf den ReactWrapper :: -Knoten zuzugreifen, der zuvor eine private Eigenschaft in Enzyme ReactWrapper-Instanzen war, aber nicht mehr vorhanden ist und auf den man sich nicht verlassen sollte. Verwenden Sie stattdessen die Methode getElement (). `` `
Davi Lima
2
@DaviLima für die neuere Version des Enzyms, statt .nodeSie verwenden sollten , .instance()oder .getDOMNode()hängt , wenn Sie das Ergebnis als ReactElement oder DOMComponent verwendet.
Jee Mok