Enzym - jak uzyskać dostęp i ustawić wartość <input>?

90

Nie mam pojęcia, jak uzyskać dostęp do <input>wartości podczas używania mount. Oto, co mam jako mój 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();
  });

Konsola drukuje undefined. Ale jeśli trochę zmodyfikuję kod, działa:

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

Tyle że, oczywiście, input.simulatelinia zawodzi, ponieważ używam renderteraz. Potrzebuję obu, aby działać poprawnie. Jak to naprawić?

EDYCJA :

Powinienem wspomnieć, że <EditableText />nie jest elementem kontrolowanym. Ale kiedy przechodzę defaultValuedo <input />, wydaje się , że ustawia wartość. Drugi blok kodu powyżej wypisuje wartość i podobnie, jeśli sprawdzę element wejściowy w Chrome i wpiszę $0.valuew konsoli, pokazuje oczekiwaną wartość.

ffxsam
źródło

Odpowiedzi:

99

Myślę, że chcesz:

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

Oto moje źródło .

Nie powinieneś używać render()nigdzie, aby ustawić wartość. I po prostu do Twojej wiadomości, używasz dwóch różnych render(). Ten w twoim pierwszym bloku kodu pochodzi z Enzyme i jest metodą na obiekt opakowujący mounti finddaje. Drugi, choć nie jest w 100% jasny, jest prawdopodobnie tym z react-dom. Jeśli używasz enzym, wystarczy użyć shallowalbo mountjako właściwe i nie ma potrzeby renderz react-dom.

Tyler Collier
źródło
Nie input.render()jest react-domrenderowany. To jest to: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam,
3
Poza shallow()tym z jakiegoś powodu nie działa ... focuszdarzenie wyzwala metodę, która próbuje się odwołać this.refs.input, co kończy się niepowodzeniem. Ale kiedy zamieniam się shallowna mount, działa zgodnie z oczekiwaniami. Głównie ... (jeszcze jeden problem z symulacją klawisza ESC)
ffxsam
Powinienem być bardziej dokładny. Miałem na myśli render, który wygląda render(<EditableText defaultValue="Hello" />). Myślę, że Twój przypadek użycia jest bardziej wyspecjalizowany niż myślałem; Widzę, że zajmuje się uwagą tylko z ustawieniem wartości wejściowej, ale z fokusem i „anulowaniem zmian”. Byłoby wspaniale, gdybyś mógł stworzyć plunkera .
Tyler Collier
44

W przypadku Enzyme 3 , jeśli chcesz zmienić wartość wejściową, ale nie musisz uruchamiać onChangefunkcji, możesz po prostu zrobić to ( nodewłaściwość została usunięta ):

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

Możesz użyć wrapper.find('input').simulate("change", { target: { value: "foo" }})do wywołania, onChangejeśli masz do tego właściwość (np. Dla kontrolowanych komponentów).

bjudson
źródło
7
NOTE: can only be called on a wrapper instance that is also the root instance.- z dokumentacji na airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb
2
instance()można wywołać w dowolnym opakowaniu podrzędnym, jeśli zostało wyrenderowane przez mount.
Vladimir Chervanev
41

Rozumiem. (zaktualizowana / ulepszona wersja)

  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
źródło
Ciekawe, jak to działa dla Ciebie. Używamy PhantomJS i mount()nie wstawiamy komponentów do DOM. Więc nie mogą się skupić. Musimy dodać element DOM i użyć contextopcjimount()
Pre101
@ Pre101 Właściwie zacząłem używać Jest zamiast Enzyme. Wysoce rekomendowane!
ffxsam,
1
@ffxsam: input.get (0) .value zawsze wyświetla „undefined”
Siddharth_Vyas
3
@Siddharth_Vyas tryinput.prop('value')
Ersel Aker
16

Tak wiele różnych opinii tutaj. Jedyną rzeczą, która działała dla mnie, nie było żadne z powyższych, to było używanie input.props().value. Mam nadzieję że to pomogło.

Y2H
źródło
1
To jedyna odpowiedź, która pozwoliła mi zapytać o wartość wejścia.
mojave
1
Warto zauważyć, że możesz również użyć: input.prop('value')jeśli znasz nazwę swojego klucza rekwizytu.
Sterling Bourne
4

