top of page
Writer's pictureVani Suruvu

Cypress - Part 3 - Handling Child Tabs, iFrames, Tables, Mouse Events, File Upload, Hooks & Tags

Welcome back to third part of Cypress series. Second part of blog can be found here. In this blog, we will be seeing how to handle Child Tabs, iFrames, Tables, Mouse Events, File Upload, Hooks & Tags in Cypress.


Handling Child Tabs:

  • Handling Child Tabs in same window or different window opened from initial window.

  • When target = “_blank” for <a> tag, the window opens in new tab in same window. Without target attribute in anchor tag, the link opens in same tab.

  • Invoke method helps to remove attribute at runtime, here we remove target attribute.

// Appraoch1: remove target attribute
describe('Handle Tabs', ()=> {
	it('Approach1', () => {
		cy.visit('https://the-internet.herokuapp.com/windows')
		cy.get('.example >a').invoke('removeAttr', 'target').click();
		//verify child window
		cy.url().should('include','https://the-internet.herokuapp.com/windows/new')
		//go back to parent tab
		cy.wait(4000);
		cy.go('back'); 
		
	})
})

Approach2: Open parent tab, get href attribute value, then visit the url in href, in the same tab.

Limitation in this approach: parent and child domain should be same. In this case, 'https://the-internet.herokuapp.com/' should be same for both parent and child URLs. Subdomains can be different. Here target page opens on same tab, like before approach.

     // visit href value in same tab
    it('Approach2', () => {
		cy.visit('https://the-internet.herokuapp.com/windows')
		cy.get('.example >a').then((e)=>{
            let url = e.prop('href'); // extract href value
            cy.visit(url);
        })
        
        // do validations 
		//verify child window
		cy.url().should('include','https://the-internet.herokuapp.com/windows/new')
		//go back to parent tab
		cy.wait(4000);
		cy.go('back'); 
		
	})

Child Window also works the same way, we need to write a jquery function, to open in same window.


Handling iFrames:

In the page, we have a frame, with default text. To provide text in the frame, we have to handle frame. We cannot directly interact with elements in the frame. We will see various approaches to handle iFrames in Cypress.


Approach1: iFrame will be in #document tag, which has <html> tag inside, like a new HTML page inside #document. First, we have to get iFrame, then get document, then body and then go to elements.

// Approach1
describe("Handling Frames", ()=>{
	it('Approach1', ()=>{
		cy.visit("http://the-internet.herokuapp.com/iframe")
		const iframe = cy.get("#mce_0_ifr")
				.its('0.contentDocument.body')
				.should('be.visible')
				.then(cy.wrap);
		iframe.clear().type("Welcome");
	})
})

To access first document inside frame, use its('0.contentDocument.body')

then(cy.wrap) --> wraps frame and returns frame.

To bold the entered text "Welcome":

iframe.clear().type("Welcome {cmd+a}") // select all text

cy.get("[aria-label='Bold']").click();


Approach2: When there are many iFrames in the web page, we can use custom command in Cypress to handle this. In commands.js file, add below lines, which can be reused for calling other iframes.

Cypress.Commands.add('getIFrame', (iframe) =>{
	return cy.get(iframe)
	.its('0.contentDocument.body')
	.should('be.visible')
	.then(cy.wrap);
})
// Approach2 using reusable commands
it('Approach2 - using custom command', ()=>{
        cy.visit("http://the-internet.herokuapp.com/iframe")
        cy.getIFrame("#mce_0_ifr").clear().type("Welcome {ctrl+a}");
        cy.get("[aria-label='Bold']").click();
    })

Approach3: Using Cypress iFrame plugin.

Install cypress-iframe plugin with command: npm install -D cypress-iframe

We get additional commands like frameLoaded, iframe, enter, etc.

Also, import 'cypress-iframe' as first line in iframes.cy.js file.


// Approach3 - using cypress-iframe plugin 
// available in latest version of cypress
    it('Approach3 - using cypress-iframe plugin', ()=>{
        cy.visit("http://the-internet.herokuapp.com/iframe")
        cy.frameLoaded('#mce_0_ifr')  // loads the frame
        cy.iframe('#mce_0_ifr').clear().type("Welcome")   // switch to the frame
    })

Handling Tables:

For this, we will see https://demo.opencart.com/admin/index.php page, which requires login to access tables. If alert is there, which is by default handled. Security notification, if appears, needs to be closed. Navigate to Customers -> Customers table. Data is rendered in multiple pages, which we can see handling pagination.


We will be using beforeEach hook in Cypress, to login to the web page for every test case - it block. We can also keep common steps in this hook.


We will see four tasks to read data from table.

a. Check Number of Rows & Columns

b. Check cell data from specific Row & Column

c. Read all the rows & columns data in the first page

