должен
Создать утверждение. Утверждения автоматически повторяются до тех пор, пока они не пройдут или не истечёт время ожидания.
Псевдоним
.and()
Примечание:
.should()предполагает, что вы уже знакомы с основными понятиями, такими как утверждения
Синтаксис
.should(chainers)
.should(chainers, value)
.should(chainers, method, value)
.should(callbackFn)
Использование
Правильное использование
cy.get('.error').should('be.empty') // Assert that '.error' is empty
cy.contains('Login').should('be.visible') // Assert that el is visible
cy.wrap({ foo: 'bar' }).its('foo').should('eq', 'bar') // Assert the 'foo' property equals 'bar'
Неправильное использование
cy.should('eq', '42') // Should not be chained off 'cy'
Аргументы
chainers (Строка)
Любой допустимый цепной метод, который происходит из Chai или Chai-jQuery или Sinon-Chai.
value (Строка)
Значение для проверки с использованием цепного метода.
method (Строка)
Метод, который должен быть вызван для цепного метода.
callbackFn (Функция)
Передайте функцию, которая может содержать любое количество явных утверждений в ней. То, что было передано в функцию, и будет возвращено.
Возвращаемые значения
- В большинстве случаев,
.should()возвращает тот же объект, который был передан из предыдущей команды.
cy.get('nav') // yields <nav>
.should('be.visible') // yields <nav>
Однако, некоторые цепные методы изменяют объект. В примере ниже, второе .should() возвращает строку sans-serif, потому что цепной метод have.css, 'font-family' изменяет объект.
cy.get('nav') // yields <nav>
.should('be.visible') // yields <nav>
.should('have.css', 'font-family') // yields 'sans-serif'
.and('match', /serif/) // yields 'sans-serif'
Примеры
Цепные методы
Проверить, что флажок отключён
cy.get(':checkbox').should('be.disabled')
Возвращается текущий DOM-элемент
cy.get('option:first')
.should('be.selected')
.then(($option) => {
// $option is yielded
})
Значение
Проверить, что класс равен 'form-horizontal'
cy.get('form').should('have.class', 'form-horizontal')
Проверить, что значение не равно 'Jane'
cy.get('input').should('not.have.value', 'Jane')
Возвращается текущий объект
cy.get('button')
.should('have.id', 'new-user')
.then(($button) => {
// $button is yielded
})
Метод и значение
Проверить, что у элемента есть атрибут href
// have.attr comes from chai-jquery
cy.get('#header a').should('have.attr', 'href')
Проверить, что значение атрибута href равно '/users'
cy.get('#header a').should('have.attr', 'href', '/users')
Примечание: утверждение have.attr изменяет объект с исходного элемента на значение атрибута
cy.get('#header a') // yields the element
.should('have.attr', 'href') // yields the "href" attribute
.and('equal', '/users') // checks the "href" value
Фокус
Проверить, что поле ввода получает фокус после нажатия кнопки
cy.get('#btn-focuses-input').click()
cy.get('#input-receives-focus').should('have.focus') // equivalent to should('be.focused')
Функция
Передача функции в .should() позволяет выполнить несколько проверок на возвращаемом объекте. Это также даёт возможность изменять проверяемые значения.
Убедитесь, что в вашей функции обратного вызова нет кода, который вызывает побочные эффекты. Функция обратного вызова будет повторно выполняться снова и снова, пока никакие утверждения в ней не вызовут ошибку.
Проверить длину, содержимое и классы из множества <p>
<div>
<p class="text-primary">Hello World</p>
<p class="text-danger">You have an error</p>
<p class="text-default">Try again later</p>
</div>
cy.get('p').should(($p) => {
// should have found 3 elements
expect($p).to.have.length(3)
// make sure the first contains some text content
expect($p.first()).to.contain('Hello World')
// use jquery's map to grab all of their classes
// jquery's map returns a new jquery object
const classes = $p.map((i, el) => {
return Cypress.$(el).attr('class')
})
// call classes.get() to make this a plain array
expect(classes.get()).to.deep.eq([
'text-primary',
'text-danger',
'text-default',
])
})
Предупреждение Любое значение, возвращаемое функцией обратного вызова .should(), будет проигнорировано. Исходный объект будет возвращён следующей команде.
cy.get('p')
.should(($p) => {
expect($p).to.have.length(3)
return 'foo'
})
.then(($p) => {
// the argument $p will be the 3 elements, not "foo"
})
Проверить, что имя класса содержит heading-
<div class="docs-header">
<div class="main-abc123 heading-xyz987">Introduction</div>
</div>
cy.get('.docs-header')
.find('div')
// .should(cb) callback function will be retried
.should(($div) => {
expect($div).to.have.length(1)
const className = $div[0].className
expect(className).to.match(/heading-/)
})
// .then(cb) callback is not retried,
// it either passes or fails
.then(($div) => {
expect($div).to.have.text('Introduction')
})
Вы даже можете генерировать собственные ошибки из функции обратного вызова.
cy.get('.docs-header')
.find('div')
.should(($div) => {
if ($div.length !== 1) {
// you can throw your own errors
throw new Error('Did not find 1 element')
}
const className = $div[0].className
if (!className.match(/heading-/)) {
throw new Error(`No class "heading-" in ${className}`)
}
})
Проверить текстовое содержимое 3 элементов
В примере ниже сначала проверяется, что элементов 3, а затем проверяется текстовое содержимое каждого из них.
<ul class="connectors-list">
<li>Walk the dog</li>
<li>Feed the cat</li>
<li>Write JavaScript</li>
</ul>
cy.get('.connectors-list > li').should(($lis) => {
expect($lis).to.have.length(3)
expect($lis.eq(0)).to.contain('Walk the dog')
expect($lis.eq(1)).to.contain('Feed the cat')
expect($lis.eq(2)).to.contain('Write JavaScript')
})
Прочитайте Cypress should callback пост блога, чтобы увидеть больше вариантов вышеупомянутого примера.
Для ясности, вы можете передать строковое сообщение в качестве второго аргумента к любому утверждению expect, см. Chai#expect.
cy.get('.connectors-list > li').should(($lis) => {
expect($lis, '3 items').to.have.length(3)
expect($lis.eq(0), 'first item').to.contain('Walk the dog')
expect($lis.eq(1), 'second item').to.contain('Feed the cat')
expect($lis.eq(2), 'third item').to.contain('Write JavaScript')
})
Эти строковые сообщения будут отображаться в журнале команд, придавая каждому утверждению больше контекста.
Сравнение текстовых значений двух элементов
В примере ниже извлекается текст, содержащийся в одном элементе, и сохраняется в переменной закрытия. Затем тест извлекает текст из другого элемента и утверждает, что два текстовых значения одинаковы после нормализации.
<div class="company-details">
<div class="title">Acme Developers</div>
<div class="identifier">ACMEDEVELOPERS</div>
</div>
const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase()
// will keep text from title element
let titleText
cy.get('.company-details')
.find('.title')
.then(($title) => {
// save text from the first element
titleText = normalizeText($title.text())
})
cy.get('.company-details')
.find('.identifier')
.should(($identifier) => {
// we can massage text before comparing
const idText = normalizeText($identifier.text())
// text from the title element should already be set
expect(idText, 'ID').to.equal(titleText)
})
Множественные утверждения
Цепные утверждения
Cypress упрощает цепочку утверждений.
В этом примере мы используем .and(), что идентично .should().
// our subject is not changed by our first assertion,
// so we can continue to use DOM based assertions
cy.get('option:first').should('be.selected').and('have.value', 'Metallica')
Ожидание выполнения утверждений
Cypress не разрешит ваши команды, пока все утверждения не пройдут.
// Application Code
$('button').click(function () {
$button = $(this)
setTimeout(() => {
$button.removeClass('inactive').addClass('active')
}, 1000)
})
cy.get('button')
.click()
.should('have.class', 'active')
.and('not.have.class', 'inactive')
Примечания
Объекты
Как узнать, какие утверждения меняют объект, а какие нет?
Цепные методы, полученные из Chai или Chai-jQuery всегда будут документировать то, что они возвращают.
Использование функции обратного вызова не изменит то, что возвращается
Всё, что возвращается в функции, игнорируется. Cypress всегда заставляет команду возвращать значение от предыдущей команды cy (которое в примере ниже — <button>)
cy.get('button')
.should(($button) => {
expect({ foo: 'bar' }).to.deep.eq({ foo: 'bar' })
return { foo: 'bar' } // return is ignored, .should() yields <button>
})
.then(($button) => {
// do anything we want with <button>
})
Различия
В чём разница между .then() и .should()/.and()?
Использование .then() позволяет использовать возвращаемый объект в функции обратного вызова и должно использоваться, когда нужно манипулировать значениями или выполнять какие-либо действия.
При использовании функции обратного вызова с .should() или .and(), с другой стороны, есть специальная логика для повторного выполнения функции обратного вызова до тех пор, пока ни одно утверждение в ней не выбросит ошибку. Вы должны быть осторожны с побочными эффектами в функции обратного вызова .should() или .and(), которые вы не хотите выполнять многократно.
Правила
Требования
-
.should()требует цепочки с предыдущей командой.
Таймауты
-
.should()будет продолжать повторные попытки указанных утверждений до истечения времени ожидания.
cy.get('input', { timeout: 10000 }).should('have.value', '10')
// timeout here will be passed down to the '.should()'
// and it will retry for up to 10 secs
cy.get('input', { timeout: 10000 }).should(($input) => {
// timeout here will be passed down to the '.should()'
// unless an assertion throws earlier,
// ALL of the assertions will retry for up to 10 secs
expect($input).to.not.be('disabled')
expect($input).to.not.have.class('error')
expect($input).to.have.value('US')
})
Журнал команд
Утверждение о том, что в навигации должно быть 8 дочерних элементов
cy.get('.left-nav>.nav').children().should('have.length', 8)
Приведённые выше команды будут отображаться в журнале команд как:
При нажатии на assert в журнале команд, консоль выведет следующее:
История
| Версия | Изменения |
|---|---|
| 0.11.4 | Разрешает аргумент функции обратного вызова |
| < 0.3.3 |
.should() команда добавлена |
См. также
© 2017 Cypress.io
Licensed under the MIT License.
https://docs.cypress.io/api/commands/should