sbabcoc / selenium-foundation Goto Github PK
View Code? Open in Web Editor NEWSelenium Foundation is an automation framework designed to extend and enhance the capabilities provided by Selenium (WebDriver).
License: Apache License 2.0
Selenium Foundation is an automation framework designed to extend and enhance the capabilities provided by Selenium (WebDriver).
License: Apache License 2.0
The implementation of javaGlueLib.js
causes some JavaScript engines (e.g. - Rhino) to throw errors. Revise this library with less exotic implementation so that it behaves correctly, regardless of the JavaScript engine of the current browser.
For example, specific feature may be presented in different formats based on the capabilities of the target browser.
I few weeks ago, I cloned this project so I could hack together a version that supports Selenium 3. This approach is unsustainable, as it creates a maintenance nightmare. The solution is to create a base project that uses weak references to the core WebDriver API, with sub-projects for Selenium 2 and Selenium 3.
The constants in the SeleniumSettings enumeration currently include only minimal documentation. This needs to be expanded to explain what each setting actually does within its corresponding context.
We should provide a mechanism to specify servlets for the Selenium Grid server to load. Currently, we specify a hardcoded list of servlets that provided the example page used for the project unit tests.
JDK 11 and proxies in a world past sun.misc.Unsafe
This blog post explains the challenges of implementing dynamic proxies on newer versions of Java. Selenium Foundation uses Byte Buddy in three contexts:
The Selenium Foundation project includes a discrete JAR containing the OperaDriver class for Selenium 2. This was extracted from the 2.53.1 uber-JAR. For some reason, this was never published as an official artifact.
In a recent project, I used Selenium Foundation
to create stand-alone automation built on JUnitBase
. Due to time constraints, I chose to abandon an attempt to run my automation via JUnitCore
. The issue that caused me to change course was lack of a defined mechanism to inject parameters into the test object. Also, although JUnit Foundation
is brought in as a transitive dependency, I didn't run the Java agent that installs its hooks. This meant that my code was responsible for:
I could have injected parameters via System properties. Also, I could have built on TestNgBase
to get full framework support without needing to run a Java agent. TestNG enables on-the-fly creation of XmlTest
and XmlSuite
objects, which can be used to attach listeners and inject parameters.
Selendroid is another Selenuim driver for automating interactions with Android applications. This interface provides a node server that works with Selenium Grid. Create plugins to enable local grid to manage Selendroid nodes.
The GitHub project for Selendroid is here: https://github.com/selendroid/selendroid
Remember: Features that no one can find don't exist!
I strongly suspect that the getScriptResource()
method is only able to read resources from the standard file system; resources contained in JAR files may not be accessibly via this method as it's currently implemented.
The lack of support for JUnit 5 is a serious deficiency at this point. Add this support, examining the possibility of migrating the existing support for TestNG and JUnit 4 into platform-specific subprojects.
The page load completion
mechanism of the container method interceptor includes the ability to register transition error detectors
- service providers that implement the TransitionErrorDetector
interface. This feature enables implementers to provide detectors for scenario-specific error conditions (error messages, error pages, etcetera). In conjunction with its own page load completion
checks, the container method interceptor invokes registered transition error detectors
to determine if a recognized error condition has been encountered.
This transition error detector
feature needs to be documented so implementers are informed of its existence, along with description, examples, and reference implementations.
https://www.youtube.com/watch?v=4F-laDV9Pl8
This video shows how to use this feature locally, but it's apparently possible to construct a servlet to make this work on Grid sessions: https://stackoverflow.com/questions/48585187/chrome-remote-debugging-in-a-seleniumgrid
Other references: https://stackoverflow.com/questions/6827310/chrome-remote-debugging-doesnt-work-with-ip
https://developers.google.com/web/tools/chrome-devtools/remote-debugging
Potentially applicable to all drivers (not just Chrome): https://tarunlalwani.com/post/reusing-existing-browser-session-selenium/
Question: Once references to the driver object go out of scope, does the server get closed automatically, or would this leave a zombie behind? I probably need to determine how to close the driver without terminating the browser session (if this is possible).
This interface defines the following:
The configuration JSON file for the standard node server will be assembled dynamically, based on the drivers that it's configured to provided. If no drivers are specified, the standard node will not be launched. The configuration JSON file for stand-alone node servers must be provided by their associated plugins.
The hash code added to node configuration file names is intended to skip writing the configuration to disk if the file already exists. Because this hash code omits the hub host URL, though, the configuration won't be written if this is the only thing that's changed.
This should mostly be just a copy/paste/format task, because the settings enumeration includes JavaDoc for each setting.
The client code defines its own interpretation of what a "platform" is. The framework merely calls the client's implementation to set and check the "platform" on which each test runs.
The "platform" to be activated by any given test is determined in the TestNG method interceptor. Avoid the temptation to allow a single test method to specify multiple "platforms", as it complicates the implementation quite a bit. Test results get very messy as well.
The interceptor encodes the "platform" specifier as JSON and stores it in the method description (which is the only writable attribute available).
Currently, the only way to specify Local Grid node plugins is via the ServiceLoader provider configuration file. This really doesn't work in the context of command line Grid launchers like local-grid-utility
.
In addition to the load
method, ServiceLoader provides a loadInstalled
method that discovers service provider classes that have already been loaded. To facilitate settings-based local Grid configuration, add a setting to specify a semicolon-delimited list of fully-qualified service provider class names. Each provider will be loaded via Class.forName(String.class)
, then iterated using ServiceProvider.loadInstalled(Class<S>)
.
NOTE: If this setting is specified, the provider configuration file will be ignored.
'appium' provides the ability to specify default capabilities that get merged into driver session requests. A good rationale for integrating this option as a Selenium Foundation
local Grid feature is presented here. The challenge is that default capabilities apply to all session requests; however, each driver plug-in can support multiple "personalities", which can be augmented at runtime through driver-keyed modifications in the configuration.
How do we determine which "defaults" to specify if the aggregation of driver "personalities" and configured modifications yields multiple choices?
Note that the use of the --default-capabilities
option may be unnecessary, due to the ability to specify personality-keyed session request modifications in the configuration. Another approach is to simply use the generic APPIUM_CLI_ARGS
setting.
Ensure to document the following:
Currently, it's only possible to alter built-in driver "personality" records. We should provide the ability to define additional "personality" records as well.
JUnit added the ability to specify order of execution directly in the @Rule
annotation with the order
attribute. The documentation here still refers to the deprecated RuleChain
, though. Update the documentation to reflect current practice, but include notes on how to update legacy code.
Also revise reference to RuleChainWalker
, which is still available but should no longer be necessary.
I need to document system variables and common configuration files for Java, Gradle, and Maven.
There are several tools that need to be installed, global settings that need to be configured, and system properties that must be specified.
Due to the auto-recovery behavior of RobustWebElement objects, it's possible to have the items in an existing component collection silently fall out of sync with the actual page content they represent.
All of the solutions I've thought about so far will either impose overhead on every collection access or fire too late to be bulletproof.
This issue is complicated by the prospect of nested collections. When an element goes stale, all of the collections that contain the element must be rebuilt. This will require logic in the reference refresh implementation to check for collection associations. Ultimately, it may prove to be impossible to implement bulletproof auto-recovery for nested collections.
Use a configured default if timeout is unspecified. Be sure to include adjustment for driver acquisition delay.
Eliminate duplicated code between JUnitPlatformBase and TestNGPlatformBase by extracting an abstract base class.
Occasionally, a driver acquisition request will fail due to some transient condition. To account for this, DriverManager.beforeInvocation() should employ some sort of retry logic.
Document the ShadowRoot
feature in the main README and applicable documentation pages:
In its current form, the browser plugin implementation lacks a mechanism to inject arbitrary capabilities into the supported configurations. There's no way to alter the specifications of existing "personalities" to introduce additional capabilities, which makes such things as ignoring certificate issues much more involved.
The only option at this point is to provide a fully-specified JSON capabilities object in the [selenium.browser.caps] System property.
It would be convenient if we provided an "additional capabilities" mechanism to augment the canned "personalities".
It pretty common for components to exist under certain conditions, but to be absent in others. To model this sort of "optional" component, we should allow for the specification of an optional element as context. Currently, I think it's possible to specify an optional context element, but the base component implementation lack methods to realize "optional" component behavior.
Element references returned by JavaScript functions are native WebElement objects, which means that we have no automatic recovery if references go stale. We should provide methods to enable implementers to wrap returned references in RobustWebElement objects.
This is especially useful for JavaScript functions that return lists of references. For this scenario, clients would supply the list of element references and an Xpath locator as a regular expression pattern that includes a placeholder for an index. An example of a scenario for this sort of method can be found in the OPCT project, in SearchResults.getSearchResultRows()
Currently, SNAPSHOT builds installed to local repository are non-functional due to the lack of a customized POM that correctly identifies transitive dependencies. Gradle build files are dark art, and my efforts to this point have been fruitless.
The existing getDriver()
method always uses the "current" settings for Selenium Grid and desired browser when creating a new driver instance. This is less than ideal. At the very least, we should provide a method that accepts any arbitrary configuration object.
Currently, there's no way to specify a FirefoxShadowRoot search context as a JavaScript execution argument. This makes component-bound search operations impossible. We need to implement a mechanism that decomposes the search context into its shadow host element and a JavaScript statement to acquire the shadow root.
Currently, the names assigned to "enhanced" versions of page model classes are auto-generated by Byte Buddy. We should instead use a defined naming strategy, such as appending "$Enhanced" to the class simple name.
Test classes the implement the DriverProvider interface may blow up when we attempt to create a wrapper for the HtmlUnitWebElement class. The issue has to do with the expectation that the concrete implementation of the WebElement class will use the implicit no-argument constructor, and HtmlUnitWebElement uses a three-argument constructor instead.
java.lang.IllegalArgumentException: None of [public org.openqa.selenium.htmlunit.RobustHtmlUnitWebElement(org.openqa.selenium.htmlunit.HtmlUnitDriver,int,com.gargoylesoftware.htmlunit.html.DomElement)] allows for delegation from public abstract java.lang.Object com.nordstrom.automation.selenium.model.RobustElementFactory$InstanceCreator.makeInstance()
at net.bytebuddy.implementation.bind.MethodDelegationBinder$Processor.bind(MethodDelegationBinder.java:1096)
at net.bytebuddy.implementation.MethodDelegation$Appender.apply(MethodDelegation.java:1282)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:713)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:698)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:605)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5133)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1933)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:225)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:198)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3404)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3600)
at com.nordstrom.automation.selenium.model.RobustElementFactory.getCreator(RobustElementFactory.java:124)
at com.nordstrom.automation.selenium.model.RobustElementFactory.makeRobustElement(RobustElementFactory.java:78)
at com.nordstrom.automation.selenium.model.RobustElementFactory.getElement(RobustElementFactory.java:208)
at com.nordstrom.automation.selenium.model.RobustElementFactory.getElement(RobustElementFactory.java:195)
at com.nordstrom.automation.selenium.model.ComponentContainer.findElement(ComponentContainer.java:339)
at com.nordstrom.automation.selenium.model.EnhancedExamplePage.findElement$accessor$xx432NvJ(Unknown Source)
at com.nordstrom.automation.selenium.model.EnhancedExamplePage$auxiliary$Q46N7vBr.call(Unknown Source)
at com.nordstrom.automation.selenium.model.ContainerMethodInterceptor.intercept(ContainerMethodInterceptor.java:124)
at com.nordstrom.automation.selenium.model.EnhancedExamplePage.findElement(Unknown Source)
at com.nordstrom.automation.selenium.QuickStart.dummyTest(QuickStart.java:173)
This behavior would depend on the addition of retry support in TestNG Foundation. There may be a way to extend this support to JUnit as well, but this will require additional research.
Modifications for Grid node configurations and browser desired capabilities are specified via settings whose names correspond to the "personality" of the configuration they support. Document the naming patterns for these settings.
Whenever Selenium Foundation launches a local Selenium Grid instance, it should subsequently shut it down. The current implementation can fail in any number of ways, leaving the local Grid running. To make sure that such Grid instances get shut down eventually, I propose adding the following:
It appears that lifecycle management is available by default on grid hub servers. This means that the LifecycleServlet is unnecessary for hub servers.
Local grid setup fails on Windows if the dependencies include classes loaded from file. This is caused by a bug in the code that tries to extract the repository root from the file URI. The error is in using the platform-specific file separator. This is a URI, so the separator is always the slash ('/') character.
In production environments, it's common to have multiple presentations of any given feature operating within a single application. For example, different pages within a single application may use different incarnations of a common navigation menu component, depending on whether each page has been updated to use the latest version or not.
To accommodate this reality, add an annotation that associates the base class with a context-matching resolver that returns the component subclass that corresponds to the component version presented by the system under test.
Calls made to getCurrentUrl()
before the driver has been asked to open a specified URL return with some browser-specific initial value (e.g. - about:blank
). The code in insertBaseElement()
assumes that the current URL will always be fully formed, blowing up with NPE if it's not.
To increase the visibility of exactly why container load verification failed, add code that catches the TimeoutException and throws a disposition-specific exception in its place.
Implement the framework for an error page detection feature. Projects that wish to use this feature provide implementations of an ErrorPageMatcher
interface and specify them under META-INF/services
. The framework will access the specified implementations via the ServiceLoader, iterating through them to see if any of them indicates a match. If a match is found, the framework will throw an exception that indicates the specific error page that was identified.
The three files that differ between S2 and S3 configurations are still largely the same. The common code should be factored out into abstract base classes to eliminate the duplication that currently exists.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.