Como usar o transferidor para verificar se um elemento está visível?

111

Estou tentando testar se um elemento é visível usando o transferidor. Esta é a aparência do elemento:

<i class="icon-spinner icon-spin ng-hide" ng-show="saving"></i>

Quando no console do Chrome, posso usar este seletor jQuery para testar se o elemento está visível:

$('[ng-show=saving].icon-spin')
[
<i class=​"icon-spinner icon-spin ng-hide" ng-show=​"saving">​</i>​
]
> $('[ng-show=saving].icon-spin:visible')
[]

No entanto, quando tento fazer o mesmo no transferidor, recebo este erro no tempo de execução:

InvalidElementStateError: 
invalid element state: Failed to execute 'querySelectorAll' on 'Document': 
'[ng-show=saving].icon-spin:visible' is not a valid selector.

Por que isso não é válido? Como posso verificar a visibilidade usando o transferidor?

limp_chimp
fonte
Ei @limp_chimp minha resposta abaixo ajudou você?
Leo Gallucci
@limp_chimp para coisas como visibilidade, pense em usar testes de unidade DOM do cliente AngularJS. Eles são muito mais rápidos de executar e mais fáceis de desenvolver.
Offirmo

Respostas:

144

Isso deve servir:

expect($('[ng-show=saving].icon-spin').isDisplayed()).toBe(true);

Lembre-se de que o transferidor $não é jQuery e ainda:visible não faz parte dos seletores + pseudo-seletores CSS disponíveis

Mais informações em https://stackoverflow.com/a/13388700/511069

Leo Gallucci
fonte
1
Aw, meu. Tão legal. Isso é exatamente o que eu precisava ser capaz de determinar. Muito obrigado cara.
racl101
2
A resposta abaixo também usa, isDisplayed()mas apenas se expande para resolver a promessa de integridade, embora essa etapa seja opcional e destinada apenas a incluir condicionais em seus testes, o que é uma prática ruim. @asenovm, você pode elaborar mais o seu comentário "Isso é totalmente errado"?
Leo Gallucci
@LeoGallucci, isDisplayed () retorna ElementFinder e não um booleano.
asenovm
1
Por favor, não use .toBeTruthy();use .toBe(true). .toBeTruthy();irá corresponder a coisas como [], 'falso', 42. Basicamente, qualquer coisa que espere 0, "", nulo, indefinido, NaN ou falso é verdadeiro.
Brian de
78

A maneira correta de verificar a visibilidade de um elemento com o Protractor é chamar o isDisplayedmétodo. Você deve ter cuidado, pois isDisplayednão retorna um booleano, mas sim promisefornece a visibilidade avaliada. Já vi muitos exemplos de código que usam esse método incorretamente e, portanto, não avaliam sua visibilidade real.

Exemplo para obter a visibilidade de um elemento:

element(by.className('your-class-name')).isDisplayed().then(function (isVisible) {
    if (isVisible) {
        // element is visible
    } else {
        // element is not visible
    }
});

No entanto, você não precisa disso se estiver apenas verificando a visibilidade do elemento (em vez de obtê-lo) porque os patches do transferidor Jasmine esperam (), portanto, ele sempre espera que as promessas sejam resolvidas. Consulte github.com/angular/jasminewd

Então você pode apenas fazer:

expect(element(by.className('your-class-name')).isDisplayed()).toBeTruthy();

Já que você está usando AngularJSpara controlar a visibilidade desse elemento, você também pode verificar seu atributo de classe ng-hideassim:

var spinner = element.by.css('i.icon-spin');
expect(spinner.getAttribute('class')).not.toMatch('ng-hide'); // expect element to be visible
Mobiletainment
fonte
8

Eu tive um problema semelhante, pois queria retornar apenas os elementos que estavam visíveis em um objeto de página. Descobri que consigo usar o css :not. No caso deste problema, isso deve fazer você ...

expect($('i.icon-spinner:not(.ng-hide)').isDisplayed()).toBeTruthy();

No contexto de um objeto de página, você pode obter SOMENTE os elementos que são visíveis dessa maneira também. Por exemplo. dada uma página com vários itens, onde apenas alguns são visíveis, você pode usar:

this.visibileIcons = $$('i.icon:not(.ng-hide)'); 

Isso irá retornar todos os i.icons visíveis

Salmoura
fonte
1
isDisplayed () deve estar no escopo esperado como @leoGallucci explicou.
Listrado em
5

Se houver vários elementos no DOM com o mesmo nome de classe. Mas apenas um dos elementos é visível.

element.all(by.css('.text-input-input')).filter(function(ele){
        return ele.isDisplayed();
    }).then(function(filteredElement){
        filteredElement[0].click();
    });

Neste exemplo, o filtro pega uma coleção de elementos e retorna um único elemento visível usando isDisplayed () .

A Qadeer Qureshi
fonte
Esta é uma ótima resposta; considere o caso em que não existe tal elemento! $ ('. text-input-input') alertaria o usuário elegantemente; isso pode falhar porque filteredElement.length === 0?
The Red Pea
1

Essa resposta será robusta o suficiente para funcionar com elementos que não estão na página, portanto, falhará normalmente (não lançará uma exceção) se o seletor não conseguir encontrar o elemento.

const nameSelector = '[data-automation="name-input"]';
const nameInputIsDisplayed = () => {
    return $$(nameSelector).count()
        .then(count => count !== 0)
}
it('should be displayed', () => {
    nameInputIsDisplayed().then(isDisplayed => {
        expect(isDisplayed).toBeTruthy()
    })
})
activedecay
fonte
1

Para esperar pela visibilidade

const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(element(by.css('.icon-spinner icon-spin ng-hide')))).then(function() {
  //do stuff
})

Truque Xpath para encontrar apenas elementos visíveis

element(by.xpath('//i[not(contains(@style,"display:none")) and @class="icon-spinner icon-spin ng-hide"]))
Drew Royster
fonte
1
 element(by.className('your-class-name')).isDisplayed().then(function (isVisible) {
if (isVisible) {
    // element is visible
} else {
    // element is not visible
}
}).catch(function(err){
console.log("Element is not found");
})
Anil Kumar
fonte
0

Aqui estão alguns trechos de código que podem ser usados ​​para frameworks que usam Typescript, protractor, jasmine

browser.wait(until.visibilityOf(OversightAutomationOR.lblContentModal), 3000, "Modal text is present");

// Asserting a text

OversightAutomationOR.lblContentModal.getText().then(text => {
                    this.assertEquals(text.toString().trim(), AdminPanelData.lblContentModal);
                });

// Asserting an element

expect(OnboardingFormsOR.masterFormActionCloneBtn.isDisplayed()).to.eventually.equal(true

    );

OnboardingFormsOR.customFormActionViewBtn.isDisplayed().then((isDisplayed) => {
                        expect(isDisplayed).to.equal(true);
                });

// Asserting a form

formInfoSection.getText().then((text) => {
                        const vendorInformationCount = text[0].split("\n");
                        let found = false;
                        for (let i = 0; i < vendorInformationCount.length; i++) {
                            if (vendorInformationCount[i] === customLabel) {
                                found = true;
                            };
                        };
                        expect(found).to.equal(true);
                    });     
Khyati Sehgal
fonte