|
14 | 14 | # See the License for the specific language governing permissions and |
15 | 15 | # limitations under the License. |
16 | 16 |
|
17 | | -import time |
18 | | - |
19 | 17 | from selenium.common.exceptions import WebDriverException |
20 | 18 | from selenium.webdriver.support import expected_conditions as EC |
21 | 19 | from selenium.webdriver.support.ui import WebDriverWait |
22 | 20 |
|
23 | | -from SeleniumLibrary.base import keyword |
24 | | -from SeleniumLibrary.base import LibraryComponent |
25 | | -from SeleniumLibrary.utils import is_truthy |
| 21 | +from SeleniumLibrary.base import keyword, LibraryComponent |
| 22 | +from SeleniumLibrary.utils import is_truthy, secs_to_timestr, timestr_to_secs |
26 | 23 |
|
27 | 24 |
|
28 | 25 | class AlertKeywords(LibraryComponent): |
| 26 | + ACCEPT = 'ACCEPT' |
| 27 | + DISMISS = 'DISMISS' |
| 28 | + LEAVE = 'LEAVE' |
| 29 | + _next_alert_action = ACCEPT |
29 | 30 |
|
30 | | - ACCEPT_ALERT = 'accept' |
31 | | - DISMISS_ALERT = 'dismiss' |
| 31 | + @keyword |
| 32 | + def input_text_into_prompt(self, text): |
| 33 | + """Deprecated. Use `Input Text Into Alert` instead. |
32 | 34 |
|
33 | | - def __init__(self, ctx): |
34 | | - LibraryComponent.__init__(self, ctx) |
35 | | - self._next_alert_dismiss_type = self.ACCEPT_ALERT |
| 35 | + Types the given ``text`` into an input field in an alert. |
| 36 | + Leaves the alert open. |
| 37 | + """ |
| 38 | + self.input_text_into_alert(text, self.LEAVE) |
36 | 39 |
|
37 | 40 | @keyword |
38 | | - def input_text_into_prompt(self, text): |
39 | | - """Types the given `text` into alert box. """ |
40 | | - try: |
41 | | - alert = self._wait_alert() |
42 | | - alert.send_keys(text) |
43 | | - except WebDriverException: |
44 | | - raise RuntimeError('There were no alerts') |
| 41 | + def input_text_into_alert(self, text, action=ACCEPT, timeout=None): |
| 42 | + """Types the given ``text`` into an input field in an alert. |
| 43 | +
|
| 44 | + The alert is accepted by default, but that behavior can be controlled |
| 45 | + by using the ``action`` argument same way as with `Handle Alert`. |
| 46 | +
|
| 47 | + ``timeout`` specifies how long to wait for the alert to appear. |
| 48 | + If it is not given, the global default `timeout` is used instead. |
| 49 | +
|
| 50 | + New in SeleniumLibrary 3.0. |
| 51 | + """ |
| 52 | + alert = self._wait_alert(timeout) |
| 53 | + alert.send_keys(text) |
| 54 | + self._handle_alert(alert, action) |
| 55 | + |
| 56 | + @keyword |
| 57 | + def alert_should_be_present(self, text='', action=ACCEPT, timeout=None): |
| 58 | + """Verifies that an alert is present and, by default, accepts it. |
| 59 | +
|
| 60 | + Fails if no alert is present. If ``text`` is a non-empty string, |
| 61 | + then it is used to verify alert's message. The alert is accepted |
| 62 | + by default, but that behavior can be controlled by using the |
| 63 | + ``action`` argument same way as with `Handle Alert`. |
| 64 | +
|
| 65 | + ``timeout`` specifies how long to wait for the alert to appear. |
| 66 | + If it is not given, the global default `timeout` is used instead. |
| 67 | +
|
| 68 | + ``action`` and ``timeout`` arguments are new in SeleniumLibrary 3.0. |
| 69 | + In earlier versions the alert was always accepted and timeout was |
| 70 | + hard coded to one second. |
| 71 | + """ |
| 72 | + message = self.handle_alert(action, timeout) |
| 73 | + if text and text != message: |
| 74 | + raise AssertionError("Alert message should have been '%s' but it " |
| 75 | + "was '%s'." % (text, message)) |
45 | 76 |
|
46 | 77 | @keyword |
47 | | - def alert_should_be_present(self, text=''): |
48 | | - """Verifies an alert is present and dismisses it. |
| 78 | + def alert_should_not_be_present(self, action=ACCEPT, timeout=0): |
| 79 | + """Verifies that no alert is present. |
49 | 80 |
|
50 | | - If `text` is a non-empty string, then it is also verified that the |
51 | | - message of the alert equals to `text`. |
| 81 | + If the alert actually exists, the ``action`` argument determines |
| 82 | + how it should be handled. By default the alert is accepted, but |
| 83 | + it can be also dismissed or left open the same way as with the |
| 84 | + `Handle Alert` keyword. |
52 | 85 |
|
53 | | - Will fail if no alert is present. Note that following keywords |
54 | | - will fail unless the alert is dismissed by this |
55 | | - keyword or another like `Get Alert Message`. |
| 86 | + ``timeout`` specifies how long to wait for the alert to appear. |
| 87 | + By default the alert is not waited at all, but a custom time can |
| 88 | + be given if alert may be delayed. See the `time format` section |
| 89 | + for information about the syntax. |
| 90 | +
|
| 91 | + New in SeleniumLibrary 3.0. |
56 | 92 | """ |
57 | | - alert_text = self._handle_alert(self.ACCEPT_ALERT) |
58 | | - if text and alert_text != text: |
59 | | - raise AssertionError("Alert text should have been " |
60 | | - "'%s' but was '%s'" |
61 | | - % (text, alert_text)) |
| 93 | + try: |
| 94 | + alert = self._wait_alert(timeout) |
| 95 | + except AssertionError: |
| 96 | + return |
| 97 | + text = self._handle_alert(alert, action) |
| 98 | + raise AssertionError("Alert with message '%s' present." % text) |
62 | 99 |
|
63 | 100 | @keyword |
64 | 101 | def choose_cancel_on_next_confirmation(self): |
65 | | - """Cancel will be selected the next time `Confirm Action` is used.""" |
66 | | - self._next_alert_dismiss_type = self.DISMISS_ALERT |
| 102 | + """Deprecated. Use `Handle Alert` directly instead. |
| 103 | +
|
| 104 | + In versions prior to SeleniumLibrary 3.0, the alert handling |
| 105 | + approach needed to be set separately before using the `Confirm |
| 106 | + Action` keyword. New `Handle Alert` keyword accepts the action how |
| 107 | + to handle the alert as a normal argument and should be used instead. |
| 108 | + """ |
| 109 | + self._next_alert_action = self.DISMISS |
67 | 110 |
|
68 | 111 | @keyword |
69 | 112 | def choose_ok_on_next_confirmation(self): |
70 | | - """Undo the effect of using keywords `Choose Cancel On Next Confirmation`. Note |
71 | | - that Selenium's overridden window.confirm() function will normally |
72 | | - automatically return true, as if the user had manually clicked OK, so |
73 | | - you shouldn't need to use this command unless for some reason you need |
74 | | - to change your mind prior to the next confirmation. After any |
75 | | - confirmation, Selenium will resume using the default behavior for |
76 | | - future confirmations, automatically returning true (OK) unless/until |
77 | | - you explicitly use `Choose Cancel On Next Confirmation` for each |
78 | | - confirmation. |
79 | | -
|
80 | | - Note that every time a confirmation comes up, you must |
81 | | - consume it by using a keywords such as `Get Alert Message`, or else |
82 | | - the following selenium operations will fail. |
| 113 | + """Deprecated. Use `Handle Alert` directly instead. |
| 114 | +
|
| 115 | + In versions prior to SeleniumLibrary 3.0, the alert handling |
| 116 | + approach needed to be set separately before using the `Confirm |
| 117 | + Action` keyword. New `Handle Alert` keyword accepts the action how |
| 118 | + to handle the alert as a normal argument and should be used instead. |
83 | 119 | """ |
84 | | - self._next_alert_dismiss_type = self.ACCEPT_ALERT |
| 120 | + self._next_alert_action = self.ACCEPT |
85 | 121 |
|
86 | 122 | @keyword |
87 | 123 | def confirm_action(self): |
88 | | - """Dismisses currently shown confirmation dialog and returns it's message. |
| 124 | + """Deprecated. Use `Handle Alert` instead. |
89 | 125 |
|
90 | | - By default, this keyword chooses 'OK' option from the dialog. If |
91 | | - 'Cancel' needs to be chosen, keyword `Choose Cancel On Next |
92 | | - Confirmation` must be called before the action that causes the |
93 | | - confirmation dialog to be shown. |
94 | | -
|
95 | | - Examples: |
96 | | - | Click Button | Send | # Shows a confirmation dialog | |
97 | | - | ${message}= | Confirm Action | # Chooses Ok | |
98 | | - | Should Be Equal | ${message} | Are your sure? | |
99 | | - | | | | |
100 | | - | Choose Cancel On Next Confirmation | | | |
101 | | - | Click Button | Send | # Shows a confirmation dialog | |
102 | | - | Confirm Action | | # Chooses Cancel | |
| 126 | + By default accepts an alert, but this behavior can be altered |
| 127 | + with `Choose Cancel On Next Confirmation` and `Choose Ok On Next |
| 128 | + Confirmation` keywords. New `Handle Alert` keyword accepts the action |
| 129 | + how to handle the alert as a normal argument and should be used |
| 130 | + instead. |
103 | 131 | """ |
104 | | - text = self._handle_alert(self._next_alert_dismiss_type) |
105 | | - self._next_alert_dismiss_type = self.DISMISS_ALERT |
| 132 | + text = self.handle_alert(self._next_alert_action) |
| 133 | + self._next_alert_action = self.ACCEPT |
106 | 134 | return text |
107 | 135 |
|
108 | 136 | @keyword |
109 | 137 | def get_alert_message(self, dismiss=True): |
110 | | - """Returns the text of current JavaScript alert. |
| 138 | + """Deprecated. Use `Handle Alert` instead. |
111 | 139 |
|
112 | | - By default the current JavaScript alert will be dismissed. |
113 | | - This keyword will fail if no alert is present. Note that |
114 | | - following keywords will fail unless the alert is |
115 | | - dismissed by this keyword or another like `Dismiss Alert`. |
| 140 | + Returns the message the alert has. Dismisses the alert by default |
| 141 | + (i.e. presses ``Cancel``) and setting ``dismiss`` to false leaves |
| 142 | + the alert open. There is no support to accept the alert (i.e. to |
| 143 | + press ``Ok``). |
| 144 | +
|
| 145 | + `Handle Alert` has better support for controlling should the alert |
| 146 | + be accepted, dismissed, or left open. |
116 | 147 | """ |
117 | | - if is_truthy(dismiss): |
118 | | - return self._handle_alert(self.DISMISS_ALERT) |
119 | | - else: |
120 | | - return self._handle_alert() |
| 148 | + action = self.DISMISS if is_truthy(dismiss) else self.LEAVE |
| 149 | + return self.handle_alert(action) |
121 | 150 |
|
122 | 151 | @keyword |
123 | 152 | def dismiss_alert(self, accept=True): |
124 | | - """ Returns true if alert was confirmed, false if it was dismissed |
| 153 | + """Deprecated. Use `Handle Alert` instead. |
| 154 | +
|
| 155 | + Contrary to its name, this keyword accepts the alert by default |
| 156 | + (i.e. presses ``Ok``). ``accept`` can be set to a false value |
| 157 | + to dismiss the alert (i.e. to press ``Cancel``). |
125 | 158 |
|
126 | | - This keyword will fail if no alert is present. Note that |
127 | | - following keywords will fail unless the alert is |
128 | | - dismissed by this keyword or another like `Get Alert Message`. |
| 159 | + `Handle Alert` has better support for controlling should the alert |
| 160 | + be accepted, dismissed, or left open. |
129 | 161 | """ |
130 | 162 | if is_truthy(accept): |
131 | | - return self._handle_alert(self.ACCEPT_ALERT) |
132 | | - else: |
133 | | - return self._handle_alert() |
| 163 | + self.handle_alert(self.ACCEPT) |
| 164 | + return True |
| 165 | + self.handle_alert(self.DISMISS) |
| 166 | + return False |
134 | 167 |
|
135 | | - def _handle_alert(self, dismiss_type=None): |
136 | | - """Alert re-try for Chrome |
| 168 | + @keyword |
| 169 | + def handle_alert(self, action=ACCEPT, timeout=None): |
| 170 | + """Handles the current alert and returns its message. |
| 171 | +
|
| 172 | + By default the alert is accepted, but this can be controlled |
| 173 | + with the ``action`` argument that supports the following |
| 174 | + case-insensitive values: |
137 | 175 |
|
138 | | - Because Chrome has difficulties to handle alerts, like:: |
| 176 | + - ``ACCEPT``: Accept the alert i.e. press ``Ok``. Default. |
| 177 | + - ``DISMISS``: Dismiss the alert i.e. press ``Cancel``. |
| 178 | + - ``LEAVE``: Leave the alert open. |
139 | 179 |
|
140 | | - alert.text |
141 | | - alert.dismiss |
| 180 | + The ``timeout`` argument specifies how long to wait for the alert |
| 181 | + to appear. If it is not given, the global default `timeout` is used |
| 182 | + instead. |
142 | 183 |
|
143 | | - This function creates a re-try functionality to better support |
144 | | - alerts in Chrome. |
| 184 | + Examples: |
| 185 | + | Handle Alert | | | # Accept alert. | |
| 186 | + | Handle Alert | action=DISMISS | | # Dismiss alert. | |
| 187 | + | Handle Alert | timeout=10 s | | # Use custom timeout and accept alert. | |
| 188 | + | Handle Alert | DISMISS | 1 min | # Use custom timeout and dismiss alert. | |
| 189 | + | ${message} = | Handle Alert | | # Accept alert and get its message. | |
| 190 | + | ${message} = | Handle Alert | LEAVE | # Leave alert open and get its message. | |
| 191 | +
|
| 192 | + New in SeleniumLibrary 3.0. |
145 | 193 | """ |
146 | | - retry = 0 |
147 | | - while retry < 4: |
148 | | - try: |
149 | | - return self._alert_worker(dismiss_type) |
150 | | - except WebDriverException: |
151 | | - time.sleep(0.2) |
152 | | - retry += 1 |
153 | | - raise RuntimeError('There were no alerts') |
154 | | - |
155 | | - def _alert_worker(self, dismiss_type=None): |
156 | | - alert = self._wait_alert() |
| 194 | + alert = self._wait_alert(timeout) |
| 195 | + return self._handle_alert(alert, action) |
| 196 | + |
| 197 | + def _handle_alert(self, alert, action): |
| 198 | + action = action.upper() |
157 | 199 | text = ' '.join(alert.text.splitlines()) |
158 | | - if dismiss_type == self.DISMISS_ALERT: |
159 | | - alert.dismiss() |
160 | | - elif dismiss_type == self.ACCEPT_ALERT: |
| 200 | + if action == self.ACCEPT: |
161 | 201 | alert.accept() |
| 202 | + elif action == self.DISMISS: |
| 203 | + alert.dismiss() |
| 204 | + elif action != self.LEAVE: |
| 205 | + raise ValueError("Invalid alert action '%s'." % action) |
162 | 206 | return text |
163 | 207 |
|
164 | | - def _wait_alert(self): |
165 | | - return WebDriverWait(self.browser, 1).until(EC.alert_is_present()) |
| 208 | + def _wait_alert(self, timeout=None): |
| 209 | + timeout = self.get_timeout(timeout) |
| 210 | + wait = WebDriverWait(self.browser, timeout) |
| 211 | + try: |
| 212 | + return wait.until(EC.alert_is_present()) |
| 213 | + except WebDriverException: |
| 214 | + raise AssertionError('Alert not found in %s.' |
| 215 | + % secs_to_timestr(timeout)) |
0 commit comments