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

Support more IFrames #297

Merged
merged 12 commits into from
Aug 22, 2019
97 changes: 97 additions & 0 deletions src/main/java/de/retest/web/FrameConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package de.retest.web;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

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

import de.retest.recheck.ui.DefaultValueFinder;
import de.retest.recheck.ui.descriptors.Attribute;
import de.retest.recheck.ui.descriptors.Element;
import de.retest.recheck.ui.descriptors.RootElement;
import de.retest.recheck.ui.descriptors.idproviders.RetestIdProvider;
import de.retest.web.mapping.PathsToWebDataMapping;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@AllArgsConstructor
@Slf4j
public class FrameConverter {

private final String queryJs;
private final RetestIdProvider retestIdProvider;
private final AttributesProvider attributesProvider;
private final DefaultValueFinder defaultValueFinder;

public void addChildrenFromFrames( final WebDriver driver, final Set<String> cssAttributes,
final RootElement lastChecked ) {
final List<Element> frames =
de.retest.web.selenium.By.findElements( lastChecked.getContainedElements(), isFrame() );
log.debug( "Found {} frame(s), getting data per frame.", frames.size() );
for ( final Element frame : frames ) {
addChildrenFromFrame( driver, cssAttributes, frame );
driver.switchTo().defaultContent();
}
}

private void addChildrenFromFrame( final WebDriver driver, final Set<String> cssAttributes, final Element frame ) {
try {
final String framePath = frame.getIdentifyingAttributes().getPath();
final String frameXPath = "/" + framePath;
final WebElement frameWebElement = driver.findElement( By.xpath( frameXPath ) );

log.debug( "Switching to frame '{}'.", frame );
driver.switchTo().frame( frameWebElement );

log.debug( "Retrieving data content of frame '{}'.", frame );
final JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
@SuppressWarnings( "unchecked" )
final PathsToWebDataMapping mapping = new PathsToWebDataMapping( framePath,
(Map<String, Map<String, Object>>) jsExecutor.executeScript( queryJs, cssAttributes ) );
final RootElement frameContent = convert( mapping, getFrameTitle( frame ), framePath );
frame.addChildren( frameContent.getContainedElements() );
} catch ( final Exception e ) {
log.error( "Exception retrieving data content of frame '{}'.", frame, e );
}
}

private String getFrameTitle( final Element frame ) {
final String prefix = "frame-";
final Attribute id = frame.getIdentifyingAttributes().getAttribute( AttributesUtil.ID );
if ( id != null ) {
return prefix + id.getValue();
}
final Attribute name = frame.getIdentifyingAttributes().getAttribute( AttributesUtil.NAME );
if ( name != null ) {
return prefix + name.getValue();
}
return prefix + frame.getRetestId();
}

private RootElement convert( final PathsToWebDataMapping mapping, final String frameTitle,
final String framePath ) {
final PeerConverter peerConverter = new PeerConverter( retestIdProvider, attributesProvider, mapping,
frameTitle, null, defaultValueFinder ) {
@Override
protected boolean isRoot( final String parentPath ) {
// Handle trailing slashes.
return framePath.equals( parentPath.replaceAll( "/$", "" ) );
}
};
return peerConverter.convertToPeers();
}

private static Predicate<Element> isFrame() {
return element -> {
final String type = element.getIdentifyingAttributes().getType();
return Stream.of( "iframe", "frame" ).anyMatch( type::equalsIgnoreCase );
};
}

}
42 changes: 3 additions & 39 deletions src/main/java/de/retest/web/RecheckSeleniumAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
Expand Down Expand Up @@ -73,7 +72,9 @@ public Set<RootElement> convert( final Object toVerify ) {
final RootElement lastChecked =
convert( tagMapping, driver.getCurrentUrl(), driver.getTitle(), shoot( driver ) );

addChildrenFromFrames( driver, cssAttributes, lastChecked );
final FrameConverter frameConverter =
new FrameConverter( getQueryJS(), retestIdProvider, attributesProvider, defaultValueFinder );
frameConverter.addChildrenFromFrames( driver, cssAttributes, lastChecked );

if ( driver instanceof UnbreakableDriver ) {
((UnbreakableDriver) driver).setLastActualState( lastChecked );
Expand All @@ -91,43 +92,6 @@ public RootElement convert( final Map<String, Map<String, Object>> tagMapping, f
.convertToPeers();
}

private void addChildrenFromFrames( final WebDriver driver, final Set<String> cssAttributes,
final RootElement lastChecked ) {
final JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
final List<Element> frames =
de.retest.web.selenium.By.findElements( lastChecked.getContainedElements(), isFrame );

logger.debug( "Found {} frames, getting data per frame.", frames.size() );
for ( final Element frame : frames ) {
final String frameId = frame.getIdentifyingAttributes().get( "id" );
if ( frameId == null ) {
// TODO Implement handling e.g. via name, XPaht, etc.
logger.error( "Cannot retrieve frame with ID null from {}.", frame );
continue;
}
try {
logger.debug( "Switching to frame with ID {}.", frameId );
driver.switchTo().frame( frameId );
final String framePath = frame.getIdentifyingAttributes().getPath();
@SuppressWarnings( "unchecked" )
final PathsToWebDataMapping mapping = new PathsToWebDataMapping( framePath,
(Map<String, Map<String, Object>>) jsExecutor.executeScript( getQueryJS(), cssAttributes ) );
final RootElement frameContent = new PeerConverter( retestIdProvider, attributesProvider, mapping,
"frame-" + frameId, null, defaultValueFinder ) {
@Override
protected boolean isRoot( final String parentPath ) {
// handle trailing slashes...
return framePath.equals( parentPath.replaceAll( "/$", "" ) );
}
}.convertToPeers();
frame.addChildren( frameContent.getContainedElements() );
} catch ( final Exception e ) {
logger.error( "Exception retrieving data content of frame with ID {}.", frameId, e );
}
driver.switchTo().defaultContent();
}
}

private String getQueryJS() {
try ( final InputStream url = getClass().getResourceAsStream( GET_ALL_ELEMENTS_BY_PATH_JS_PATH ) ) {
return String.join( "\n", IOUtils.readLines( url, StandardCharsets.UTF_8 ) );
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/pages/special-container.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
}
</script>

<iframe id="myiframe" height="200" frameborder="0" title="description">
<iframe height="200" frameborder="0" title="description">
<html>
<head></head>
<body class="frameBody">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<reTestXmlDataContainer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" reTestVersion="1.1.0-SNAPSHOT" dataType="de.retest.recheck.ui.descriptors.SutState" dataTypeVersion="4">
<reTestXmlDataContainer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" reTestVersion="1.4.0" dataType="de.retest.recheck.ui.descriptors.SutState" dataTypeVersion="4">
<data xsi:type="sutState">
<descriptors retestId="html" screenId="1" screen="retest - Java Swing GUI Testing" title="retest - Java Swing GUI Testing">
<identifyingAttributes>
Expand Down Expand Up @@ -5960,6 +5960,35 @@
</entry>
</attributes>
</attributes>
<containedElements retestId="body">
<identifyingAttributes>
<attributes>
<attribute key="absolute-outline" xsi:type="outlineAttribute">
<x>8</x>
<y>8</y>
<height>272</height>
<width>498</width>
</attribute>
<attribute key="outline" xsi:type="outlineAttribute">
<x>8</x>
<y>8</y>
<height>-16</height>
<width>-16</width>
</attribute>
<attribute key="path" xsi:type="pathAttribute">html[1]/body[1]/section[1]/div[2]/ul[1]/li[1]/div[1]/div[2]/iframe[1]/html[1]/body[1]</attribute>
<attribute key="suffix" xsi:type="suffixAttribute">1</attribute>
<attribute key="type" xsi:type="stringAttribute">body</attribute>
</attributes>
</identifyingAttributes>
<attributes>
<attributes>
<entry>
<key>shown</key>
<value xsi:type="xsd:string">true</value>
</entry>
</attributes>
</attributes>
</containedElements>
</containedElements>
</containedElements>
<containedElements retestId="div-8bec1">
Expand Down
Loading