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/improve error msg #388

Merged
merged 5 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
64 changes: 31 additions & 33 deletions src/main/java/de/retest/web/selenium/TestHealer.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@ private WebElement findElement( final By by ) {
return findElementByLinkText( (ByLinkText) by );
}
if ( by instanceof ByCssSelector ) {
final String rawSelector = ByWhisperer.retrieveCssSelector( (ByCssSelector) by );
if ( rawSelector.startsWith( "#" ) && !isComplexCssSelector( rawSelector ) ) {
return findElement( By.id( rawSelector.substring( 1 ) ) );
}
if ( !rawSelector.startsWith( "." ) && !isComplexCssSelector( rawSelector ) ) {
return findElement( By.tagName( rawSelector ) );
}
return findElementByCssSelector( (ByCssSelector) by );
}
if ( by instanceof ByXPath ) {
Expand All @@ -84,10 +77,6 @@ private WebElement findElement( final By by ) {
"Healing tests with " + by.getClass().getSimpleName() + " not yet implemented" );
}

private boolean isComplexCssSelector( final String rawSelector ) {
return rawSelector.contains( " " ) || rawSelector.contains( "[" );
}

private WebElement findElementById( final ById by ) {
final String id = retrieveId( by );
final Element actualElement =
Expand Down Expand Up @@ -152,10 +141,26 @@ private WebElement findElementByLinkText( final ByLinkText by ) {
}

private WebElement findElementByCssSelector( final ByCssSelector by ) {
final String selector = retrieveUsableCssSelector( by );

final Element actualElement = de.retest.web.selenium.By.findElementByAttribute( lastExpectedState,
lastActualState, CLASS, value -> ((String) value).contains( selector ) );
final String selector = ByWhisperer.retrieveCssSelector( by );
if ( isNotYetSupportedCssSelector( selector ) ) {
logger.warn(
"Unbreakable tests are not implemented for all CSS selectors. Please report your chosen selector ('{}') at https://github.com/retest/recheck-web/issues.",
selector );
return null;
}
Element actualElement = null;
if ( selector.startsWith( "#" ) ) {
actualElement = de.retest.web.selenium.By.findElementByAttribute( lastExpectedState, lastActualState, ID,
selector.substring( 1 ) );
}
if ( selector.matches( "^[a-z\\-A-Z]*" ) ) {
actualElement = de.retest.web.selenium.By.findElementByAttribute( lastExpectedState, lastActualState, TYPE,
selector );
}
if ( selector.startsWith( "." ) ) {
actualElement = de.retest.web.selenium.By.findElementByAttribute( lastExpectedState, lastActualState, CLASS,
value -> ((String) value).contains( selector.substring( 1 ) ) );
}

if ( actualElement == null ) {
logger.warn( "{} with CSS selector '{}'.", ELEMENT_NOT_FOUND_MESSAGE, selector );
Expand All @@ -167,28 +172,21 @@ private WebElement findElementByCssSelector( final ByCssSelector by ) {
}
}

private String retrieveUsableCssSelector( final ByCssSelector by ) {
final String rawSelector = ByWhisperer.retrieveCssSelector( by );
if ( rawSelector.startsWith( "#" ) ) {
throw new IllegalArgumentException(
"To search for element by ID, use `By.id()` instead of `#id` as CSS selector." );
}
if ( !rawSelector.startsWith( "." ) ) {
throw new IllegalArgumentException(
"To search for element by tag, use `By.tagName()` instead of `tag` as CSS selector." );
}
// remove leading .
final String selector = rawSelector.substring( 1 );
if ( selector.matches( ".*[<>:+\\s\"\\[\\*].*" ) ) {
throw new IllegalArgumentException( "For now, only simple class selector is implemented." );
}
return selector;
protected static boolean isNotYetSupportedCssSelector( final String selector ) {
return selector.matches( ".*[<>:+\\s\"\\[\\*].*" );
}

protected static boolean isNotYetSupportedXPathExpression( final String xpathExpression ) {
return xpathExpression.matches( ".*[<>:+\\s\"|'@\\*].*" );
}

private WebElement findElementByXPath( final ByXPath byXPath ) {
final String xpathExpression = ByWhisperer.retrieveXPath( byXPath );
if ( xpathExpression.matches( ".*[<>:+\\s\"|'@\\*].*" ) ) {
throw new IllegalArgumentException( "For now, only simple class selector is implemented." );
if ( isNotYetSupportedXPathExpression( xpathExpression ) ) {
logger.warn(
"Unbreakable tests are not implemented for all XPath selectors. Please report your chosen selector ('{}') at https://github.com/retest/recheck-web/issues.",
xpathExpression );
return null;
}

final Element actualElement = findMatchingElement( xpathExpression );
Expand Down
94 changes: 47 additions & 47 deletions src/test/java/de/retest/web/selenium/TestHealerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import static de.retest.recheck.ui.Path.fromString;
import static de.retest.recheck.ui.descriptors.Element.create;
import static de.retest.web.selenium.TestHealer.findElement;
import static de.retest.web.selenium.TestHealer.isNotYetSupportedCssSelector;
import static de.retest.web.selenium.TestHealer.isNotYetSupportedXPathExpression;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -62,6 +63,26 @@ public void ByCssSelector_using_tag_should_redirect() {
assertThat( findElement( By.cssSelector( "div" ), wrapped ) ).isEqualTo( resultMarker );
}

@Test
public void ByCssSelector_using_tag_with_hyphen_should_redirect() {
final RecheckDriver wrapped = mock( RecheckDriver.class );
final AutocheckingWebElement resultMarker = mock( AutocheckingWebElement.class );

final RootElement state = mock( RootElement.class );
when( wrapped.getLastExpectedState() ).thenReturn( state );
when( wrapped.getLastActualState() ).thenReturn( state );

final String xpath = "html[1]/ytd-grid-video-renderer[1]";
final IdentifyingAttributes identifying =
IdentifyingAttributes.create( fromString( xpath ), "ytd-grid-video-renderer" );
final Element element = create( "id", state, identifying, new MutableAttributes().immutable() );
when( state.getContainedElements() ).thenReturn( Collections.singletonList( element ) );
when( wrapped.findElement( By.xpath( xpath ) ) ).thenReturn( resultMarker );

// assertThat( By.cssSelector( "div" ).matches( element ) ).isTrue();
assertThat( findElement( By.cssSelector( "ytd-grid-video-renderer" ), wrapped ) ).isEqualTo( resultMarker );
}

@Test
public void ByCssSelector_matches_elements_with_given_class() {
final RecheckDriver wrapped = mock( RecheckDriver.class );
Expand All @@ -87,42 +108,33 @@ public void ByCssSelector_matches_elements_with_given_class() {
}

@Test
public void not_yet_implemented_ByCssSelector_should_throw_exception() {
public void empty_selectors_should_not_throw_exception() {
final RecheckDriver wrapped = mock( RecheckDriver.class );
final RootElement state = mock( RootElement.class );
when( wrapped.getLastExpectedState() ).thenReturn( state );
when( wrapped.getLastActualState() ).thenReturn( state );

try {
findElement( By.cssSelector( ".open > .dropdown-toggle.btn-primary" ), wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}

try {
findElement( By.cssSelector( ".btn-primary[disabled]" ), wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}

try {
findElement( By.cssSelector( "fieldset[disabled]" ), wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}

try {
findElement( By.cssSelector( ".btn-group-vertical > .btn:not(:first-child):not(:last-child)" ), wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}

try {
findElement( By.cssSelector( "[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"]" ),
wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}

try {
findElement( By.cssSelector( ".input-group[class*=\"col-\"]" ), wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}
assertThat( findElement( By.cssSelector( "" ), wrapped ) ).isNull();
assertThat( findElement( By.className( "" ), wrapped ) ).isNull();
assertThat( findElement( By.id( "" ), wrapped ) ).isNull();
assertThat( findElement( By.linkText( "" ), wrapped ) ).isNull();
assertThat( findElement( By.name( "" ), wrapped ) ).isNull();
// assertThat( findElement( By.partialLinkText( "" ), wrapped ) ).isNull();
assertThat( findElement( By.tagName( "" ), wrapped ) ).isNull();
assertThat( findElement( By.xpath( "" ), wrapped ) ).isNull();
}

@Test
public void not_yet_implemented_ByCssSelector_should_be_logged() {
assertThat( isNotYetSupportedCssSelector( ".open > .dropdown-toggle.btn-primary" ) ).isTrue();
assertThat( isNotYetSupportedCssSelector( ".btn-primary[disabled]" ) ).isTrue();
assertThat( isNotYetSupportedCssSelector( "fieldset[disabled]" ) ).isTrue();
assertThat( isNotYetSupportedCssSelector( ".btn-group-vertical > .btn:not(:first-child):not(:last-child)" ) )
.isTrue();
assertThat(
isNotYetSupportedCssSelector( "[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"]" ) )
.isTrue();
assertThat( isNotYetSupportedCssSelector( ".input-group[class*=\"col-\"]" ) ).isTrue();
}

@Test
Expand All @@ -147,20 +159,8 @@ public void ByXPathExpression_matches_elements_with_given_xpath() {
}

@Test
public void not_yet_implemented_ByXPathExpression_should_throw_exception() {
final RecheckDriver wrapped = mock( RecheckDriver.class );
final RootElement state = mock( RootElement.class );
when( wrapped.getLastExpectedState() ).thenReturn( state );
when( wrapped.getLastActualState() ).thenReturn( state );

try {
findElement( By.xpath( "//div[@id='mw-content-text']/div[2]" ), wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}

try {
findElement( By.xpath( "//button[contains(.,'Search')]" ), wrapped );
fail( "Excpected exception" );
} catch ( final IllegalArgumentException e ) {}
public void not_yet_implemented_ByXPathExpression_should_log_warning() {
assertThat( isNotYetSupportedXPathExpression( "//div[@id='mw-content-text']/div[2]" ) ).isTrue();
assertThat( isNotYetSupportedXPathExpression( "//button[contains(.,'Search')]" ) ).isTrue();
}
}