O Cypress empacota a biblioteca popular de asserções Chai, assim como extensões úteis para Sinon e jQuery, trazendo dezenas de asserções poderosas gratuitamente.
Novo no Cypress?
Este documento é apenas uma referência a todas as asserções que o Cypress suporta.
Se você está procurando entender como usar essas asserções, leia sobre asserções em nosso guia de Introdução ao Cypress guide.
https://github.com/chaijs/chai
Esses encadeadores estão disponíveis para asserções BDD (expect
/should
). Os
pseudônimos listados podem ser usados de forma intercambiável com seu encadeador
original. Você pode ver a lista completa das asserções Chai BDD
aqui.
Encadeador | Exemplo |
---|---|
not | expect(name).to.not.equal('Jane') |
deep | expect(obj).to.deep.equal({ name: 'Jane' }) |
nested | expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]') expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'}) |
ordered | expect([1, 2]).to.have.ordered.members([1, 2]).but.not.have.ordered.members([2, 1]) |
any | expect(arr).to.have.any.keys('age') |
all | expect(arr).to.have.all.keys('name', 'age') |
a(type) Aliases: an |
expect('test').to.be.a('string') |
include(value) Aliases: contain, includes, contains |
expect([1,2,3]).to.include(2) |
ok | expect(undefined).to.not.be.ok |
true | expect(true).to.be.true |
false | expect(false).to.be.false |
null | expect(null).to.be.null |
undefined | expect(undefined).to.be.undefined |
exist | expect(myVar).to.exist |
empty | expect([]).to.be.empty |
arguments Aliases: Arguments |
expect(arguments).to.be.arguments |
equal(value) Aliases: equals, eq |
expect(42).to.equal(42) |
deep.equal(value) | expect({ name: 'Jane' }).to.deep.equal({ name: 'Jane' }) |
eql(value) Aliases: eqls |
expect({ name: 'Jane' }).to.eql({ name: 'Jane' }) |
greaterThan(value) Aliases: gt, above |
expect(10).to.be.greaterThan(5) |
least(value) Aliases: gte |
expect(10).to.be.at.least(10) |
lessThan(value) Aliases: lt, below |
expect(5).to.be.lessThan(10) |
most(value) Aliases: lte |
expect('test').to.have.length.of.at.most(4) |
within(start, finish) | expect(7).to.be.within(5,10) |
instanceOf(constructor) Aliases: instanceof |
expect([1, 2, 3]).to.be.instanceOf(Array) |
property(name, [value]) | expect(obj).to.have.property('name') |
deep.property(name, [value]) | expect(deepObj).to.have.deep.property('tests[1]', 'e2e') |
ownProperty(name) Aliases: haveOwnProperty, own.property |
expect('test').to.have.ownProperty('length') |
ownPropertyDescriptor(name) Aliases: haveOwnPropertyDescriptor |
expect({a: 1}).to.have.ownPropertyDescriptor('a') |
lengthOf(value) | expect('test').to.have.lengthOf(3) |
match(RegExp) Aliases: matches |
expect('testing').to.match(/^test/) |
string(string) | expect('testing').to.have.string('test') |
keys(key1, [key2], [...]) Aliases: key |
expect({ pass: 1, fail: 2 }).to.have.keys('pass', 'fail') |
throw(constructor) Aliases: throws, Throw |
expect(fn).to.throw(Error) |
respondTo(method) Aliases: respondsTo |
expect(obj).to.respondTo('getName') |
itself | expect(Foo).itself.to.respondTo('bar') |
satisfy(method) Aliases: satisfies |
expect(1).to.satisfy((num) => { return num > 0 }) |
closeTo(expected, delta) Aliases: approximately |
expect(1.5).to.be.closeTo(1, 0.5) |
members(set) | expect([1, 2, 3]).to.include.members([3, 2]) |
oneOf(values) | expect(2).to.be.oneOf([1,2,3]) |
change(function) Aliases: changes |
expect(fn).to.change(obj, 'val') |
increase(function) Aliases: increases |
expect(fn).to.increase(obj, 'val') |
decrease(function) Aliases: decreases |
expect(fn).to.decrease(obj, 'val') |
Esses obtentores (getters) também estão disponíveis para asserções BDD. Eles não fazem nada, mas permitem que se escreva frases claras em inglês.
Obtentores encadeáveis (Chainable getters) |
---|
to , be , been , is , that , which , and , has , have , with , at , of , same |
Essas asserções estão disponíveis para asserções TDD (assert
). Você pode ver
a lista completa de asserções Chai disponíveis
aqui.
Assertion | Example |
---|---|
.isOk(object, [message]) | assert.isOk('everything', 'everything is ok') |
.isNotOk(object, [message]) | assert.isNotOk(false, 'this will pass') |
.equal(actual, expected, [message]) | assert.equal(3, 3, 'vals equal') |
.notEqual(actual, expected, [message]) | assert.notEqual(3, 4, 'vals not equal') |
.strictEqual(actual, expected, [message]) | assert.strictEqual(true, true, 'bools strict eq') |
.notStrictEqual(actual, expected, [message]) | assert.notStrictEqual(5, '5', 'not strict eq') |
.deepEqual(actual, expected, [message]) | assert.deepEqual({ id: '1' }, { id: '1' }) |
.notDeepEqual(actual, expected, [message]) | assert.notDeepEqual({ id: '1' }, { id: '2' }) |
.isAbove(valueToCheck, valueToBeAbove, [message]) | assert.isAbove(6, 1, '6 greater than 1') |
.isAtLeast(valueToCheck, valueToBeAtLeast, [message]) | assert.isAtLeast(5, 2, '5 gt or eq to 2') |
.isBelow(valueToCheck, valueToBeBelow, [message]) | assert.isBelow(3, 6, '3 strict lt 6') |
.isAtMost(valueToCheck, valueToBeAtMost, [message]) | assert.isAtMost(4, 4, '4 lt or eq to 4') |
.isTrue(value, [message]) | assert.isTrue(true, 'this val is true') |
.isNotTrue(value, [message]) | assert.isNotTrue('tests are no fun', 'val not true') |
.isFalse(value, [message]) | assert.isFalse(false, 'val is false') |
.isNotFalse(value, [message]) | assert.isNotFalse('tests are fun', 'val not false') |
.isNull(value, [message]) | assert.isNull(err, 'there was no error') |
.isNotNull(value, [message]) | assert.isNotNull('hello', 'is not null') |
.isNaN(value, [message]) | assert.isNaN(NaN, 'NaN is NaN') |
.isNotNaN(value, [message]) | assert.isNotNaN(5, '5 is not NaN') |
.exists(value, [message]) | assert.exists(5, '5 is not null or undefined') |
.notExists(value, [message]) | assert.notExists(null, 'val is null or undefined') |
.isUndefined(value, [message]) | assert.isUndefined(undefined, 'val is undefined') |
.isDefined(value, [message]) | assert.isDefined('hello', 'val has been defined') |
.isFunction(value, [message]) | assert.isFunction(x => x * x, 'val is func') |
.isNotFunction(value, [message]) | assert.isNotFunction(5, 'val not funct') |
.isObject(value, [message]) | assert.isObject({num: 5}, 'val is object') |
.isNotObject(value, [message]) | assert.isNotObject(3, 'val not object') |
.isArray(value, [message]) | assert.isArray(['unit', 'e2e'], 'val is array') |
.isNotArray(value, [message]) | assert.isNotArray('e2e', 'val not array') |
.isString(value, [message]) | assert.isString('e2e', 'val is string') |
.isNotString(value, [message]) | assert.isNotString(2, 'val not string') |
.isNumber(value, [message]) | assert.isNumber(2, 'val is number') |
.isNotNumber(value, [message]) | assert.isNotNumber('e2e', 'val not number') |
.isFinite(value, [message]) | assert.isFinite('e2e', 'val is finite') |
.isBoolean(value, [message]) | assert.isBoolean(true, 'val is bool') |
.isNotBoolean(value, [message]) | assert.isNotBoolean('true', 'val not bool') |
.typeOf(value, name, [message]) | assert.typeOf('e2e', 'string', 'val is string') |
.notTypeOf(value, name, [message]) | assert.notTypeOf('e2e', 'number', 'val not number') |
https://github.com/chaijs/chai-jquery
Esses encadeadores estão disponíveis ao assertar sobre um objeto do DOM.
Normalmente, você usará esses encadeadores depois de usar os comandos do DOM
como: cy.get()
,
cy.contains()
, etc.
Encadeadores | Asserção |
---|---|
attr(name, [value]) | expect($el).to.have.attr('foo', 'bar') |
prop(name, [value]) | expect($el).to.have.prop('disabled', false) |
css(name, [value]) | expect($el).to.have.css('background-color', 'rgb(0, 0, 0)') |
data(name, [value]) | expect($el).to.have.data('foo', 'bar') |
class(className) | expect($el).to.have.class('foo') |
id(id) | expect($el).to.have.id('foo') |
html(html) | expect($el).to.have.html('I love testing') |
text(text) | expect($el).to.have.text('I love testing') |
value(value) | expect($el).to.have.value('test@dev.com') |
visible | expect($el).to.be.visible |
hidden | expect($el).to.be.hidden |
selected | expect($option).not.to.be.selected |
checked | expect($input).not.to.be.checked |
focus[ed] | expect($input).not.to.be.focused expect($input).to.have.focus |
enabled | expect($input).to.be.enabled |
disabled | expect($input).to.be.disabled |
empty | expect($el).not.to.be.empty |
exist | expect($nonexistent).not.to.exist |
match(selector) | expect($emptyEl).to.match(':empty') |
contain(text) | expect($el).to.contain('text') |
descendants(selector) | expect($el).to.have.descendants('div') |
https://github.com/domenic/sinon-chai
Esses encadeadores são usados em asserções com
cy.stub()
e
cy.spy()
.
Sinon.JS propriedade/método | Asserção |
---|---|
called | expect(spy).to.be.called |
callCount | expect(spy).to.have.callCount(n) |
calledOnce | expect(spy).to.be.calledOnce |
calledTwice | expect(spy).to.be.calledTwice |
calledThrice | expect(spy).to.be.calledThrice |
calledBefore | expect(spy1).to.be.calledBefore(spy2) |
calledAfter | expect(spy1).to.be.calledAfter(spy2) |
calledWithNew | expect(spy).to.be.calledWithNew |
alwaysCalledWithNew | expect(spy).to.always.be.calledWithNew |
calledOn | expect(spy).to.be.calledOn(context) |
alwaysCalledOn | expect(spy).to.always.be.calledOn(context) |
calledWith | expect(spy).to.be.calledWith(...args) |
alwaysCalledWith | expect(spy).to.always.be.calledWith(...args) |
calledWithExactly | expect(spy).to.be.calledWithExactly(...args) |
alwaysCalledWithExactly | expect(spy).to.always.be.calledWithExactly(...args) |
calledWithMatch | expect(spy).to.be.calledWithMatch(...args) |
alwaysCalledWithMatch | expect(spy).to.always.be.calledWithMatch(...args) |
returned | expect(spy).to.have.returned(returnVal) |
alwaysReturned | expect(spy).to.have.always.returned(returnVal) |
threw | expect(spy).to.have.thrown(errorObjOrErrorTypeStringOrNothing) |
alwaysThrew | expect(spy).to.have.always.thrown(errorObjOrErrorTypeStringOrNothing) |
Como estamos usando chai
, isso significa que você pode estendê-lo como quiser.
O Cypress "simplesmente funcionará" com novas asserções adicionadas ao chai
.
Você pode:
- Escrever suas próprias asserções
chai
como documentado aqui. - Instalar qualquer biblioteca
chai
existente comnpm
e importar em seu arquivo de teste ou de suporte.
Aqui está uma lista de asserções de elementos comuns. Observe como usamos essas
asserções (listadas acima) com
.should()
.
Você também pode querer ler sobre como o Cypress
tenta novamente
as asserções.
// tenta até encontrar 3 <li.selected> correspondentes
cy.get('li.selected').should('have.length', 3);
// tenta até esse input não tenha a classe disabled
cy.get('form').find('input').should('not.have.class', 'disabled');
// tenta até esse textarea contenha o valor correto
cy.get('textarea').should('have.value', 'foo bar baz');
// alega que o conteúdo do texto do elemento é exatamente o texto fornecido
cy.get('#user-name').should('have.text', 'Joe Smith');
// alega que o texto do elemento inclui a substring fornecida
cy.get('#address').should('include.text', 'Atlanta');
// tenta até que este span não contenha 'click me'
cy.get('a').parent('span.help').should('not.contain', 'click me');
// o texto do elemento deve começar com "Hello"
cy.get('#greeting')
.invoke('text')
.should('match', /^Hello/);
// dica: use cy.contains para encontrar o elemento com seu texto
// correspondendo com a expressão regular fornecida
cy.contains('#a-greeting', /^Hello/);
Dica: leia sobre asserções em um texto com entidades de espaçamentos ininterruptos em Como obtenho o conteúdo de texto de um elemento?
// tenta até que o button com id "form-submit" esteja visível
cy.get('button#form-submit').should('be.visible');
// tenta até que o item da lista com
// o texto "write tests" esteja visível
cy.contains('.todo li', 'write tests').should('be.visible');
Nota: se houverem múltiplos elementos, as asserções be.visible
e
not.be.visible
agem de forma diferente:
// tenta até que ALGUNS elementos estejam visíveis
cy.get('li').should('be.visible');
// tenta até que TODOS elementos estejam invisíveis
cy.get('li.hidden').should('not.be.visible');
Assista ao pequeno vídeo "Múltiplos elementos e asserções should('be.visible')" que mostra como verificar corretamente a visibilidade dos elementos.
// tenta até que o elemento com id loading não exista mais
cy.get('#loading').should('not.exist');
// tenta até que o elemento de type radio esteja selecionado
cy.get(':radio').should('be.checked');
// tenta até que .completed esteja com o css correspondente
cy.get('.completed').should('have.css', 'text-decoration', 'line-through');
// tenta enquanto .accordion o css não tenha a propriedade "display: none"
cy.get('#accordion').should('not.have.css', 'display', 'none');
<input type="text" id="example-input" disabled />
cy.get('#example-input')
.should('be.disabled')
// vamos habilitar este elemento do teste
.invoke('prop', 'disabled', false);
cy.get('#example-input')
// podemos usar a asserção "enabled"
.should('be.enabled')
// ou negar a asserção "disabled"
.and('not.be.disabled');
Existem asserções que são positivas e negativas. Exemplos de asserções positivas:
cy.get('.todo-item').should('have.length', 2).and('have.class', 'completed');
As asserções negativas têm o encadeador "not" prefixado à asserção. Exemplos de asserções negativas:
cy.contains('first todo').should('not.have.class', 'completed');
cy.get('#loading').should('not.be.visible');
Asserções negativas podem passar por motivos inesperados. Digamos que queremos testar que uma aplicação de lista de tarefas adiciona um novo item à lista após digitar a tarefa e pressionar enter.
Ao adicionar um elemento à lista de tarefas e usando uma asserção positiva, o teste verifica o número específico de itens na lista em nosso aplicativo.
O teste abaixo ainda pode passar erroneamente se o aplicativo se comportar de maneira inesperada, como adicionar uma tarefa em branco, ao invés de adicionar a nova tarefa com o texto "Write tests".
cy.get('li.todo').should('have.length', 2);
cy.get('input#new-todo').type('Write tests{enter}');
// usando uma asserção positiva para verificar o número exato de itens
cy.get('li.todo').should('have.length', 3);
Porém, ao usar uma asserção negativa no teste abaixo, o teste pode passar erroneamente quando o aplicativo se comporta de diversas maneiras inesperadas:
- O aplicativo exclui toda a lista de itens de tarefas em vez de inserir a terceira tarefa
- O aplicativo exclui uma tarefa ao invés de adicionar uma nova tarefa
- O aplicativo adiciona uma tarefa em branco
- Uma variedade infinita de erros de aplicação possíveis
cy.get('li.todo').should('have.length', 2);
cy.get('input#new-todo').type('Write tests{enter}');
// usando asserção negativa para verificar se não tem o número de itens
cy.get('li.todo').should('not.have.length', 2);
Recomendamos o uso de asserções negativas para verificar se uma condição específica não está mais presente depois que o aplicativo executa uma ação. Por exemplo, quando um item concluído previamente é desmarcado, podemos verificar se uma classe CSS foi removida.
// primeiramente, o item é marcado como concluído
cy.contains('li.todo', 'Write tests')
.should('have.class', 'completed')
.find('.toggle')
.click();
// a classe CSS foi removida
cy.contains('li.todo', 'Write tests').should('not.have.class', 'completed');
Para obter mais exemplos, leia a postagem do blog Cuidado com as afirmações negativas..
Se as asserções construídas não forem suficientes, você pode escrever sua
própria função de asserção e passá-la como um callback para o comando
.should()
. O Cypress irá automaticamente fazer uma
nova tentativa da
função de callback até que ela passe ou o tempo limite do comando se esgote.
Veja a documentação
.should()
.
<div class="main-abc123 heading-xyz987">Introduction</div>
cy.get('div').should(($div) => {
expect($div).to.have.length(1);
const className = $div[0].className;
// className será uma string como "main-abc123 heading-xyz987"
expect(className).to.match(/heading-/);
});
Você pode anexar várias asserções em um mesmo comando.
<a class="assertions-link active" href="https://on.cypress.io" target="_blank"
>Cypress Docs</a
>
cy.get('.assertions-link')
.should('have.class', 'active')
.and('have.attr', 'href')
.and('include', 'cypress.io');
Observe que todas as asserções encadeadas usarão a mesma referência ao elemento original. Por exemplo, se você quiser testar um elemento de loading que primeiro aparece e depois desaparece, o posterior NÃO FUNCIONARÁ porque o mesmo elemento não pode ser visível e invisível ao mesmo tempo:
// ⛔️ NÃO FUNCIONA
cy.get('#loading').should('be.visible').and('not.be.visible');
Em vez disso, você deve dividir as asserções e consultar novamente o elemento:
// ✅ A MANEIRA CORRETA
cy.get('#loading').should('be.visible');
cy.get('#loading').should('not.be.visible');