Um dia desses recebi um email com uma dúvida específica, sobre como selecionar (com o Protractor) uma data qualquer, quando a aplicação utiliza MaterializeCSS.
Até então eu nunca havia tido que interagir com tal elemento nos projetos em que utilizei Protractor, porém, visto que gosto de explorar novas tecnologias e também gosto de ajudar as pessoas, resolvi experimentar.
A ideia deste post é compartilhar este aprendizado, para o caso em que alguém tenha que lidar com tal situação também.
Aos que preferem ver o código logo, o mesmo pode ser encontrado a partir do seguinte repositório no GitHub.
Aos que preferem acompanhar o processo, desde seu início até a resolução, aí vai:
Inicialmente comecei com alguns testes simples, para entender como o Materialize funciona. Neste momento criei os seguintes casos de teste:
- Clica no campo de data (birthdate) e verifica que o date picker é aberto
- Com o date picker aberto, clica no link Today e verifica que uma data foi selecionada, clica no link Close, e verifica que uma data continua selecionada e que o date picker não está mais aberto
- Com o date picker aberto, clica no link Today, clica no link Clear, e verifica que não há uma data selecionada (uma nova verificação foi adicionada a este caso de teste depois, mais detalhes mais para o final do post)
Até aqui tudo tranquilo. Mas daí chegou a hora de testar a seleção de uma data qualquer no futuro ou no passado. Neste momento resolvi realizar a uma pesquisa no Google, a qual no primeiro resultado me levou ao stackoverflow.
E ali estava exatamente o que eu procurava. O post do stackoverflow comentava sobre a API do datepicker.js, a qual é utilizada pelo Materialize. Neste post foi possível descobrir como setar uma data em um campo date picker, através do seguinte código:
var $input = $('.datepicker').pickadate(); var picker = $input.pickadate('picker');
picker.set('select', [2015, 3, 20]);
Porém, como eu faria para utilizar tal código com o Protractor? Para isso o Protractor dispõe da seguinte função, que pode ser executada pelo navegador. A função executeScript.
A função executeScript funciona da seguinte forma:
// Isto é um exemplo de uso da função executeScript: browser.executeScript("alert('Olá');");
Então eu poderia utilizar a função executeScript do Protractor para executar o código da API do datepicker.js para fazer a seleção de qualquer data. Bastou criar a função auxiliar setDate, a qual pude utilizar nos próximos dois casos de teste:
function setDate(date) { const setDatescript = "var $input = $('.datepicker').pickadate();" + "var picker = $input.pickadate('picker');" + "return picker.set('select', [" + date +"]);"; return setDatescript; }
Os casos de teste criados foram os seguintes:
it('select some date in the future', () => { // In the below date, consider that January is equal to 0, February is 1, ..., December is 11 const futureDate = '2033, 11, 25'; browser.executeScript(setDate(futureDate)); sleepOneSecond(); expect(pickerDaySelected.isPresent()).toBe(true); pickerCloseLink.click(); sleepOneSecond(); // Verificação aqui. }); it('select some date in the past', () => { // In the below date, consider that January is equal to 0, February is 1, ..., December is 11 const pastDate = '1982, 3, 15'; browser.executeScript(setDate(pastDate)); sleepOneSecond(); expect(pickerDaySelected.isPresent()).toBe(true); pickerCloseLink.click(); sleepOneSecond(); // Verificação aqui. });
Observação.: Os sleep times no testes foram adicionados para fins de demonstração quando os testes são executados, para tornar tal execução um pouco mais lenta, para simular a utilização por um humano.
Mas e como verificar que a data correta foi realmente setada? Para isso foi criada uma nova função auxiliar getDate, a qual pode ser consultada a seguir:
function getDate() { const getDatescript = "var $input = $('.datepicker').pickadate();" + "var picker = $input.pickadate('picker');" + "return picker.get();"; return getDatescript; }
Como a função setDate, a função getDate também pode ser executada pela função executeScript do Protractor, porém, de uma forma diferente, onde desta vez se verifica o retorno da promessa de tal função, para fazer a verificação.
it('select some date in the future', () => { // In the below date, consider that January is equal to 0, February is 1, ..., December is 11 const futureDate = '2033, 11, 25'; const year = futureDate.substr(0, 4); const monthAsNumber = futureDate.substr(6, 2); const monthAsString = months[monthAsNumber]; const day = futureDate.substr(10, 2); const dateNewFormat = day + ' ' + monthAsString + ', ' + year; browser.executeScript(setDate(futureDate)); sleepOneSecond(); expect(pickerDaySelected.isPresent()).toBe(true); pickerCloseLink.click(); sleepOneSecond(); browser.executeScript(getDate()).then((date) => { expect(date).toEqual(dateNewFormat); }); }); it('select some date in the past', () => { // In the below date, consider that January is equal to 0, February is 1, ..., December is 11 const pastDate = '1982, 3, 15'; const year = pastDate.substr(0, 4); const monthAsNumber = pastDate.substr(6, 1); const monthAsString = months[monthAsNumber]; const day = pastDate.substr(9, 2); const dateNewFormat = day + ' ' + monthAsString + ', ' + year; browser.executeScript(setDate(pastDate)); sleepOneSecond(); expect(pickerDaySelected.isPresent()).toBe(true); pickerCloseLink.click(); sleepOneSecond(); browser.executeScript(getDate()).then((date) => { expect(date).toEqual(dateNewFormat); }); });
Veja que neste momento, além da verificação adicionada, também foram adicionadas algumas outras variáveis, necessárias para gerar a data em um novo formato, o qual é o retorno da função getDate.
Além disso, para geração da data neste novo formato, o seguinte array de meses foi criado:
const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
E também aproveitei a nova função getDate para adicionar uma nova verificação ao caso de teste que selecionava a data de hoje e logo após a limpava, conforme comentado mais acima. A nova verificação foi a seguinte:
browser.executeScript(getDate()).then((date) => { expect(date).toEqual(''); });
Executando o testes, obtive o seguinte resultado:
> materialize-protractor@0.0.1 test /Users/user/www/materialize-protractor > protractor [23:18:13] I/direct - Using ChromeDriver directly... [23:18:13] I/launcher - Running 1 instances of WebDriver Spec started Started 1 Materialize - Forms ✓ open date picker (5 secs) . ✓ pick today's date and close date picker (5 secs) . ✓ clear birthdate field right after picking today's date (7 secs) . ✓ select some date in the future (5 secs) . ✓ select some date in the past (5 secs) . Executed 5 of 5 specs SUCCESS in 26 secs. 5 specs, 0 failures Finished in 26.226 seconds [23:18:40] I/launcher - 0 instance(s) of WebDriver still running [23:18:40] I/launcher - chrome #01 passed
Uhuu! Tudos os testes passaram.
Ainda há espaço para melhorias, mas por enquanto foi aqui que cheguei, e creio já valer o post para compartilhar com a comunidade.
Uma versão refatorada dos testes está disponível através do seguinte link.
Gostou do post? Gostaria de saber mais o que é possível fazer com o framework Protractor? Veja o livro que publiquei pela editora Casa do Código sobre testes end-to-end automatizados com Protractor.
Bons testes!
=)
Show de bola!! Me ajudou bastante!
Show de bola! Me ajudou bastante!
Valeu!