Używam aplikacji Create-React-App, która jest domyślnie dostarczana z jest i enzymem 2.7.0.

To zadziałało dla mnie:

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
źródło
3

Żadne z powyższych nie działało dla mnie. Oto, co zadziałało dla mnie w Enzyme ^ 3.1.1:

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

Oto reszta kodu kontekstu:

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

źródło
3

Używam Reaguj z TypeScript i działały dla mnie następujące

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

Bezpośrednie ustawienie wartości

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

powodowało ostrzeżenie dotyczące kompilacji.

Joe King
źródło
1

To działa dla mnie przy użyciu enzymu 2.4.1:

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

console.log(input.node.value);
SunshinyDoyle
źródło
4
Kiedy zacząłem używać Jest / enzyme, często korzystałem console.logz obiektu i przeszukiwałem (pod-) właściwości, aby uzyskać to, czego potrzebowałem. Robiąc to, często kończyłem na używaniu .nodew jakiejś formie, tak jak masz. Jednak nie przypominam sobie, .nodeaby ktoś o tym wspominał w oficjalnej dokumentacji, co sugeruje, że może się to zmieniać / przerywać między wydaniami, ponieważ nie jest oficjalnie częścią reklamowanego publicznie interfejsu API. Często wydaje się, że istnieją alternatywy. np . input.node.value=== input.get(0).value. Więc .nodemoże zadziałać i podejrzewam, że czasami zapewni dobry hack, ale używaj go ostrożnie.
Andrew Willems
To już nie jest metoda publiczna.
Faissaloo
1

oto mój kod ..

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)

Zaktualizowałem swój DOM za pomocą componentname.update() A następnie sprawdzam walidację przycisku przesyłania (wyłącz / włącz) o długości 10 cyfr.

Anupam Maurya
źródło
0

W moim przypadku korzystałem z wywołań zwrotnych,

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

Aby uzyskać wartość. Więc enzym nie zmieni wartości this._username.

Musiałem więc:

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

Aby móc ustawić wartość, wywołaj zmianę. A potem potwierdzaj.

cabaji99
źródło
0

To zadziałało dla mnie:

let wrapped = mount(<Component />);
expect(wrapped.find("input").get(0).props.value).toEqual("something");
Mahmoud Abd AL Kareem
źródło
0

Na wypadek, gdyby ktoś miał problemy, zauważyłem, że działa dla mnie następujący

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

Wygląda na to, że musisz najpierw zdefiniować, co dzieje się w zdarzeniu zmiany, a następnie to zasymulować (zamiast symulować zdarzenie zmiany za pomocą danych)

César Palacios
źródło
0

Rozwiązałem w bardzo prosty sposób:

  1. Ustaw wartość na podstawie rekwizytów :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. Kod HTML :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Uzyskaj dostęp do atrybutu z wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

Twoje zdrowie

Daniel Santana
źródło
0

Żadne z powyższych rozwiązań nie zadziałało, ponieważ korzystałem z Formika i musiałem zaznaczyć pole „dotknięte” wraz ze zmianą wartości pola. Poniższy kod zadziałał dla mnie.

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

emailField.simulate('focus')
emailField.simulate('change', { target: { value: '[email protected]', name: 'email' } })
emailField.simulate('blur')
Farhan Haider
źródło
-1

.simulate()jakoś nie działa dla mnie, działało po prostu uzyskując dostęp do node.valuebez konieczności dzwonienia .simulate(); w Twoim przypadku:

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

Mam nadzieję, że to pomoże innym!

Jee Mok
źródło
Zgłasza `` Próbowano uzyskać dostęp do ReactWrapper :: node, który wcześniej był własnością prywatną w instancjach Enzyme ReactWrapper, ale nie jest już i nie należy na nim polegać. Zamiast tego rozważ użycie metody getElement (). ``
Davi Lima
2
@DaviLima dla nowszej wersji Enzyme, zamiast .nodeużywać .instance()lub .getDOMNode(), zależy od tego, czy użyłeś wyniku jako ReactElement czy DOMComponent.
Jee Mok