Enzima: ¿Cómo acceder y configurar el valor <input>?

90

Estoy confundido acerca de cómo acceder al <input>valor cuando lo uso mount. Esto es lo que tengo como prueba:

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

Se imprime la consola undefined. Pero si modifico ligeramente el código, funciona:

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

Excepto, por supuesto, que la input.simulatelínea falla ya que la estoy usando renderahora. Necesito que ambos funcionen correctamente. ¿Cómo puedo solucionar esto?

EDITAR :

Debo mencionar <EditableText />que no es un componente controlado. Pero cuando paso defaultValueen <input />, al parecer para ajustar el valor. El segundo bloque de código anterior imprime el valor y, de la misma manera, si inspecciono el elemento de entrada en Chrome y escribo $0.valueen la consola, muestra el valor esperado.

ffxsam
fuente

Respuestas:

99

Creo que lo que quieres es:

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

Aquí está mi fuente .

No debería necesitar usar render()ningún lugar para establecer el valor. Y solo para su información, está utilizando dos diferentes render(). El que está en su primer bloque de código es de Enzyme, y es un método en el objeto envoltorio mounty le findproporciona. El segundo, aunque no está 100% claro, es probablemente el de react-dom. Si está utilizando la enzima, sólo tiene que utilizar shallowo mountsegún el caso y no hay necesidad de renderpartir react-dom.

Tyler Collier
fuente
No input.render()es react-domrender. Es esto: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam
3
Además, shallow()no funciona por alguna razón ... el focusevento activa un método que intenta hacer referencia this.refs.input, que falla. Pero cuando intercambiar shallowpara mount, funciona como se esperaba. Principalmente ... (un problema más con la simulación de la tecla ESC)
ffxsam
Debería haber sido más claro. Me refiero al render que parece render(<EditableText defaultValue="Hello" />). Creo que su caso de uso es más especializado de lo que pensaba; Veo que se ocupa de la nota solo con establecer el valor de entrada pero con el enfoque y "cancelar cambios". Sería genial si pudieras crear un plunker .
Tyler Collier
44

Con la Enzima 3 , si necesita cambiar un valor de entrada pero no necesita onChangeactivar la función, simplemente puede hacer esto (la nodepropiedad ha sido eliminada ):

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

Puede usar wrapper.find('input').simulate("change", { target: { value: "foo" }})para invocar onChangesi tiene un accesorio para eso (es decir, para componentes controlados).

bjudson
fuente
7
NOTE: can only be called on a wrapper instance that is also the root instance.- de los documentos en airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb
2
instance()se puede llamar en cualquier contenedor secundario si se procesó a través de mount.
Vladimir Chervanev
41

Entendido. (versión actualizada / mejorada)

  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
fuente
Curioso cómo funciona esto para ti. Estamos usando PhantomJS y mount()no inserta componentes en el DOM. Entonces, no pueden recibir atención. Tenemos que agregar un elemento DOM y usar la contextopción paramount()
Pre101
@ Pre101 De hecho, comencé a usar Jest en lugar de Enzyme. ¡Muy recomendable!
ffxsam
1
@ffxsam: input.get (0) .value siempre muestra "undefined"
Siddharth_Vyas
3
@Siddharth_Vyas tryinput.prop('value')
Ersel Aker
16

Hay muchas opiniones diferentes aquí. Lo único que funcionó para mí fue nada de lo anterior, estaba usando input.props().value. Espero que eso ayude.

Y2H
fuente
1
Esta es la única respuesta que me permitió interrogar el valor de la entrada.
Mojave
1
Cabe destacar que también puede usar: input.prop('value')si conoce el nombre de su clave de apoyo.
Sterling Bourne
4

Estoy usando create-react-app que viene con jest por defecto y enzima 2.7.0.

Esto funcionó para mí:

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

Ninguno de los anteriores funcionó para mí. Esto es lo que funcionó para mí en Enzyme ^ 3.1.1:

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

Aquí está el resto del código para el contexto:

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

fuente
3

Estoy usando react con TypeScript y lo siguiente funcionó para mí

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

Establecer el valor directamente

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

me estaba provocando una advertencia de compilación.

Joe King
fuente
1

Esto me funciona usando la enzima 2.4.1:

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

console.log(input.node.value);
SunshinyDoyle
fuente
4
Cuando comencé a usar Jest / enzima, a menudo console.logbuscaba un objeto y buscaba (sub) propiedades para obtener lo que necesitaba. Al hacerlo, a menudo terminé usando .nodede alguna forma, como tú. Sin embargo, no recuerdo haber .nodesido mencionado en ninguna de la documentación oficial, lo que sugiere que podría cambiar / interrumpirse entre lanzamientos, ya que no forma parte oficialmente de la API anunciada públicamente. Además, a menudo parece haber alternativas. por ejemplo input.node.value=== input.get(0).value. Entonces, .nodepodría funcionar, y sospecho que a veces proporcionará un buen truco, pero utilícelo con precaución.
Andrew Willems
Este ya no es un método público.
Faissaloo
1

aquí está mi código ..

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)

He actualizado mi DOM con componentname.update() Y luego verifiqué la validación del botón de envío (deshabilitar / habilitar) con una longitud de 10 dígitos.

Anupam Maurya
fuente
0

En mi caso, estaba usando devoluciones de llamada de referencia,

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

Para obtener el valor. Así que la enzima no cambiará el valor de this._username.

Entonces tuve que:

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

Para poder establecer el valor, llame al cambio. Y luego afirmar.

cabaji99
fuente
0

Esto funcionó para mí:

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

En caso de que alguien tenga dificultades, encontré lo siguiente que me funciona

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

Parece que primero debe definir lo que sucede en el evento de cambio y luego simularlo (en lugar de simular el evento de cambio con datos)

César Palacios
fuente
0

Resolví de una manera muy simple:

  1. Establezca el valor de los accesorios :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. Código HTML :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Acceda al atributo desde wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

Salud

Daniel Santana
fuente
0

Ninguna de las soluciones anteriores funcionó para mí porque estaba usando Formik y necesitaba marcar el campo como "tocado" junto con cambiar el valor del campo. El siguiente código funcionó para mí.

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

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

.simulate()no funciona para mí de alguna manera, lo hice funcionar con solo acceder node.valuesin necesidad de llamar .simulate(); en tu 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

¡Espero que esto ayude a los demás!

Jee Mok
fuente
Lanza `` `Intentó acceder a ReactWrapper :: node, que anteriormente era una propiedad privada en las instancias de Enzyme ReactWrapper, pero ya no lo es y no se debe confiar en él. Considere utilizar el método getElement () en su lugar. ``
Davi Lima
2
@DaviLima para la versión más reciente de Enzyme, en lugar de .nodedebe usar .instance()o .getDOMNode(), depende de si usó el resultado como ReactElement o DOMComponent.
Jee Mok