Skip to content

Commit e2c20ee

Browse files
add a test
1 parent 7b3ffc6 commit e2c20ee

File tree

6 files changed

+160
-21
lines changed

6 files changed

+160
-21
lines changed

src/e2eIosTest/java/io/appium/java_client/ios/AppIOSTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static void beforeClass() {
2121
.setDeviceName(DEVICE_NAME)
2222
.setCommandTimeouts(Duration.ofSeconds(240))
2323
.setApp(TEST_APP_ZIP)
24+
.enableBiDi()
2425
.setWdaLaunchTimeout(WDA_LAUNCH_TIMEOUT);
2526
try {
2627
driver = new IOSDriver(service.getUrl(), options);

src/e2eIosTest/java/io/appium/java_client/ios/BaseIOSWebViewTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ public static void beforeClass() {
3939
.setDeviceName(DEVICE_NAME)
4040
.setWdaLaunchTimeout(WDA_LAUNCH_TIMEOUT)
4141
.setCommandTimeouts(Duration.ofSeconds(240))
42-
.setShowIosLog(true)
4342
.setApp(VODQA_ZIP);
4443
Supplier<IOSDriver> createDriver = () -> new IOSDriver(service.getUrl(), options);
4544
try {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* See the NOTICE file distributed with this work for additional
5+
* information regarding copyright ownership.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appium.java_client.ios;
18+
19+
import org.junit.jupiter.api.Disabled;
20+
import org.junit.jupiter.api.Test;
21+
import org.openqa.selenium.bidi.log.LogEntry;
22+
import org.openqa.selenium.bidi.module.LogInspector;
23+
24+
import java.util.concurrent.CopyOnWriteArrayList;
25+
26+
import static org.junit.jupiter.api.Assertions.assertFalse;
27+
28+
public class IOSBiDiTest extends AppIOSTest {
29+
30+
@Test
31+
@Disabled("Need to resolve compatibility issues")
32+
public void listenForIosLogs() {
33+
var logs = new CopyOnWriteArrayList<LogEntry>();
34+
try (var logInspector = new LogInspector(driver)) {
35+
logInspector.onLog(logs::add);
36+
driver.getPageSource();
37+
}
38+
assertFalse(logs.isEmpty());
39+
}
40+
41+
}

src/main/java/io/appium/java_client/AppiumDriver.java

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.appium.java_client.remote.AppiumCommandExecutor;
2222
import io.appium.java_client.remote.AppiumW3CHttpCommandCodec;
2323
import io.appium.java_client.remote.options.BaseOptions;
24+
import io.appium.java_client.remote.options.SupportsWebSocketUrlOption;
2425
import io.appium.java_client.service.local.AppiumDriverLocalService;
2526
import io.appium.java_client.service.local.AppiumServiceBuilder;
2627
import lombok.Getter;
@@ -31,6 +32,7 @@
3132
import org.openqa.selenium.UnsupportedCommandException;
3233
import org.openqa.selenium.WebDriverException;
3334
import org.openqa.selenium.bidi.BiDi;
35+
import org.openqa.selenium.bidi.BiDiException;
3436
import org.openqa.selenium.bidi.HasBiDi;
3537
import org.openqa.selenium.remote.CapabilityType;
3638
import org.openqa.selenium.remote.DriverCommand;
@@ -44,6 +46,7 @@
4446
import org.openqa.selenium.remote.http.HttpClient;
4547
import org.openqa.selenium.remote.http.HttpMethod;
4648

49+
import javax.annotation.Nonnull;
4750
import java.net.URI;
4851
import java.net.URISyntaxException;
4952
import java.net.URL;
@@ -152,8 +155,8 @@ public AppiumDriver(Capabilities capabilities) {
152155
* !!! This API is supposed to be used for **debugging purposes only**.
153156
*
154157
* @param remoteSessionAddress The address of the **running** session including the session identifier.
155-
* @param platformName The name of the target platform.
156-
* @param automationName The name of the target automation.
158+
* @param platformName The name of the target platform.
159+
* @param automationName The name of the target automation.
157160
*/
158161
public AppiumDriver(URL remoteSessionAddress, String platformName, String automationName) {
159162
super();
@@ -268,19 +271,46 @@ public Optional<BiDi> maybeGetBiDi() {
268271
return Optional.ofNullable(this.biDi);
269272
}
270273

274+
@Override
275+
@Nonnull
276+
public BiDi getBiDi() {
277+
var webSocketUrl = ((BaseOptions<?>) this.capabilities).getWebSocketUrl().orElseThrow(
278+
() -> new BiDiException(
279+
String.format(
280+
"BiDi is not enabled for this driver session. " +
281+
"Did you set %s to true?", SupportsWebSocketUrlOption.WEB_SOCKET_URL
282+
)
283+
)
284+
);
285+
if (this.biDiUri == null) {
286+
throw new BiDiException(
287+
String.format(
288+
"BiDi is not enabled for this driver session. " +
289+
"Is the %s '%s' received from the create session response valid?",
290+
SupportsWebSocketUrlOption.WEB_SOCKET_URL, webSocketUrl
291+
)
292+
);
293+
}
294+
if (this.biDi == null) {
295+
// This should not happen
296+
throw new IllegalStateException();
297+
}
298+
return this.biDi;
299+
}
300+
271301
protected HttpClient getHttpClient() {
272302
return ((HttpCommandExecutor) getCommandExecutor()).client;
273303
}
274304

275305
@Override
276-
protected void startSession(Capabilities capabilities) {
306+
protected void startSession(Capabilities requestCapabilities) {
277307
var response = Optional.ofNullable(
278-
execute(DriverCommand.NEW_SESSION(singleton(capabilities)))
308+
execute(DriverCommand.NEW_SESSION(singleton(requestCapabilities)))
279309
).orElseThrow(() -> new SessionNotCreatedException(
280310
"The underlying command executor returned a null response."
281311
));
282312

283-
var rawCapabilities = Optional.ofNullable(response.getValue())
313+
var rawResponseCapabilities = Optional.ofNullable(response.getValue())
284314
.map(value -> {
285315
if (!(value instanceof Map)) {
286316
throw new SessionNotCreatedException(String.format(
@@ -296,13 +326,15 @@ protected void startSession(Capabilities capabilities) {
296326
);
297327

298328
// TODO: remove this workaround for Selenium API enforcing some legacy capability values in major version
299-
rawCapabilities.remove("platform");
300-
if (rawCapabilities.containsKey(CapabilityType.BROWSER_NAME)
301-
&& isNullOrEmpty((String) rawCapabilities.get(CapabilityType.BROWSER_NAME))) {
302-
rawCapabilities.remove(CapabilityType.BROWSER_NAME);
329+
rawResponseCapabilities.remove("platform");
330+
if (rawResponseCapabilities.containsKey(CapabilityType.BROWSER_NAME)
331+
&& isNullOrEmpty((String) rawResponseCapabilities.get(CapabilityType.BROWSER_NAME))) {
332+
rawResponseCapabilities.remove(CapabilityType.BROWSER_NAME);
333+
}
334+
this.capabilities = new BaseOptions<>(rawResponseCapabilities);
335+
if (Boolean.TRUE.equals(requestCapabilities.getCapability(SupportsWebSocketUrlOption.WEB_SOCKET_URL))) {
336+
this.initBiDi((BaseOptions<?>) capabilities);
303337
}
304-
this.capabilities = new BaseOptions<>(rawCapabilities);
305-
this.initBiDi(capabilities);
306338
setSessionId(response.getSessionId());
307339
}
308340

@@ -343,8 +375,8 @@ protected static Capabilities ensureAutomationName(
343375
* Changes platform and automation names if they are not set
344376
* and returns merged capabilities.
345377
*
346-
* @param originalCapabilities the given {@link Capabilities}.
347-
* @param defaultPlatformName a platformName value which has to be set up
378+
* @param originalCapabilities the given {@link Capabilities}.
379+
* @param defaultPlatformName a platformName value which has to be set up
348380
* @param defaultAutomationName The default automation name to set up for this class
349381
* @return {@link Capabilities} with changed platform/automation name value or the original capabilities
350382
*/
@@ -354,16 +386,27 @@ protected static Capabilities ensurePlatformAndAutomationNames(
354386
return ensureAutomationName(capsWithPlatformFixed, defaultAutomationName);
355387
}
356388

357-
private void initBiDi(Capabilities responseCaps) {
358-
var webSocketUrl = CapabilityHelpers.getCapability(responseCaps, "webSocketUrl", String.class);
359-
if (webSocketUrl == null) {
389+
private void initBiDi(BaseOptions<?> responseCaps) {
390+
var webSocketUrl = responseCaps.getWebSocketUrl();
391+
if (webSocketUrl.isEmpty()) {
360392
return;
361393
}
394+
URISyntaxException uriSyntaxError = null;
362395
try {
363-
this.biDiUri = new URI(webSocketUrl);
396+
this.biDiUri = new URI(String.valueOf(webSocketUrl.get()));
364397
} catch (URISyntaxException e) {
365-
// no valid url -> no BiDi
366-
return;
398+
uriSyntaxError = e;
399+
}
400+
if (uriSyntaxError != null || this.biDiUri.getScheme() == null) {
401+
var message = String.format(
402+
"BiDi cannot be enabled for this driver session. " +
403+
"Is the %s '%s' received from the create session response valid?",
404+
SupportsWebSocketUrlOption.WEB_SOCKET_URL, webSocketUrl.get()
405+
);
406+
if (uriSyntaxError == null) {
407+
throw new BiDiException(message);
408+
}
409+
throw new BiDiException(message, uriSyntaxError);
367410
}
368411
var executor = getCommandExecutor();
369412
final HttpClient wsClient;

src/main/java/io/appium/java_client/remote/options/BaseOptions.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public class BaseOptions<T extends BaseOptions<T>> extends MutableCapabilities i
4949
SupportsFullResetOption<T>,
5050
SupportsNewCommandTimeoutOption<T>,
5151
SupportsBrowserNameOption<T>,
52-
SupportsPlatformVersionOption<T> {
52+
SupportsPlatformVersionOption<T>,
53+
SupportsWebSocketUrlOption<T> {
5354

5455
/**
5556
* Creates new instance with no preset capabilities.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* See the NOTICE file distributed with this work for additional
5+
* information regarding copyright ownership.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appium.java_client.remote.options;
18+
19+
import org.openqa.selenium.Capabilities;
20+
21+
import java.util.Optional;
22+
23+
public interface SupportsWebSocketUrlOption<T extends BaseOptions<T>> extends
24+
Capabilities, CanSetCapability<T> {
25+
String WEB_SOCKET_URL = "webSocketUrl";
26+
27+
/**
28+
* Enable BiDi session support.
29+
*
30+
* @return self instance for chaining.
31+
*/
32+
default T enableBiDi() {
33+
return amend(WEB_SOCKET_URL, true);
34+
}
35+
36+
/**
37+
* Whether to enable BiDi session support.
38+
*
39+
* @return self instance for chaining.
40+
*/
41+
default T setWebSocketUrl(boolean value) {
42+
return amend(WEB_SOCKET_URL, value);
43+
}
44+
45+
/**
46+
* For input capabilities: whether enable BiDi session support is enabled.
47+
* For session creation response capabilities: BiDi web socket URL.
48+
*
49+
* @return If called on request capabilities if BiDi support is enabled for the driver session
50+
*/
51+
default Optional<Object> getWebSocketUrl() {
52+
return Optional.ofNullable(getCapability(WEB_SOCKET_URL));
53+
}
54+
}

0 commit comments

Comments
 (0)