Skip to content

Commit

Permalink
[plugin-web-app-playwright] Incorporate visibility consideration in e…
Browse files Browse the repository at this point in the history
…lement locating
  • Loading branch information
avinBar committed Jun 13, 2024
1 parent c922a6c commit 10e47b5
Show file tree
Hide file tree
Showing 14 changed files with 410 additions and 45 deletions.
32 changes: 32 additions & 0 deletions docs/modules/plugins/pages/plugin-web-app-playwright.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ Playwright captures a set of complete DOM snapshots for each action.

== Locator

----
By.<locatorType>(<locatorValue>):<visibility>
----

[IMPORTANT]

By. prefix is optional.

. `locatorType` - *[mandatory]* type of the locator
. `locatorValue` - *[mandatory]* value of the locator
. `visibility` - *[optional]* visibility of element (visible by default)


=== Locator Types

[cols="1,3,2", options="header"]
Expand All @@ -70,6 +83,25 @@ Playwright captures a set of complete DOM snapshots for each action.

|===

=== Visibility types

[cols="1,1,3", options="header"]
|===

|Visibility type
|Usage example
|Description

|VISIBLE
|xpath(//a)
|Default visibility option. Only visible elements will be found

|all
|xpath(//a):a
|Either visible and invisible elements will be found

|===

== Steps
include::plugins:partial$common-web-app-steps.adoc[]
include::plugins:partial$ui-context-management-steps.adoc[]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 the original author or authors.
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,14 +16,9 @@

package org.vividus.ui.action.search;

import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.vividus.ui.State;

public enum Visibility
public enum Visibility implements ElementVisibility
{
VISIBLE(State.VISIBLE, "visible"),
INVISIBLE(State.NOT_VISIBLE, "invisible"),
Expand All @@ -50,23 +45,6 @@ public String getDescription()

public static Visibility getElementType(String input)
{
Validate.isTrue(StringUtils.isNotBlank(input), "Visibility type can not be empty. %s",
getExpectedVisibilityMessage());

String inputInUpperCase = input.toUpperCase().trim();
return Stream.of(values())
.filter(v -> v.name().startsWith(inputInUpperCase))
.findFirst()
.orElseThrow(() ->
new IllegalArgumentException(
String.format("Illegal visibility type '%s'. %s", input, getExpectedVisibilityMessage())));
}

private static String getExpectedVisibilityMessage()
{
return Stream.of(values()).map(Visibility::name)
.map(String::toLowerCase)
.map(type -> StringUtils.wrap(type, '\''))
.collect(Collectors.joining(", ", "Expected one of ", ""));
return ElementVisibility.getElementType(input, Visibility.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.ui.action.search;

import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

public interface ElementVisibility
{
static <T extends Enum<T> & ElementVisibility> T getElementType(String input, Class<T> enumClass)
{
Validate.isTrue(StringUtils.isNotBlank(input), "Visibility type can not be empty. %s",
getExpectedVisibilityMessage(enumClass));

String inputInUpperCase = input.toUpperCase().trim();
return Stream.of(enumClass.getEnumConstants())
.filter(v -> v.name().startsWith(inputInUpperCase))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(String.format(
"Illegal visibility type '%s'. %s", input, getExpectedVisibilityMessage(enumClass))));
}

private static <T extends Enum<T> & ElementVisibility> String getExpectedVisibilityMessage(Class<T> enumClass)
{
return Stream.of(enumClass.getEnumConstants()).map(Enum::name)
.map(String::toLowerCase)
.map(type -> StringUtils.wrap(type, '\''))
.collect(Collectors.joining(", ", "Expected one of ", ""));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.ui.action.search;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;

class ElementVisibilityTests
{
enum TestVisibility implements ElementVisibility
{
VISIBLE, HIDDEN, ANY
}

@Test
void shouldGetElementType()
{
TestVisibility visibility = ElementVisibility.getElementType("visible", TestVisibility.class);
assertEquals(TestVisibility.VISIBLE, visibility);
}

@Test
void shouldThrowExceptionWhenInputIsEmpty()
{
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> ElementVisibility.getElementType(StringUtils.EMPTY, TestVisibility.class));
String expectedMessage = "Visibility type can not be empty. Expected one of 'visible', 'hidden', 'any'";
assertEquals(expectedMessage, exception.getMessage());
}

@Test
void shouldThrowExceptionWhenIllegalVisibilityType()
{
String illegalVisibilityType = "illegal";
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> ElementVisibility.getElementType(illegalVisibilityType, TestVisibility.class));
String expectedMessage = String.format(
"Illegal visibility type '%s'. Expected one of 'visible', 'hidden', 'any'", illegalVisibilityType);
assertEquals(expectedMessage, exception.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2023 the original author or authors.
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,6 +24,7 @@

import org.vividus.testcontext.TestContext;
import org.vividus.ui.web.playwright.locator.PlaywrightLocator;
import org.vividus.ui.web.playwright.locator.Visibility;

public class UiContext
{
Expand Down Expand Up @@ -57,7 +58,10 @@ public void reset()
public Locator locateElement(PlaywrightLocator playwrightLocator)
{
String locator = playwrightLocator.getLocator();
return getInCurrentContext(context -> context.locator(locator), page -> page.locator(locator));
Locator locatorInContext = getInCurrentContext(context -> context.locator(locator),
page -> page.locator(locator));
return (playwrightLocator.getVisibility() == Visibility.VISIBLE)
? locatorInContext.locator("visible=true") : locatorInContext;
}

public Locator getCurrentContexOrPageRoot()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class PlaywrightLocator
{
private final String locatorType;
private final String locatorValue;
private Visibility visibility = Visibility.VISIBLE;

public PlaywrightLocator(String locatorType, String locatorValue)
{
Expand All @@ -34,6 +35,16 @@ public String getLocator()
return locatorType + "=" + locatorValue;
}

public Visibility getVisibility()
{
return visibility;
}

public void setVisibility(Visibility visibility)
{
this.visibility = visibility;
}

@Override
public boolean equals(Object o)
{
Expand All @@ -46,18 +57,19 @@ public boolean equals(Object o)
return false;
}
PlaywrightLocator that = (PlaywrightLocator) o;
return Objects.equals(locatorType, that.locatorType) && Objects.equals(locatorValue, that.locatorValue);
return Objects.equals(locatorType, that.locatorType) && Objects.equals(locatorValue,
that.locatorValue) && Objects.equals(visibility, that.visibility);
}

@Override
public int hashCode()
{
return Objects.hash(locatorType, locatorValue);
return Objects.hash(locatorType, locatorValue, visibility);
}

@Override
public String toString()
{
return locatorType + '(' + locatorValue + ')';
return locatorType + '(' + locatorValue + ')' + " with visibility: " + visibility.toString().toLowerCase();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2023 the original author or authors.
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,11 +17,21 @@
package org.vividus.ui.web.playwright.locator;

import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.vividus.ui.locator.LocatorParser;

public final class PlaywrightLocatorConverter
{
private static final int ATTRIBUTE_TYPE_GROUP = 1;
private static final int SEARCH_VALUE_GROUP = 2;
private static final int ELEMENT_TYPE_GROUP = 3;
private static final int VISIBILITY_GROUP = 4;
private static final char CLOSING_BRACKET = ']';
private static final String LOCATOR_FORMAT = "(?:By\\.)?([a-zA-Z-]+)\\((.*)\\)(:(.*))?";
private static final Pattern LOCATOR_PATTERN = Pattern.compile(LOCATOR_FORMAT);

private PlaywrightLocatorConverter()
{
}
Expand All @@ -33,7 +43,22 @@ public static Set<PlaywrightLocator> convertToLocatorSet(String locatorsAsString

public static PlaywrightLocator convertToLocator(String locatorAsString)
{
return LocatorParser.parseSingleLocator(locatorAsString, PlaywrightLocatorConverter::convertToLocator);
Matcher matcher = LOCATOR_PATTERN.matcher(locatorAsString);
if (matcher.matches())
{
String elementActionType = matcher.group(ATTRIBUTE_TYPE_GROUP).toLowerCase();
String searchValue = matcher.group(SEARCH_VALUE_GROUP);
String elementType = matcher.group(ELEMENT_TYPE_GROUP);
PlaywrightLocator convertedLocator = convertToLocator(elementActionType, searchValue);
if (elementType != null)
{
String visibilityType = matcher.group(VISIBILITY_GROUP);
convertedLocator.setVisibility(Visibility.getElementType(visibilityType));
}
return convertedLocator;
}
throw new IllegalArgumentException("Invalid locator format. Expected matches [" + LOCATOR_FORMAT
+ CLOSING_BRACKET + " Actual: [" + locatorAsString + CLOSING_BRACKET);
}

private static PlaywrightLocator convertToLocator(String type, String value)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.ui.web.playwright.locator;

import org.vividus.ui.action.search.ElementVisibility;

public enum Visibility implements ElementVisibility
{
VISIBLE,
ALL;

public static Visibility getElementType(String input)
{
return ElementVisibility.getElementType(input, Visibility.class);
}
}
Loading

0 comments on commit 10e47b5

Please sign in to comment.