Finally, I find the way to do it. Although Cypress doesn't provide such a feature, but since Cypress uses Chai, we can just define Chai methods.
Note: it's not possible to define have.text.trimmed, since assertion method text is a Chai method. rather than a chainable method, there is no way to provide a trimmed after it.
But there are still two options:
Define a Chai method textTrimmed. It allows us using .should('have.textTrimmed', 'sometext'), which is preferred since we can define a custom assertion message and no tricky hacking on jQuery instances.
Define a Chai chainable method trimmed. It allows using .should('have.trimmed.text', 'sometext'), which seems to work, but the assertion is determined by the Chai method text, which may be confusion. It is not recommended.
have.textTrimmed
This is in 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
);
});
Put the code in cypress/support/index.js file to make sure running it before tests.
You may want to see the complete demo here: https://github.com/freewind-demos/typescript-cypress-add-custom-assertion-method-textTrimmed-demo/blob/master/cypress/support/textTrimmed.ts
File 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()
}
});
})
As I said, it's not recommended because of the tricky hack and unclear assertion message.
You can also see the complete demo here: https://github.com/freewind-demos/typescript-cypress-custom-operator-have-trimmed-text-demo/blob/master/cypress/support/index.ts