I think we all know that cypress and soft assertions has been discussed to death, and various solutions to implementing soft solutions are out there. For some time now, I've been using the following code, based on the old stack question Does cypress support soft assertion?:
let isSoftAssertion = false;
let errors = [];
chai.softExpect = function ( ...args ) {
isSoftAssertion = true;
return chai.expect(...args);
},
chai.softAssert = function ( ...args ) {
isSoftAssertion = true;
return chai.assert(...args);
}
const origAssert = chai.Assertion.prototype.assert;
chai.Assertion.prototype.assert = function (...args) {
if ( isSoftAssertion ) {
try {
origAssert.call(this, ...args)
} catch ( error ) {
errors.push(error);
}
isSoftAssertion = false;
} else {
origAssert.call(this, ...args)
}
};
// monkey-patch `Cypress.log` so that the last `cy.then()` isn't logged to command log
const origLog = Cypress.log;
Cypress.log = function ( data ) {
if ( data && data.error && /soft assertions/i.test(data.error.message) ) {
data.error.message = '\n\n\t' + data.error.message + '\n\n';
throw data.error;
}
return origLog.call(Cypress, ...arguments);
};
// monkey-patch `it` callback so we insert `cy.then()` as a last command
// to each test case where we'll assert if there are any soft assertion errors
function itCallback ( func ) {
func();
cy.then(() => {
if ( errors.length ) {
const _ = Cypress._;
let msg = '';
if ( Cypress.browser.isHeaded ) {
msg = 'Failed soft assertions... check log above ↑';
} else {
_.each( errors, error => {
msg += '\n' + error;
});
msg = msg.replace(/^/gm, '\t');
}
throw new Error(msg);
}
});
}
const origIt = window.it;
window.it = (title, func) => {
origIt(title, func && (() => itCallback(func)));
};
window.it.only = (title, func) => {
origIt.only(title, func && (() => itCallback(func)));
};
window.it.skip = (title, func) => {
origIt.skip(title, func);
};
beforeEach(() => {
errors = [];
});
afterEach(() => {
errors = [];
isSoftAssertion = false;
});
This has been working beautifully... until now! I'm now need to test cross-origin... For assertions against my base URL, nothing has changed.... but when I try and use softExpect within cy.origin, the assertions are correctly passed / failed, but the parent test is passed regardless. For example:
describe('dummy test', () => {
it('tests without cy.origin - this will fail correctly', () => {
chai.softExpect(1).to.equal(2)
})
it('tests without cy.origin - the assertion will fail, but test is passed', () => {
cy.origin('some.url', () => {
Cypress.require('../../support/modules/soft_assertions.js')
chai.softExpect(1).to.equal(3)
})
})
})
Can anyone advise why this is? Or how I can pass the fact that 1+ softassertion has failed back to the top level "it" block where cy.origin has been used?
TIA!