Skip to content

Providing W3C compliance - #829

Merged
TikhomirovSergey merged 15 commits into
appium:masterfrom
TikhomirovSergey:master
Feb 13, 2018
Merged

Providing W3C compliance#829
TikhomirovSergey merged 15 commits into
appium:masterfrom
TikhomirovSergey:master

Conversation

@TikhomirovSergey

Copy link
Copy Markdown
Contributor

Change list

  • added additional capability 'MobileCapabilityType.FORCE_MJSONWP'
  • added org.openqa.selenium.remote.NewSessionPayload
  • update of selenium to 3.9.1

Types of changes

  • No changes in production code.
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Details

I am not sure that this solution is 100% good but it seem the goal is achived.

@BeforeClasspublicstaticvoidbeforeClass() {
service = AppiumDriverLocalService.buildDefaultService();
service.start();
if (service == null || !service.isRunning()) {
thrownewAppiumServerHasNotBeenStartedLocallyException(
"An appium server node is not started!");
}
FileappDir = newFile("src/test/java/io/appium/java_client");
Fileapp = newFile(appDir, "ApiDemos-debug.apk");
DesiredCapabilitiescapabilities = newDesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
capabilities.setCapability(MobileCapabilityType.FORCE_MJSONWP, true);
driver = newAndroidDriver<>(service.getUrl(), capabilities);
}

https://gist.github.com/TikhomirovSergey/0bcaf79e96cd1ef6644e5e8c2b975596

@BeforeClasspublicstaticvoidbeforeClass() {
service = AppiumDriverLocalService.buildDefaultService();
service.start();
if (service == null || !service.isRunning()) {
thrownewAppiumServerHasNotBeenStartedLocallyException(
"An appium server node is not started!");
}
FileappDir = newFile("src/test/java/io/appium/java_client");
Fileapp = newFile(appDir, "ApiDemos-debug.apk");
DesiredCapabilitiescapabilities = newDesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
//capabilities.setCapability(MobileCapabilityType.FORCE_MJSONWP, true);driver = newAndroidDriver<>(service.getUrl(), capabilities);
}

https://gist.github.com/TikhomirovSergey/5987f5c74e37110427b8f5651030aa3b

shs96cand others added 10 commits February 9, 2018 22:43
There's a lot of overlap between the ProtocolHandshake and
the NewSessionPayload. Time to deal with this overlap between
the two.
The main change is to make the NewSessionPayload capable of
writing to an Appendable. It does so by streaming the
Capabilities used to create the payload as the OSS capabilities
and those used by old geckodrivers, and then streaming every
capability through transforms to generate spec compliant
capabilities.
There appears to be a bug where we always generate synthetic
capabilities, but we can deal with that later.
Using the magic of Buck's "maven-importer" and the following maven
coordinates:
```
'org.seleniumhq.selenium:htmlunit-driver:jar:2.28.5' \
'junit:junit:jar:4.12' \
'net.bytebuddy:byte-buddy:jar:1.7.9' \
'com.google.code.gson:gson:jar:2.8.2' \
'com.google.guava:guava:jar:23.6-jre' \
'org.apache.commons:commons-exec:jar:1.3' \
'org.eclipse.jetty:jetty-security:jar:9.4.8.v20171121' \
'org.testng:testng:jar:6.13.1' \
'org.pantsbuild:jarjar:jar:1.6.5' \
'org.eclipse.jetty:jetty-util:jar:9.4.8.v20171121' \
'org.eclipse.jetty:jetty-server:jar:9.4.8.v20171121' \
'org.eclipse.jetty:jetty-servlet:jar:9.4.8.v20171121' \
'org.hamcrest:hamcrest-library:jar:1.3' \
'com.github.javaparser:javaparser-core:jar:3.5.7' \
'org.eclipse.jetty:jetty-jmx:jar:9.4.8.v20171121' \
'net.jcip:jcip-annotations:jar:1.0' \
'org.yaml:snakeyaml:jar:1.19' \
'org.mockito:mockito-core:jar:2.13.0' \
'io.netty:netty-all:jar:4.1.19.Final' \
'org.eclipse.mylyn.github:org.eclipse.egit.github.core:jar:2.1.5' \
'org.littleshoot:littleproxy:jar:1.1.2' \
'org.slf4j:slf4j-jdk14:jar:1.7.25'
```
The version of LittleProxy we use is a snapshot and is the old
version from previously with dependencies updated.
@jsf-clabot

jsf-clabot commented Feb 11, 2018

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 3 committers have signed the CLA.

✅ TikhomirovSergey
❌ shs96c
❌ barancev


