View Javadoc
1   /*
2    * Copyright 2023 Adrian Herscu
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
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 dev.aherscu.qa.testing.example.scenarios.tutorial4;
18  
19  import static io.appium.java_client.remote.MobilePlatform.*;
20  import static io.appium.java_client.remote.options.SupportsAppOption.*;
21  import static io.appium.java_client.remote.options.SupportsAutoWebViewOption.*;
22  import static io.appium.java_client.remote.options.SupportsDeviceNameOption.*;
23  import static io.appium.java_client.remote.options.SupportsPlatformVersionOption.*;
24  import static org.hamcrest.MatcherAssert.*;
25  import static org.hamcrest.Matchers.*;
26  import static org.openqa.selenium.remote.CapabilityType.*;
27  
28  import java.net.*;
29  import java.time.*;
30  import java.time.format.*;
31  
32  import org.openqa.selenium.*;
33  import org.openqa.selenium.remote.*;
34  import org.testng.annotations.*;
35  
36  import edu.umd.cs.findbugs.annotations.*;
37  import io.appium.java_client.android.*;
38  import lombok.*;
39  
40  /**
41   * TODO should run against one of the Android applications, e.g. Calculator
42   */
43  public class TestingAndroidOnSauceLabs {
44  
45      private WebDriver webDriver;
46  
47      @java.lang.SuppressWarnings("serial")
48      @SneakyThrows
49      static AndroidDriver saucelabsApp(
50          final String name) {
51          return new AndroidDriver(new URL(
52              // FIXME should get these credentials from system enviroment
53              // SAUCELABS_USERNAME and SAUCELABS_PASSWORD
54              "https://TBD:TBD@ondemand.saucelabs.com:443/wd/hub"),
55              new DesiredCapabilities() {
56                  {
57                      setCapability(PLATFORM_NAME, ANDROID);
58                      setCapability(PLATFORM_VERSION_OPTION, "8");
59                      setCapability(DEVICE_NAME_OPTION,
60                          "Samsung Galaxy S9 Plus WQHD GoogleAPI Emulator");
61                      setCapability(AUTO_WEB_VIEW_OPTION, true);
62                      setCapability(APP_OPTION, "sauce-storage:app.apk");
63                      setCapability("name", name);
64                      setCapability("build", "local-"
65                          + DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
66                              .withZone(ZoneOffset.UTC)
67                              .format(Instant.now()));
68                  }
69              });
70      }
71  
72      @Test
73      public void shouldRequireEmail() {
74          assertThat(webDriver
75              .findElements(By.xpath("//*[text()='Please enter valid email']")),
76              not(empty()));
77      }
78  
79      @SuppressFBWarnings(
80          value = "UPM_UNCALLED_PRIVATE_METHOD",
81          justification = "called by testng framework")
82      @AfterClass(alwaysRun = true) // important, otherwise we may leak resources
83      private void afterClassCloseWebDriver() {
84          webDriver.quit();
85      }
86  
87      @SuppressFBWarnings(
88          value = "UPM_UNCALLED_PRIVATE_METHOD",
89          justification = "called by testng framework")
90      @BeforeClass
91      @SneakyThrows
92      private void beforeClassOpenWebDriver() {
93          // NOTE: ensure you have TBD.apk uploaded to SauceLabs
94          // curl -u "TBD:TBD" -X POST
95          // https://saucelabs.com/rest/v1/storage/TBD --data-binary
96          // @TBD.apk
97          webDriver = saucelabsApp(getClass().getSimpleName());
98          webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
99      }
100 }