All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.seleniumtests.uipage.aspects.SeleniumNativeActions Maven / Gradle / Ivy

There is a newer version: 4.23.18
Show newest version
/**
 * Orignal work: Copyright 2015 www.seleniumtests.com
 * Modified work: Copyright 2016 www.infotel.com
 * 				Copyright 2017-2019 B.Hecquet
 *
 * 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
 *
 * 	http://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 com.seleniumtests.uipage.aspects;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchFrameException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.pagefactory.DefaultElementLocator;
import org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.seleniumtests.core.SeleniumTestsContextManager;
import com.seleniumtests.driver.WebUIDriver;
import com.seleniumtests.uipage.htmlelements.FrameElement;
import com.seleniumtests.uipage.htmlelements.HtmlElement;

@Aspect
public class SeleniumNativeActions {

	private Map currentFrame = new HashMap<>();

	private Boolean doOverride() {
		return SeleniumTestsContextManager.getThreadContext().getOverrideSeleniumNativeAction();
	}
	
	private FrameElement getCurrentFrame() {
		WebUIDriver uiDriver = WebUIDriver.getWebUIDriver(false);
		if (uiDriver == null) {
			return null;
		}
		if (!currentFrame.containsKey(uiDriver)) {
			currentFrame.put(uiDriver, null);
		}
		
		return currentFrame.get(uiDriver);
	}
	
	private void setCurrentFrame(FrameElement frame) {
		WebUIDriver uiDriver = WebUIDriver.getWebUIDriver(false);
		if (uiDriver == null) {
			return;
		}
		currentFrame.put(uiDriver, frame);
	}
	
	/**
	 * Intercept any call to driver.findElement(By.xx) made from a PageObject subclass and returns a HtmlElement instead of a RemoteWebElement
	 * This way, every action done on this element will benefit from HtmlElement mechanism
	 * @param joinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around("this(com.seleniumtests.uipage.PageObject) && call(public * org.openqa.selenium.WebDriver+.findElement (..))")
	public Object interceptFindHtmlElement(ProceedingJoinPoint joinPoint) throws Throwable {
		if (Boolean.TRUE.equals(doOverride())) {
			return new HtmlElement("", (By)(joinPoint.getArgs()[0]), getCurrentFrame());
		} else {
			return joinPoint.proceed(joinPoint.getArgs());			
		}
	}
	
	@Around("this(com.seleniumtests.uipage.PageObject) && " +					// caller is a PageObject
			"(call(public * org.openqa.selenium.WebDriver+.findElements (..))"
			+ ")"			
			)
	public Object interceptFindsHtmlElement(ProceedingJoinPoint joinPoint) throws Throwable {
		if (Boolean.TRUE.equals(doOverride())) {
			return new HtmlElement("", (By)(joinPoint.getArgs()[0]), getCurrentFrame()).findElements();
		} else {
			return joinPoint.proceed(joinPoint.getArgs());
		}
	}
	
	/**
	 * Intercept "findElement" action done in LocatingElementHandler class so that we can override returned element and replace it by HtmlElement
	 * This helps handling PageObjectFactory method
	 * @param joinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around(" this(org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler) && call(public *  org.openqa.selenium.support.pagefactory.ElementLocator+.findElement (..))"			
			)
	public Object interceptPageFactoryElementLocation(ProceedingJoinPoint joinPoint) throws Throwable {
		if (Boolean.TRUE.equals(doOverride())) {
			DefaultElementLocator locator = ((DefaultElementLocator)joinPoint.getTarget());
			Field byField = DefaultElementLocator.class.getDeclaredField("by");
			byField.setAccessible(true);
			return new HtmlElement("", (By)byField.get(locator), getCurrentFrame());
		} else {
			return joinPoint.proceed(joinPoint.getArgs());			
		}
	}
	
	/**
	 * Intercept "findElements" action done in LocatingElementListHandler class so that we can override returned element and replace it by HtmlElement
	 * This helps handling PageObjectFactory method
	 * @param joinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around(" this(org.openqa.selenium.support.pagefactory.internal.LocatingElementListHandler) && call(public *  org.openqa.selenium.support.pagefactory.ElementLocator+.findElements (..))"			
			)
	public Object interceptPageFactoryElementsLocation(ProceedingJoinPoint joinPoint) throws Throwable {
		if (doOverride()) {
			DefaultElementLocator locator = ((DefaultElementLocator)joinPoint.getTarget());
			Field byField = DefaultElementLocator.class.getDeclaredField("by");
			byField.setAccessible(true);
			return new HtmlElement("", (By)byField.get(locator), getCurrentFrame()).findElements();
		} else {
			return joinPoint.proceed(joinPoint.getArgs());			
		}
	}
	
	/**
	 * Method interceptFindHtmlElement creates an HtmlElement from findElement, but does not handle frames. 
	 * Here, we record all switchTo().frame(WebElement) call to create a FrameElement chain
	 * @param joinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around("this(com.seleniumtests.uipage.PageObject) && " +					// caller is a PageObject
			"(call(public * org.openqa.selenium.support.ui.ExpectedConditions.frameToBeAvailableAndSwitchToIt (..))"
			+ ")"			
			)
	public Object recordFrameSwitch(ProceedingJoinPoint joinPoint) throws Throwable {
		if (Boolean.TRUE.equals(doOverride())) {
			Object frameArg = joinPoint.getArgs()[0];
			FrameElement frameEl = getFrameElement(frameArg);
			
			if (frameEl == null) {
				return joinPoint.proceed(joinPoint.getArgs());
			}
			
			if (getCurrentFrame() == null) {
				setCurrentFrame(frameEl);
			} else {
				frameEl.setFrameElement(getCurrentFrame());
				setCurrentFrame(frameEl);
			}

			return new ExpectedCondition() {
			      @Override
			      public WebDriver apply(WebDriver driver) {
			        try {
			          return driver;
			        } catch (NoSuchFrameException e) {
			          return null;
			        }
			      }

			      @Override
			      public String toString() {
			        return "frame to be available: " + frameArg;
			      }
			    };
			
		} else {
			return joinPoint.proceed(joinPoint.getArgs());
		}
	}
	
	/**
	 * Method interceptFindHtmlElement creates an HtmlElement from findElement, but does not handle frames. 
	 * Here, we record all switchTo().frame(WebElement) call to create a FrameElement chain
	 * @param joinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around("this(com.seleniumtests.uipage.PageObject) && " +					// caller is a PageObject
			"(call(public * org.openqa.selenium.WebDriver.TargetLocator+.frame (..))"
			+ ")"			
			)
	public Object recordSwitchToFramCalls(ProceedingJoinPoint joinPoint) throws Throwable {
		if (Boolean.TRUE.equals(doOverride())) {
			Object frameArg = joinPoint.getArgs()[0];
			FrameElement frameEl = getFrameElement(frameArg);
			
			if (frameEl == null) {
				return joinPoint.proceed(joinPoint.getArgs());
			}

			if (getCurrentFrame() == null) {
				setCurrentFrame(frameEl);
			} else {
				frameEl.setFrameElement(getCurrentFrame());
				setCurrentFrame(frameEl);
			}
			return null;
		} else {
			return joinPoint.proceed(joinPoint.getArgs());
		}
	}
	
	/**
	 * Returns a FrameElement based on the object passed in argument
	 * @param frameArg
	 * @return
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	private FrameElement getFrameElement(Object frameArg) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
		FrameElement frameEl = null;
		
		if (frameArg instanceof HtmlElement) {
			frameEl = new FrameElement("", ((HtmlElement)frameArg).getBy());
		} else if (frameArg instanceof WebElement && frameArg.getClass().getName().contains("Proxy")) {
			LocatingElementHandler locatingEh = (LocatingElementHandler)Proxy.getInvocationHandler(frameArg);
			Field locatorField = LocatingElementHandler.class.getDeclaredField("locator");
			locatorField.setAccessible(true);
			DefaultElementLocator locator = ((DefaultElementLocator)locatorField.get(locatingEh));
			Field byField = DefaultElementLocator.class.getDeclaredField("by");
			byField.setAccessible(true);
			frameEl = new FrameElement("", (By)byField.get(locator));
		} else if (frameArg instanceof By) {
			frameEl = new FrameElement("", (By)frameArg);
		} else if (frameArg instanceof Integer) {
			frameEl = new FrameElement("", By.tagName("iframe"), (Integer) frameArg);
		} else if (frameArg instanceof String) {
			String name = ((String)frameArg).replaceAll("(['\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-/\\[\\]\\(\\)])", "\\\\$1");
			frameEl = new FrameElement("", By.cssSelector("frame[name='" + name + "'],iframe[name='" + name + "'],frame#" + name + ",iframe#" + name));
		}
		return frameEl;
	}
	
	@Around("this(com.seleniumtests.uipage.PageObject) && " +					// caller is a PageObject
			"(call(public * org.openqa.selenium.WebDriver.TargetLocator+.defaultContent (..))"
			+ ")"			
			)
	public Object recordSwitchDefaultContext(ProceedingJoinPoint joinPoint) throws Throwable {
		setCurrentFrame(null);
		return joinPoint.proceed(joinPoint.getArgs());
	}
	
	
	@Around("this(com.seleniumtests.uipage.PageObject) && " +					// caller is a PageObject
			"(call(public * org.openqa.selenium.WebDriver.TargetLocator+.parentFrame (..))"
			+ ")"			
			)
	public Object recordSwitchParentFrame(ProceedingJoinPoint joinPoint) throws Throwable {
		FrameElement curFrame = getCurrentFrame();
		if (curFrame == null || !doOverride()) {
			return joinPoint.proceed(joinPoint.getArgs());
		} else {
			setCurrentFrame(curFrame.getFrameElement());
		}
		return null;
		
	}
	
	
	
	// TODO: handle findElementBy... (from RemoteWebDriver) => should be useless as SeleniuRobot only expose a WebDriverInstance
	// TODO: check behavior with WebDriverWait & CompositeActions
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy