robotframework-apex 0.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- BrowserApex/__init__.py +3 -0
- BrowserApex/browser.py +547 -0
- BrowserApex/cli/__init__.py +0 -0
- BrowserApex/cli/apex/__init__.py +4 -0
- BrowserApex/cli/apex/apexlang-26.1.peg +381 -0
- BrowserApex/cli/apex/ebnf/apexlang-26.1.ebnf +11743 -0
- BrowserApex/cli/apex/grammar.py +928 -0
- BrowserApex/cli/apex/objects.py +291 -0
- BrowserApex/cli/apex/reader.py +189 -0
- BrowserApex/cli/commands/__init__.py +5 -0
- BrowserApex/cli/commands/config.py +19 -0
- BrowserApex/cli/commands/dump.py +23 -0
- BrowserApex/cli/commands/generate.py +182 -0
- BrowserApex/cli/commands/parse.py +25 -0
- BrowserApex/cli/commands/show.py +63 -0
- BrowserApex/cli/main.py +24 -0
- BrowserApex/cli/templates/custom-settings.template +1 -0
- BrowserApex/cli/templates/keywords.template +1 -0
- BrowserApex/cli/templates/pageobject.template +12 -0
- BrowserApex/cli/templates/pageobjects-resource.template +3 -0
- BrowserApex/cli/templates/rfapex.toml.template +3 -0
- BrowserApex/cli/templates/settings.template +2 -0
- BrowserApex/cli/templates/variables.template +9 -0
- BrowserApex/cli/utils.py +41 -0
- BrowserApex/keywords/__init__.py +0 -0
- BrowserApex/keywords/commands.py +0 -0
- BrowserApex/version.py +1 -0
- robotframework_apex-0.0.0.dist-info/METADATA +36 -0
- robotframework_apex-0.0.0.dist-info/RECORD +32 -0
- robotframework_apex-0.0.0.dist-info/WHEEL +4 -0
- robotframework_apex-0.0.0.dist-info/entry_points.txt +3 -0
- robotframework_apex-0.0.0.dist-info/licenses/LICENSE +21 -0
BrowserApex/__init__.py
ADDED
BrowserApex/browser.py
ADDED
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Oracle APEX support
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from robot.libraries.BuiltIn import BuiltIn
|
|
6
|
+
from robot.api.deco import keyword, not_keyword, library
|
|
7
|
+
from Browser import AssertionOperator, SelectAttribute, ElementState, Browser
|
|
8
|
+
from Browser.utils import PageLoadStates
|
|
9
|
+
|
|
10
|
+
selector_prefix = {
|
|
11
|
+
'/': 'xpath',
|
|
12
|
+
'.': 'css',
|
|
13
|
+
'#': 'id'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@library(scope='GLOBAL', auto_keywords=True)
|
|
17
|
+
class BrowserApex(Browser):
|
|
18
|
+
def __init__(self, **kwargs):
|
|
19
|
+
Browser.__init__(self, **kwargs)
|
|
20
|
+
|
|
21
|
+
# self.add_library_components()
|
|
22
|
+
|
|
23
|
+
self.container = None
|
|
24
|
+
self.classic_report_row = None
|
|
25
|
+
|
|
26
|
+
self.field_input_callbacks = {
|
|
27
|
+
'TextField': self.fill_text_field,
|
|
28
|
+
'NumberField': self.fill_number_field,
|
|
29
|
+
'Password': self.fill_password_field,
|
|
30
|
+
'SelectList': self.fill_select_field,
|
|
31
|
+
'RadioGroup': self.fill_radio_group,
|
|
32
|
+
'DatePicker': self.fill_date_picker,
|
|
33
|
+
'PopupLOV': self.fill_popup_lov,
|
|
34
|
+
}
|
|
35
|
+
self.field_get_callbacks = {
|
|
36
|
+
'Hidden': self.get_value_hidden,
|
|
37
|
+
'DisplayOnly': self.get_value_displayonly
|
|
38
|
+
}
|
|
39
|
+
self.field_check_callbacks = {
|
|
40
|
+
'DisplayOnly': self.check_display_only
|
|
41
|
+
}
|
|
42
|
+
self.field_commands = {
|
|
43
|
+
'var': self.command_var
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
self.cell_check_callbacks = {
|
|
47
|
+
'PlainText': self.check_cell_plaintext
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
self.locators = {
|
|
51
|
+
'login_container': ".t-Login-region",
|
|
52
|
+
'login_button': "//button/span[contains(text(),'##TEXT##')]",
|
|
53
|
+
'block_container': "//div[@aria-label='##TEXT##']",
|
|
54
|
+
'block_button': "//button/span[contains(text(),'##TEXT##')]",
|
|
55
|
+
'page_button': "//button/span[contains(text(),'##TEXT##')]",
|
|
56
|
+
'wizard_button': "//button/span[contains(text(),'##TEXT##')]",
|
|
57
|
+
'tab_button': "//button/span[contains(text(),'##TEXT##')]",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@not_keyword
|
|
62
|
+
def command_var(self, *args):
|
|
63
|
+
print(f"*DEBUG* COMMAND VAR args: {args}")
|
|
64
|
+
value = BuiltIn().get_variable_value(args[0])
|
|
65
|
+
return value
|
|
66
|
+
|
|
67
|
+
@keyword
|
|
68
|
+
def register_field_commands(self, **commands_to_register):
|
|
69
|
+
if type(commands_to_register) is not dict:
|
|
70
|
+
raise AttributeError(f"Register Field Commands expect a dictionary as argument")
|
|
71
|
+
|
|
72
|
+
self.field_commands.update(commands_to_register)
|
|
73
|
+
print(f"*INFO* Test")
|
|
74
|
+
|
|
75
|
+
@not_keyword
|
|
76
|
+
def check_container_visible(self, container_name, container):
|
|
77
|
+
try:
|
|
78
|
+
container_prefix = selector_prefix.get(container[0],'id')
|
|
79
|
+
element = self.get_element(f"{container_prefix}={container}")
|
|
80
|
+
self.get_element_states(element, AssertionOperator.contains, 'visible')
|
|
81
|
+
except:
|
|
82
|
+
raise AssertionError(f"Container '{container_name}' not avaiable or visible")
|
|
83
|
+
|
|
84
|
+
@not_keyword
|
|
85
|
+
def check_data_in_definition(self, block_name, field_definition, data):
|
|
86
|
+
|
|
87
|
+
for key, _ in data.items():
|
|
88
|
+
if key not in field_definition:
|
|
89
|
+
print(f"*WARN* Data field '{key}' not found in definition of block '{block_name}'" )
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@not_keyword
|
|
93
|
+
def check_button(self, block_name, button_fields, button_name):
|
|
94
|
+
if button_name not in button_fields:
|
|
95
|
+
raise AssertionError(f"Button '{button_name}' not in button definition for block '{block_name}'")
|
|
96
|
+
|
|
97
|
+
@not_keyword
|
|
98
|
+
def fill_text_field(self, field_name, field_id, value, field_args):
|
|
99
|
+
print(f"*INFO* Filling text field '{field_name}' with value: {value}")
|
|
100
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
101
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}")
|
|
102
|
+
self.fill_text(element, value)
|
|
103
|
+
|
|
104
|
+
@not_keyword
|
|
105
|
+
def fill_number_field(self, field_name, field_id, value, field_args):
|
|
106
|
+
print(f"*INFO* Filling text field '{field_name}' with value: {value}")
|
|
107
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
108
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}")
|
|
109
|
+
self.fill_text(element, value)
|
|
110
|
+
|
|
111
|
+
@not_keyword
|
|
112
|
+
def fill_password_field(self, field_name, field_id, value, field_args):
|
|
113
|
+
print(f"*INFO* Filling password field '{field_name}'")
|
|
114
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
115
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}")
|
|
116
|
+
self.fill_text(element, value)
|
|
117
|
+
|
|
118
|
+
@not_keyword
|
|
119
|
+
def fill_select_field(self, field_name, field_id, value, field_args):
|
|
120
|
+
print(f"*INFO* Filling select field '{field_name}' with value: {value}")
|
|
121
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
122
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}")
|
|
123
|
+
self.select_options_by(element, SelectAttribute.label, value)
|
|
124
|
+
|
|
125
|
+
@not_keyword
|
|
126
|
+
def fill_radio_group(self, field_name, field_id, value, field_args):
|
|
127
|
+
print(f"*INFO* Filling radio group '{field_name}' with value: {value}")
|
|
128
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
129
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id} >> xpath=//label[normalize-space(text())='{value}']")
|
|
130
|
+
self.click(element)
|
|
131
|
+
self.wait_for_elements_state(f"{container_prefix}={self.container} >> id={field_id}", ElementState.stable)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@not_keyword
|
|
135
|
+
def fill_date_picker(self, field_name, field_id, value, field_args):
|
|
136
|
+
print(f"*INFO* Filling date picker '{field_name}' with value: {value}")
|
|
137
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
138
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id} >> xpath=//input")
|
|
139
|
+
self.type_text(element, value)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@not_keyword
|
|
143
|
+
def fill_popup_lov(self, field_name, field_id, value, field_args):
|
|
144
|
+
print(f"*INFO* Filling popup '{field_name}' with value: {value}")
|
|
145
|
+
# direct input = <id>
|
|
146
|
+
# popup button = <id>_lov_btn
|
|
147
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
148
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}_lov_btn")
|
|
149
|
+
self.click(element)
|
|
150
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
151
|
+
|
|
152
|
+
# zoeken zit buiten de dialog (in hoofdpagina) in de DOM
|
|
153
|
+
old_prefix = self.set_selector_prefix("")
|
|
154
|
+
|
|
155
|
+
nr_retries = 5
|
|
156
|
+
while nr_retries > 0:
|
|
157
|
+
nr_retries -= 1
|
|
158
|
+
search_element = self.get_element(f'xpath=//div[contains(@class, "a-PopupLOV-dialog") and contains(@id, "{field_id}")] '
|
|
159
|
+
'>> xpath=//input[@aria-label="Zoeken"]')
|
|
160
|
+
self.clear_text(search_element)
|
|
161
|
+
BuiltIn().sleep(1)
|
|
162
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
163
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
164
|
+
|
|
165
|
+
self.type_text(search_element, value)
|
|
166
|
+
BuiltIn().sleep(1)
|
|
167
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
168
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
169
|
+
|
|
170
|
+
old_mode = self.set_strict_mode(False)
|
|
171
|
+
self.wait_for_elements_state(f'xpath=//div[contains(@class, "a-PopupLOV-dialog") and contains(@id, "{field_id}")] '
|
|
172
|
+
'>> xpath=//div[contains(@class, "a-PopupLOV-results")] '
|
|
173
|
+
'>> xpath=//tbody/tr')
|
|
174
|
+
self.set_strict_mode(True)
|
|
175
|
+
|
|
176
|
+
if 'manualentry' in field_args:
|
|
177
|
+
search_element = self.get_element(f'xpath=//div[contains(@class, "a-PopupLOV-dialog") and contains(@id, "{field_id}")] '
|
|
178
|
+
'>> xpath=//input[@aria-label="Zoeken"]')
|
|
179
|
+
self.press_keys(search_element, 'Enter')
|
|
180
|
+
|
|
181
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
182
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
183
|
+
|
|
184
|
+
else:
|
|
185
|
+
elements = self.get_elements(f'xpath=//div[contains(@class, "a-PopupLOV-dialog") and contains(@id, "{field_id}")] '
|
|
186
|
+
'>> xpath=//div[contains(@class, "a-PopupLOV-results")]'
|
|
187
|
+
f'>> xpath=//tbody/tr[contains(., "{value}")]')
|
|
188
|
+
|
|
189
|
+
if len(elements) > 0:
|
|
190
|
+
element = elements[0]
|
|
191
|
+
|
|
192
|
+
self.click(element)
|
|
193
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
194
|
+
|
|
195
|
+
states = self.get_element_states(f'xpath=//div[contains(@class, "a-PopupLOV-dialog") and contains(@id, "{field_id}")] '
|
|
196
|
+
'>> xpath=//div[contains(@class, "a-PopupLOV-results")]')
|
|
197
|
+
|
|
198
|
+
if 'visible' not in states:
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
# TODO: try, until selected value holds in input
|
|
202
|
+
|
|
203
|
+
self.set_selector_prefix(old_prefix)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@not_keyword
|
|
207
|
+
def process_command(self, value):
|
|
208
|
+
used_value = None
|
|
209
|
+
if value[0] in ['&', '!', '$']:
|
|
210
|
+
args = value[1:].split(':')
|
|
211
|
+
cmd_name = args.pop(0)
|
|
212
|
+
print(f"*INFO* command: {cmd_name} args: {args}")
|
|
213
|
+
if cmd_name in self.field_commands:
|
|
214
|
+
cmd = self.field_commands[cmd_name]
|
|
215
|
+
if type(cmd) is str:
|
|
216
|
+
# run as keyword
|
|
217
|
+
used_value = BuiltIn().run_keyword(cmd, *args)
|
|
218
|
+
|
|
219
|
+
else:
|
|
220
|
+
# run as function
|
|
221
|
+
used_value = cmd(*args)
|
|
222
|
+
|
|
223
|
+
else:
|
|
224
|
+
raise AttributeError(f"Field command `{cmd_name}` not found")
|
|
225
|
+
print(f"*INFO* command: {cmd_name} returned: {used_value}")
|
|
226
|
+
|
|
227
|
+
else:
|
|
228
|
+
used_value = value
|
|
229
|
+
|
|
230
|
+
return used_value
|
|
231
|
+
|
|
232
|
+
@not_keyword
|
|
233
|
+
def fill_fields(self, field_definition, data):
|
|
234
|
+
for key, value in data.items():
|
|
235
|
+
if key in field_definition:
|
|
236
|
+
field = field_definition[key]
|
|
237
|
+
if ':' not in field:
|
|
238
|
+
raise AssertionError(f"Field '{key}' has invalid definition: '{field}'")
|
|
239
|
+
field_id, field_type, *field_args = field.split(':')
|
|
240
|
+
print(f'*INFO* field_id: {field_id} field_type: {field_type} field_args: {field_args}')
|
|
241
|
+
cb = self.field_input_callbacks.get(field_type)
|
|
242
|
+
|
|
243
|
+
used_value = self.process_command(value)
|
|
244
|
+
|
|
245
|
+
if used_value:
|
|
246
|
+
if cb is None:
|
|
247
|
+
raise RuntimeError(f"Field type {field_type} not supported")
|
|
248
|
+
cb(key, field_id, used_value, field_args)
|
|
249
|
+
|
|
250
|
+
# set focus on container, to trigger validation on focus lost of field
|
|
251
|
+
self.focus(self.container)
|
|
252
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@not_keyword
|
|
256
|
+
def check_display_only(self, field_name, field_id, value):
|
|
257
|
+
print(f"*INFO* Checking DisplayOnly '{field_name}' with value: {value}")
|
|
258
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
259
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}_DISPLAY")
|
|
260
|
+
real_value = self.get_text(element)
|
|
261
|
+
BuiltIn().should_be_equal_as_strings(value, real_value, f"Field values not equal: {value} <-> {real_value}")
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@not_keyword
|
|
265
|
+
def check_fields(self, field_definition, data):
|
|
266
|
+
for key, value in data.items():
|
|
267
|
+
if key in field_definition:
|
|
268
|
+
field = field_definition[key]
|
|
269
|
+
if ':' not in field:
|
|
270
|
+
raise AssertionError(f"Field '{key}' has invalid definition: '{field}'")
|
|
271
|
+
field_id, field_type, *field_args = field.split(':')
|
|
272
|
+
print(f'*INFO* field_id: {field_id} field_type: {field_type} field_args: {field_args}')
|
|
273
|
+
cb = self.field_check_callbacks.get(field_type)
|
|
274
|
+
|
|
275
|
+
used_value = self.process_command(value)
|
|
276
|
+
|
|
277
|
+
if used_value:
|
|
278
|
+
if cb is None:
|
|
279
|
+
raise RuntimeError(f"Field type {field_type} not supported")
|
|
280
|
+
cb(key, field_id, used_value)
|
|
281
|
+
|
|
282
|
+
@keyword
|
|
283
|
+
def block_fill(self, block_name, field_definition, data):
|
|
284
|
+
container = self.locators.get('block_container').replace('##TEXT##', block_name)
|
|
285
|
+
self.check_container_visible(block_name, container)
|
|
286
|
+
self.check_data_in_definition(block_name, field_definition, data)
|
|
287
|
+
self.container = container
|
|
288
|
+
self.fill_fields(field_definition, data)
|
|
289
|
+
self.container = None
|
|
290
|
+
|
|
291
|
+
@keyword
|
|
292
|
+
def block_button(self, block_name, button_text):
|
|
293
|
+
container = self.locators.get('block_container').replace('##TEXT##', block_name)
|
|
294
|
+
self.check_container_visible(block_name, container)
|
|
295
|
+
self.container = container
|
|
296
|
+
|
|
297
|
+
locator = self.locators.get('block_button').replace('##TEXT##', button_text)
|
|
298
|
+
|
|
299
|
+
container_prefix = selector_prefix.get(self.container[0],'text')
|
|
300
|
+
button_prefix = selector_prefix.get(locator[0],'text')
|
|
301
|
+
element = self.get_element(f"{container_prefix}={self.container} >> {button_prefix}={locator}")
|
|
302
|
+
|
|
303
|
+
self.click(element)
|
|
304
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
305
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
306
|
+
self.container = None
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
@not_keyword
|
|
310
|
+
def get_value_hidden(self, field_id):
|
|
311
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
312
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}")
|
|
313
|
+
value = self.get_text(element)
|
|
314
|
+
return value
|
|
315
|
+
|
|
316
|
+
@not_keyword
|
|
317
|
+
def get_value_displayonly(self, field_id):
|
|
318
|
+
container_prefix = selector_prefix.get(self.container[0],'id')
|
|
319
|
+
element = self.get_element(f"{container_prefix}={self.container} >> id={field_id}_DISPLAY")
|
|
320
|
+
value = self.get_text(element)
|
|
321
|
+
return value
|
|
322
|
+
|
|
323
|
+
@not_keyword
|
|
324
|
+
def _get_field_value(self, field_definition, field_name):
|
|
325
|
+
field = field_definition[field_name]
|
|
326
|
+
if ':' not in field:
|
|
327
|
+
raise AssertionError(f"Field '{field_name}' has invalid definition: '{field}'")
|
|
328
|
+
field_id, field_type, *field_args = field.split(':')
|
|
329
|
+
print(f'*INFO* field_id: {field_id} field_type: {field_type} field_args: {field_args}')
|
|
330
|
+
cb = self.field_get_callbacks.get(field_type)
|
|
331
|
+
if cb is None:
|
|
332
|
+
raise AttributeError(f"*WARN* No getter for field type: {field_type}")
|
|
333
|
+
|
|
334
|
+
value = cb(field_id)
|
|
335
|
+
print(f"*INFO* get value from: '{field_name}' of type '{field_type}' returned: {value}")
|
|
336
|
+
return value
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@keyword
|
|
340
|
+
def block_get_value(self, block_name, field_definition, field_name):
|
|
341
|
+
container = self.locators.get('block_container').replace('##TEXT##', block_name)
|
|
342
|
+
self.check_container_visible(block_name, container)
|
|
343
|
+
self.container = container
|
|
344
|
+
|
|
345
|
+
if field_name not in field_definition:
|
|
346
|
+
raise AttributeError(f"*WARN* Field '{field_name}' not in definition of block {block_name}")
|
|
347
|
+
|
|
348
|
+
self.container = container
|
|
349
|
+
value = self._get_field_value(field_definition, field_name)
|
|
350
|
+
self.container = None
|
|
351
|
+
|
|
352
|
+
return value
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
@keyword
|
|
356
|
+
def block_check(self, block_name, field_definition, data):
|
|
357
|
+
container = self.locators.get('block_container').replace('##TEXT##', block_name)
|
|
358
|
+
self.check_container_visible(block_name, container)
|
|
359
|
+
self.check_data_in_definition(block_name, field_definition, data)
|
|
360
|
+
self.container = container
|
|
361
|
+
self.check_fields(field_definition, data)
|
|
362
|
+
self.container = None
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
@not_keyword
|
|
366
|
+
def tab_select_helper(self, tab_name):
|
|
367
|
+
|
|
368
|
+
tab_header = f"//a/span[text()='{tab_name}']"
|
|
369
|
+
tab_container = f"//div[@aria-label='{tab_name}']"
|
|
370
|
+
self.check_container_visible(f"{tab_name}.header", tab_header)
|
|
371
|
+
|
|
372
|
+
header_prefix = selector_prefix.get(tab_header[0], 'id')
|
|
373
|
+
element = self.get_element(f"{header_prefix}={tab_header}")
|
|
374
|
+
self.click(element)
|
|
375
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
376
|
+
|
|
377
|
+
self.check_container_visible(f"{tab_name}.body", tab_container)
|
|
378
|
+
return tab_container
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
@keyword
|
|
382
|
+
def tab_fill(self, tab_name, field_definition, data):
|
|
383
|
+
tab_container = self.tab_select_helper(tab_name)
|
|
384
|
+
|
|
385
|
+
self.container = tab_container
|
|
386
|
+
|
|
387
|
+
self.fill_fields(field_definition, data)
|
|
388
|
+
|
|
389
|
+
self.container = None
|
|
390
|
+
|
|
391
|
+
@keyword
|
|
392
|
+
def tab_button(self, tab_name, button_text):
|
|
393
|
+
tab_container = self.tab_select_helper(tab_name)
|
|
394
|
+
|
|
395
|
+
self.container = tab_container
|
|
396
|
+
locator = self.locators.get('tab_button').replace('##TEXT##', button_text)
|
|
397
|
+
|
|
398
|
+
container_prefix = selector_prefix.get(self.container[0],'text')
|
|
399
|
+
button_prefix = selector_prefix.get(locator[0],'text')
|
|
400
|
+
element = self.get_element(f"{container_prefix}={self.container} >> {button_prefix}={locator}")
|
|
401
|
+
|
|
402
|
+
self.click(element)
|
|
403
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
404
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
405
|
+
self.container = None
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@keyword
|
|
409
|
+
def wizard_button(self, button_text):
|
|
410
|
+
locator = self.locators.get('wizard_button').replace('##TEXT##', button_text)
|
|
411
|
+
button_prefix = selector_prefix.get(locator[0],'text')
|
|
412
|
+
element = self.get_element(f"{button_prefix}={locator}")
|
|
413
|
+
self.click(element)
|
|
414
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
415
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
@keyword
|
|
419
|
+
def page_button(self, button_text):
|
|
420
|
+
locator = self.locators.get('page_button').replace('##TEXT##', button_text)
|
|
421
|
+
button_prefix = selector_prefix.get(locator[0],'text')
|
|
422
|
+
element = self.get_element(f"{button_prefix}={locator}")
|
|
423
|
+
|
|
424
|
+
self.click(element)
|
|
425
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
426
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
427
|
+
|
|
428
|
+
@keyword
|
|
429
|
+
def page_get_value(self, field_definition, field_name):
|
|
430
|
+
self.container = ".t-Dialog-body"
|
|
431
|
+
if field_name not in field_definition:
|
|
432
|
+
raise AttributeError(f"*WARN* Field '{field_name}' not in definition of page")
|
|
433
|
+
|
|
434
|
+
value = self._get_field_value(field_definition, field_name)
|
|
435
|
+
self.container = None
|
|
436
|
+
return value
|
|
437
|
+
|
|
438
|
+
@not_keyword
|
|
439
|
+
def check_cell_plaintext(self, column_name, column_id, value):
|
|
440
|
+
print(f"*INFO* Checking PlainText '{column_name}' with value: {value}")
|
|
441
|
+
text = self.get_text(self.classic_report_row + f">> xpath=//td[@headers='{column_id}']")
|
|
442
|
+
BuiltIn().should_be_equal_as_strings(value, text, f"Field values not equal: {value} <-> {text}")
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
@not_keyword
|
|
446
|
+
def _check_columns(self, column_definition, data):
|
|
447
|
+
for key, value in data.items():
|
|
448
|
+
if key in column_definition:
|
|
449
|
+
field = column_definition[key]
|
|
450
|
+
if ':' not in field:
|
|
451
|
+
raise AssertionError(f"Column '{key}' has invalid definition: '{field}'")
|
|
452
|
+
field_id, field_type, *field_args = field.split(':')
|
|
453
|
+
print(f'*INFO* field_id: {field_id} field_type: {field_type} field_args: {field_args}')
|
|
454
|
+
cb = self.cell_check_callbacks.get(field_type)
|
|
455
|
+
|
|
456
|
+
used_value = self.process_command(value)
|
|
457
|
+
|
|
458
|
+
if used_value:
|
|
459
|
+
if cb is None:
|
|
460
|
+
raise RuntimeError(f"Column type {field_type} not supported")
|
|
461
|
+
cb(key, field_id, used_value)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
@not_keyword
|
|
465
|
+
def _classic_report_select_row(self, rownumber):
|
|
466
|
+
container_prefix = selector_prefix.get(self.container[0],'text')
|
|
467
|
+
element = self.get_element(f'{container_prefix}={self.container} '
|
|
468
|
+
'>> xpath=//table[@class="t-Report-report"] '
|
|
469
|
+
f'>> xpath=//tbody/tr[{rownumber}]')
|
|
470
|
+
self.click(element)
|
|
471
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
472
|
+
|
|
473
|
+
@not_keyword
|
|
474
|
+
def _classic_report_check_row(self, columns_definition, rownumber, data):
|
|
475
|
+
container_prefix = selector_prefix.get(self.container[0],'text')
|
|
476
|
+
row_element = self.get_element(f'{container_prefix}={self.container} '
|
|
477
|
+
'>> xpath=//table[@class="t-Report-report"] '
|
|
478
|
+
f'>> xpath=//tbody/tr[{rownumber}]')
|
|
479
|
+
|
|
480
|
+
self.classic_report_row = row_element
|
|
481
|
+
self._check_columns(columns_definition, data)
|
|
482
|
+
self.classic_report_row = None
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
@keyword
|
|
486
|
+
def block_classic_report_select_row(self, block_name, rownumber):
|
|
487
|
+
container = self.locators.get('block_container').replace('##TEXT##', block_name)
|
|
488
|
+
self.check_container_visible(block_name, container)
|
|
489
|
+
|
|
490
|
+
self.container = container
|
|
491
|
+
self._classic_report_select_row(rownumber)
|
|
492
|
+
|
|
493
|
+
self.container = None
|
|
494
|
+
|
|
495
|
+
@keyword
|
|
496
|
+
def block_classic_report_check_row(self, block_name, tab_columns_definition, rownumber, data):
|
|
497
|
+
container = self.locators.get('block_container').replace('##TEXT##', block_name)
|
|
498
|
+
|
|
499
|
+
self.container = container
|
|
500
|
+
self._classic_report_check_row(tab_columns_definition, rownumber, data)
|
|
501
|
+
self.container = None
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
@keyword
|
|
505
|
+
def tab_classic_report_select_row(self, tab_name, rownumber):
|
|
506
|
+
tab_container = self.tab_select_helper(tab_name)
|
|
507
|
+
|
|
508
|
+
self.container = tab_container
|
|
509
|
+
self._classic_report_select_row(rownumber)
|
|
510
|
+
self.container = None
|
|
511
|
+
|
|
512
|
+
@keyword
|
|
513
|
+
def tab_classic_report_check_row(self, tab_name, tab_columns_definition, rownumber, data):
|
|
514
|
+
tab_container = self.tab_select_helper(tab_name)
|
|
515
|
+
|
|
516
|
+
self.container = tab_container
|
|
517
|
+
self._classic_report_check_row(tab_columns_definition, rownumber, data)
|
|
518
|
+
self.container = None
|
|
519
|
+
|
|
520
|
+
# Template: Login
|
|
521
|
+
@keyword
|
|
522
|
+
def login_fill(self, block_name, field_definition, data):
|
|
523
|
+
container = self.locators.get('login_container').replace('##TEXT##', block_name)
|
|
524
|
+
|
|
525
|
+
self.check_container_visible(block_name, container)
|
|
526
|
+
self.check_data_in_definition(block_name, field_definition, data)
|
|
527
|
+
self.container = container
|
|
528
|
+
self.fill_fields(field_definition, data)
|
|
529
|
+
self.container = None
|
|
530
|
+
|
|
531
|
+
@keyword
|
|
532
|
+
def login_button(self, block_name, button_text):
|
|
533
|
+
|
|
534
|
+
container = self.locators.get('login_container').replace('##TEXT##', block_name)
|
|
535
|
+
self.check_container_visible(block_name, container)
|
|
536
|
+
self.container = container
|
|
537
|
+
|
|
538
|
+
locator = self.locators.get('login_button').replace('##TEXT##', button_text)
|
|
539
|
+
|
|
540
|
+
container_prefix = selector_prefix.get(self.container[0],'text')
|
|
541
|
+
button_prefix = selector_prefix.get(locator[0],'text')
|
|
542
|
+
element = self.get_element(f"{container_prefix}={self.container} >> {button_prefix}={locator}")
|
|
543
|
+
|
|
544
|
+
self.click(element)
|
|
545
|
+
self.wait_for_load_state(PageLoadStates.networkidle, 10)
|
|
546
|
+
self.wait_for_load_state(PageLoadStates.domcontentloaded, 1)
|
|
547
|
+
self.container = None
|
|
File without changes
|