I have a method that gets the href-attribute of an element hrefAppTheme
and checks if its one of the values of the string-array appThemes
:
describe('...',() => {
it('should ...', () => {
(...)
let defaultAppTheme = '';
onMenuPage.hrefAppTheme.invoke('attr', 'href')
.then(hrefVal => {
if (typeof hrefVal !== 'undefined') {
expect(hrefVal).to.be.oneOf(onMenuPage.appThemes);
defaultAppTheme = hrefVal;
//referencing the variable 'defaultAppTheme' further below...
}
});
It is safe to assume that this.hrefAppTheme.invoke('attr', 'href')
always returns one of the user-themes (a string), because the code above works reliably.
Since it turned out that I need to use that logic in several different places, I want to extract it into a method and put it into the page-object-class. This is what I've got:
export default class MenuPage {
(...)
getUserTheme(): string {
let userTheme = '';
cy.then(() => {
this.hrefAppTheme.invoke('attr', 'href')
.then(resVal => {
if (typeof resVal !== 'undefined') {
userTheme = resVal;
}
});
});
return userTheme;
}
I figured that I need to use the cy.wrap()
-method to assign the string that is being returned:
describe('...',() => {
it('should ...', () => {
(...)
let defaultAppTheme = '';
cy.wrap(onMenuPage.getUserTheme()).then(resVal => {
defaultAppTheme = resVal;
expect(defaultAppTheme).to.be.oneOf(onMenuPage.appThemes);
});
//referencing the variable 'defaultAppTheme' further below...
However, there is something wrong with this, because the value being returned is always an empty string, not the resolved-value:
AssertionError: expected '' to be one of [ 'theme-light.css', 'theme-dark.css' ]
+ expected - actual
+[ 'theme-light.css', 'theme-dark.css' ]
How do you return the resolve-value of myWebelement.invoke('attr', 'href').then(hrefVal => {
(...), and how can you assign it to a variable by calling this method?
Or is there a better approach to extract the working code into a method?
The this.hrefAppTheme
is already a Chainer, since it can use .invoke('attr', 'href')
after it. You can simplify by just returning it.
The .then(resVal...)
that follows is all about modifying the resVal
. Move your userTheme
var inside there and return it. The return value modifies the result of the previous chainers.
export default class MenuPage {
(...)
getUserTheme(): Chainable<string> {
return this.hrefAppTheme.invoke('attr','href') // return the whole chain
.then(resVal => {
let userTheme = '';
if (typeof resVal !== 'undefined') {
userTheme = resVal;
}
return userTheme; // return here to modify the chainer result
});
}
Then in the test, just use it like any Custom Command
describe('...',() => {
it('should ...', () => {
onMenuPage.getUserTheme().then(defaultAppTheme => {
expect(defaultAppTheme).to.be.oneOf(onMenuPage.appThemes);
});
AssertionError: expected '' to be one of [ 'theme-light.css', 'theme-dark.css' ]
You can probably now see why that error occurs, since the return value is userTheme = ''
when the resVal is undefined
.
That can be fixed by returning one on the expcted strings as default:
export default class MenuPage {
(...)
getUserTheme(): Chainable<string> {
return this.hrefAppTheme.invoke('attr','href')
.then(resVal => {
let userTheme = 'theme-light.css'; // change default value
if (typeof resVal !== 'undefined') {
userTheme = resVal;
}
return userTheme;
});
}