Chromium Code Reviews| 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 | |
| 23 import argparse | |
| 24 import os | |
| 25 import shutil | |
| 26 import tempfile | |
| 27 import time | |
| 28 | |
| 29 from selenium import webdriver | |
| 30 from selenium.webdriver.chrome.options import Options | |
| 31 | |
| 32 CWS_URL = 'https://chrome.google.com/webstore/detail' | |
| 33 WEBSTORE_BUTTON_LABEL = 'webstore-test-button-label' | |
| 34 FREE_BUTTON_XPATH = ( | |
| 35 '//div[contains(@class, \"%s\") and text() = \"Free\"]' % | |
| 36 (WEBSTORE_BUTTON_LABEL)) | |
| 37 LAUNCH_BUTTON_XPATH = ( | |
| 38 '//div[contains(@class, \"%s\") and text() = \"Launch app\"]' % | |
| 39 (WEBSTORE_BUTTON_LABEL)) | |
| 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 main(): | |
| 90 | |
| 91 args = ParseCmdLineArgs() | |
| 92 | |
| 93 org_profile_dir = args.profile_dir | |
| 94 print 'Creating temp-dir using profile-dir %s' % org_profile_dir | |
| 95 tmp_dir, profile_dir = CreateTempProfileDir(org_profile_dir) | |
| 96 | |
| 97 options = Options() | |
| 98 options.add_argument('--user-data-dir=' + profile_dir) | |
| 99 # Suppress the confirmation dialog that comes up. | |
| 100 # With M39, this flag will no longer work. See https://crbug/357774. | |
| 101 # TODO(anandc): Work with a profile-dir that already has extension downloaded, | |
| 102 # and also add support for loading extension from a local directory. | |
| 103 options.add_argument('--apps-gallery-install-auto-confirm-for-tests=accept') | |
| 104 driver = webdriver.Chrome(args.driver_dir, chrome_options=options) | |
| 105 | |
| 106 try: | |
| 107 | |
| 108 # Navigate to chrome:apps first. | |
| 109 # TODO(anandc): add check to make sure the app we are testing isn't already | |
|
garykac
2014/09/18 23:33:16
nit: "Add"
(and "Is" below)
anandc
2014/09/19 21:05:31
Done.
| |
| 110 # added for this user. | |
| 111 chrome_apps_link = 'chrome://apps' | |
| 112 driver.get(chrome_apps_link) | |
| 113 # TODO(anandc): is there any event or state we could wait on? For now, | |
| 114 # we have hard-coded sleeps. | |
| 115 time.sleep(2) | |
| 116 | |
| 117 cws_app_detail_link = '%s/%s' % (CWS_URL, args.app_id) | |
| 118 # Navigate to the app page at Chrome Web Store. | |
| 119 driver.get(cws_app_detail_link) | |
| 120 # Get the page again, to get all controls. This seems to be a bug, either | |
| 121 # in ChromeDriver, or the app-page. Without this additional GET, we don't | |
| 122 # get all controls. Even sleeping for 5 seconds doesn't suffice. | |
| 123 # TODO(anandc): Investigate why the page doesn't work with just 1 call. | |
| 124 driver.get(cws_app_detail_link) | |
| 125 time.sleep(2) | |
|
garykac
2014/09/18 23:33:16
Not sure if it's worth doing, but these time.sleep
anandc
2014/09/19 21:05:31
Done.
| |
| 126 | |
| 127 # Install the app by clicking the button that says "Free". | |
| 128 free_button = driver.find_element_by_xpath(FREE_BUTTON_XPATH) | |
| 129 free_button.click() | |
| 130 time.sleep(2) | |
| 131 | |
| 132 # We should now be at a new tab; switch to it. | |
| 133 current_tab = driver.window_handles[-1] | |
| 134 driver.switch_to_window(current_tab) | |
| 135 # Go to Chrome Apps | |
| 136 # TODO(anandc): add check to make sure the app we are testing is now added. | |
| 137 driver.get(chrome_apps_link) | |
| 138 # Now that the app has been installed, go back to its details page, | |
| 139 # and launch it. (2 GET calls again, once is not enough; see not above.) | |
|
garykac
2014/09/18 23:33:16
The code will be a bit easier to follow if you hav
anandc
2014/09/19 21:05:32
Makes sense. Thanks.
Done, with a slight differe
| |
| 140 driver.get(cws_app_detail_link) | |
| 141 driver.get(cws_app_detail_link) | |
| 142 time.sleep(2) | |
| 143 | |
| 144 launch_button = driver.find_element_by_xpath(LAUNCH_BUTTON_XPATH) | |
|
garykac
2014/09/18 23:33:16
This chunk can be re-used as well:
def click_wait
anandc
2014/09/19 21:05:32
Done.
| |
| 145 launch_button.click() | |
| 146 time.sleep(2) | |
| 147 | |
| 148 # For now, make sure the "connecting" dialog comes up. | |
| 149 # TODO(anandc): add more validation; ideally, wait for the separate app | |
| 150 # window to appear. | |
| 151 success = False | |
| 152 for handle in driver.window_handles: | |
| 153 driver.switch_to_window(handle) | |
| 154 if driver.title == args.app_window_title: | |
| 155 success = True | |
| 156 print 'Webapp launched successfully.' | |
| 157 break | |
| 158 | |
| 159 if not success: | |
| 160 print 'Webapp did not launch successfully.' | |
| 161 | |
| 162 except Exception, e: | |
| 163 raise e | |
| 164 finally: | |
| 165 # Cleanup | |
| 166 print 'Deleting %s' % tmp_dir | |
| 167 shutil.rmtree(profile_dir) | |
| 168 os.rmdir(tmp_dir) | |
| 169 driver.quit() | |
| 170 | |
| 171 | |
| 172 if __name__ == '__main__': | |
| 173 main() | |
| OLD | NEW |