Examining the order in which tabs are navigated

Ensuring correct tab keyboard navigation order within a form is crucial for one of our tests.

Query: How can the tab navigation order be verified using protractor?


Our current method involves repeating the following steps for each input field in a form (see code snippet below):

  • Retrieve the ID of the currently focused element (using getId())
  • Send the TAB key to the currently focused element

Sample spec:

it("should navigate with tab correctly", function () {
    var regCodePage = new RegCodePage();
    browser.wait(protractor.ExpectedConditions.visibilityOf(regCodePage.title), 10000);

    // Default focus on registration code field
    expect(regCodePage.registrationCode.getId()).toEqual(browser.driver.switchTo().activeElement().getId());

    // Move focus to Remember Registration Code
    regCodePage.registrationCode.sendKeys(protractor.Key.TAB);
    expect(regCodePage.rememberRegistrationCode.getId()).toEqual(browser.driver.switchTo().activeElement().getId());

    // Move focus to Request Code
    regCodePage.rememberRegistrationCode.sendKeys(protractor.Key.TAB);
    expect(regCodePage.requestCode.getId()).toEqual(browser.driver.switchTo().activeElement().getId());

    // Move focus to Cancel
    regCodePage.requestCode.sendKeys(protractor.Key.TAB);
    expect(regCodePage.cancelButton.getId()).toEqual(browser.driver.switchTo().activeElement().getId());

    // Move focus back to the input
    regCodePage.cancelButton.sendKeys(protractor.Key.TAB);
    expect(regCodePage.registrationCode.getId()).toEqual(browser.driver.switchTo().activeElement().getId());
});

Here, regCodePage is a Page Object:

var RegCodePage = function () {
    this.title = element(by.css("div.modal-header b.login-modal-title"));
    this.registrationCode = element(by.id("regCode"));

    this.rememberRegistrationCode = element(by.id("rememberRegCode"));
    this.requestCode = element(by.id("forgotCode"));

    this.errorMessage = element(by.css("div.auth-reg-code-block div#message"));

    this.sendRegCode = element(by.id("sendRegCode"));
    this.cancelButton = element(by.id("cancelButton"));
    this.closeButton = element(by.css("div.modal-header button.close"));
};

module.exports = RegCodePage;

The current approach works, but lacks explicitness and readability, making maintenance challenging. Additionally, there is code duplication present.

If you also use a similar approach, any suggestions for enhancing reusability would be highly appreciated.

Answer №1

In my opinion, it would be beneficial for the PageObject to have a tab order list defined as a direct property of the page. This information can easily be expressed as simple data in the form of an array of items. For example:

this.tabOrder = [ this.registrationCode, this.rememberRegistrationCode, this.requestCode, this.cancelButton ];

Subsequently, a generic code snippet is needed to verify the tab order.

function testTabOrder(tabOrder) {
    // Assumes TAB order hasn't been modified and the page is on the default element
    tabOrder.forEach(function(el) {
       expect(el.getId()).toEqual(browser.driver.switchTo().activeElement().getId());
       el.sendKeys(protractor.Key.TAB);
    });
}

Following that, your test case could look like this:

it('has correct tab order', function() {
    var regCodePage = new RegCodePage();  // perhaps this should be placed in the beforeEach function
    testTabOrder(regCodePage.tabOrder);
});

This approach assumes that each element has a functioning "getId()" method. While this might seem like a reasonable assumption to make, some environments may not support it.

I find that isolating the tab order within the PageObject makes it easier to synchronize with the page content and prevents it from getting lost amidst the verification code. The testing code appears to be optimistic (although I suspect real-world scenarios may require additional modifications).

Although untested, I welcome feedback or adjustments if needed. :)

Furthermore, I anticipate that the forEach loop will function smoothly, but explicit promise handling may be necessary to clarify dependencies.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Selenium error: Element not found - Element for login cannot be located

Attempting to leverage Selenium for downloading a file from . To access the file, logging in is required. However, encountering difficulty as an error is displayed when trying to fetch the email input field. Below is the code snippet: from selenium import ...

Incorporate a Vue.js computed property into the data retrieved from a server

Coming from Knockout.js, where observables are easily created by defining them, I'm curious if there's a similar approach in Vue.js. let vm = { someOtherVar: ko.observable(7), entries: ko.observableArray() }; function addServerDataToEnt ...

Utilize a MongoDB query to locate a single document and include a conditional statement within the update operation

I've been struggling with this problem for quite some time now and I could really use some guidance from experts here on SO. Essentially, what I am trying to achieve is to locate a specific document using a provided _id, and then execute a conditional ...

