OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """A Chromedriver smoke-test that installs and launches a web-app. |
| 7 |
| 8 Args: |
| 9 driver_dir: Location of Chromedriver binary on local machine. |
| 10 profile_dir: A user-data-dir containing login token for the app-user. |
| 11 app_id: App ID of web-app in Chrome web-store. |
| 12 app_window_title: The title of the window that should come up on app launch. |
| 13 |
| 14 TODO(anandc): Reduce the # of parameters required from the command-line. |
| 15 Maybe read from a JSON file. Also, map appID to expected app window title. |
| 16 |
| 17 This script navigates to the app-detail page on Chrome Web Store for the |
| 18 specified app-id. From there, it then installs the app and launches it. It |
| 19 then checks if the resulting new window has the expected title. |
| 20 """ |
| 21 |
| 22 import argparse |
| 23 import os |
| 24 import shutil |
| 25 import tempfile |
| 26 import time |
| 27 |
| 28 from selenium import webdriver |
| 29 from selenium.webdriver.chrome.options import Options |
| 30 |
| 31 CWS_URL = 'https://chrome.google.com/webstore/detail' |
| 32 WEBSTORE_BUTTON_LABEL = 'webstore-test-button-label' |
| 33 FREE_BUTTON_XPATH = ( |
| 34 '//div[contains(@class, \"%s\") and text() = \"Free\"]' % |
| 35 (WEBSTORE_BUTTON_LABEL)) |
| 36 LAUNCH_BUTTON_XPATH = ( |
| 37 '//div[contains(@class, \"%s\") and text() = \"Launch app\"]' % |
| 38 (WEBSTORE_BUTTON_LABEL)) |
| 39 WAIT_TIME = 2 |
| 40 |
| 41 |
| 42 def CreateTempProfileDir(source_dir): |
| 43 """Creates a temporary profile directory, for use by the test. |
| 44 |
| 45 This avoids modifying the input user-data-dir by actions that the test |
| 46 performs. |
| 47 |
| 48 Args: |
| 49 source_dir: The directory to copy and place in a temp folder. |
| 50 |
| 51 Returns: |
| 52 tmp_dir: Name of the temporary folder that was created. |
| 53 profile_dir: Name of the profile-dir under the tmp_dir. |
| 54 """ |
| 55 |
| 56 tmp_dir = tempfile.mkdtemp() |
| 57 print 'Created folder %s' % (tmp_dir) |
| 58 profile_dir = os.path.join(tmp_dir, 'testuser') |
| 59 # Copy over previous created profile for this execution of Chrome Driver. |
| 60 shutil.copytree(source_dir, profile_dir) |
| 61 return tmp_dir, profile_dir |
| 62 |
| 63 |
| 64 def ParseCmdLineArgs(): |
| 65 """Parses command line arguments and returns them. |
| 66 |
| 67 Returns: |
| 68 args: Parse command line arguments. |
| 69 """ |
| 70 parser = argparse.ArgumentParser() |
| 71 parser.add_argument( |
| 72 '-d', '--driver_dir', required=True, |
| 73 help='path to folder where Chromedriver has been installed.') |
| 74 parser.add_argument( |
| 75 '-p', '--profile_dir', required=True, |
| 76 help='path to user-data-dir with trusted-tester signed in.') |
| 77 parser.add_argument( |
| 78 '-a', '--app_id', required=True, |
| 79 help='app-id of web-store app being tested.') |
| 80 parser.add_argument( |
| 81 '-e', '--app_window_title', required=True, |
| 82 help='Title of the app window that we expect to come up.') |
| 83 |
| 84 # Use input json file if specified on command line. |
| 85 args = parser.parse_args() |
| 86 return args |
| 87 |
| 88 |
| 89 def GetLinkAndWait(driver, link_to_get): |
| 90 """Navigates to the specified link. |
| 91 |
| 92 Args: |
| 93 driver: Active window for this Chromedriver instance. |
| 94 link_to_get: URL of the destination. |
| 95 """ |
| 96 driver.get(link_to_get) |
| 97 # TODO(anandc): Is there any event or state we could wait on? For now, |
| 98 # we have hard-coded sleeps. |
| 99 time.sleep(WAIT_TIME) |
| 100 |
| 101 |
| 102 def ClickAndWait(driver, button_xpath): |
| 103 """Clicks button at the specified XPath of the current document. |
| 104 |
| 105 Args: |
| 106 driver: Active window for this Chromedriver instance. |
| 107 button_xpath: XPath in this document to button we want to click. |
| 108 """ |
| 109 button = driver.find_element_by_xpath(button_xpath) |
| 110 button.click() |
| 111 time.sleep(WAIT_TIME) |
| 112 |
| 113 |
| 114 def WindowWithTitleExists(driver, title): |
| 115 """Verifies if one of the open windows has the specified title. |
| 116 |
| 117 Args: |
| 118 driver: Active window for this Chromedriver instance. |
| 119 title: Title of the window we are looking for. |
| 120 |
| 121 Returns: |
| 122 True if an open window in this session with the specified title was found. |
| 123 False otherwise. |
| 124 """ |
| 125 for handle in driver.window_handles: |
| 126 driver.switch_to_window(handle) |
| 127 if driver.title == title: |
| 128 return True |
| 129 return False |
| 130 |
| 131 |
| 132 def main(): |
| 133 |
| 134 args = ParseCmdLineArgs() |
| 135 |
| 136 org_profile_dir = args.profile_dir |
| 137 print 'Creating temp-dir using profile-dir %s' % org_profile_dir |
| 138 tmp_dir, profile_dir = CreateTempProfileDir(org_profile_dir) |
| 139 |
| 140 options = Options() |
| 141 options.add_argument('--user-data-dir=' + profile_dir) |
| 142 # Suppress the confirmation dialog that comes up. |
| 143 # With M39, this flag will no longer work. See https://crbug/357774. |
| 144 # TODO(anandc): Work with a profile-dir that already has extension downloaded, |
| 145 # and also add support for loading extension from a local directory. |
| 146 options.add_argument('--apps-gallery-install-auto-confirm-for-tests=accept') |
| 147 driver = webdriver.Chrome(args.driver_dir, chrome_options=options) |
| 148 |
| 149 try: |
| 150 |
| 151 chrome_apps_link = 'chrome://apps' |
| 152 cws_app_detail_link = '%s/%s' % (CWS_URL, args.app_id) |
| 153 |
| 154 # Navigate to chrome:apps first. |
| 155 # TODO(anandc): Add check to make sure the app we are testing isn't already |
| 156 # added for this user. |
| 157 GetLinkAndWait(driver, chrome_apps_link) |
| 158 |
| 159 # Navigate to the app detail page at the Chrome Web Store. |
| 160 GetLinkAndWait(driver, cws_app_detail_link) |
| 161 # Get the page again, to get all controls. This seems to be a bug, either |
| 162 # in ChromeDriver, or the app-page. Without this additional GET, we don't |
| 163 # get all controls. Even sleeping for 5 seconds doesn't suffice. |
| 164 # TODO(anandc): Investigate why the page doesn't work with just 1 call. |
| 165 GetLinkAndWait(driver, cws_app_detail_link) |
| 166 |
| 167 # Install the app by clicking the button that says "Free". |
| 168 ClickAndWait(driver, FREE_BUTTON_XPATH) |
| 169 |
| 170 # We should now be at a new tab. Get its handle. |
| 171 current_tab = driver.window_handles[-1] |
| 172 # And switch to it. |
| 173 driver.switch_to_window(current_tab) |
| 174 |
| 175 # From this new tab, go to Chrome Apps |
| 176 # TODO(anandc): Add check to make sure the app we are testing is now added. |
| 177 GetLinkAndWait(driver, chrome_apps_link) |
| 178 |
| 179 # Back to the app detail page. |
| 180 GetLinkAndWait(driver, cws_app_detail_link) |
| 181 # Again, do this twice, for reasons noted above. |
| 182 GetLinkAndWait(driver, cws_app_detail_link) |
| 183 |
| 184 # Click to launch the newly installed app. |
| 185 ClickAndWait(driver, LAUNCH_BUTTON_XPATH) |
| 186 |
| 187 # For now, make sure the "connecting" dialog comes up. |
| 188 # TODO(anandc): Add more validation; ideally, wait for the separate app |
| 189 # window to appear. |
| 190 if WindowWithTitleExists(driver, args.app_window_title): |
| 191 print 'Web-App %s launched successfully.' % args.app_window_title |
| 192 else: |
| 193 print 'Web-app %s did not launch successfully.' % args.app_window_title |
| 194 |
| 195 except Exception, e: |
| 196 raise e |
| 197 finally: |
| 198 # Cleanup. |
| 199 print 'Deleting %s' % tmp_dir |
| 200 shutil.rmtree(profile_dir) |
| 201 os.rmdir(tmp_dir) |
| 202 driver.quit() |
| 203 |
| 204 |
| 205 if __name__ == '__main__': |
| 206 main() |
OLD | NEW |