Cypress 软断言与 cy.origin - 为什么它通过了失败断言的测试?

use*_*513 3 chai cypress cypress-origin

我想我们都知道 cypress 和软断言已经被讨论得很厉害,并且有各种实现软解决方案的解决方案。一段时间以来,我一直在使用以下代码,基于旧的堆栈问题赛普拉斯是否支持软断言?

\n
let isSoftAssertion = false;\nlet errors = [];\n\nchai.softExpect = function ( ...args ) {\n    isSoftAssertion = true;\n    return chai.expect(...args);\n},\nchai.softAssert = function ( ...args ) {\n    isSoftAssertion = true;\n    return chai.assert(...args);\n}\n\nconst origAssert = chai.Assertion.prototype.assert;\nchai.Assertion.prototype.assert = function (...args) {\n    if ( isSoftAssertion ) {\n        try {\n            origAssert.call(this, ...args)\n        } catch ( error ) {\n            errors.push(error);\n        }\n        isSoftAssertion = false;\n    } else {\n\n        origAssert.call(this, ...args)\n    }\n};\n\n// monkey-patch `Cypress.log` so that the last `cy.then()` isn\'t logged to command log\nconst origLog = Cypress.log;\nCypress.log = function ( data ) {\n    if ( data && data.error && /soft assertions/i.test(data.error.message) ) {\n        data.error.message = \'\\n\\n\\t\' + data.error.message + \'\\n\\n\';\n        throw data.error;\n    }\n    return origLog.call(Cypress, ...arguments);\n};\n\n// monkey-patch `it` callback so we insert `cy.then()` as a last command \n// to each test case where we\'ll assert if there are any soft assertion errors\nfunction itCallback ( func ) {\n    func();\n    cy.then(() => {\n        if ( errors.length ) {\n            const _ = Cypress._;\n            let msg = \'\';\n\n            if ( Cypress.browser.isHeaded ) {\n\n                msg = \'Failed soft assertions... check log above \xe2\x86\x91\';\n            } else {\n\n                _.each( errors, error => {\n                    msg += \'\\n\' + error;\n                });\n\n                msg = msg.replace(/^/gm, \'\\t\');\n            }\n\n            throw new Error(msg);\n        }\n    });\n}\n\nconst origIt = window.it;\nwindow.it = (title, func) => {\n    origIt(title, func && (() => itCallback(func)));\n};\nwindow.it.only = (title, func) => {\n    origIt.only(title, func && (() => itCallback(func)));\n};\nwindow.it.skip = (title, func) => {\n    origIt.skip(title, func);\n};\n\nbeforeEach(() => {\n    errors = [];\n});\nafterEach(() => {\n    errors = [];\n    isSoftAssertion = false;\n});\n
Run Code Online (Sandbox Code Playgroud)\n

这一直工作得很好......直到现在!我现在需要测试跨源...对于针对我的基本 URL 的断言,没有任何改变....但是当我尝试在 cy.origin 中使用 softExpect 时,断言正确通过/失败,但是无论如何,家长测试都会通过。例如:

\n
\ndescribe(\'dummy test\', () => {\n\n    it(\'tests without cy.origin - this will fail correctly\', () => {\n        chai.softExpect(1).to.equal(2)\n    })\n\n    it(\'tests without cy.origin - the assertion will fail, but test is passed\', () => {\n        cy.origin(\'some.url\', () => {\n            Cypress.require(\'../../support/modules/soft_assertions.js\')\n            chai.softExpect(1).to.equal(3)\n        })\n    })    \n})\n
Run Code Online (Sandbox Code Playgroud)\n

谁能告诉我这是为什么吗?或者我如何才能将 1+ 软断言失败的事实传递回使用 cy.origin 的顶级“it”块?

\n

蒂亚!

\n

Lol*_*ola 8

为什么它通过测试的简短答案是cy.origin()给你一个不同的 Cypress 实例。使用 导入的任何模块Cypress.require()也有一个单独的实例。

外部(主)实例不知道内部原始实例中发现的软断言。

最快的解决方法是按照Singleton 模式更改模块,但由于猴子补丁,我坚持使用您的代码。


我是根据这个问题How can I use softassertion in Cypress using the npm package soft-assert来做到这一点的。

您也许能够使该模式适应您的代码,因此我将尽可能保持示例的通用性。

一般来说,跨多个来源使用任何包

  • Cypress.require()使用原始回调导入包(在您的情况下已经完成)

  • cy.origin()根据Yielding-a-value返回的产量数据

  • 协调来自原点的数据与主 Cypress 实例

执行

软断言实现示例

赛普拉斯/支持/e2e

const jsonAssertion = require("soft-assert")

Cypress.Commands.add('softAssert', (actual, expected, message) => {
  jsonAssertion.softAssert(actual, expected, message)
  if (jsonAssertion.jsonDiffArray?.length) {
    jsonAssertion.jsonDiffArray.forEach(diff => {
      const log = Cypress.log({
        name: 'Soft assertion error',
        displayName: 'softAssert',
        message: diff.error.message.split('message:')[1].trim()
      })
      log.set({state: 'failed', end: true})
    })
  }
  cy.wrap(jsonAssertion, {log:false})  // return the internal instance (data only)
});

Cypress.Commands.add('combineSoftResults', (resultsFromOrigin) => {
  resultsFromOrigin.jsonDiffArray.forEach(jsonDiff => {
    const {actual, expected, message} = jsonDiff.error
    jsonAssertion.softAssert(actual, expected, message)  // sync with main instance
  })
})

Cypress.Commands.add('softAssertAll', () => {
  if (jsonAssertion.softAssertCount) throw new Error('Failed soft assertions')
})
Run Code Online (Sandbox Code Playgroud)

测试

我添加了一个新cy.origin2()命令来组合结果,但如果愿意,您可以只应用 Cypress 文档中给出的模式。

context('soft assert', () => {

  Cypress.Commands.add('origin2', (...args) => {
    cy.origin(...args).then(result => {
      cy.combineSoftResults(result)
    })
  })

  it('testing numbers with soft-assert', () => {
    cy.softAssert(1, 2)                                // main test soft fail
  
    cy.origin2('https://example.com', () => {
      Cypress.require('../support/e2e')
      cy.softAssert(1, 3)                              // origin soft fail
    })
  
    cy.softAssert(1, 4)                                // main test soft fail

    cy.softAssertAll()                                 // throw to fail test
  })
})
Run Code Online (Sandbox Code Playgroud)

结果

内部和外部均出现软故障cy.origin()

在此输入图像描述

仅在内部出现软故障cy.origin()

在此输入图像描述

如果不调用cy.softAssertAll(),测试会通过,但会显示软故障。

在此输入图像描述