summaryrefslogtreecommitdiffstats
path: root/chrome/test/remoting/install_and_launch_app.py
blob: 5a120ad4b95beb1c3af042c1e7a5709f49e7a14d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/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))
WAIT_TIME = 2


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 GetLinkAndWait(driver, link_to_get):
  """Navigates to the specified link.

  Args:
    driver: Active window for this Chromedriver instance.
    link_to_get: URL of the destination.
  """
  driver.get(link_to_get)
  # TODO(anandc): Is there any event or state we could wait on? For now,
  # we have hard-coded sleeps.
  time.sleep(WAIT_TIME)


def ClickAndWait(driver, button_xpath):
  """Clicks button at the specified XPath of the current document.

  Args:
    driver: Active window for this Chromedriver instance.
    button_xpath: XPath in this document to button we want to click.
  """
  button = driver.find_element_by_xpath(button_xpath)
  button.click()
  time.sleep(WAIT_TIME)


def WindowWithTitleExists(driver, title):
  """Verifies if one of the open windows has the specified title.

  Args:
    driver: Active window for this Chromedriver instance.
    title: Title of the window we are looking for.

  Returns:
    True if an open window in this session with the specified title was found.
    False otherwise.
  """
  for handle in driver.window_handles:
    driver.switch_to_window(handle)
    if driver.title == title:
      return True
  return False


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:

    chrome_apps_link = 'chrome://apps'
    cws_app_detail_link = '%s/%s' % (CWS_URL, args.app_id)

    # Navigate to chrome:apps first.
    # TODO(anandc): Add check to make sure the app we are testing isn't already
    # added for this user.
    GetLinkAndWait(driver, chrome_apps_link)

    # Navigate to the app detail page at the Chrome Web Store.
    GetLinkAndWait(driver, 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.
    GetLinkAndWait(driver, cws_app_detail_link)

    # Install the app by clicking the button that says "Free".
    ClickAndWait(driver, FREE_BUTTON_XPATH)

    # We should now be at a new tab. Get its handle.
    current_tab = driver.window_handles[-1]
    # And switch to it.
    driver.switch_to_window(current_tab)

    # From this new tab, go to Chrome Apps
    # TODO(anandc): Add check to make sure the app we are testing is now added.
    GetLinkAndWait(driver, chrome_apps_link)

    # Back to the app detail page.
    GetLinkAndWait(driver, cws_app_detail_link)
    # Again, do this twice, for reasons noted above.
    GetLinkAndWait(driver, cws_app_detail_link)

    # Click to launch the newly installed app.
    ClickAndWait(driver, LAUNCH_BUTTON_XPATH)

    # For now, make sure the "connecting" dialog comes up.
    # TODO(anandc): Add more validation; ideally, wait for the separate app
    # window to appear.
    if WindowWithTitleExists(driver, args.app_window_title):
      print 'Web-App %s launched successfully.' % args.app_window_title
    else:
      print 'Web-app %s did not launch successfully.' % args.app_window_title

  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()