/**
* This is the flag which forces server to switch to the mobile WSONWP.
* If {@code false} when it is switched to W3C mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when->then

private final FileBackedOutputStream backingStore;
private final ImmutableSet<Dialect> dialects;

private static List<String> getAppiumCapabilities(Class<?> capabilityList) {

@mykola-mokhnachmykola-mokhnachFeb 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List<String> or List<Object>?

@TikhomirovSergeyTikhomirovSergeyFeb 11, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mykola-mokhnach
List<String>

privatestaticList<String> getAppiumCapabilities(Class<?> capabilityList) {
returnArrays.stream(capabilityList.getDeclaredFields()).map(field -> {
field.setAccessible(true);
try {
returnfield.get(capabilityList).toString(); //<-!!!!
} catch (IllegalAccessExceptione) {
thrownewIllegalArgumentException(e);
}
}).filter(s -> !FORCE_MJSONWP.equals(s)).collect(toList());
}

// We need to convert the capabilities into a new session payload. At this point we're dealing
// with references, so I'm Just Sure This Will Be Fine.
boolean forceMobileJSONWP = ofNullable(caps.getCapability(FORCE_MJSONWP))
.map(o -> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could use ternary operator here

}

public static NewSessionPayload create(Capabilities caps) throws IOException {
// We need to convert the capabilities into a new session payload. At this point we're dealing

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

return new NewSessionPayload(source, forceMobileJSONWP);
}

private NewSessionPayload(Reader source, boolean forceMobileJSONWP) throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This copies a lot of stuff from the original selenium code. Is it somehow possible to avoid such duplication?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for example using reflection

// Opera: operaOptions
// SafariDriver: safari.options
//
// We can't use the constants defined in the classes because it would introduce circular

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need all the commented stuff above?

public String getKey() {
String key = stringObjectEntry.getKey();
if (APPIUM_CAPABILITIES.contains(key) && !forceMobileJSONWP) {
return "appium:" + key;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appium: might be a constant

.map(this::applyTransforms)
.map(map -> map.entrySet().stream()
.filter(entry -> {
if (forceMobileJSONWP) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ternary operator might be more useful here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.filter(entry -> forceMobileJSONWP && ACCEPTED_W3C_PATTERNS.test(entry.getKey()) || !forceMobileJSONWP)

return Stream.concat(fromOss, fromW3c).distinct();
}

private Map<String, Object> convertOssToW3C(Map<String, Object> capabilities) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mark as Nullable

name = input.nextName();
if ("alwaysMatch".equals(name)) {
return input.read(MAP_TYPE);
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this else seems redundant

name = input.nextName();
if ("firstMatch".equals(name)) {
return input.read(LIST_OF_MAPS_TYPE);
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

return null;
}

private Collection<Map<String, Object>> getFirstMatches() throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullable

return toReturn;
}

private Map<String, Object> getAlwaysMatch() throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullable

backingStore.reset();
}

private Map<String, Object> getOss() throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullable

String name = input.nextName();
if ("desiredCapabilities".equals(name)) {
return input.read(MAP_TYPE);
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else is redundant

"Illegal key values seen in w3c capabilities: " + illegalKeys);
}
})
.forEach(map -> {});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the purpose of this operator?

}

// Write the first capability we get as the desired capability.
json.name("desiredCapabilities");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather put all there magic strings into constants

- removal of redundant code from the original NewSessionPayload
@TikhomirovSergey

Copy link
Copy Markdown
ContributorAuthor

@SrinivasanTarget Could you try it on iOS?

@appiumappium deleted a comment Feb 12, 2018
/**
* Which mobile OS platform to use.
*/
String PLATFORM_NAME = "platformName";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where this constant is present now?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in org.openqa.selenium.remote.CapabilityType

publicinterfaceMobileCapabilityTypeextendsCapabilityType


public static NewSessionPayload create(Capabilities caps) throws IOException {
boolean forceMobileJSONWP = ofNullable(caps.getCapability(FORCE_MJSONWP))
.map(o -> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.map(o -> Boolean.class.isAssignableFrom(o.getClass()) && Boolean.class.cast(o))

String name = input.nextName();
if (DESIRED_CAPABILITIES.equals(name)) {
return input.read(MAP_TYPE);
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else is redundant

@TikhomirovSergey

Copy link
Copy Markdown
ContributorAuthor

Updated.
@SrinivasanTarget does it work fine on iOS?

@appiumappium deleted a comment Feb 13, 2018
return null;
}

private @Nullable Collection<Map<String, Object>> getFirstMatches() throws IOException {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getFirstMatch

name = input.nextName();
if (FIRST_MATCH.equals(name)) {
return input.read(LIST_OF_MAPS_TYPE);
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else is redundant. same comment to other similar blocks

@mykola-mokhnachmykola-mokhnach left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor comments

@SrinivasanTargetSrinivasanTarget left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks fine on iOS on both W3C and JSONWP

@appiumappium deleted a comment Feb 13, 2018
@TikhomirovSergey
TikhomirovSergey merged commit 409e6f3 into appium:masterFeb 13, 2018
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@TikhomirovSergey@jsf-clabot@mykola-mokhnach@SrinivasanTarget@shs96c@barancev