Transcripted Summary

In this lecture, we are going to be discussing how to switch from one window to the next, or how to switch from one tab to the next. We will also be discussing how to interact with IFrames.

If we scroll down [on the application home page], we realize that we have something called Multiple Windows.



If we open this, and then Click Here, it takes us to our new tab.

Let us now get this element.



This element is in “.example a” (anchor tag).

Let's go in our Page Object and say

get hereLink() { return $('.example a') }



After we Click Here, the way that the switchWindow works in WebdriverIO is that you have to enter some matching URL in order to switch or focus on a particular tab or window.

So, in this case, when we say “Click Here” this [http://the-internet.herokuapp.com/windows/new] is the new URL that we will have to enter as a parameter, to get WebdriverIO to switch. So, we need to make a note of this.



Also, we should make a note that on this new page, there is this h3. And we can use this h3 to verify that our test works, as when it is that we have switched window, this h3 should now be displayed, and should exist. So, we can use a couple different states to verify our test.


Let us create a function called clickHereLink.


/**
* Click the "click here" link
*/
clickHereLink() {
    this.hereLink.waitForDisplayed()
    this.hereLink.click()
}

Let us now create a new test file called “switchWindow.test.js".

And we are going to import our internet page.

# switchWindow.test.js


internetPage = require('../pages/internet.page')
describe('Switch Window', function () {
    it('Should switch to the next window', () => {
        browser.url('${browser.options.baseUrl}/windows')
        internetPage.clickHereLink()

        browser.switchWindow('${browser.options.baseUrl}/windows/new')
        assert.equal(true, internetPage.h3Header.isExisting())
        assert.equal(true, internetPage.h3Header.isDisplayed())
        assert.equal('New Window', internetPage.h3Header.getText())
    })
})

We're going to say, browser.url, and we are going to use the baseUrl and then we're going to append to it, /windows. And that should bring us to this page that we want.

Then we're going to say


internetPage.clickHereLink()

And after it clicks the “hereLink”, we need to switch to the new window. So, we're going to say — browser.switchWindow — and we're going to enter the URL. We can use our baseUrl and append to it the new window, /windows/new.

After we have done that, we can assert our test. We need to create a next element so remember that we need to create this h3 element, and we can say


assert.equal(true, internetPage.h3Header.isExisting())

And we can add some more just to say isDisplayed

assert.equal(true, internetPage.h3Header.isDisplayed())

And we can even say


assert.equal('New Window', internetPage.h3Header.getText())

And check what the text should be, which should be “New Window”


Let's run this specific test by saying in the terminal — npm test -- --spec ./test/switchWindow.test.js

Let's just run our test.

And we can see that it passes. So, it clicked on the hereLink, it switched window, and then the header that we were expecting is there.

Let's do a quick browser.pause.



And if we run the test again using the same command as before, we see that it opens a new window and switches to the new window.


Let us now look at IFrames.

If we go here on the application home page we have Frames > IFrame.

And if we Inspect (right-click and then Inspect), we see that we have an IFrame with an id here.

And we want to go into that IFrame that contains an entirely different head and body and interact with it. So ideally, we would want to send some text here.



Webdriver has this protocol called switchToFrame that allows you to go into the IFrame, and then you can operate on it as you would normally would. But you would have to the frame first.

Based on the layout of this IFrame, we have to use the id of the body, as it contains contenteditable="true".



For other IFrames, they may have some input fields and other elements that you can interact with, such as a play button or radio buttons that you can click on. For this IFrame, it only contains a paragraph and a body.

So, we are going to use the body to send text and clear this value. And then, after we have sent the text, we are going to verify that the text we sent is there.


Let us go and add our element in our Page Object.

And we're going to say


get iframeBody() { return $('#tinymce') }

since it had an id of “tinymce”

Then we're going to use the id here, and we're also going to map with this id because the IFrame is within this div here.


get iframe() { return $('#mceu_27 #mce_0_ifr') }

Then let us create our function to send the text that we want to the body here.

So, the function sendTextToBody is going to accept a parameter of text, which is going to be coming from our test.

We're going to say


this.iframeBody.waitForDisplayed()

...because after we switch to the frame, we want to ensure that everything is displayed.

Then we want to clear the value that's there. So, we're going to say


this.iframeBody.clearValue()

And then we're going to click on the IFrame body, because we want to use keys to send it in. We cannot use setValue because it's not a text area or an input field. So, it wouldn't really work as well as we expected it to. It perhaps would give us some error.

Therefore, in this case, we're going to use keys, and if we remember from a previous lecture where we discuss keys, it sends any keyboard clicks to the element that we want.

In this case we're going to first click on the IFrame body


this.iframeBody.click()

And then we're going to say


this.iframeBody.keys(text)

...and the text that we are getting from our test.


/**
* Enter text in the iframe
* @param {String} text the text to be entered
*/
sendTextToBody(text) {
    this.iframeBody.waitForDisplayed()
    this.iframeBody.clearValue()
    this.iframeBody.click()
    this.iframeBody.keys(text)
}

Let us now create a test file, and we're going to name that file, “switchToIframe.test.js”.

We're going to import our internet page.

# switchToIframe.test.js


internetPage = require('../pages/internet.page')

describe('Switch to Iframe', function () {
    it('Should switch to iframe', () => {
        browser.url(`${browser.options.baseUrl}/iframe`)
        internetPage.h3Header.waitForDisplayed()
        internetPage.iframe.waitForDisplayed()
        browser.switchToFrame(internetPage.iframe)
        internetPage.sendTextToBody('This is the text in the iframe body')
        assert.equal('This is the text in the iframe body', internetPage.iframeBody.getText())
    })
})

Then we're going to say browser.url and we're going to use the baseUrl here, which you should be pretty familiar with at this time — ${browser.options.baseUrl} — and we're going to add onto it /iframe which is the URL here.

Then we're going to wait until this header is displayed. And it's the same h3 header that we always have on the pages.

Note

For every application it's different, so you have to determine for your application, what is that element that you're going to wait to be displayed when you switch to a new page, or when you're loading the browser for the first time. \

In our case, it is the h3 header. So, we're going to say

internetPage.h3Header.waitForDisplayed()

Then we're going to wait until the IFrame is displayed, and this is kind of a double wait. But just in case the h3 tab loads faster than the IFrame, we just want to be safe.

And then we're now going to use this function WebDriver protocol has, switchToFrame. And the id that we're going to pass is the element that we have created here.

So, let us say

browser.switchToFrame(internetPage.iframe)

And we're going to pass in our element.

Now we're going to use our function sendTextToBody and we're going to say


internetPage.sendTextToBody()

And the text that we're going to enter is “This is the text in the iframe body”


internetPage.sendTextToBody('This is the text in the iframe body')

Let's now do our assertion to ensure that the text was cleared out, so that text that is here, your content goes here, was cleared out and our new text of this is the text in the IFrame body, is now there.

assert.equal, the text that we have there, which is “This is the text in the iframe body”. And we're going to be comparing that against — internetPage.iframeBody.getText — we're going to be getting the text that is there.


assert.equal('This is the text in the iframe body', internetPage.iframeBody.getText())

Okay, this looks like everything, so let's go ahead and run our single test.

We're going to do that by running the command


npm run test -- --spec ./test/switchToIframe.test.js

And as we saw, maybe it was a bit fast, but the test passed. It waited until the h3 header was displayed, it waited for the IFrame to be displayed, it then switched to the IFrame, and then it sent the text to it and it verified that the text we entered was there.

Let us slow it down a bit.

Let us add a browser.pause to verify that this indeed happened.



And let's run our test again. As you saw, it cleared it out, and then it entered that text.

So, if it is that we did not say browser.switchToFrame we would get an error, because we would not be able to interact with the body of the IFrame.

Let us comment out browser.switchToFrame and see the error that we would get.

So, comment out the switchToFrame and run our test again.

We realize it's looking for that element here, but it cannot find it, because we have not switched to IFrame.



And we get an error that says the element tinymce (which is the IFrame body, because we're looking to send text to it) is not displayed. And so, the global timeout that we set of 10,000 milliseconds, it was up.

Switching to the IFrame is important, because we have to switch to it in order to interact with it. If we don't, then we won't be able to interact with the elements within it.

So if we take out the comments run our test again, it should pass.


internetPage = require('../pages/internet.page')

describe('Switch to Iframe', function () {
    it('Should switch to iframe', () => {
        browser.url('${browser.options.baseUrl}/iframe')
        internetPage.h3Header.waitForDisplayed()
        internetPage.iframe.waitForDisplayed()
        browser.switchToFrame(internetPage.iframe)
        internetPage.sendTextToBody('This is the text in the iframe body')
        assert.equal('This is the text in the iframe body', internetPage.iframeBody.getText())
    })
})


Resources



Quiz

The quiz for this chapter can be found in section 3.5