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.

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.


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


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

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.


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

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

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.


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

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.


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)


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 = "mario@com.com";
    user.simulate('change');
    expect(login.state('mailValid')).toBe(true);

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


0

Isso funcionou para mim:

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

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


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: 'test@example.com', name: 'email' } })
emailField.simulate('blur')


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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.