You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

188 line
4.8 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals, print_function
  4. from selenium.webdriver.common.keys import Keys
  5. from selenium import webdriver
  6. from selenium.webdriver.common.by import By
  7. from selenium.webdriver.support.ui import WebDriverWait
  8. from selenium.webdriver.support.select import Select
  9. from selenium.webdriver.support import expected_conditions as EC
  10. from selenium.common.exceptions import TimeoutException
  11. from urllib import unquote
  12. import time, subprocess
  13. import signal
  14. import sys
  15. host = "http://localhost"
  16. pipe = None
  17. port = "8000"
  18. _driver = None
  19. _verbose = None
  20. logged_in = False
  21. cur_route = False
  22. input_wait = 0
  23. def get_localhost():
  24. return "{host}:{port}".format(host=host, port=port)
  25. def start(verbose=None, driver=None):
  26. global _driver, _verbose
  27. _verbose = verbose
  28. _driver = getattr(webdriver, driver or "PhantomJS")()
  29. _driver.set_window_size(1080,800)
  30. signal.signal(signal.SIGINT, signal_handler)
  31. def signal_handler(signal, frame):
  32. close()
  33. sys.exit(0)
  34. def start_test_server(verbose):
  35. global pipe
  36. pipe = subprocess.Popen(["bench", "serve", "--port", port], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  37. #time.sleep(5)
  38. while not pipe.stderr.readline():
  39. time.sleep(0.5)
  40. if verbose:
  41. print("Test server started")
  42. def get(url):
  43. _driver.get(url)
  44. def login(wait_for_id="#page-desktop"):
  45. global logged_in
  46. if logged_in:
  47. return
  48. get(get_localhost() + "/login")
  49. wait("#login_email")
  50. set_input("#login_email", "Administrator")
  51. set_input("#login_password", "admin", key=Keys.RETURN)
  52. wait(wait_for_id)
  53. logged_in = True
  54. def go_to_module(module_name, item=None):
  55. global cur_route
  56. # desktop
  57. find(".navbar-home", True)[0].click()
  58. cur_route = None
  59. wait("#page-desktop")
  60. page = "Module/" + module_name
  61. m = find('#page-desktop [data-link="{0}"] .app-icon'.format(page))
  62. if not m:
  63. page = "List/" + module_name
  64. m = find('#page-desktop [data-link="{0}"] .app-icon'.format(page))
  65. if not m:
  66. raise Exception("Module {0} not found".format(module_name))
  67. m[0].click()
  68. wait_for_page(page)
  69. if item:
  70. elem = find('[data-label="{0}"]'.format(item))[0]
  71. elem.click()
  72. page = elem.get_attribute("data-route")
  73. wait_for_page(page)
  74. def new_doc(module, doctype):
  75. go_to_module(module, doctype)
  76. primary_action()
  77. wait_for_page("Form/" + doctype)
  78. def add_child(fieldname):
  79. find('[data-fieldname="{0}"] .grid-add-row'.format(fieldname))[0].click()
  80. wait('[data-fieldname="{0}"] .form-grid'.format(fieldname))
  81. def done_add_child(fieldname):
  82. selector = '[data-fieldname="{0}"] .grid-row-open .btn-success'.format(fieldname)
  83. scroll_to(selector)
  84. wait_till_clickable(selector).click()
  85. def find(selector, everywhere=False):
  86. if cur_route and not everywhere:
  87. selector = cur_route + " " + selector
  88. return _driver.find_elements_by_css_selector(selector)
  89. def set_field(fieldname, value, fieldtype="input"):
  90. _driver.switch_to.window(_driver.current_window_handle)
  91. selector = '{0}[data-fieldname="{1}"]'.format(fieldtype, fieldname)
  92. set_input(selector, value, key=Keys.TAB)
  93. wait_for_ajax()
  94. def set_select(fieldname, value):
  95. select = Select(find('select[data-fieldname="{0}"]'.format(fieldname))[0])
  96. select.select_by_value(value)
  97. wait_for_ajax()
  98. def primary_action():
  99. selector = ".page-actions .primary-action"
  100. scroll_to(selector)
  101. wait_till_clickable(selector).click()
  102. wait_for_ajax()
  103. def wait_for_page(name):
  104. global cur_route
  105. cur_route = None
  106. route = '[data-page-route="{0}"]'.format(name)
  107. wait_for_ajax()
  108. elem = wait(route)
  109. wait_for_ajax()
  110. cur_route = route
  111. return elem
  112. def wait_till_clickable(selector):
  113. if cur_route:
  114. selector = cur_route + " " + selector
  115. return get_wait().until(EC.element_to_be_clickable((By.CSS_SELECTOR, selector)))
  116. def wait_till_visible(selector):
  117. if cur_route:
  118. selector = cur_route + " " + selector
  119. return get_wait().until(EC.visibility_of_element_located((By.CSS_SELECTOR, selector)))
  120. def wait_for_ajax():
  121. wait('body[data-ajax-state="complete"]', True)
  122. def wait_for_state(state):
  123. return wait(cur_route + '[data-state="{0}"]'.format(state), True)
  124. def wait(selector, everywhere=False):
  125. if cur_route and not everywhere:
  126. selector = cur_route + " " + selector
  127. time.sleep(0.5)
  128. elem = get_wait().until(EC.presence_of_element_located((By.CSS_SELECTOR, selector)))
  129. return elem
  130. def get_wait():
  131. return WebDriverWait(_driver, 20)
  132. def set_input(selector, text, key=None):
  133. elem = find(selector)[0]
  134. elem.clear()
  135. elem.send_keys(text)
  136. if key:
  137. time.sleep(0.5)
  138. elem.send_keys(key)
  139. if input_wait:
  140. time.sleep(input_wait)
  141. def scroll_to(selector):
  142. execute_script("frappe.ui.scroll('{0}')".format(selector))
  143. def execute_script(js):
  144. _driver.execute_script(js)
  145. def close():
  146. global _driver, pipe
  147. if _driver:
  148. _driver.quit()
  149. if pipe:
  150. pipe.kill()
  151. _driver = pipe = None