|
| 1 | +""" |
| 2 | +Converts a Selenium IDE WebDriver-exported test file into a SeleniumBase file |
| 3 | +
|
| 4 | +Usage: |
| 5 | +python convert_ide.py [MY_TEST.py] |
| 6 | +Output: |
| 7 | +[MY_TEST_SB.py] (Adds "_SB" to the file name) |
| 8 | +""" |
| 9 | + |
| 10 | +import codecs |
| 11 | +import re |
| 12 | +import sys |
| 13 | + |
| 14 | + |
| 15 | +def main(): |
| 16 | + expected_arg = "[A Selenium IDE recording exported to Python WebDriver]" |
| 17 | + num_args = len(sys.argv) |
| 18 | + if num_args < 2 or num_args > 2: |
| 19 | + raise Exception("\n* INVALID RUN COMMAND! * Usage:\n" |
| 20 | + "python convert_ide.py %s\n" % expected_arg) |
| 21 | + elif num_args == 2: |
| 22 | + if not sys.argv[1].endswith('.py'): |
| 23 | + raise Exception("Not a Python file!") |
| 24 | + webdriver_python_file = sys.argv[1] |
| 25 | + |
| 26 | + seleniumbase_lines = [] |
| 27 | + seleniumbase_lines.append("from seleniumbase import BaseCase") |
| 28 | + seleniumbase_lines.append("") # Flake8 is very specific on whitespace |
| 29 | + seleniumbase_lines.append("") |
| 30 | + |
| 31 | + ide_base_url = "" |
| 32 | + in_test_method = False |
| 33 | + has_unicode = False |
| 34 | + |
| 35 | + f = open(webdriver_python_file, 'r') |
| 36 | + all_code = f.read() |
| 37 | + f.close() |
| 38 | + if "def test_" not in all_code: |
| 39 | + raise Exception("Not a valid Python test file!") |
| 40 | + code_lines = all_code.split('\n') |
| 41 | + for line in code_lines: |
| 42 | + |
| 43 | + # Handle class definition |
| 44 | + data = re.findall('^class\s\S+\(unittest\.TestCase\):\s*$', line) |
| 45 | + if data: |
| 46 | + data = data[0].replace("unittest.TestCase", "BaseCase") |
| 47 | + seleniumbase_lines.append(data) |
| 48 | + continue |
| 49 | + |
| 50 | + # Get base_url if defined |
| 51 | + data = re.match('^\s*self.base_url = "(\S+)"\s*$', line) |
| 52 | + if data: |
| 53 | + ide_base_url = data.group(1) |
| 54 | + continue |
| 55 | + |
| 56 | + # Handle method definitions |
| 57 | + data = re.match('^\s*def\s(\S+)\(self[,\s\S]*\):\s*$', line) |
| 58 | + if data: |
| 59 | + method_name = data.group(1) |
| 60 | + if method_name.startswith('test_'): |
| 61 | + in_test_method = True |
| 62 | + seleniumbase_lines.append("") |
| 63 | + seleniumbase_lines.append(data.group()) |
| 64 | + else: |
| 65 | + in_test_method = False |
| 66 | + continue |
| 67 | + |
| 68 | + # If not in a test method, skip |
| 69 | + if not in_test_method: |
| 70 | + continue |
| 71 | + |
| 72 | + # If a comment, skip |
| 73 | + if line.strip().startswith("#"): |
| 74 | + continue |
| 75 | + |
| 76 | + # If a blank line, skip |
| 77 | + if len(line.strip()) == 0: |
| 78 | + continue |
| 79 | + |
| 80 | + # If .clear(), skip because .update_text() already does this |
| 81 | + if line.strip().endswith(".clear()"): |
| 82 | + continue |
| 83 | + |
| 84 | + # Skip edge case |
| 85 | + data = re.findall('^\s*driver = self.driver\s*$', line) |
| 86 | + if data: |
| 87 | + continue |
| 88 | + |
| 89 | + # Handle page loads |
| 90 | + data = re.findall( |
| 91 | + '^\s*driver\.get\(self\.base_url \+ \"/\"\)\s*$', line) |
| 92 | + if data: |
| 93 | + data = data[0].replace("self.base_url", '"%s"' % ide_base_url) |
| 94 | + if ' + "/"' in data: |
| 95 | + data = data.replace(' + "/"', '') |
| 96 | + data = data.replace('driver.get(', 'self.open(') |
| 97 | + seleniumbase_lines.append(data) |
| 98 | + continue |
| 99 | + |
| 100 | + # Handle .find_element_by_id() + .click() |
| 101 | + data = re.match( |
| 102 | + '''^(\s*)driver\.find_element_by_id\(\"(\S+)\"\)''' |
| 103 | + '''\.click\(\)\s*$''', line) |
| 104 | + if data: |
| 105 | + whitespace = data.group(1) |
| 106 | + css_selector = '#%s' % data.group(2) |
| 107 | + command = '''%sself.click('%s')''' % (whitespace, css_selector) |
| 108 | + seleniumbase_lines.append(command) |
| 109 | + continue |
| 110 | + |
| 111 | + # Handle .find_element_by_id() + .send_keys() |
| 112 | + data = re.match( |
| 113 | + '''^(\s*)driver\.find_element_by_id\(\"(\S+)\"\)''' |
| 114 | + '''\.send_keys\(\"([\S\s]+)\"\)\s*$''', line) |
| 115 | + if data: |
| 116 | + whitespace = data.group(1) |
| 117 | + css_selector = '#%s' % data.group(2) |
| 118 | + text = data.group(3) |
| 119 | + command = '''%sself.update_text('%s', '%s')''' % ( |
| 120 | + whitespace, css_selector, text) |
| 121 | + seleniumbase_lines.append(command) |
| 122 | + continue |
| 123 | + |
| 124 | + # Handle .find_element_by_name() + .click() |
| 125 | + data = re.match( |
| 126 | + '''^(\s*)driver\.find_element_by_name\(\"(\S+)\"\)''' |
| 127 | + '''\.click\(\)\s*$''', line) |
| 128 | + if data: |
| 129 | + whitespace = data.group(1) |
| 130 | + css_selector = '[name="%s"]' % data.group(2) |
| 131 | + command = '''%sself.click('%s')''' % (whitespace, css_selector) |
| 132 | + seleniumbase_lines.append(command) |
| 133 | + continue |
| 134 | + |
| 135 | + # Handle .find_element_by_name() + .send_keys() |
| 136 | + data = re.match( |
| 137 | + '''^(\s*)driver\.find_element_by_name\(\"(\S+)\"\)''' |
| 138 | + '''\.send_keys\(\"([\S\s]+)\"\)\s*$''', line) |
| 139 | + if data: |
| 140 | + whitespace = data.group(1) |
| 141 | + css_selector = '[name="%s"]' % data.group(2) |
| 142 | + text = data.group(3) |
| 143 | + command = '''%sself.update_text('%s', '%s')''' % ( |
| 144 | + whitespace, css_selector, text) |
| 145 | + seleniumbase_lines.append(command) |
| 146 | + continue |
| 147 | + |
| 148 | + # Handle .find_element_by_css_selector() + .click() |
| 149 | + data = re.match( |
| 150 | + '''^(\s*)driver\.find_element_by_css_selector\(\"([\S\s]+)\"\)''' |
| 151 | + '''\.click\(\)\s*$''', line) |
| 152 | + if data: |
| 153 | + whitespace = data.group(1) |
| 154 | + css_selector = '%s' % data.group(2) |
| 155 | + command = '''%sself.click('%s')''' % (whitespace, css_selector) |
| 156 | + if command.count('\\"') == command.count('"'): |
| 157 | + command = command.replace('\\"', '"') |
| 158 | + seleniumbase_lines.append(command) |
| 159 | + continue |
| 160 | + |
| 161 | + # Handle .find_element_by_css_selector() + .send_keys() |
| 162 | + data = re.match( |
| 163 | + '''^(\s*)driver\.find_element_by_css_selector\(\"([\S\s]+)\"\)''' |
| 164 | + '''\.send_keys\(\"([\S\s]+)\"\)\s*$''', line) |
| 165 | + if data: |
| 166 | + whitespace = data.group(1) |
| 167 | + css_selector = '%s' % data.group(2) |
| 168 | + text = data.group(3) |
| 169 | + command = '''%sself.update_text('%s', '%s')''' % ( |
| 170 | + whitespace, css_selector, text) |
| 171 | + if command.count('\\"') == command.count('"'): |
| 172 | + command = command.replace('\\"', '"') |
| 173 | + seleniumbase_lines.append(command) |
| 174 | + continue |
| 175 | + |
| 176 | + # Handle Select / by_css_selector() / select_by_visible_text() |
| 177 | + data = re.match( |
| 178 | + '''^(\s*)Select\(driver\.find_element_by_css_selector\(''' |
| 179 | + '''\"([\S\s]+)\"\)\)\.select_by_visible_text\(''' |
| 180 | + '''\"([\S\s]+)\"\)\s*$''', line) |
| 181 | + if data: |
| 182 | + whitespace = data.group(1) |
| 183 | + css_selector = '%s' % data.group(2) |
| 184 | + visible_text = '%s' % data.group(3) |
| 185 | + command = '''%sself.pick_select_option_by_text('%s', '%s')''' % ( |
| 186 | + whitespace, css_selector, visible_text) |
| 187 | + if command.count('\\"') == command.count('"'): |
| 188 | + command = command.replace('\\"', '"') |
| 189 | + seleniumbase_lines.append(command) |
| 190 | + continue |
| 191 | + |
| 192 | + # Handle .find_element_by_xpath() + .click() |
| 193 | + data = re.match( |
| 194 | + '''^(\s*)driver\.find_element_by_xpath\(u?\"([\S\s]+)\"\)''' |
| 195 | + '''\.click\(\)\s*$''', line) |
| 196 | + if data: |
| 197 | + whitespace = data.group(1) |
| 198 | + xpath = '%s' % data.group(2) |
| 199 | + if '(u"' in line: |
| 200 | + uni = "u" |
| 201 | + has_unicode = True |
| 202 | + command = '''%sself.click_xpath(%s"%s")''' % ( |
| 203 | + whitespace, uni, xpath) |
| 204 | + seleniumbase_lines.append(command) |
| 205 | + continue |
| 206 | + |
| 207 | + # Handle .find_element_by_link_text() + .click() |
| 208 | + data = re.match( |
| 209 | + '''^(\s*)driver\.find_element_by_link_text\(u?\"([\S\s]+)\"\)''' |
| 210 | + '''\.click\(\)\s*$''', line) |
| 211 | + if data: |
| 212 | + whitespace = data.group(1) |
| 213 | + link_text = '''%s''' % data.group(2) |
| 214 | + uni = "" |
| 215 | + if '(u"' in line: |
| 216 | + uni = "u" |
| 217 | + has_unicode = True |
| 218 | + command = '''%sself.click_link_text(%s"%s")''' % ( |
| 219 | + whitespace, uni, link_text) |
| 220 | + seleniumbase_lines.append(command) |
| 221 | + continue |
| 222 | + |
| 223 | + # Convert driver. to self.driver. if not already done |
| 224 | + if 'driver.' in line and 'self.driver' not in line: |
| 225 | + command = line.replace('driver.', 'self.driver.') |
| 226 | + seleniumbase_lines.append(command) |
| 227 | + continue |
| 228 | + |
| 229 | + # Add all other lines to final script without making changes |
| 230 | + seleniumbase_lines.append(line) |
| 231 | + |
| 232 | + seleniumbase_code = "" |
| 233 | + if has_unicode: |
| 234 | + seleniumbase_code = "# -*- coding: utf-8 -*-\n" |
| 235 | + for line in seleniumbase_lines: |
| 236 | + seleniumbase_code += line |
| 237 | + seleniumbase_code += "\n" |
| 238 | + # print seleniumbase_code # (For debugging) |
| 239 | + |
| 240 | + # Create SeleniumBase test file |
| 241 | + base_file_name = webdriver_python_file.split('.py')[0] |
| 242 | + converted_file_name = base_file_name + "_SB.py" |
| 243 | + out_file = codecs.open(converted_file_name, "w+") |
| 244 | + out_file.writelines(seleniumbase_code) |
| 245 | + out_file.close() |
| 246 | + |
| 247 | + |
| 248 | +if __name__ == "__main__": |
| 249 | + main() |
0 commit comments