Chromium Code Reviews| Index: chrome/test/remoting/install_and_launch_app.py |
| diff --git a/chrome/test/remoting/install_and_launch_app.py b/chrome/test/remoting/install_and_launch_app.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..6fb235e2c034fcbe6e7deaedb6e506320eaf11a2 |
| --- /dev/null |
| +++ b/chrome/test/remoting/install_and_launch_app.py |
| @@ -0,0 +1,173 @@ |
| +#!/usr/bin/python |
| +# Copyright 2014 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""A Chromedriver smoke-test that installs and launches a web-app. |
| + |
| + Args: |
| + driver_dir: Location of Chromedriver binary on local machine. |
| + profile_dir: A user-data-dir containing login token for the app user. |
| + app_id: App ID of web-app in Chrome web-store. |
| + app_window_title: The title of the window that should come up on app launch. |
| + |
| + TODO(anandc): Reduce the # of parameters required from the command-line. |
| + Maybe read from a JSON file. Also, map appID to expected app window title. |
| + |
| + This script navigates to the app-detail page on Chrome Web Store for the |
| + specified app-id. From there, it then installs the app and launches it. It |
| + then checks if the resulting new window has the expected title. |
| + |
| +""" |
| + |
| +import argparse |
| +import os |
| +import shutil |
| +import tempfile |
| +import time |
| + |
| +from selenium import webdriver |
| +from selenium.webdriver.chrome.options import Options |
| + |
| +CWS_URL = 'https://chrome.google.com/webstore/detail' |
| +WEBSTORE_BUTTON_LABEL = 'webstore-test-button-label' |
| +FREE_BUTTON_XPATH = ( |
| + '//div[contains(@class, \"%s\") and text() = \"Free\"]' % |
| + (WEBSTORE_BUTTON_LABEL)) |
| +LAUNCH_BUTTON_XPATH = ( |
| + '//div[contains(@class, \"%s\") and text() = \"Launch app\"]' % |
| + (WEBSTORE_BUTTON_LABEL)) |
| + |
| + |
| +def CreateTempProfileDir(source_dir): |
| + """Creates a temporary profile directory, for use by the test. |
| + |
| + This avoids modifying the input user-data-dir by actions that the test |
| + performs. |
| + |
| + Args: |
| + source_dir: The directory to copy and place in a temp folder. |
| + |
| + Returns: |
| + tmp_dir: Name of the temporary folder that was created. |
| + profile_dir: Name of the profile-dir under the tmp_dir. |
| + """ |
| + |
| + tmp_dir = tempfile.mkdtemp() |
| + print 'Created folder %s' % (tmp_dir) |
| + profile_dir = os.path.join(tmp_dir, 'testuser') |
| + # Copy over previous created profile for this execution of Chrome Driver. |
| + shutil.copytree(source_dir, profile_dir) |
| + return tmp_dir, profile_dir |
| + |
| + |
| +def ParseCmdLineArgs(): |
| + """Parses command line arguments and returns them. |
| + |
| + Returns: |
| + args: Parse command line arguments. |
| + """ |
| + parser = argparse.ArgumentParser() |
| + parser.add_argument( |
| + '-d', '--driver_dir', required=True, |
| + help='path to folder where Chromedriver has been installed.') |
| + parser.add_argument( |
| + '-p', '--profile_dir', required=True, |
| + help='path to user-data-dir with trusted-tester signed in.') |
| + parser.add_argument( |
| + '-a', '--app_id', required=True, |
| + help='app-id of web-store app being tested.') |
| + parser.add_argument( |
| + '-e', '--app_window_title', required=True, |
| + help='Title of the app window that we expect to come up.') |
| + |
| + # Use input json file if specified on command line. |
| + args = parser.parse_args() |
| + return args |
| + |
| + |
| +def main(): |
| + |
| + args = ParseCmdLineArgs() |
| + |
| + org_profile_dir = args.profile_dir |
| + print 'Creating temp-dir using profile-dir %s' % org_profile_dir |
| + tmp_dir, profile_dir = CreateTempProfileDir(org_profile_dir) |
| + |
| + options = Options() |
| + options.add_argument('--user-data-dir=' + profile_dir) |
| + # Suppress the confirmation dialog that comes up. |
| + # With M39, this flag will no longer work. See https://crbug/357774. |
| + # TODO(anandc): Work with a profile-dir that already has extension downloaded, |
| + # and also add support for loading extension from a local directory. |
| + options.add_argument('--apps-gallery-install-auto-confirm-for-tests=accept') |
| + driver = webdriver.Chrome(args.driver_dir, chrome_options=options) |
| + |
| + try: |
| + |
| + # Navigate to chrome:apps first. |
| + # 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.
|
| + # added for this user. |
| + chrome_apps_link = 'chrome://apps' |
| + driver.get(chrome_apps_link) |
| + # TODO(anandc): is there any event or state we could wait on? For now, |
| + # we have hard-coded sleeps. |
| + time.sleep(2) |
| + |
| + cws_app_detail_link = '%s/%s' % (CWS_URL, args.app_id) |
| + # Navigate to the app page at Chrome Web Store. |
| + driver.get(cws_app_detail_link) |
| + # Get the page again, to get all controls. This seems to be a bug, either |
| + # in ChromeDriver, or the app-page. Without this additional GET, we don't |
| + # get all controls. Even sleeping for 5 seconds doesn't suffice. |
| + # TODO(anandc): Investigate why the page doesn't work with just 1 call. |
| + driver.get(cws_app_detail_link) |
| + 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.
|
| + |
| + # Install the app by clicking the button that says "Free". |
| + free_button = driver.find_element_by_xpath(FREE_BUTTON_XPATH) |
| + free_button.click() |
| + time.sleep(2) |
| + |
| + # We should now be at a new tab; switch to it. |
| + current_tab = driver.window_handles[-1] |
| + driver.switch_to_window(current_tab) |
| + # Go to Chrome Apps |
| + # TODO(anandc): add check to make sure the app we are testing is now added. |
| + driver.get(chrome_apps_link) |
| + # Now that the app has been installed, go back to its details page, |
| + # 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
|
| + driver.get(cws_app_detail_link) |
| + driver.get(cws_app_detail_link) |
| + time.sleep(2) |
| + |
| + 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.
|
| + launch_button.click() |
| + time.sleep(2) |
| + |
| + # For now, make sure the "connecting" dialog comes up. |
| + # TODO(anandc): add more validation; ideally, wait for the separate app |
| + # window to appear. |
| + success = False |
| + for handle in driver.window_handles: |
| + driver.switch_to_window(handle) |
| + if driver.title == args.app_window_title: |
| + success = True |
| + print 'Webapp launched successfully.' |
| + break |
| + |
| + if not success: |
| + print 'Webapp did not launch successfully.' |
| + |
| + except Exception, e: |
| + raise e |
| + finally: |
| + # Cleanup |
| + print 'Deleting %s' % tmp_dir |
| + shutil.rmtree(profile_dir) |
| + os.rmdir(tmp_dir) |
| + driver.quit() |
| + |
| + |
| +if __name__ == '__main__': |
| + main() |