As a part of the agile software development practice, the growing demand for fast and reliable CI/CD processes has led to the growing demand to speed up the automation testing processes. And as far as Web Development goes, what better way to make your E2E tests run faster than running parallel tests on different tabs?
In Chrome, this form of parallelization is supported out of the box when using Puppeteer, which uses the native ChromeDevtoolsProtocol, but in Firefox, not so much. Microsoft’s Playwright library supports this partially, but since it uses a custom build of Firefox beta, it limits your choices for other browser versions.
The solution briefly explained
Setting up the Express Server
As mentioned above, the Express Server is being used to serve a locally hosted page, which will manage our newly opened tabs. In addition, new tabs will first browse to a different locally hosted path, that will set a unique id to each page for later retrieval and recognition by the Foxdriver.
In order to make it easier for you to follow along, this is my folder structure:
As can be seen, we have two functions on the page: createTab(tabId: String) and closeTab(tabId: String). createTab will launch a new tab by using window.open and will place the returning window object in the tabs Map under the tabId key. This will be used later for closing the tab.
Another thing to notice is the browsing location. As mentioned above, the unique id of the tab is being placed in the browsing URL (i.e. http://localhost:5325/firefox/somerandomid ) to be later viewed by the Foxdriver
Now let’s set up the server. In express-server/index.js we first need to serve the static “TabManager” HTML file. In addition, we need to set the /firefox/:tabId path
If you are somewhat familiar with Express servers, you might find it odd that I’m exporting the app and not starting listening to a port. The reason for this will be revealed in the next section when we will discuss the Foxdriver code.
Making it work
Here we will view the Foxdriver code for linking it all together. First, let’s view the startServer function, it will be placed in the index.js file in the root directory
Now, the reason for exporting the app makes sense. The startServer function will return the randomly generated port for later use.
For our main part, let’s see the use of this function together with the Foxdriver APIs
So far I have launched a browser with one tab, browsed to http://localhost/, and retrieved the page’s title. I’ve added the custom pref “dom.disable_open_during_load” to enable popups which will be very handy in a second.
The openTab function is where the magic happens. Inside, I’m using the evaluateJSAsync API of the Foxdriver’s tab object to run a JS command on the “TabManager” page. Then, I’m using the browser.listTabs() API, again, from Foxdriver, to list all of the currently opened tabs on the Firefox browser. And by looking at each tab's URL I’m able to retrieve the correct one back to the user.
And the code addition in the anonymous async function
Few final notes
- The full solution can be found under my GitHub, in the link here
2. Due to performance reasons, I’d highly recommend not using more than 5 tabs open at the same time. But, with that being said, you can always use machines with more memory.