d. Pagination


describe('Handle Tables', ()=>{
	beforeEach('Login',()=>{  // hook
        cy.visit("https://demo.opencart.com/admin/index.php")
        cy.get("#input-username").type("demo");
        cy.get("#input-password").type("demo");
        cy.get("button[type='submit']").click();

        cy.get(".btn-close").click();
        // Customers  --> Customers
        cy.get("#menu-customer>a").click();  // left menu
        cy.get("#menu-customer>ul>li:first-child").click();

	})
	
    // it.skip, skips execution of that test case.
	it('Check Number of Rows & Columns', ()=>{
        // here every page has same number of rows and columns
        cy.get("table[class='table table-bordered table-hover']>tbody>tr").should('have.length', '10');
        cy.get("table[class='table table-bordered table-hover']>thead>tr>td").should('have.length', '7');

	})

	it('Check cell data from specific Row & Column', ()=>{
        cy.get("table[class='table table-bordered table-hover']>tbody>tr:nth-child(5)>td:nth-child(3)")
            .contains("princytrainings4@gmail.com");
	})

	it('Read all the rows & columns data in the first page', ()=>{
        cy.get("table[class='table table-bordered table-hover']>tbody>tr")
            .each( ($row, index, $rows)=>{   // arrow function
                cy.wrap($row).within( ()=>{
                    cy.get("td").each(($col, index, $cols) =>{
                        cy.log($col.text());
                    })
                })
            })
	})

	it('Pagination', ()=>{
        let totalPages;
        // find total number of pages
        cy.get(".col-sm-6.text-end").then( (e)=> {
            let mytext = e.text(); // showing 1 to 10 of 5581 (559 Pages)
            totalPages = mytext.substring(mytext.indexOf("(")+1, mytext.indexOf("Pages")-1);
            cy.log("Total number of pages in a table --> "+ totalPages);
        })

        let totalPagesTest = 5;  // test for only 5 pages instead of 559 pages
        for(let p=1; p<=totalPagesTest; p++ ){
            if(totalPagesTest >1){
                cy.log("Active page is-->" +p);
                cy.get("ul[class='pagination']>li:nth-child("+p+")").click();
                cy.wait(1000);

                // read data from particular page
                cy.get("table[class='table table-bordered table-hover']>tbody>tr")
                    .each( ($row, index, $rows) =>{
                        cy.wrap($row).within( ()=>{
                            cy.get('td:nth-child(3)').then( (e)=>{
                                cy.log(e.text());  // log only email
                            })
                        })
                    })
            }
        }
    })
})

Handling Mouse Events:

We will be seeing Mouse Hover, Right Click, Double Click, Drag and Drop using plugin, Scrolling Page.


import 'cypress-iframe'
require ('@4tw/cypress-drag-drop')

describe("Mouse Operations", () =>{
    it('MouseHover', ()=>{
        cy.visit("https://demo.opencart.com/")
        cy.get(':nth-child(1) > .dropdown-menu > .dropdown-inner > .list-unstyled > :nth-child(2) > .nav-link')
        .should('not.be.visible');
        // click on second element : Desktops --> Mac(1) element
        cy.get(".nav > :nth-child(1) > .dropdown-toggle").trigger('mouseover').click();
        cy.get(':nth-child(1) > .dropdown-menu > .dropdown-inner > .list-unstyled > :nth-child(2) > .nav-link')
            .should('be.visible');
    })

    it('Right Click', ()=>{
        cy.visit("http://swisnl.github.io/jQuery-contextMenu/demo.html")
        // Approach1 --> right click on button and click copy
        // cy.get('.context-menu-one').trigger('contextmenu');
        // cy.get('.context-menu-icon-copy > span').should('be.visible');

        // Approach2 
        cy.get('.context-menu-one').rightclick();
        cy.get('.context-menu-icon-copy > span').should('be.visible');
    })

    it('Double Click', ()=>{
        cy.visit("https://w3schools.com/tags/tryit.asp?filename=tryhtml5_ev_ondblclick3")
        // using cypress-iframe plugin
        cy.frameLoaded('#iframeResult')  // load the frame
        // approach1 - using trigger
        // cy.iframe('#iframeResult').find("button[ondblclick='myFunction()']").trigger('dblclick');
        // cy.iframe('#iframeResult').find('#field2').should('have.value','Hello World!');
        // approach2 - using dblclick
        cy.iframe('#iframeResult').find("button[ondblclick='myFunction()']").dblclick();
        cy.iframe('#iframeResult').find('#field2').should('have.value','Hello World!');
    })

    it('Drag and Drop using plugin', ()=>{
        // using cypress-drag-drop plugin (or using trigger, not shown here)
        // npm install --save-dev @4tw/cypress-drag-drop, use require at the top
        cy.visit("http://dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html")
        // cy.get('#box6').drag('#box106');
        // forcefully drag and drop
        cy.get('#box6').drag('#box106', {force:true});
    })

    it('Scrolling Page', ()=>{
        cy.visit("https://countries-ofthe-world.com/flags-of-the-world.html")
        //duration optional  - find india text beside flag
        cy.get(':nth-child(1) > tbody > :nth-child(86) > :nth-child(2)').scrollIntoView({duration:2000});
        cy.get(':nth-child(1) > tbody > :nth-child(86) > :nth-child(2)').should('be.visible');

        // go to the top for Mauritius flag
        cy.get(':nth-child(2) > tbody > :nth-child(10) > :nth-child(1) > img').scrollIntoView({default:1000});
        cy.get(':nth-child(2) > tbody > :nth-child(10) > :nth-child(1) > img').should('be.visible');

        // to footer
        cy.get('#footer').scrollIntoView();
    })
})

