{{announcement.body}}
{{announcement.title}}

E2E Test — Use Probe Attribute As Element Locator

DZone 's Guide to

E2E Test — Use Probe Attribute As Element Locator

If you have experiences to create an E2E test project on a web application, you should be familiar with codes like this! Check it out!

· Performance Zone ·
Free Resource

If you have experiences to create an E2E test project on a web application, you should be familiar with codes like this.

JavaScript
 




xxxxxxxxxx
1


 
1
// Manipulate browser to enter text to an input box
2
    const fooInput = await getElement('.fooInput');
3
    fooInput.type("user.name@email.com");
4
 
          
5
    // Manipulate browser to click the submit button
6
    const fooButton = await getElement('button[type=sybmit]');
7
    fooButton.click();
8
 
          
9
    // Then verify what is happening after form submit



The test actions are quite intuitively — get the references or handlers of specified elements in the view and then interact with them. We can see the CSS selectors are used to locate the target elements. Everything looks pretty good before you write the real test code. Test developers are always bothered by how to locate elements. 

At first, we cannot choose the existed class attributes as element Locator although they exist in most HTML tags. The 'class' of an element is often generated for CSS binding, it is not a surprise when we see the class attributes with strange values as the following HTML snippet.

HTML
 




xxxxxxxxxx
1


1
<form class='UserForm__form__34jfdf9r'>
2
    <input type='text' class='UserForm__input__fdfd9%O3' />
3
    <button type='submit' class='d#ere9i2'>
4
        Submit
5
    </button>
6
</form>



I believe no one wants to use these random strings as locators in the test code. But this is not the worst thing, the class value will be changed after each build (refer webpack and CSS module). That means we couldn't use them in test code to locate elements at all.

So we have to choose selectors other than a class attribute, like 'button[type=submit]'. But those selectors are not available for all elements, they are conflict with each other and hard to specify the single element.

How about choose using another type of locator — XPath. All elements in DOM could be retrieved by XPath, and most browser drivers or crawling APIs provide methods for XPath accessing. Sure, it works, but make things worse.

JavaScript
 




xxxxxxxxxx
1


1
// Manipulate browser to enter text to an input box
2
    const fooInput = await getElementByXPath('//*[@id="ui — setting-container"]/div[5]/div/div/div[2]/div/input');
3
    fooInput.type("user.name@email.com");
4
 
          
5
    // Manipulate browser to click the submit button
6
    const fooButton = await getElementByXPath('//*[@id="ui-setting-container"]/div[5]/div/div/button');
7
    fooButton.click();
8
 
          
9
    // Then verify what is happening after form submit



Lets put the ugly XPath name aside, the important thing is the XPath is fragile because it depends on the HTML hierarchy. The XPath will be crashed after some tags changed. Just think about how many conditional tags and 3-party components exist on a page, the HTML is always changing even after the developing stage.

Anyway, we should add a dedicated Probe to target elements for testing. These probe locators should be readable with easy syntax, and not conflict with others in DOM.

Most developers like to add 'id' attributes as a testing probe. The 'id' is a good probe working in most scenarios.

JavaScript
 




xxxxxxxxxx
1


 
1
// Manipulate browser to enter text to an input box
2
    const fooInput = await getElementById('#Login_Email_Input');
3
    fooInput.type("user.name@email.com");
4
 
          
5
    // Manipulate browser to click the submit button
6
    const fooButton = await ById('#Login_Submit_Button');
7
    fooButton.click();
8
 
          
9
    // Then verify what is happening after form submit



However, the 'id' attribute is often used for CSS binding and HTML reference purposes. Sometimes we can not add the id to some elements, or the id will conflict with other components out of control, e.g., some HTML snippets will be generated and insert to the current page.

Another drawback of using 'id' is the 'id' attribute should be unique in the current view. We shouldn't add the same ids to a group of elements. Sometimes we have to add computed ids to target elements, e.g. adding ids to cells of a table. That means extra work in UI coding, and it is not acceptable usually.

The correct solution is choosing a custom attribute as Probe attribute, make sure this attribute is not used for other purposes, for example:

HTML
 




xxxxxxxxxx
1


 
1
<form class='UserForm__form__34jfdf9r'>
2
    <input e2e='Login_Email_Input' type='text' class='UserForm__input__fdfd9%O3' />
3
    <button e2e='Login_Submit_Button' type='submit' class='d#ere9i2'>
4
        Submit
5
    </button>
6
</form>



Locate elements by custom attributes would more verbose than getElementById, but we can add a syntax parser in a test project to keep the coding clean. Then the test code will be:

JavaScript
 




xxxxxxxxxx
1


 
1
// Manipulate browser to enter text to an input box
2
    const fooInput = await getElementByProbe('Login_Email_Input@e2e');
3
    fooInput.type("user.name@email.com");
4
 
          
5
    // Manipulate browser to click the submit button
6
    const fooButton = await getElementByProbe('Login_Submit_Button@e2e');
7
    fooButton.click();



With the help of the probe syntax parser, we can locate elements sophisticatedly but still with the clean syntax:

JavaScript
 




xxxxxxxxxx
1


 
1
// Get the 4th token in token list
2
const user = await getElementByProbe('Expired_Token@e2e(3)');
3
 
          
4
// Get the 4th token of tokens with text content "Super Token"
5
const user = await getElementByProbe('Expired_Token@e2e("Super Token", 3)');



The dedicated element locators are used for the E2E test only, we don't want to keep them in the product package. It is easy to do this if you use custom probe attribute, just process the HTML and remove this attribute in the build pipeline.

How is the first E2E test tool implement Probe syntax as CSS selector and XPath? It supports parsing the following probe locator.

  • Locate one element: _"expired-token@e2e"_ by selector or XPath retrieve.
  • Locate all elements: _"expired-token@e2e"_ by selector or XPath retrieve.
  • locate the nth element: _"expired-token@e2e([number])"_ by selector or xpath retrieve..
  • Locate all elements with content: _"expired-token@e2e([string])"_ by xpath retrieve.
  • locate the nth element with content: _"expired-token@e2e([string], \[number\])"_ by xpath retrieve.

Please refer Handow Documentation to see more details.

Here is a Live Demo of a Handow E2E test project.

Topics:
cypress, e2e testing, jest, performance, puppeteer, uat

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}