Utilizing URL-based conditions in Reactjs

Currently, I am working with Reactjs and utilizing the Next.js framework. My goal is to display different text depending on whether the URL contains "?id=pinned". How can I achieve this? Below is the snippet of my code located in [slug.js] return( ...

What is the module system that fabric composer utilizes for its logic JavaScript files?

I am currently in the process of creating a business-network-definition for Hyperledger using Fabric (based on generator-hyperledger-fabric). Everything has been running smoothly so far, but as we move onto our Proof of Concept (PoC), a few questions have ...

Tips for utilizing identical properties across numerous styled elements:

Utilizing the styled-components library, I have enhanced the header components from the Blueprintjs library. The current template for the H6 component appears as follows: export const DH6 = styled(H6)` color: ${(props) => (props.white ? "white&qu ...

Navigating through Switch cases and If Statements with multiple arguments can be complex for beginners in the world of JavaScript

Hi there, I have a specific case that I'm struggling to find a solution for. I am using Angular with a Firebase back-end to retrieve true or false values from a variable called ref. The variable contains 4 properties with either true or false values - ...

Instructions for implementing a "Load More" feature on blogs using either HTML or JavaScript

When retrieving blogs from a SQL Database, some of them tend to be lengthy. To tackle this issue, I plan on trimming each blog down to around 30 words (this amount may vary) and then incorporating a Load More link at the end. This link will enable users to ...

Creating crypto.createCipheriv arguments from fixed origins

Currently, I am implementing a code snippet in my node.js application to perform string encryption. I am seeking guidance on how to create the KEY and HMAC_KEY from a predetermined source. At the moment, these keys are randomly generated within the progra ...

Is there a way to handle templates in AngularJS that is reminiscent of Handlebars?

Is there a way to handle an AngularJS template using a syntax similar to Handlebar? <script type="text/ng-template" id="mytemplate"> Name is {{name}} </script> I know how to retrieve the template using $templateCache.get('mytemplate&ap ...

In the Android Chrome browser, the settings of the meta viewport attribute do not take effect when the device is in full screen mode

While using the fullscreen api in Android, I noticed that the values of meta viewport attributes like initial-scale and user-scalable are not reflected in the browser when in full screen mode. However, when not in full screen mode, these values work as exp ...

React is currently in the process of downloading images that were not fetched during

(Update: Initially, I suspected React Router was the cause of this issue. However, after eliminating React Router from the codebase, the problem persists. Therefore, I have extensively revised this inquiry.) Situation: I am dealing with paginated pages th ...

Strip certain tags from HTML without including iframes

Removing specific tags from HTML can be tricky, especially when working with PHP and JavaScript. One approach is to fetch an HTML page in a PHP file using curl and getJSON, storing the result in a .js file. However, this method may encounter issues with mu ...

Error: the function is not defined, therefore the variable is being passed

I'm attempting to pass a variable in the URL in order to automatically check a radio button on a different page depending on which link is clicked. However, I keep encountering an "Uncaught ReferenceError: radio_onload is not defined" error. Could th ...

Custom React component - DataGrid

Just starting out in the world of React and attempting to create a custom component with parameters. I'm curious about the correct approach for achieving this. Here's my current code snippet - how do I properly pass Columns, ajax, and datasourc ...

Why is my jQuery clearQueue function malfunctioning?

I'm facing an issue with my AJAX function where multiple notifications are being displayed if the user calls it repeatedly in a short span of time. I want to show the notification only once and avoid queuing them up. AJAX FUNCTION function update(up ...

Having trouble with running `npm start` on a computer that has different versions of Node and

I have encountered an issue with running a React application on two different computers. One computer, a MacBook, is running the app without any problems, while the other, an Ubuntu 18.04 machine, is having trouble starting it. Here are the configurations ...

Counting Clicks with the Button Counter

I'm having an issue with my jQuery code that is supposed to count button clicks - it stops after just one click. I need help fixing this problem. $(function() { $('.btn').click(function() { $(this).val(this.textContent + 1); }); } ...

Rearranging div placement based on the width of the screen

I am currently working on building a responsive website and I need two divs to switch positions depending on the screen width, both on initial load and when resizing. Despite my efforts in researching and trying various options, I have not been successful ...

A guide on viewing the output of an AJAX request using Python and Selenium

Currently experimenting with Selenium testing on a Django website. I recently implemented a feature to track javascript errors through Google Analytics. How can I create a test to verify that when a javascript error occurs, an AJAX request is triggered a ...