Preparing Oracle JET Composite Components for Automation Testing

Prepare Oracle JET composite components for automation testing using the automation tools of your choice and the getNodeBySubId() and getSubIdByNode() APIs.

Use the getNodeBySubId() or getSubIdByNode() APIs to identify the name of the components using the particular sub element associated with the Oracle JET component. While you run a test case, you can record gestures such as a finger tap or a mouse click on Oracle JET buttons, text boxex, or other components that accept input.

By using the getNodeBySubId() or getSubIdByNode() methods and element subIds in your test cases you will be consistent with the existing JET components and enable delegation to aggregated components. Also, this will allow the test framework to provide higher-level events that can be played back in tests to encapsulate complex and difficult to time or capture gestures, for example swipes, taps, two finger actions, and so on.

For page level test cases, you can use oj.BusyContext whenReady API to ensure components on that page have been fully rendered before interacting with them for automation.

You can use the static method oj.Components.getComponentElementByNode for recording. This method returns the component that automation APIs should be called on; treating DOM specified in the composite view as private and slotted children as public. You must also use this static method for the existing JET components, as cases like ojAccordion are similar to composites. In such cases, the recording code would want to call getSubIdByNode on ojAccordion even if the inner ojCollapsible was clicked to record the correct subId.

Static Functions getNodeBySubId() / getSubIdByNode()

The static functions oj.Components.getNodeBySubId() and oj.Components.getSubIdByNode() can identify the elements in both JQuery UI components and web components for testing.

Syntax Purpose Arguments

oj.Components.getComponentElementByNode = function(node){}

Retrieves the JET component element that the node is in.

  • @param {Element} node - DOM node

  • @return {Element} componentElement - JET component element

oj.Components.getSubIdByNode = function(componentElement, node){}

Retrieves the subId of the node as part of a locator object that is at least {subId: subIdofNode}

  • @param {Element} componentElement - JET component element

  • @param {Element} node - DOM node

  • @return {Object|null} locator - object with at least a subId or null if the node does not have a subId

oj.Components.getNodeBySubId = function(componentElement, locator){}

Returns the component DOM node indicated by the locator parameter.

  • @param {Element} componentElement - JET component element

  • @param {Object} locator - Object containing, at minimum, a subId property, whose value is a string that identifies a particular DOM node in this component.

  • @return {Element|null} node - The DOM node located by the locator, or null if none is found

oj.Components.getComponentOption = function(componentElement, option){}

Retrieves the specified option of the specified JET component element

  • @param {Element} componentElement - JET component element

  • @param {string} option - option to retrieve

  • @return {*} value of option

oj.Components.setComponentOption = function(componentElement, option, value){

Sets the specified option of the specified JET component element to the specified value

  • @param {Element} componentElement - JET component element

  • @param {string} option - option to set

  • @param {*} value - value to set option to

oj.Components.callComponentMethod = function(componentElement, method, arguments){}

Calls the specified JET component element's method with the given arguments

  • @param {Element} componentElement - JET component element

  • @param {string} method - name of JET component element method to call

  • @param {...*} arguments - list of arguments to pass to method call

  • @return {Object}

Expanded getSubIdByNode()

The expanded getSubIdByNode() method returns the following values:

  • Returns null for nodes that the JET component did not render.

  • Returns the subId for nodes that the JET component rendered and are required for testing.

  • Returns a subId of the oj-ignore for nodes that the JET component rendered whose events must not be recorded.

SubId Mapping

As part of preparing the composites for automation testing, you should be able to provide custom subIds even for existing JET components. For example, for a composite with an ojChart and an ojSlider the custom subIds can be provided with a composite subId that overrides the mapped JET component subId as follows:

Composite SubId JET Component SubId

forecast-dashboard-display-axis-title

oj-chart-axis-title

forecast-dashboard-display-group

oj-chart-group

forecast-dashboard-display-item

oj-chart-item

forecast-dashboard-range-bar

oj-slider-bar

forecast-dashboard-range-first-thumb

oj-slider-thumb-0

forecast-dashboard-range-second-thumb

oj-slider-thumb-1

The JET framework can determine the subId mapping if the composite adds data-oj-subid or data-ojsubid-map attributes. The data-oj-subid attribute would take a single string which would map that element with the given subId and the data-oj-subid-map attribute would take a JSON object containing custom subIds that map to the component provided subIds where the component can be another composite for JET component. These attributes are not limited to JET components, they can be specified on any DOM element.

<forecast-dashboard>
    <oj-chart data-oj-subid-map='{"forecast-dashboard-display-item": "oj-chart-item", "forecast-dashboard-legend-item":"oj-legend-item"}' ... ></oj-chart>
    <oj-slider data-oj-subid-map='{"forecast-dashboard-range-first-thumb":"oj-slider-thumb-0", "forecast-dashboard-range-second-thumb":"oj-slider-thumb-1"}' ... ></oj-slider>
    <button data-oj-subid="forecast-dashboard-update-button" ... ></button>
</forecast-dashboard>

Method Implementation

In the JET framework the getNodeBySubId() and getSubIdByNode() methods are always exposed on the composite element. Similarly, if you can allow composites to expose all necessary subIds through the data-oj-subid or data-oj-subid-map attributes, then the composites need not provide its own implementation. However, for cases like exposing subIds on stamped items, the composite can provide its own implementation on the composite ViewModel which takes as an extra last parameter, the default framework implementation of that method.

define([],
  function () {
    function model (context) {
       
      ....
 
      this.getNodeBySubId = function(locator, defaultImpl) {
        if (locator.subId == 'sample-memory-game-card') {
          var card = element.getElementsByTagName('sample-memory-card')[locator.index];
          return card.getNodeBySubId({subId: 'test-memory-card'});
        }
        return defaultImpl(locator);
      }
 
      this.getSubIdByNode = function(node, defaultImpl) {
        var cards = element.getElementsByTagName('sample-memory-card');
        for (var i = 0; i < cards.length; i++) {
          if (cards[i].getNodeBySubId({subId: 'sample-memory-card'}) === node)
            return {subId: 'sample-memory-game-card', index: i};
        }
        return defaultImpl(node);
      }
     
      ...
 
    }

For information related to testing and debugging of Oracle JET web applications, see Testing and Debugging.