Как я могу определить пользовательский оператор утверждения в Cypress?

#javascript #cypress #chai #assertion

#javascript #cypress #чай #утверждение

Вопрос:

В Cypress test мне часто нужно проверить, соответствует ли текст в элементе DOM некоторому ожидаемому тесту. Но поскольку вокруг текста могут быть некоторые пробелы, я не могу просто написать:

 cy.get('.cell')
  .should('have.text', 'Hello')
  

Вместо этого я должен написать:

 cy.get('.cell')
  .then($cell => $cell.text().trim())
  .should('eq', 'Hello')
  

Я хочу определить пользовательский оператор утверждения, подобный have.text.trimmed , позвольте мне использовать его следующим образом:

 cy.get('.cell')
  .should('have.text.trimmed', 'Hello');
  

Но я не могу найти ни одного документа на официальном сайте об этом. Кто-нибудь поделится каким-нибудь примером?

Ответ №1:

Наконец, я нахожу способ сделать это. Хотя Cypress не предоставляет такой функции, но поскольку Cypress использует Chai, мы можем просто определить методы Chai.

Примечание: определить это невозможно have.text.trimmed , поскольку метод утверждения text является методом Chai. вместо цепочечного метода нет способа предоставить trimmed после него.

Но все еще есть два варианта:

  1. Определите метод Chai textTrimmed . Это позволяет нам использовать .should('have.textTrimmed', 'sometext') , что предпочтительнее, поскольку мы можем определить пользовательское сообщение с утверждением и без сложного взлома экземпляров jQuery.

  2. Определите метод Chai chainable trimmed . Это позволяет использовать .should('have.trimmed.text', 'sometext') , который, кажется, работает, но утверждение определяется методом Chai text , что может привести к путанице. Это не рекомендуется.

have.textTrimmed

Это в TypeScript:

 chai.Assertion.addMethod('textTrimmed', function (expectedString: string) {
  const $element = this._obj;

  new chai.Assertion($element).to.be.exist;

  const actual = $element.text().trim();
  const expected = expectedString.trim();
  this.assert(
    actual === expected
    , ' Expected #{this} to have text #{exp} after trimmed, but the text was #{act} after trimmed'
    , 'expected #{this} not to have text #{exp} after trimmed'
    , expected
    , actual
  );
});
  

Поместите код в cypress/support/index.js файл, чтобы убедиться, что он запущен перед тестированием.

Возможно, вы захотите посмотреть полную демонстрацию здесь: https://github.com/freewind-demos/typescript-cypress-add-custom-assertion-method-textTrimmed-demo/blob/master/cypress/support/textTrimmed.ts

Файл have.trimmed.text

 chai.use((chai, utils) => {

  chai.Assertion.addChainableMethod("trimmed", () => {
  }, function () {
    const obj = utils.flag(this, 'object')

    const oldText = obj.text.bind(obj);
    obj.text = () => {
      return oldText().trim()
    }
  });
})
  

Как я уже сказал, это не рекомендуется из-за сложного взлома и неясного сообщения об утверждении.

Вы также можете посмотреть полную демонстрацию здесь: https://github.com/freewind-demos/typescript-cypress-custom-operator-have-trimmed-text-demo/blob/master/cypress/support/index.ts

Ответ №2:

В настоящее время это невозможно из коробки для Cypress. Запрос на функцию заключается в том, чтобы предоставить «Cypress» способ доступа к команде textContent (и / или innerText) — .text() (#630).

Но вы можете обойти это, добавив пользовательские команды в support/commands.js и используйте эти команды в вашем testscript. В конечном итоге вы получите это в commands.js:

 Cypress.Commands.add('haveText', function (text) {
  cy.get('.cell')
  .then($cell => $cell.text().trim())
  .should('eq', text)
})
  

В тестовом скрипте вы получите:

 cy.haveText('Hello')
  

Вместо использования trim() в command.js вы также могли бы использовать contains() , это приводит к частичному совпадению, поэтому пробелы не являются проблемой (обратите внимание, что ‘apple pie’ также соответствует требованиям, если вы ищете ‘apple’, если это не проблема, вы можете использовать contains() . Commands.js будет выглядеть следующим образом:

 Cypress.Commands.add('haveText', function (text) {
  cy.get('.cell')
  .should('contains', text)
})
  

Но что, вероятно, еще больше соответствует вашим требованиям, так это использование contains() в сочетании с регулярным выражением. Вам не нужны никакие скрипты в commands.js но только в тестовом скрипте вы можете использовать это:

 cy.contains(/^s*Hellos*$/))
  

s* Должен соответствовать любому символу пробела ноль или более раз.
^ Заключается в том, чтобы начать сопоставление в начале текста
$ Заключается в том, чтобы завершить сопоставление в конце текста.

Регулярное выражение не может быть использовано в should() , к сожалению, достаточно.

Комментарии:

1. Спасибо. Использование command — это возможный способ, но для меня это немного тяжеловато. И использование contains не полностью соответствует моим требованиям, например, ячейка имеет содержимое Hello world , которое удовлетворяет .should('contains', 'Hello') , но это не то, что я хочу

2. чек, вот почему я действительно объяснил нечеткость чека. Но, насколько я знаю, вы не можете создавать пользовательские утверждения. Я добавлю еще одно предложение к своему ответу.

3. Спасибо за обновление. Я собираюсь создать проблему в cypress github

4. Еще раз обновил мой ответ, добавив к запросу функции. Не знал, что запрос функции для Cypress уже существует.

5. Я нахожу способ сделать это, пожалуйста, смотрите мой ответ