Enzyme - Como acessar e definir o valor de <input>?

91

Estou confuso sobre como acessar o <input>valor ao usar mount. Aqui está o que tenho como meu teste:

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

O console imprime undefined. Mas se eu modificar um pouco o código, ele 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();
  });

Exceto, é claro, a input.simulatelinha falha, já que estou usando renderagora. Eu preciso de ambos para funcionar corretamente. Como faço para corrigir isso?

EDITAR :

Devo mencionar, <EditableText />não é um componente controlado. Mas quando passo defaultValuepara <input />, parece definir o valor. O segundo bloco de código acima imprime o valor e, da mesma forma, se eu inspecionar o elemento de entrada no Chrome e digitar $0.valueno console, ele mostra o valor esperado.

ffxsam
fonte

Respostas:

100

Acho que o que você quer é:

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

Aqui está minha fonte .

Você não deve precisar usar render()nenhum lugar para definir o valor. E apenas para sua informação, você está usando dois diferentes render(). Aquele em seu primeiro bloco de código é da Enzyme e é um método no objeto wraper mounte finddá a você. O segundo, embora não seja 100% claro, é provavelmente o de react-dom. Se você estiver usando Enzyme, apenas use shallowou mountconforme apropriado e não há necessidade renderde react-dom.

Tyler Collier
fonte
O input.render()não é react-domrenderizar. É este: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam
3
Além disso, shallow()não funciona por algum motivo .. o focusevento dispara um método que tenta fazer referência this.refs.input, mas falha. Mas quando troco shallowpor mount, funciona como esperado. Principalmente .. (mais um problema com a simulação da tecla ESC)
ffxsam
Eu deveria ter sido mais claro. Eu quis dizer a renderização que parece render(<EditableText defaultValue="Hello" />). Acho que seu caso de uso é mais especializado do que eu pensava; Vejo que trata da nota apenas com a configuração do valor de entrada, mas com foco e "cancelando alterações". Seria ótimo se você pudesse criar um êmbolo .
Tyler Collier
Olá, tive um problema com os valores padrão, como this.state = {inputNum: 10};, e o recebido sempre será 1, embora o esperado seja 100 conforme definido em input.simulate('change', { target: { value: '100' } }). Alguém poderia ajudar?
nambk
@nambk Seria melhor fazer uma nova pergunta. Talvez tenha algo a ver com as aspas em torno do '100'. Não tenho certeza sobre a discrepância com 10 e 1.
Tyler Collier
44

Com a Enzima 3 , se você precisa alterar um valor de entrada, mas não precisa disparar a onChangefunção, você pode apenas fazer isso (a nodepropriedade foi removida ):

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

Você pode usar wrapper.find('input').simulate("change", { target: { value: "foo" }})para invocar onChangese tiver um prop para isso (ou seja, para componentes controlados).

Bjudson
fonte
7
NOTE: can only be called on a wrapper instance that is also the root instance.- dos documentos em airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb
2
instance()pode ser chamado em qualquer wrapper filho se tiver sido renderizado por meio de mount.
Vladimir Chervanev
41

Entendi. (versão atualizada / melhorada)

  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
fonte
Curioso como isso funciona para você. Estamos usando o PhantomJS e mount()não insere componentes no DOM. Então, eles não podem receber foco. Temos que adicionar um elemento DOM e usar a contextopção paramount()
Pre101
@ Pre101 Na verdade, comecei a usar Jest em vez de Enzyme. Altamente recomendado!
ffxsam
1
@ffxsam: input.get (0) .value sempre exibe "undefined"
Siddharth_Vyas
3
@Siddharth_Vyas tryinput.prop('value')
Ersel Aker,
16

Então, muitas opiniões diferentes aqui. A única coisa que funcionou para mim foi nenhuma das opções acima, estava usando input.props().value. Espero que ajude.

Y2H
fonte
1
Esta é a única resposta que me permitiu interrogar o valor da entrada.
mojave
1
Observe que você também pode usar: input.prop('value')se souber o nome da sua chave de suporte.
Sterling Bourne de
4

Estou usando o aplicativo criar-reagir, que vem com o jest por padrão e a enzima 2.7.0.

Isso funcionou para mim:

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

Nenhuma das opções acima funcionou para mim. Isso é o que funcionou para mim no Enzyme ^ 3.1.1:

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

Aqui está o resto do código para 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);

fonte
3

Estou usando o react com TypeScript e o seguinte funcionou para mim

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

Definir o valor diretamente

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

estava me causando um aviso de compilação.

Joe King
fonte
1

Isso funciona para mim usando a enzima 2.4.1:

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

console.log(input.node.value);
SunshinyDoyle
fonte
4
Quando comecei a usar Jest / enzima, muitas vezes usava console.logum objeto e vasculhava (sub) propriedades para obter o que precisava. Fazendo isso, muitas vezes acabei usando .nodede alguma forma, como você fez. No entanto, não me lembro de ter .nodesido mencionado em qualquer documentação oficial, sugerindo que poderia mudar / quebrar entre os lançamentos, pois não faz parte oficialmente da API anunciada publicamente. Além disso, frequentemente parece haver alternativas. por exemplo input.node.value=== input.get(0).value. Então, .nodepode funcionar, e eu suspeito que às vezes ele fornecerá um bom hack, mas use com cuidado.
Andrew Willems
Este não é mais um método público.
Faissaloo
1

aqui está meu 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)

Eu atualizei meu DOM com componentname.update() E, em seguida, verifiquei a validação do botão de envio (desativar / ativar) com comprimento de 10 dígitos.

Anupam Maurya
fonte
1

No caso de alguém estar com dificuldades, descobri que o seguinte funciona para mim

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 você precisa definir o que acontece no evento de mudança primeiro e, em seguida, simulá-lo (em vez de simular o evento de mudança com dados)

César Palacios
fonte
Isso funcionou para mim. Embora eu tenha que colocar o evento onChange em ação ().
Pankaj
0

No meu caso, eu estava usando callbacks 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}}
                                                    >

Para obter o valor. Portanto, a enzima não mudará o valor de this._username.

Então eu tive que:

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

Para poder definir o valor, chame a mudança. E então afirme.

cabaji99
fonte
0

Isso funcionou para mim:

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

Resolvi de uma forma muito simples:

  1. Defina o valor dos adereços :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. Código Html :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Acesse o atributo de wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

Felicidades

Daniel Santana
fonte
0

Nenhuma das soluções acima funcionou para mim porque eu estava usando o Formik e precisava marcar o campo como "tocado" junto com a alteração do valor do campo. O código a seguir funcionou para mim.

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

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

.simulate()não funciona para mim de alguma forma, consegui funcionar apenas acessando o node.valuesem precisar ligar .simulate(); no seu 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 ajude outras pessoas!

Jee Mok
fonte
Lança `` `Tentativa de acessar ReactWrapper :: node, que era anteriormente uma propriedade privada nas instâncias do Enzyme ReactWrapper, mas não é mais e não deve ser confiável. Considere usar o método getElement (). `` `
Davi Lima
2
@DaviLima para a versão mais recente da Enzyme, em vez de .nodevocê deve usar .instance()ou .getDOMNode(), depende se você usou o resultado como ReactElement ou DOMComponent.
Jee Mok