From 5fc802d3a6a7aaf4ea69d76893fe380b338537d3 Mon Sep 17 00:00:00 2001 From: Alexei Barantsev Date: Sun, 23 Sep 2018 15:44:11 +0300 Subject: [PATCH] [java] Handling a special case of a driver returning null as a result of findElement command. Fixes #5809 --- .../selenium/remote/RemoteWebDriver.java | 4 + .../selenium/remote/RemoteWebElement.java | 5 + .../test/org/openqa/selenium/remote/BUCK | 1 + .../selenium/remote/RemoteClientTests.java | 1 + .../remote/RemoteWebDriverUnitTest.java | 98 +++++++++++++++++++ 5 files changed, 109 insertions(+) create mode 100644 java/client/test/org/openqa/selenium/remote/RemoteWebDriverUnitTest.java diff --git a/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java index b50e48e247c90..bca3bf46b7deb 100644 --- a/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -36,6 +36,7 @@ import org.openqa.selenium.ImmutableCapabilities; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.MutableCapabilities; +import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.NoSuchFrameException; import org.openqa.selenium.NoSuchWindowException; import org.openqa.selenium.OutputType; @@ -322,6 +323,9 @@ protected WebElement findElement(String by, String using) { Response response = execute(DriverCommand.FIND_ELEMENT, ImmutableMap.of("using", by, "value", using)); Object value = response.getValue(); + if (value == null) { // see https://github.com/SeleniumHQ/selenium/issues/5809 + throw new NoSuchElementException(String.format("Cannot locate an element using %s=%s", by, using)); + } WebElement element; try { element = (WebElement) value; diff --git a/java/client/src/org/openqa/selenium/remote/RemoteWebElement.java b/java/client/src/org/openqa/selenium/remote/RemoteWebElement.java index ea504569d08dc..9301e81defec2 100644 --- a/java/client/src/org/openqa/selenium/remote/RemoteWebElement.java +++ b/java/client/src/org/openqa/selenium/remote/RemoteWebElement.java @@ -22,6 +22,7 @@ import org.openqa.selenium.Beta; import org.openqa.selenium.By; import org.openqa.selenium.Dimension; +import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.OutputType; import org.openqa.selenium.Point; import org.openqa.selenium.Rectangle; @@ -185,6 +186,9 @@ protected WebElement findElement(String using, String value) { ImmutableMap.of("id", id, "using", using, "value", value)); Object responseValue = response.getValue(); + if (responseValue == null) { // see https://github.com/SeleniumHQ/selenium/issues/5809 + throw new NoSuchElementException(String.format("Cannot locate an element using %s=%s", using, value)); + } WebElement element; try { element = (WebElement) responseValue; @@ -346,6 +350,7 @@ public Dimension getSize() { return new Dimension(width, height); } + @SuppressWarnings({"unchecked"}) public Rectangle getRect() { Response response = execute(DriverCommand.GET_ELEMENT_RECT, ImmutableMap.of("id", id)); Map rawRect = (Map) response.getValue(); diff --git a/java/client/test/org/openqa/selenium/remote/BUCK b/java/client/test/org/openqa/selenium/remote/BUCK index 09a3e4062f71f..e94232eb8b295 100644 --- a/java/client/test/org/openqa/selenium/remote/BUCK +++ b/java/client/test/org/openqa/selenium/remote/BUCK @@ -30,6 +30,7 @@ java_test(name = 'client-tests', 'RemoteClientTests.java', 'RemoteLogsTest.java', 'RemoteWebDriverInitializationTest.java', + 'RemoteWebDriverUnitTest.java', 'W3CHandshakeResponseTest.java', 'W3CRemoteDriverTest.java', 'internal/ApacheHttpClientTest.java', diff --git a/java/client/test/org/openqa/selenium/remote/RemoteClientTests.java b/java/client/test/org/openqa/selenium/remote/RemoteClientTests.java index 7e2a4faf7f135..19799de71d609 100644 --- a/java/client/test/org/openqa/selenium/remote/RemoteClientTests.java +++ b/java/client/test/org/openqa/selenium/remote/RemoteClientTests.java @@ -30,6 +30,7 @@ ProtocolHandshakeTest.class, RemoteLogsTest.class, RemoteWebDriverInitializationTest.class, + RemoteWebDriverUnitTest.class, W3CHandshakeResponseTest.class }) public class RemoteClientTests { diff --git a/java/client/test/org/openqa/selenium/remote/RemoteWebDriverUnitTest.java b/java/client/test/org/openqa/selenium/remote/RemoteWebDriverUnitTest.java new file mode 100644 index 0000000000000..64c3f2a9a09ad --- /dev/null +++ b/java/client/test/org/openqa/selenium/remote/RemoteWebDriverUnitTest.java @@ -0,0 +1,98 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you 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 org.openqa.selenium.remote; + +import static java.util.Collections.EMPTY_MAP; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.ImmutableCapabilities; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; + +import java.io.IOException; +import java.util.List; + +public class RemoteWebDriverUnitTest { + + @Test + public void returnsEmptyListIfRemoteEndReturnsNullFromFindElements() throws IOException { + CommandExecutor executor = prepareExecutorMock(); + + RemoteWebDriver driver = new RemoteWebDriver(executor, new ImmutableCapabilities()); + List result = driver.findElements(By.id("id")); + assertThat(result).isNotNull().isEmpty(); + } + + @Test + public void returnsEmptyListIfRemoteEndReturnsNullFromFindChildren() throws IOException { + CommandExecutor executor = prepareExecutorMock(); + + RemoteWebDriver driver = new RemoteWebDriver(executor, new ImmutableCapabilities()); + RemoteWebElement element = new RemoteWebElement(); + element.setParent(driver); + element.setId("unique"); + + List result = element.findElements(By.id("id")); + assertThat(result).isNotNull().isEmpty(); + } + + @Test + public void throwsIfRemoteEndReturnsNullFromFindElement() throws IOException { + CommandExecutor executor = prepareExecutorMock(); + + RemoteWebDriver driver = new RemoteWebDriver(executor, new ImmutableCapabilities()); + assertThatExceptionOfType(NoSuchElementException.class) + .isThrownBy(() -> driver.findElement(By.id("id"))); + } + + @Test + public void throwIfRemoteEndReturnsNullFromFindChild() throws IOException { + CommandExecutor executor = prepareExecutorMock(); + + RemoteWebDriver driver = new RemoteWebDriver(executor, new ImmutableCapabilities()); + RemoteWebElement element = new RemoteWebElement(); + element.setParent(driver); + element.setId("unique"); + + assertThatExceptionOfType(NoSuchElementException.class) + .isThrownBy(() -> element.findElement(By.id("id"))); + } + + private CommandExecutor prepareExecutorMock() throws IOException { + CommandExecutor executor = mock(CommandExecutor.class); + when(executor.execute(any())).thenAnswer(invocation -> { + if (invocation.getArgument(0).getName().equals(DriverCommand.NEW_SESSION)) { + Response newSessionResponse = new Response(); + newSessionResponse.setValue(EMPTY_MAP); + return newSessionResponse; + } else { + Response nullResponse = new Response(); + nullResponse.setValue(null); + return nullResponse; + } + }); + return executor; + } + +}