Handling File Upload:

We will see five different tasks and how to perform them here.

a. Single File Upload

b. Renaming file while uploading

c. File Upload Drag & Drop

d. Multiple Files Upload

e. File Upload in Shadow Dom


import 'cypress-file-upload'

// install package cypress-file-upload 
// npm install --save-dev cypress-file-upload
describe('File Uploads', ()=>{
    it('Single File Upload', ()=>{
        cy.visit("http://the-internet.herokuapp.com/upload");
        // attachFile reads file only from "fixtures" folder
        cy.get('#file-upload').attachFile('vmodel.jpg');
        cy.get('#file-submit').click();
        cy.wait(2000);
        cy.get("div[class='example'] h3").should('have.text', 'File Uploaded!');
    })

    it('File Upload - Rename When Uploading', ()=>{
        cy.visit("http://the-internet.herokuapp.com/upload");
        // attachFile reads file only from "fixtures" folder
        cy.get('#file-upload').attachFile({filePath:'vmodel.jpg', fileName:'pavan.jpg'});
        cy.get('#file-submit').click();
        cy.wait(2000);
        cy.get("div[class='example'] h3").should('have.text', 'File Uploaded!');        
    })

    it('File Upload - Drag and Drop', ()=>{
        cy.visit("http://the-internet.herokuapp.com/upload");
        // attachFile reads file only from "fixtures" folder
        cy.get('#drag-drop-upload').attachFile('vmodel.jpg', {subjectType: 'drag-n-drop'});
        // cy.get('#file-submit').click();
        cy.wait(2000);
        // verify drag and drop area has file name (as submit giving error on web page)
        cy.get('#drag-drop-upload > .dz-preview > .dz-details > .dz-filename > span').contains('vmodel.jpg');        
    })

    it('Multiple files Upload', ()=>{
        cy.visit("http://davidwalsh.name/demo/multiple-file-upload.php")
        cy.get('#filesToUpload').attachFile( ["vmodel.jpg", "vmodel2.jpg"] );
        cy.get(':nth-child(6) > strong').should('contain.text', 'Files You Selected:');
    })

    // when file upload option is present inside shadow DOM 
    // dom inside dom / sub dom
    it('File Upload - Shadow Dom', ()=>{
        cy.visit("https://www.htmlelements.com/demos/fileupload/shadow-dom/index.htm")
        cy.get('.smart-browse-input', {includeShadowDom:true}).attachFile("vmodel.jpg");
        cy.wait(2000);
        cy.get('.smart-item-name', {includeShadowDom:true}).contains('vmodel.jpg');
    })
})


Hooks & Tags:

Four hooks in Cypress are:

before --> executed once before all the tests are executed (once per describe block)

after --> executed once after all the tests are executed (once per describe block)

beforeEach --> executed once before each test is executed (once per it block)

beforeEach --> executed once after each test is executed (once per it block)

All these 4 hooks are in Mocha framework.


describe('MyTestSuite', () =>{
    before( ()=>{
        cy.log('******** Launch App ********');
    })

    after( ()=>{
        cy.log('******** Close App ********');
    })

    beforeEach( ()=>{
        cy.log('********** Login ************');
    })

    afterEach( ()=>{
        cy.log('********* Logout   *************');
    })

    it('search', ()=>{
        cy.log('********* Search   *************');
    })

    it('advanced search', ()=>{
        cy.log('********* Advanced Search   *************');
    })

    it('listing products', ()=>{
        cy.log('********* Listing Products   *************');
    })
})

Tags: it.skip --> skips this test; it.only --> executes only this test


Conclusion:

We have seen how to handle Child Tabs, iFrames, Tables, Mouse Events, File Upload and use Hooks & Tags.

Hope you enjoyed doing Cypress.

921 views
bottom of page