Nightwatch JS provides two API commands to handle iframes. frame() changes focus to another frame on the page. .frameParent() changes focus to the parent context.

Simple iFrame:

Let’s automate a scenario where we have one iframe on the root level. It is also applicable when you are having multiple iframes on the root level.

We have a web page where we one iFrame on the root level, as seen below in the screenshot.

single iframe

To access the iframe we will use the command frame() with the index number. So if you have only one frame, you can use frame(0) or when you have two frames at the same level you can use frame(0) and frame(1) and so on.

1
2
3
4
5
6
7
8
9
10
  'Handling iFrames': function (browser) {
    browser
      .url('https://the-internet.herokuapp.com/iframe')
      .waitForElementVisible('body')
      .frame(0)
      .click('#tinymce')
      .clearValue('#tinymce')
      .setValue('#tinymce', 'Test Input')
      .assert.containsText('#tinymce', 'Test Input')
  }

So in the above test, we go inside the iframe, then clear the existing content, input the text ‘Test Input’ and then validate that the text is updated inside the text editor.

Nested iFrame:

Things get a bit tricky when we are dealing with nested iFrames (iFrame within iFrame). Here we will make use of both the commands .frame() and .frameParent().

nested iFrames

In this example we will validate the 4 texts written inside 4 different iFrames – ‘LEFT’, ‘MIDDLE’, ‘RIGHT’, ‘BOTTOM’.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  'Handling Nested iFrames': function (browser) {
    browser
      .url('https://the-internet.herokuapp.com/nested_frames')
      .frame(0)
      .frame(0)
      .assert.containsText('body', 'LEFT')

      .frameParent('[src="/frame_left"]')
      .frameParent('[src="/frame_top"]')
      .frame(0)
      .frame(1)
      .assert.containsText('#content', 'MIDDLE')

      .frameParent('[src="/frame_middle"]')
      .frameParent('[src="/frame_top"]')
      .frame(0)
      .frame(2)
      .assert.containsText('body', 'RIGHT')

      .frameParent('[src="/frame_right"]')
      .frameParent('[src="/frame_top"]')
      .waitForElementVisible('html > frameset')
      .frame(1)
      .assert.containsText('body', 'BOTTOM')
  }

Let’s dig deeper into the code –

1
2
3
4
.url('https://the-internet.herokuapp.com/nested_frames')
      .frame(0)
      .frame(0)
      .assert.containsText('body', 'LEFT')

In this part of the code, we are visiting the URL, since at the root level we have two iFrames (frame_top & frame_bottom) we will use frame(0) to go inside frame_top. Now inside frame_top we have frame_left, which is again the first iFrame in the list, hence we will again use frame(0). Then, once we have reached inside the frame_left we are asserting that body has the text ‘LEFT’.

1
2
3
4
5
.frameParent('[src="/frame_left"]')
      .frameParent('[src="/frame_top"]')
      .frame(0)
      .frame(1)
      .assert.containsText('#content', 'MIDDLE')

As we saw before we went inside frame_left and validated the text. Now to go to frame_middle, we have to first move our control to frame_top and then reach frame_middle. So to move out of frame_left, we will first use frameParent(‘[src=”/frame_left”]’) and then frameParent(‘[src=”/frame_top”]’) . Since now our control is at frame_top, we will use frame(0) to go inside frame_top and then frame(1) to go inside frame_middle which is the second iFrame in the list. Then, once we have reached inside frame_middle we are asserting that #content has the text ‘MIDDLE’.

1
2
3
4
5
.frameParent('[src="/frame_middle"]')
      .frameParent('[src="/frame_top"]')
      .frame(0)
      .frame(2)
      .assert.containsText('body', 'RIGHT')

Similarly like before, we need to first move out of frame_middle and then reach to frame_top and then find our way to frame_right. We used frame(2) as frame_right is the third iFrame in the list. Then, we are asserting that body has the text ‘RIGHT’.

1
2
3
4
5
.frameParent('[src="/frame_right"]')
      .frameParent('[src="/frame_top"]')
      .waitForElementVisible('html > frameset')
      .frame(1)
      .assert.containsText('body', 'BOTTOM')

Since frame_top and frame_bottom are at the same level we need to go one step above frame_top, that is why we wrote waitForElementVisible(‘html > frameset’), so that the control is outside of frame_top. So at this point frame(0) denotes frame_top and frame(1) denotes frame_bottom, hence we used the latter and then directly asserted that the body has the text ‘BOTTOM’, as there aren’t any further iFrames inside frame_bottom.

Entire Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
module.exports = {
  before: function (browser) {
    //Declaring Global Timeout
    browser.globals.waitForConditionTimeout = 7000
  },

  'Handling iFrames': function (browser) {
    browser
      .url('https://the-internet.herokuapp.com/iframe')
      .waitForElementVisible('body')
      .frame(0)
      .click('#tinymce')
      .clearValue('#tinymce')
      .setValue('#tinymce', 'Test Input')
      .assert.containsText('#tinymce', 'Test Input')
  },

  'Handling Nested iFrames': function (browser) {
    browser
      .url('https://the-internet.herokuapp.com/nested_frames')
      .frame(0)
      .frame(0)
      .assert.containsText('body', 'LEFT')

      .frameParent('[src="/frame_left"]')
      .frameParent('[src="/frame_top"]')
      .frame(0)
      .frame(1)
      .assert.containsText('#content', 'MIDDLE')

      .frameParent('[src="/frame_middle"]')
      .frameParent('[src="/frame_top"]')
      .frame(0)
      .frame(2)
      .assert.containsText('body', 'RIGHT')

      .frameParent('[src="/frame_right"]')
      .frameParent('[src="/frame_top"]')
      .waitForElementVisible('html > frameset')
      .frame(1)
      .assert.containsText('body', 'BOTTOM')
  },

  after: function (browser) {
    browser.end()
  }
}

iframes Nightwatch JS code

Upon execution:

Nightwatch JS iFrame execution

Do check out 🙂

Github: https://github.com/alapanme/NightwatchJS
All Nightwatch JS Articles: https://testersdock.com/nightwatch-js-tutorial/