Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add js helper methods #159

Merged
merged 39 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9a3bf80
Added sendKeys and clear methods to Js class
AndreaDotDev Apr 18, 2024
f1f155a
Added getRect, getSize, getTagName methods to Js class
AndreaDotDev Apr 19, 2024
825a27f
Better descriptions for Js class methods
AndreaDotDev Apr 19, 2024
17345ad
Added submit and getLocation methods for Js class; removed KeyPresses…
AndreaDotDev Apr 23, 2024
a3fbbc8
Added getDomAttribute method to js class
AndreaDotDev Apr 24, 2024
386641f
Added getDomProperty and getAttribute methods to js class
AndreaDotDev Apr 26, 2024
e061add
Updated test methods
AndreaDotDev Apr 26, 2024
99c455c
Added StringUtils unit test
AndreaDotDev Apr 26, 2024
9b27fe8
Added isSelected, isEnabled and isDisplayed methods to Js class
AndreaDotDev Apr 28, 2024
f317e5e
Added part of the unit tests for Js Class
AndreaDotDev Apr 29, 2024
0331e5f
Added Js getCssValue method and test
AndreaDotDev May 6, 2024
a52657e
Added JsMethodsUtils and unit tests
AndreaDotDev May 6, 2024
724c145
Added getShadowRoot method to Js class
AndreaDotDev May 7, 2024
7c54aa9
Formatted code in Js class
AndreaDotDev May 7, 2024
5ee74c7
Added getText method to js class
AndreaDotDev May 8, 2024
be542c1
WIP - added findElement method to Js class
AndreaDotDev May 8, 2024
448a9cf
WIP - used method overloading for findElement method
AndreaDotDev May 9, 2024
597d161
WIP - added xpath Locator for findElement method
AndreaDotDev May 9, 2024
879f43c
added findElement method to Js class
AndreaDotDev May 9, 2024
80bb009
Refactoring of variable name
AndreaDotDev May 9, 2024
e47410e
Refactoring of StringUtils to JsStringUtils
AndreaDotDev May 9, 2024
e20705c
Refactoring of code and added test case
AndreaDotDev May 9, 2024
8fe0192
WIP - findElements method for Js class
AndreaDotDev May 9, 2024
6326ffb
WIP - refactored JsMethodsUtils
AndreaDotDev May 9, 2024
c06d7b5
WIP - added findElements to Js class (to be tested)
AndreaDotDev May 9, 2024
016078d
added findElements method to Js class
AndreaDotDev May 10, 2024
e611aa2
added Unit tests for JsMethodUtils
AndreaDotDev May 10, 2024
8d8eb90
added Unit tests for findElement and findElements methods
AndreaDotDev May 11, 2024
8b38f44
added all Unit tests for Js class
AndreaDotDev May 11, 2024
fd53599
Cleaner code and refactoring of methods and field attributes
AndreaDotDev May 13, 2024
141e611
Added suppression for warnings in Js Class
AndreaDotDev May 13, 2024
5665e01
Refactoring of JsMethodsUtils class (deleted) and findElement/findEle…
AndreaDotDev May 14, 2024
3c12c15
stored converted string in variable and renamed convertCssProperty in…
AndreaDotDev May 15, 2024
cd0e45f
changed casting in getRect method, updated JsTest
AndreaDotDev May 15, 2024
67b0f7c
updated typo error in LocatorType
AndreaDotDev May 15, 2024
d05f3b3
updated findElement/findElements parameters
AndreaDotDev May 15, 2024
c4569d6
Added logging for LocatorType class
AndreaDotDev May 15, 2024
d7ac6c6
Removed unused imports
AndreaDotDev May 15, 2024
0efcb6a
Updated unit tests for Js class
AndreaDotDev May 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@
@SuppressWarnings("unused")
public class LandingPage extends SpectrumPage<LandingPage, Void> {

@FindBy(id = "login")
private WebElement form;

@FindBy(tagName = "h1")
private WebElement title;

@FindBy(linkText = "Checkboxes")
private WebElement checkboxLink;

@FindBy(linkText = "Form Authentication")
private WebElement formLoginLink;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public class LoginPage extends SpectrumPage<LoginPage, Void> {
@FindBy(id = "login")
private WebElement form;

@FindBy(id = "content")
private WebElement contentDiv;

@FindBy(className = "subheader")
private WebElement subHeader;

@Override
public LoginPage waitForPageLoading() {
log.info("Wait for page loading: waiting for errorMessage to disappear");
Expand Down
119 changes: 114 additions & 5 deletions it/src/test/java/io/github/giulong/spectrum/it/tests/JavascriptIT.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package io.github.giulong.spectrum.it.tests;

import io.github.giulong.spectrum.SpectrumTest;
import io.github.giulong.spectrum.enums.LocatorType;
import io.github.giulong.spectrum.it.pages.CheckboxPage;
import io.github.giulong.spectrum.it.pages.LandingPage;
import io.github.giulong.spectrum.it.pages.LoginPage;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.NoSuchShadowRootException;
import org.openqa.selenium.WebElement;

import static org.junit.jupiter.api.Assertions.*;
Expand All @@ -13,8 +16,8 @@
public class JavascriptIT extends SpectrumTest<Void> {

private LandingPage landingPage;

private CheckboxPage checkboxPage;
private LoginPage loginPage;

@Test
public void testWithNoDisplayName() {
Expand All @@ -27,13 +30,119 @@ public void testWithNoDisplayName() {
final WebElement firstCheckbox = checkboxPage.getCheckboxes().getFirst();
final WebElement secondCheckbox = checkboxPage.getCheckboxes().get(1);

assertFalse(firstCheckbox.isSelected());
assertTrue(secondCheckbox.isSelected());
assertFalse(js.isSelected(firstCheckbox));
assertTrue(js.isSelected(secondCheckbox));

assertTrue(js.isEnabled(firstCheckbox));
assertTrue(js.isDisplayed(firstCheckbox));

js.click(firstCheckbox);
assertTrue(firstCheckbox.isSelected());
assertTrue(js.isSelected(firstCheckbox));

// Take a screenshot with a custom message
screenshotInfo("After checking the first checkbox");
}
}

@Test
public void testFindElementMethod() {
driver.get(configuration.getApplication().getBaseUrl());

assertEquals(landingPage.getFormLoginLink(), js.findElement(LocatorType.LINK_TEXT, "Form Authentication"));
assertEquals(landingPage.getFormLoginLink(), js.findElement(LocatorType.PARTIAL_LINK_TEXT, "Form Aut"));

js.click(landingPage.getFormLoginLink());
loginPage.waitForPageLoading();

final WebElement usernameField = loginPage.getUsername();
final WebElement subHeader = loginPage.getSubHeader();
final WebElement contentDiv = loginPage.getContentDiv();
final WebElement form = loginPage.getForm();

assertEquals(subHeader, js.findElement(contentDiv, LocatorType.CLASS_NAME, "subheader"));
assertEquals(form, js.findElement(contentDiv, LocatorType.TAG_NAME, "form"));
assertEquals(usernameField, js.findElement(LocatorType.NAME, "username"));
assertEquals(usernameField, js.findElement(LocatorType.CSS_SELECTOR, "input[id='username']"));
assertEquals(usernameField, js.findElement(LocatorType.XPATH, "//*[@id='username']"));

assertNotEquals(js.findElement(LocatorType.CLASS_NAME, "row"), js.findElement(contentDiv, LocatorType.CLASS_NAME, "row"));
}

@Test
public void testFindElementsMethod() {
driver.get(configuration.getApplication().getBaseUrl());

final WebElement mainContentDiv = js.findElement(LocatorType.ID, "content");

assertEquals(1, js.findElements(mainContentDiv, LocatorType.LINK_TEXT, "Dropdown").size());
assertEquals(1, js.findElements(LocatorType.LINK_TEXT, "Dropdown").size());
assertEquals(3, js.findElements(mainContentDiv, LocatorType.PARTIAL_LINK_TEXT, "File").size());
assertEquals(3, js.findElements(LocatorType.PARTIAL_LINK_TEXT, "File").size());

js.click(landingPage.getFormLoginLink());
loginPage.waitForPageLoading();

final WebElement form = loginPage.getForm();
final WebElement contentDiv = loginPage.getContentDiv();
final WebElement usernameField = loginPage.getUsername();

// Every test use two test cases, one with context=document (not passed) and other one with context passed
assertEquals(5, js.findElements(LocatorType.CLASS_NAME, "row").size());
assertEquals(2, js.findElements(form, LocatorType.CLASS_NAME, "row").size());
assertEquals(1, js.findElements(LocatorType.NAME, "login").size());
assertEquals(1, js.findElements(contentDiv, LocatorType.NAME, "login").size());
assertEquals(12, js.findElements(LocatorType.TAG_NAME, "div").size());
assertEquals(4, js.findElements(form, LocatorType.TAG_NAME, "div").size());
assertEquals(usernameField, js.findElements(LocatorType.CSS_SELECTOR, "input[id='username'").getFirst());
assertEquals(usernameField, js.findElements(form, LocatorType.CSS_SELECTOR, "input[id='username'").getFirst());
assertEquals(5, js.findElements(LocatorType.CSS_SELECTOR, "div[class='row'").size());
assertEquals(usernameField, js.findElements(LocatorType.XPATH, "//*[@id='username']").getFirst());
}

@Test
public void testWebElementGetMethods() {
driver.get(configuration.getApplication().getBaseUrl());

js.click(landingPage.getFormLoginLink());
loginPage.waitForPageLoading();

final WebElement form = loginPage.getForm();
final WebElement usernameField = loginPage.getUsername();
final WebElement contentDiv = loginPage.getContentDiv();

assertEquals(js.getTagName(usernameField), "input");

// Asserting that custom js methods return same value as selenium WebElement methods
assertEquals(js.getSize(usernameField), usernameField.getSize());
assertEquals(js.getRect(usernameField), usernameField.getRect());

assertEquals(js.getDomAttribute(usernameField, "name"), "username");
assertEquals(js.getAttribute(contentDiv, "class"), "large-12 columns");
assertEquals(js.getText(form), "Username\nPassword\n Login");

assertEquals(js.getCssValue(usernameField, "color"), "rgba(0, 0, 0, 0.75)");
assertEquals(js.getCssValue(usernameField, "background"), "rgb(255, 255, 255) none repeat scroll 0% 0% / auto padding-box border-box");

assertThrows(NoSuchShadowRootException.class, () -> js.getShadowRoot(usernameField));
}

@Test
public void testInputFieldActions() {
driver.get(configuration.getApplication().getBaseUrl());

js.click(landingPage.getFormLoginLink());
loginPage.waitForPageLoading();

final WebElement usernameField = loginPage.getUsername();
final WebElement passwordField = loginPage.getPassword();
final WebElement form = loginPage.getForm();

js.sendKeys(usernameField, "tomsmith");
js.clear(usernameField);
assertTrue(js.getDomProperty(usernameField, "value").isEmpty());
js.sendKeys(usernameField, "tomsmith");
js.sendKeys(passwordField, "SuperSecretPassword!");

js.submit(form);
assertEquals("https://the-internet.herokuapp.com/secure", driver.getCurrentUrl());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.github.giulong.spectrum.enums;

import io.github.giulong.spectrum.interfaces.WebElementFinder;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;

import java.util.List;

@Slf4j
@Getter
@AllArgsConstructor
public enum LocatorType implements WebElementFinder {

ID("return %s.getElementById('%s');", "return %s.querySelectorAll('#%s');"),
CLASS_NAME("return %s.getElementsByClassName('%s')[0];", "return %s.getElementsByClassName('%s');"),
CSS_SELECTOR("return %s.querySelector('%s');", "return %s.querySelectorAll('%s');"),
NAME("return %s.querySelector('[name=\"%s\"]');", "return %s.querySelectorAll('[name=\"%s\"]');"),
TAG_NAME("return %s.getElementsByTagName('%s')[0];", "return %s.getElementsByTagName('%s');"),

XPATH("return %s.evaluate('%s', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;",
"var webElements = %s.evaluate('%s', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);" +
"return Array.from({length: webElements.snapshotLength}, (_, i) => webElements.snapshotItem(i));"),

LINK_TEXT("return %s.evaluate('//a[text()=\"%s\"]', " +
"document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;",
"return Array.from(%s.querySelectorAll('a')).filter(link => link.textContent === '%s');"),

PARTIAL_LINK_TEXT("return %s.evaluate('//a[contains(text(), \"%s\")]', " +
"document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;",
"return Array.from(%s.querySelectorAll('a')).filter(link => link.textContent.includes('%s'));");

private final String findElementScript;
private final String findElementsScript;

@Override
public WebElement findElement(JavascriptExecutor driver, WebElement context, String locatorValue) {
String jsCommand = String.format(findElementScript, context != null ? "arguments[0]" : "document", locatorValue);
AndreaDotDev marked this conversation as resolved.
Show resolved Hide resolved
log.debug("Executing js for finding web element. Script: {}", jsCommand);
return (WebElement) driver.executeScript(jsCommand, context);
}

@SuppressWarnings("unchecked")
@Override
public List<WebElement> findElements(JavascriptExecutor driver, WebElement context, String locatorValue) {
String jsCommand = String.format(findElementsScript, context != null ? "arguments[0]" : "document", locatorValue);
log.debug("Executing js for finding multiple web elements. Script: {}", jsCommand);
return (List<WebElement>) driver.executeScript(jsCommand, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.giulong.spectrum.interfaces;

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;

import java.util.List;

public interface WebElementFinder {
AndreaDotDev marked this conversation as resolved.
Show resolved Hide resolved

WebElement findElement(JavascriptExecutor driver, WebElement context, String locatorValue);

List<WebElement> findElements(JavascriptExecutor driver, WebElement context, String locatorValue);
}
Loading