1. Create file Platform_Login.cy.js under Cypress\e2e\Platform\Login
describe('My First Test', () => {
it('Visits Sana framwork', () => {
cy.visit('https://staging-platform.sana-commerce.com/')
// that the value has been updated
cy.get('#Email')
.type('s.kodagoda@sana-commerce.com')
.should('have.value', 's.kodagoda@sana-commerce.com')
cy.get('#Password')
.type('xxxxxxxxx@123')
.should('have.value', 'xxxxxxxxx@123')
cy.get('[type=submit]').click()
cy.title().should('eq','Sana Platform')
})
})
2. Create Folder Cypress\testbase\testbase.js
class testbase{
Fill(locator, text)
{
//Get element by by Html element
cy.get(locator).type(text)
}
Click(locator)
{
cy.get(locator).click()
}
}
module.exports = new testbase();
Make it advance with Xpath Addon
class testbase{
Fill(locator, text)
{
//Get element by by Xpath
if(locator.includes('//')) {
cy.xpath(locator).type(text)
}
//Get element by by Html element
else {
cy.get(locator).type(text)
}
}
Click(locator)
{
cy.get(locator).click()
}
}
module.exports = new testbase();
Update Login.cy.js
const I = require('../../../testbase/testbase')
describe('Test Login', () => {
beforeEach(()=>{
cy.visit('https://staging-platform.sana-commerce.com/')
})
it('Test Login',()=>{
I.Fill('#Email','s.kodagoda@sana-commerce.com')
})
})
Add file cypress/ pageObjects/loginPages.json
{
"Login": {
"LoginData": {
"Email": "#Email",
"Password": "#Password",
"CaptureCheckBox": "div.recaptcha-checkbox-border",
"LoginButton": "button.btn-block"
}
}
}
import page objects to the login page
...
const PlatformLogin = require('../../../pageObjects/loginPages.json')
describe('Test Login', () => {
...
it('Test Login',()=>{
I.Fill(PlatformLogin.Login.LoginData.Email,'s.kodagoda@sana-commerce.com')
})
...
import test data to login page
const I = require('../../../testbase/testbase')
const PlatformLogin = require('../../../pageObjects/loginPages.json')
const TestData = require('../../../testdata/platformLoginData.json')
describe('Test Login', () => {
beforeEach(()=>{
cy.visit('https://staging-platform.sana-commerce.com/')
})
it('Test Login',()=>{
I.Fill(PlatformLogin.Login.LoginData.Email,TestData.Login.LoginUserData.Email)
})
})
Finaly Add Password and Login button
const I = require('../../../testbase/testbase')
const PlatformLogin = require('../../../pageObjects/loginPages.json')
const TestData = require('../../../testdata/platformLoginData.json')
describe('Test Login', () => {
beforeEach(()=>{
cy.visit('https://staging-platform.sana-commerce.com/')
})
it('Test Login',()=>{
I.Fill(PlatformLogin.Login.LoginData.Email,TestData.Login.LoginUserData.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,TestData.Login.LoginUserData.Password)
I.Click(PlatformLogin.Login.LoginData.LoginButton)
})
})
Stage 2
How to use Fixtures (Load set of data located in a file)
copy Platform_Login.cy.js to the fixtures folder
Fat arrow function'=>' with normal function
this keyword not working on Fat arrow function
()=> == function()
(data)) => == function(data)
describe('Test Login', () => {
...
//Not working
cy.fixture('PlatformLogins').then((data) => {
this.data = data;
cy.log('e-mail: ',this.data.Email)
})
PlatformLogins.json {
"Name":"should login to Home page",
"Email":"s.kodagoda@sana-commerce.com",
"Password":"1smStandard@123",
"Expected":"Invalid login attempt"
}
it('Test Fixture,Get All Platform Emails.', function() {
cy.fixture('PlatformLogins').then(function(TestDataList) {
this.TestDataList = TestDataList;
cy.log('e-mail: ',this.TestDataList.Email)
})
})
add another 'it'
it('Test Fixture,Login Platform Emails.', function() {
cy.fixture('PlatformLogins').then(function(TestDataList) {
this.TestDataList = TestDataList;
cy.log('e-mail: ',this.TestDataList.Email)
I.Fill(PlatformLogin.Login.LoginData.Email,this.TestDataList.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,this.TestDataList.Password)
I.Click(PlatformLogin.Login.LoginData.LoginButton)
})
Test with Multiple data
update PlatformLogins.json
[
{
"Name":"should login to Home page",
"Email":"apitestuser@sana-commerce.com",
"Password":"xxxxxxxxxxxxxxxxxxxxxx",
"Expected":"Invalid login attempt"
},
{
"Name":"should display incorrect user name message",
"Email":"xxx@sana-commerce.com",
"Password":"xxx@123",
"Expected":"Invalid login attempt"
},
{
"Name":"should display incorrect password message",
"Email":"xxx@sana-commerce.com",
"Password":"xxx@123",
"Expected":"Invalid login attempt"
}
]
add foreach to a basic method
it('Test Fixture,Get All Platform Emails.', function() {
cy.fixture('PlatformLogins').then(function(TestDataList) {
this.TestDataList = TestDataList;
this.TestDataList.forEach(testLogin => {
cy.log('e-mail: ',testLogin.Email)
})
//cy.log('e-mail: ',this.TestDataList.Email)
})
})
add foreach to a Login
it('Test Fixture,Login Platform Emails.', function() {
cy.fixture('PlatformLogins').then(function(TestDataList) {
this.TestDataList = TestDataList;
this.TestDataList.forEach(testLogin => {
I.Fill(PlatformLogin.Login.LoginData.Email,testLogin.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,testLogin.Password)
I.Click(PlatformLogin.Login.LoginData.LoginButton)
})
})
})
create a folder fixture/testData and copy PlatformLogins.json
get file
const TestDataList = require('../../../fixtures/testData/PlatformLogins.json')
// ~ ForEach Example ~
TestDataList.forEach(testLogin =>{
it(testLogin.Name,() =>{
I.Fill(PlatformLogin.Login.LoginData.Email,testLogin.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,testLogin.Password)
I.Click(PlatformLogin.Login.LoginData.LoginButton)
if(testLogin.Name=="should login to Home page")
{
}
else{
I.SeeText(PlatformLogin.Login.LoginData.ErrorMessage,testLogin.Expected)
//cy.get(PlatformLogin.Login.LoginData.ErrorMessage).should('have.text',testLogin.Expected)
}
})
})
Cypress Hooks
Create file e2e/hooks.cy.js
/*
Order
1. before --> Execute once, as soon as the first Test Script is executed
2 beforeEach > Executed Before Each TS is executed
3. testExecution
4. afterEach > Executed After Each TS is executed
5. after > Execute once, as soon as the Last Test Script is executed
*/
describe('',function(){
before(function(){
cy.log('Before')
})
beforeEach(function(){
cy.log('Before each')
})
it('TC #1',function(){
console.log('TC #1')
})
it('TC #2',function(){
console.log('TC #2')
})
it('TC #3',function(){
console.log('TC #3')
})
it('TC #4',function(){
console.log('TC #4')
})
afterEach(function(){
cy.log('After each')
})
after(function(){
cy.log('After')
})
})
Commands
video 12 (https://www.youtube.com/watch?v=66bEpdatEYQ&list=PLYDwWPRvXB8-8LG2hZv25HO6C3w_vezZb&index=12&ab_channel=JoanMedia)
support/commands.js
Cypress.Commands.add('typeLogin',(username,password)=>{
cy.get('#Email').type(username)
cy.get('#Password').type(password)
})
const PlatformLogin = require('../pageObjects/loginPages.json')
Cypress.Commands.add('typeLogin',(username,password)=>{
cy.get(PlatformLogin.Login.LoginData.Email).type(username)
cy.get(PlatformLogin.Login.LoginData.Password).type(password)
})
create file
e2e/Commands/commadsTest.cy.js
typeLogin can call anywhere ,support/e2e.js jas already import
//This is e2e.js
//Import commands.js using ES2015 syntax:
import './commands'
describe('Command example',function(){
beforeEach(function(){
cy.visit('https://staging-platform.sana-commerce.com/')
cy.typeLogin('s.kodagoda@sana-commerce.com','abc')
})
it('Visits Sana framwork', () => {
cy.log('test comands')
cy.url().should('include', 'Home')
})
})
Add logout
command.js
Cypress.Commands.add('logout',()=>{
cy.get('.image > .img-circle').click()
cy.get("#logoutForm > a").click()
})
commandTest.cy.js
it('Test Login', () => {
cy.log('test comands')
cy.url().should('include', 'Home')
})
afterEach(function(){ <--------
cy.logout()
})
Move Logout details to pageobject
cypress/pageObject/homePages.json
{
"Home": {
"HeaderPanel": {
"PlatformLogo": ".logo",
"ProfileImage" : ".image > .img-circle",
"ButonLogout" : "#logoutForm > a"
}
},
"LeftPanelMenu": {
"UserAccounts" : "//p[contains(text(),'User accounts')]",
"ManageRolesMenuItem" : "//p[contains(text(),'Manage roles')]"
}
}
update loginHelper
export function I_Login(){
...
}
export function I_Logout(){
I.Click(PlaformHome.Home.HeaderPanel.ProfileImage)
I.Click(PlaformHome.Home.HeaderPanel.ButonLogout)
}
How Login/Logout use in Sana platform Code.
use separate Hepler class cypress/helpers/loginHelper.js
const I = require('../testbase/testbase')
const PlatformTestData = require('../fixtures/platformLoginData.json')
const PlaformLogin = require('../pageObjects/loginPages.json')
export function I_Login(){
I.Fill(PlaformLogin.Login.LoginData.Email,PlatformTestData.Login.LoginUserData.Email)
I.Fill(PlaformLogin.Login.LoginData.Password,PlatformTestData.Login.LoginUserData.Password)
I.Click(PlaformLogin.Login.LoginData.LoginButton)
}
create file e2e/Platfrom/Home/PlatformHome.cy.js
import { I_Login } from "../../../helpers/loginHelper";
describe('Home page Testing', () => {
it('get url from config file', () => {
cy.visit('https://staging-platform.sana-commerce.com/')
I_Login()
})
})
How to add site URL on config file
update cypress.config.js
Old versions have cypress.json but with new version its use on cypress.config.js
...
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
baseUrl: 'https://staging-platform.sana-commerce.com/'
},
});
PlatformHome.cy.js
import { I_Login } from "../../../helpers/loginHelper";
describe('Home page Testing', () => {
it('get url from config file', () => {
cy.visit(Cypress.config().baseUrl)
I_Login()
})
})
Move Visit method to testbase.js
SeeText(locator, expectedText)
{ ... }
Open(url="")
{
cy.visit(url);
}
PlatformHome.cy.js
import { I_Login } from "../../../helpers/loginHelper";
const I = require('../../../testbase/testbase')
describe('Home page Testing', () => {
it('get url from config file', () => {
I.Open(Cypress.config().baseUrl)
I_Login()
})
})
If only import a function inside a file separately.
import { I_Login } from "../../../helpers/loginHelper";
if want to access all methods/functions
const LoginHelper = require('../../../helpers/loginHelper')
PlatformHome.cy.js
const LoginHelper = require('../../../helpers/loginHelper')
const I = require('../../../testbase/testbase')
describe('Home page Testing', () => {
it('get url from config file', () => {
I.Open(Cypress.config().baseUrl)
LoginHelper.I_Login()
LoginHelper.I_Logout()
})
})
add before each and after each.
const LoginHelper = require('../../../helpers/loginHelper')
const I = require('../../../testbase/testbase')
describe('Home page Testing', () => {
beforeEach(function(){
I.Open(Cypress.config().baseUrl)
LoginHelper.I_Login()
})
it('get url from config file', () => {
cy.log('test comands')
cy.url().should('include', 'Home')
})
afterEach(function(){
LoginHelper.I_Logout()
})
})
Log and URL assertion move to testbase.js
Open(url="")
{
...
}
Log(text){
cy.log(text)
}
UrlInclude(pageName){
cy.url().should('include', pageName)
}
SeeInTitle(pageTitle)
{
cy.title().should('contain', pageTitle);
}
PlatformHome.cy.js
describe('Home page Testing', () => {
beforeEach(function(){
..
})
it('get url from config file', () => {
I.Log('test comands')
I.UrlInclude('Home')
I.SeeInTitle('Sana Platform')
})
...
})
Login with Session
need to add following to cypress.config.js
experimentalSessionAndOrigin : true
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
baseUrl: 'https://staging-platform.sana-commerce.com/',
experimentalSessionAndOrigin : true
},
});
following example can pass session name as single string or multiple strings.
describe('Login test with session', () => {
beforeEach(()=>{
cy.session('user',()=>{ //<-------- single string
LoginHelper.I_Login()
})
})
multiple strings.
cy.session(['user','password',.....],()=>{
update login helper
export function I_Login(){
I.Open(Cypress.config().baseUrl) <--------
I.Fill(PlaformLogin.Login.LoginData.Email,PlatformTestData.Login.LoginUserData.Email)
I.Fill(PlaformLogin.Login.LoginData.Password,PlatformTestData.Login.LoginUserData.Password)
I.Click(PlaformLogin.Login.LoginData.LoginButton)
}
export function I_LoginWithSession(){
cy.session('user',()=>{
I.Open('/')
I.Fill(PlatformLogin.Login.LoginData.Email,PlatformTestData.Login.LoginUserData.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,PlatformTestData.Login.LoginUserData.Password)
I.Click(PlatformLogin.Login.LoginData.LoginButton)
})
}
When use commands.js
const PlatformLogin = require('../pageObjects/loginPages.json')
const PlatformTestData = require('../fixtures/platformLoginData.json')
const I = require('../testbase/testbase')
...
Cypress.Commands.add('LoginWithSession',()=>{
cy.session('user',()=>{
I.Open('/')
I.Fill(PlatformLogin.Login.LoginData.Email,PlatformTestData.Login.LoginUserData.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,PlatformTestData.Login.LoginUserData.Password)
I.Click(PlatformLogin.Login.LoginData.LoginButton)
})
})
before and after use session Time reduce
always need to call the base URL
it('Validate main 4 items',()=>{
I.Open('/') <---------------
cy.get('.container-fluid .row').find('.col-lg-3').should('have.length', 4)
})
use unique id for session
Install uuid
npm install uuid
command.js
import { v4 as uuidv4 } from 'uuid';
const userUuid = "user_"+uuidv4(); //<-----
Cypress.Commands.add('LoginWithSession',()=>{
cy.session(userUuid,()=>{ //<-----
//cy.session('user',()=>{
//cy.log("uuid :"+userUuid)
I.Open('/')
I.Fill(PlatformLogin.Login.LoginData.Email,PlatformTestData.Login.LoginUserData.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,PlatformTestData.Login.LoginUserData.Password)
I.Click(PlatformLogin.Login.LoginData.LoginButton)
})
})
Update homePages.json
"Home": {
...
"DashBoardCards":[
{
"Name":"ActiveTrial",
"Button":":nth-child(1) > .small-box > .small-box-footer",
"RedirectUrl":"Webstore/AllWebstores?category=Active%20Trials",
"DetailPageRedioButton":"#activeTrialsCheckBox"
},
{
"Name":"InProduction",
"Button":":nth-child(2) > .small-box > .small-box-footer",
"RedirectUrl":"Webstore/AllWebstores?category=In%20Production",
"DetailPageRedioButton":"#inProductionCheckBox"
},
{
"Name":"ExpiredTrials",
"Button":":nth-child(3) > .small-box > .small-box-footer",
"RedirectUrl":"Webstore/AllWebstores?category=Expired%20Trials",
"DetailPageRedioButton":"#extendTrialsCheckBox"
},
{
"Name":"ExpiredTrials",
"Button":":nth-child(4) > .small-box > .small-box-footer",
"RedirectUrl":"#",
"DetailPageRedioButton":"#archivedCheckBox"
}
]
PlatformHome.cy.js
...
it('Redirect to Active trails',()=>{
I.Open('/')
I.Click(HomePage.DashBoard.DashBoardCards.ActiveTrial.Name)
I.UrlInclude(HomePage.DashBoard.DashBoardCards.ActiveTrial.RedirectUrl)
//I.Wait(1000)
cy.get(HomePage.DashBoard.DashBoardCards.ActiveTrial.DetailPageRedioButton).should('be.checked').and('have.value', 'Active Trials')
})
it('Redirect to In production',()=>{
I.Open('/')
I.Click(HomePage.DashBoard.DashBoardCards.InProduction.Name)
I.UrlInclude(HomePage.DashBoard.DashBoardCards.InProduction.RedirectUrl)
cy.get('#inProductionCheckBox').should('be.checked').and('have.value', 'In Production')
})
...
To reduce code, we can write above as following
PlatformHome.cy.js
//use for each
const dashBoardCards = HomePage.DashBoardCards;
dashBoardCards.forEach(dashBoardCard =>{
it("Testing Dash board card: " + dashBoardCard.Name,() =>{
I.Open('/')
I.Click(dashBoardCard.Button)
I.UrlInclude(dashBoardCard.RedirectUrl)
I.Wait(1000)
cy.get(dashBoardCard.DetailPageRedioButton)
.should('be.checked')
.and('have.value', dashBoardCard.RedioButtonValue)
})
})
Home Header buttons
homePage.json
"Home": {
...
"TopMenu":[{
"Name":"Manage",
"Button":".main-header > .navbar-nav > :nth-child(1) > .nav-link",
"RedirectUrl":"/Webstore/AllWebstores"
},
{
"Name":"New",
"Button":".navbar-nav > :nth-child(2) > .nav-link",
"RedirectUrl":"/Webstore/Install"
},
{
"Name":"Create",
"Button":".navbar-nav > :nth-child(3) > .nav-link",
"RedirectUrl":"/User/CreateUser"
},
{
"Name":"Help",
"Button":".navbar-nav > :nth-child(4) > .nav-link",
"RedirectUrl":"/help"
}
]
}
},
How to write one by one
//Home Header buttons : Manage
it('Redirect to Expired Trials',()=>{
I.Open('/')
//const ss = HomePage.Home.HeaderPanel.TopMenu;
I.Click(HomePage.Home.HeaderPanel.TopMenu[0].Button)
I.UrlInclude(HomePage.Home.HeaderPanel.TopMenu[0].RedirectUrl)
cy.get(HomePage.Home.HeaderPanel.TopMenu[0].DetailPageRedioButton).should('be.checked')
.and('have.value', 'All')
})
Home page Left Panel menu Testing
NewInstallation.json
},
"LeftPanelMenu": {
"MenuButton":"cy.get('.main-nav-wrapper > .navbar-nav > .nav-item > .nav-link')",
"LeftPanelMenuItems":[
{
"Name":"Installations",
"Button":".active",
"MenuItems" :[{
"Name":"New installation",
"Button":".menu-open > .nav > :nth-child(1) > .nav-link",
"RedirectUrl":"/Webstore/Install"
},
{
"Name":"All installations",
"Button":".menu-open > .nav > :nth-child(2) > .nav-link",
"RedirectUrl":"/Webstore/AllWebstores"
}
]
},
{
"Name":"Approvals",
"Button":"#approvalMenu > [href='#']",
"MenuItems" :[{
"Name":"New installation",
"Button":"#approvalMenu > .nav > :nth-child(1) > .nav-link",
"RedirectUrl":"/Approval/WebstoreInstallationRequests"
}
]
}
]
},
Platform.cy.js
// Left Panel Menu --------------------------------------------------
const leftPanelMenuItems = HomePage.LeftPanelMenu.LeftPanelMenuItems;
leftPanelMenuItems.forEach(leftPanelMenuItem =>{
const subMenuItems = leftPanelMenuItem.MenuItems;
subMenuItems.forEach(subMenuItem =>{
it("Left Panel: " + leftPanelMenuItem.Name+" : " + subMenuItem.Name,() =>{
I.Open('/')
I.Click(leftPanelMenuItem.Button)
I.Click(subMenuItem.Button)
I.UrlInclude(subMenuItem.RedirectUrl)
})
})
Add Snippet for VS Code
Ctrl +shift +p
type "snippet"
select javascript it will open javascript .js file
"Console log":{
"prefix":"cl",
"body":"console.log($1);",
"description": "Console Log"
}
When yo type cl it will create the code for you
console.log();
https://snippet-generator.app/
},
"IT": {
"prefix": "it",
"body": [
"it(${1:functionName},()=>{",
"})"
],
"description": "IT"
}
after use
cypress screenshort.
it(userData.Title,() =>{
I.Fill(PlatformLogin.Login.LoginData.Email,userData.Email)
I.Fill(PlatformLogin.Login.LoginData.Password,userData.Password)
cy.screenshot(); //<----
})
it will create a new folder.
How to retry
...
baseUrl: 'https://staging-platform.sana-commerce.com/',
experimentalSessionAndOrigin : true ,
retries:2 // 1 + 2 extra times
},
});
Configure Dashboard
Cypress.config.js
login and add project id
module.exports = defineConfig({
....
retries:3,
projectId: "w81smh"
},
});
cypress dashboard
https://www.youtube.com/watch?v=ydTviHjpxh0&ab_channel=JoanMedia
past on :cypress.config.js
e2e: {
.....
retries:3,
projectId: "w81smh" // <-------
},
npx cypress run --record --key da6d9485-4c46-49f9-b5e3-c4a9926889ef
Note: To locate the project-id and record-key of your Cypress project, navigate to Project > Project Settings in the Cypress dashboard. You can find the project-id and record-key under the General and
cypress-axe
https://www.npmjs.com/package/cypress-axe
npm install --save-dev cypress-axe
package.json record adds automatically.
"cypress-axe": "^1.0.0",
add e2e.js
import 'cypress-axe'
accessbility.cy.js
describe('Testing', () => {
it("How to test accesbility",()=>{
cy.visit("https://staging-platform.sana-commerce.com/")
cy.injectAxe() // staart the injector / scan the site
cy.checkA11y()
})
})
improve
https://www.youtube.com/watch?v=TaBhwaOy1XI&ab_channel=Sparkbox
Add Emoji
click extension > type emoji
install
File >Preferance > Settings
User Tab> Extention > :emojisense > Edit in Settings .json
paset the flowing test inside
emojisense.languages
"javascript.validate.enable": false,
"abap": true,
"bat": true,
"bibtex": true,
"clojure": true,
"coffeescript": true,
"c": true,
"cpp": true,
"csharp": true,
"css": true,
"diff": true,
"dockerfile": true,
"fsharp": true,
"git-commit": true,
"git-rebase": true,
"go": true,
"groovy": true,
"handlebars": true,
"html": true,
"ini": true,
"java": true,
"javascript": true,
"javascriptreact": true,
"json": true,
"jsonc": true,
"latex": true,
"less": true,
"lua": true,
"makefile": true,
"markdown": true,
"objective-c": true,
"objective-cpp": true,
"perl6": true,
"php": true,
"powershell": true,
"jade": true,
"python": true,
"r": true,
"razor": true,
"ruby": true,
"rust": true,
"scss": true,
"sass": true,
"shaderlab": true,
"shellscript": true,
"sql": true,
"swift": true,
"typescript": true,
"typescriptreact": true,
"tex": true,
"vb": true,
"xml": true,
"xsl": true,
"yaml": true
}
full doc looks like as following
{
"diffEditor.codeLens": true,
"javascript.referencesCodeLens.enabled": true,
"javascript.referencesCodeLens.showOnAllFunctions": true,
"typescript.implementationsCodeLens.enabled": true,
"typescript.referencesCodeLens.enabled": true,
"typescript.referencesCodeLens.showOnAllFunctions": true,
"emojisense.languages": {
"markdown": true,
"plaintext": {
"markupCompletionsEnabled": true,
"emojiDecoratorsEnabled": true
},
"scminput": true,
"git-commit": true,
"javascript.validate.enable": false,
"abap": true,
"bat": true,
"bibtex": true,
"clojure": true,
"coffeescript": true,
"c": true,
"cpp": true,
"csharp": true,
"css": true,
"diff": true,
"dockerfile": true,
"fsharp": true,
"git-commit": true,
"git-rebase": true,
"go": true,
"groovy": true,
"handlebars": true,
"html": true,
"ini": true,
"java": true,
"javascript": true,
"javascriptreact": true,
"json": true,
"jsonc": true,
"latex": true,
"less": true,
"lua": true,
"makefile": true,
"markdown": true,
"objective-c": true,
"objective-cpp": true,
"perl6": true,
"php": true,
"powershell": true,
"jade": true,
"python": true,
"r": true,
"razor": true,
"ruby": true,
"rust": true,
"scss": true,
"sass": true,
"shaderlab": true,
"shellscript": true,
"sql": true,
"swift": true,
"typescript": true,
"typescriptreact": true,
"tex": true,
"vb": true,
"xml": true,
"xsl": true,
"yaml": true
}
}
Then Type -- > :Circle
/*
//checkPageA11y
//https://www.youtube.com/watch?v=TaBhwaOy1XI&ab_channel=Sparkbox
Cypress.Commands.add('checkPageA11y', (path) => {
cy.visit(path)
cy.injectAxe() // staart the injector / scan the site
cy.checkA11y(null,null,callback)
})
function callback(violations){
violations.forEach(violation =>{
const nodes = Cypress.$(violation.nodes.map(node=> node.target).join(','))
Cypress.log({
name:`${severityIndicators[violation.impact]} A11y`,
consoleProps:()=> violation,
$el:nodes,
message:`[${violation.help}](${violation.helpUrl})`
})
violation.nodes.forEach(({target}) => {
Cypress.log({
name: '🔧',
consoleProps:() => violation,
$el: Cypress.$(target.join(',')),
message:target
})
})
})
}
const severityIndicators={
minor: 'Minor ⚪',
moderate: 'Moderate 🟡',
serious: 'Serious 🟠',
critical: 'Critical 🔴'
}
*/
accesbilityhelper.js
//checkPageA11y
//https://www.youtube.com/watch?v=TaBhwaOy1XI&ab_channel=Sparkbox
const severityIndicators={
minor: 'Minor ⚪',
moderate: 'Moderate 🟡',
serious: 'Serious 🟠',
critical: 'Critical 🔴'
}
function callback(violations){
violations.forEach(violation =>{
const nodes = Cypress.$(violation.nodes.map(node=> node.target).join(','))
Cypress.log({
name:`${severityIndicators[violation.impact]} A11y`,
consoleProps:()=> violation,
$el:nodes,
message:`[${violation.help}](${violation.helpUrl})`
})
violation.nodes.forEach(({target}) => {
Cypress.log({
name: '🔧',
consoleProps:() => violation,
$el: Cypress.$(target.join(',')),
message:target
})
})
})
}
export function I_CheckPageAccesbility_A11y(path){
cy.visit(path)
cy.injectAxe() // start the injector / scan the site
cy.checkA11y(null,null,callback)
}
Type script
install
npm install --save-dev typescript
it will add record in package.json
"devDependencies": {
"cypress": "^10.3.0",
"cypress-axe": "^1.0.0",
"cypress-xpath": "^2.0.0",
"typescript": "^4.8.4" <------------------------
},
Configure tsconfig.json
We recommend creating a tsconfig.json inside your cypress folder with the following configuration:
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress", "node"]
},
"include": ["**/*.ts"]
}
Invoke
can use the Jquery function inside cypress
cy.get('#IPAddresses').invoke('attr', 'placeholder').should('contain', 'The partne..')
cypress file upload
npm install --save-dev cypress-file-upload
find
// cy.get(".card-columns").find('.card').each(($card) => {
cy.get(overviewPage.Overview.CardsPath).each(($card) => {
count += 1
}).then(() =>{
expect(count, 'count').to.equal(8)
cy.get(overviewPage.Overview.CardsPath).its('length').should('eq', count)
})
testautomationu.applitools.com
from: https://testautomationu.applitools.com/cypress-tutorial/chapter3.html
Whether Cypress will watch and restart tests on test file changes.
watchForFileChanges:false //it will control restart tests on test file changes.
Delay an element
?delay-new-todo=5000'
cy.get('.new-todo',{timeout:6000})
it("functionName",()=>{
cy.visit('http://todomvc-app-for-testing.surge.sh/?delay-new-todo=5000')
cy.get('.new-todo',{timeout:6000}).type("Clean room{enter}")
})
How to get the length of the collection and return
it.only("Multiple assertions",()=>{
cy.get("table[id='partnerGrid'] thead > tr >th")
.then(item =>{
const listingCount = item.length
//const listingCount = Cypress.$(item).length;
cy.log("List count "+listingCount)
})
})
simple way
cy.get("#partnerGrid>thead>tr>th").should('have.length','4')
How to throw an error
throw new Error("sdsdsd")
Expect text
expect(item[1]).to.contain.text('Sana ERP partner')
https://testautomationu.applitools.com/advanced-cypress-tutorial/chapter4.html
When the element is hidden
cy.get("location").invoke('show')
.click()
// add css class
cy.get("location")
.invoke('addClass','NewClassName')
//hover change event trigger
cy.get("location")
.trigger('mouseover')
environment variables
export function FillGenerateName(locator,name){
const randomName = Name_Alpha_Numeric()
name = name+randomName
cy.get(locator).type(name)
// Create Environment variables
Cypress.env('GenerateWebStoreName', name) //<-------------
return name;
}
let webStoreName = Cypress.env('GenerateWebStoreName')
Get name from and assign to the variable
cy.get(allWebStoresTable.LatestWebStoreNamePath)
.then(item =>{
webStoreName = item.text()
I.Log("Site Name inside: "+ webStoreName)
covert API response to json
convert json to string
const webstores =JSON.stringify(res.body)
cy.log(webstores)
Cypress Auto-completion use following
/// <reference types="cypress"/>
---------------------------------------------------------------------------
Install Cypress Grep for tagging
npm install -g cypress-grep
npm i -D @cypress/grep --force
it will auto-update package,json and package-lock.json
update e2e.ts
// Import commands.js using ES2015 syntax:
import './commands'
import './commands/commands'
import 'cypress-axe'
import 'cypress-file-upload'
// Alternatively you can use CommonJS syntax:
// require('./commands')
require('cypress-xpath');
const registerCypressGrep = require('@cypress/grep')
registerCypressGrep()
// if you want to use the "import" keyword
// note: `./index.d.ts` currently extends the global Cypress types and
// does not define `registerCypressGrep` so the import path is directly
// pointed to the `support.js` file
import registerCypressGrep from '@cypress/grep/src/support'
registerCypressGrep()
add command so no need to call all the cy.ts pages
describe('🥇 Field Verification',{tags:'@smoke'}, () => {
npx cypress run --env grepTags=@smoke
npx cypress run --headed --env grepTags=@smoke --record --key 56dcf788-902a-42f3-ba5f-93b05694a61d
How to run Head mode
npx cypress run --headed
Add reporting to Cypress
install cypress-mochawesome-reporter
follow this : https://www.npmjs.com/package/cypress-mochawesome-reporter
1 install cypress-mochawesome-reporter
npm i --save-dev cypress-mochawesome-reporter
--force
use following to ignore warnings
npm i --save-dev cypress-mochawesome-reporter --force
it will update package.json
"cypress-mochawesome-reporter": "^3.5.0", <--------------------
2 Change cypress reporter & setup hooks
const { defineConfig } = require('cypress');
module.exports = defineConfig({
reporter: 'cypress-mochawesome-reporter',
e2e: {
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
},
},
});
3 Add to cypress/support/e2e.js
import 'cypress-mochawesome-reporter/register';
it will create a folder as
~\cypress\reports\html
-----------------------------------------------------------------------------------------------------------
Change base URL on comandline
package.json
"scripts": {
...
"cypress:open4": "cypress open --config baseUrl=http://www.google.com/",
},
execute as follows,
npm run cypress:open4
Visual testing
https://applitools.com/
https://applitools.com/tutorials/quickstart/web/cypress#applitools-eyes-cypress-sdl
to install
npm install @applitools/eyes-cypress
and
npx eyes-setup
it will add new dependency to 'package.json'
Cypress Chrome recorder
https://www.youtube.com/watch?v=-RJuZrq-wOk&t=194s&ab_channel=Cypress.io
1. install the chrome browser extension.
2. record the process and save
3. When saving as JSON you need to convert JSON to a cypress file
to do that we are required to install following
npm install --location=global @cypress/chrome-recorder
(disable the Global protector)
4. after installation, convert the file.
create output folder path (cypress/tests/ui )
npx @cypress/chrome-recorder D:/Recordingcy.json -o=cypress/tests/ui
or use Export via extension > cypress Test
Cypress Cross-origin testing
install "@cypress/webpack-preprocessor"
cypress.config.ts set following
chromeWebSecurity:false
experimentalOriginDependencies :true,
To prevent button click exceptions use
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from failing the test
return false
})
Cypress API plugging
https://www.youtube.com/watch?v=kENXELkT4O4&ab_channel=LambdaTest
npm install --save-dev @bahmutov/cy-api
command.ts
import '@bahmutov/cy-api'
update tsconfig.json
"types": ["cypress", "node","cypress-xpath","cypress-axe","@bahmutov/cy-api"],
output
Cy spok
its uses to make expected body items value generic
chai-json-schema
npm install chai-json-schema
e2e.ts
chai.use(require('chai-json-schema'));
Json Not working with typescript
to fix add folowing to tsconfig file
{
"compilerOptions": {
...
"resolveJsonModule": true, <-------------------
"esModuleInterop": true,
"allowSyntheticDefaultImports": true, // use json import
},
}
cypress API New with new update
https://www.npmjs.com/package/cypress-plugin-api
it will add new dependent
"dependencies": {
"chai-json-schema": "^1.5.1",
"cypress-plugin-api": "^2.11.0" <--------------------------------
}