'How to call a method in another module JavaScript?
I have a class with method performing login
LoginPage.js
class loginPage {
fillCredentials(username, password) {
cy.get('[id=username]').type(username);
cy.get('[id=password]').type(password);
return this;
}
clickLogin() {
cy.contains("Login").click();
}
}
export default loginPage;
I have another spec file for testing:
login.spec.js
import {fillCredentials,clickLogin} from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password')
clickLogin()
});
});
However, it is giving an error of
(0 , _loginPage.fillCredentials) is not a function
I know its a wrong way of calling a method. Is there any way I can use the methods without creating an instance of class to access methods
Solution 1:[1]
You can do so if you make the methods static
class loginPage {
static fillCredentials(username, password) {
cy.get('[id=username]').type(username);
cy.get('[id=password]').type(password);
//return this; // you can't return "this" because there is no this for static methods
}
static clickLogin() {
cy.contains("Login").click();
}
}
export default loginPage;
import {fillCredentials,clickLogin} from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password')
clickLogin()
});
});
With static methods you lose this which refers to the class instance, and therefore lose the ability to chain methods,
import {fillCredentials,clickLogin} from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password').clickLogin() // can't do this with static
});
});
As functions instead of a class, this is the pattern
// LoginPage.js
export const fillCredentials = (username, password) => {
cy.get('[id=username]').type(username);
cy.get('[id=password]').type(password);
return this;
}
export const clickLogin = () => {
cy.contains("Login").click();
}
// login.spec (same as you have above)
import { fillCredentials, clickLogin } from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password')
clickLogin()
});
})
Be wary of encapsulating test code in page objects, it can lead to over-complicated code.
For example, if you now want to test what happens if password is not entered, you can't use fillCredentials because you can't omit the password parameter. So do you add a fillCredentialsWithoutPassword function? Do you modify fillCredentials to test if password is undefined?
Solution 2:[2]
So, what's going on is that you are mixing up the module structure with is defined by Closures with the class-instance pattern.
For this scenario (which is class-instance) the functions are NOT part of the object itself, but of it's PROTOTYPE.
So in order to get that function you should access it's prototype.
//create a class (class syntax and this one is pretty much the same)
function xx (){}
//this is what class syntax makes to create a method for the class
xx.prototype.theFunctionIwant = function (){}
//create an instance
var example = new xx()
//this is how you can spy that function in the test
xx.prototype.theFunctionIwant
//ƒ (){}
Try it out : )
Solution 3:[3]
The other answers given will work and solve your exact question, but I fear that making the functions static is an anti-pattern for the Page Object Model. Check out this article on how to set up a POM for Cypress. I would highly encourage you to instantiate the class, similar to below.
//LoginPage.js
export class LoginPage { ... }
//login.spec.js
import { LoginPage } from '../../support/PageObjects/loginPage';
describe('User Onboarding Emails', () => {
it('Verification email', () => {
const loginPage = new LoginPage()
cy.visit('/')
loginPage.fillCredentials('username','password')
loginPage.clickLogin()
});
});
You could also use a beforeEach() block to instantiate the variable before each test.
describe('User Onboarding Emails', () => {
let loginPage: LoginPage;
beforeEach(() => {
loginPage = new LoginPage();
});
it('Verification email', () => {
...
});
})
As an aside, it is usually preferred to name classes beginning with an uppercase (LoginPage vs. loginPage). When naming a class this way, you can easily differentiate the class vs. the instantiated variable.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Felipe Quirós |
| Solution 3 |
