Skip to main content

_javascript

TL;DR - Show Me The Code

3-work-with-frames/code/javascript/test/frames.spec.js
const assert = require("assert");
const {Builder, By} = require("selenium-webdriver");

describe("Frame Test", function () {
let driver;

beforeEach(async function () {
driver = await new Builder().forBrowser("firefox").build();
});

afterEach(async function () {
await driver.quit();
});

it("Example 1", async function () {
await driver.get("https://the-internet.herokuapp.com/nested_frames");
await driver
.switchTo()
.frame(await driver.findElement(By.name("frame-top")));
await driver
.switchTo()
.frame(await driver.findElement(By.name("frame-middle")));
let content = await driver.findElement(By.id("content")).getText();
assert.equal(content, "MIDDLE");
});

it("Example 2", async function () {
await driver.get("https://the-internet.herokuapp.com/tinymce");
await driver.switchTo().frame(await driver.findElement(By.id("mce_0_ifr")));
const editor = await driver.findElement(By.id("tinymce"));
let beforeText = await editor.getText();
await editor.clear();
await editor.sendKeys("Hello World!");
let afterText = await editor.getText();
assert.notEqual(afterText, beforeText);
await driver.switchTo().defaultContent();
let txt = await driver.findElement(By.css("h3")).getText();
assert.equal(txt, "An iFrame containing the TinyMCE WYSIWYG Editor");
});
});

Code Walkthrough

Importing Libraries, Setup and Teardown

The first two lines are pulling in our testing framework (e.g., require("assert")), and driving the browser with Selenium (e.g., const {Builder, By} = require("selenium-webdriver");).

After creating a describe to group our tests (e.g., describe("Frame Test")...), lines 5 to 13 are setting up and tearing down the browser instance.

The beforeEach method, will execute before each test. In it, we are launching a new instance of Firefox with Selenium and storing it in a class variable that we'll use throughout all tests. After our test executes the second method, afterEach, will execute. This calls driver.quit() which ends the session by closing the browser instance.

Example 1

Line 15 shows our first test. In it, we'll step through an example of nested frames from the-internet.

With Selenium's .switchTo().frame method we can easily switch to the frame we want. It accepts either a numbered index or WebElement (e.g., the result of a findElement).

In order to get the text of the middle frame (e.g., a frame nested within another frame), we first need to switch to the parent frame (e.g., the top frame) and then switch to the child frame (e.g., the middle frame). Once we've done that we're able to find the element we need, grab its text, and assert that it's what we expect.

While this example helps illustrate the point of frame switching, it's not very practical.

Example 2

Here is a more likely example you'll run into -- working with a WYSIWYG Editor like TinyMCE. You can see the page we're testing here.

Keep in mind that if we need to access a part of the page outside the frame we are currently in we'll need to switch to it. Thankfully Selenium has method that enables us to quickly jump back to the top level of the page -- switchTo.defaultContent().

Executing the Test

Before executing the test, we need to make sure the required dependencies are declared on the package.json file.

Toggle to see the package.json file.
3-work-with-frames/code/javascript/package.json
{
"dependencies": {
"selenium-webdriver": "4.26.0"
},
"description": "A project to showcase working with frames using official WebdriverJs",
"devDependencies": {
"mocha": "10.8.2"
},
"license": "MIT",
"name": "download-a-file",
"scripts": {
"test": "npx mocha test/**/*.spec.js --timeout 60000"
},
"version": "1.0.0"
}

Finally, we can run the test by executing npm test from the command-line.