I'm starting to work with Cypress and programming in general. I'm working on a very simple personal project executing TCs in a webpage.
I have this piece of code in 'registrationPage.js'
/// <reference types="cypress" />
import registrationData from '../fixtures/registrationData.json'
import AccountInfoPage from './accountInfoPage'
import commands from '../support/commands'
class RegistrationPage{
//Fill out Registration form with valid credentials
fillRegistrationForm(){
const userData = cy.getRegistrationData()
cy.getRegistrationData()
cy.get('[title="First Name"]').type(userData.firstname)
cy.get('#lastname').type(userData)
cy.get('[autocomplete="email"]').type(userData)
cy.get('#password').type(userData)
cy.get('#password-confirmation').type(userData)
}
//Click on submit button of Registration form
submitRegistrationForm(){
cy.contains('button', 'Create an Account').click()
}
//Verify the registration was sucesfull and user was created
verifyRegistration(){
const accountInfoPage = new AccountInfoPage();
const validUser = registrationData.validData.user1
cy.contains('Thank you for registering with Main Website Store.').should('be.visible')
cy.get('#block-collapsible-nav').find('li').contains('Account Information').click()
accountInfoPage.getFirstNameInput().invoke('val')
.should('equal', validUser.firstname)
accountInfoPage.getLastNameInput().invoke('val')
.should('equal', validUser.lastname)
}
}
export default RegistrationPage;
Since this is a logic that I wan to re-use (only the part of getting the data, not typing it) I thought it would be a good option to have it in 'commands.js' file as a Command.
I have a data set located in registrationData.json but I also wanted to use environment variables in case I want to quickly override what the data set has (I would also like to hear if there is better options to handle this)
I put the logic into commands.js:
import registrationData from '../fixtures/registrationData.json'
import loginData from '../fixtures/loginData.json'
Cypress.Commands.add('getRegistrationData', () => {
const validUser = Cypress.env('validUser') || registrationData.validData.user1
return {
firstname: Cypress.env('firstname') || validUser.firstname,
lastname: Cypress.env('lastname') || validUser.lastname,
email: Cypress.env('email') || validUser.email,
password: Cypress.env('password') || validUser.password,
passConfirm: Cypress.env('passConfirm') || validUser.passConfirm
}
})
But when I try to make use of it in registration.spec.js in this way:
import RegistrationPage from "../page-objects/registrationPage"
import LoginPage from "../page-objects/loginPage"
describe('Registration page scenario mapping', () => {
it.only('Executes a sucessfull registration in the form', () => {
const registrationPage = new RegistrationPage()
cy.visit('customer/account/create')
registrationPage.fillRegistrationForm()
registrationPage.submitRegistrationForm()
registrationPage.verifyRegistration()
})
it('login', function(){
const loginPage = new LoginPage()
cy.visit('/')
cy.contains('a', 'Sign In').should('be.visible').click()
cy.contains('h1', 'Customer Login').should('be.visible')
loginPage.fillLoginForm()
})
})
It gives me an error in registrationPage.js saying that the values withing the .type() are undefined. I tried with validUser.firstname instead but same error and if I use just 'validUser' as value it says that is an object and you can't type that. I don't understand why if I put validUser.firstname doesn't recognize the value.
CypressError
cy.type() can only accept a string or number. You passed in: undefinedLearn more
cypress/page-objects/registrationPage.js:14:40
12 |
13 | cy.getRegistrationData()
> 14 | cy.get('[title="First Name"]').type(userData.firstname)
| ^
15 | cy.get('#lastname').type(userData)
16 | cy.get('[autocomplete="email"]').type(userData)
17 | cy.get('#password').type(userData)
Sorry if I made the question in the wrongway or something, I hope someone can help me out. Thanks
The difference between a function and a Custom Command is that a function returns a value which can be assigned to a variable, but a Custom Command passes the return value down the chain.
Function
const getRegistrationData = () => {
...
return ...
})
const registrationData = getRegistrationData()
Custom Command
Cypress.Commands.add('getRegistrationData', () => {
...
return ...
})
cy.getRegistrationData().then((registrationData) => { // access value here
...
})
So to use the custom command in the registration page,
class RegistrationPage{
fillRegistrationForm() {
cy.getRegistrationData().then((userData) => {
cy.get('[title="First Name"]').type(userData.firstname)
cy.get('#lastname').type(userData)
cy.get('[autocomplete="email"]').type(userData)
cy.get('#password').type(userData)
cy.get('#password-confirmation').type(userData)
})
Also, you don't need import commands from '../support/commands'
in the Registration page because custom commands are set globally, in the same way as built-in commands like cy.get()
can just be used anywhere in the test or page object code without importing anything.