|
| 1 | +# -*- coding: UTF-8 -*- |
1 | 2 | import os
|
2 | 3 | import textwrap
|
3 | 4 |
|
@@ -109,7 +110,6 @@ def request_queue_assertions(
|
109 | 110 | if expected_length is not None:
|
110 | 111 | self.assertEqual(len(request_queue), expected_length)
|
111 | 112 |
|
112 |
| - |
113 | 113 | def test_initial_state(self):
|
114 | 114 | app = Dash(__name__)
|
115 | 115 | my_class_attrs = {
|
@@ -154,11 +154,12 @@ def test_initial_state(self):
|
154 | 154 | self.startServer(app)
|
155 | 155 | el = self.wait_for_element_by_css_selector('#react-entry-point')
|
156 | 156 |
|
| 157 | + # Note: this .html file shows there's no undo/redo button by default |
157 | 158 | _dash_app_content_html = os.path.join(
|
158 | 159 | os.path.dirname(__file__),
|
159 | 160 | 'test_assets', 'initial_state_dash_app_content.html')
|
160 | 161 | with open(_dash_app_content_html) as fp:
|
161 |
| - rendered_dom = BeautifulSoup(fp.read(), 'lxml') |
| 162 | + rendered_dom = BeautifulSoup(fp.read().strip(), 'lxml') |
162 | 163 | fetched_dom = BeautifulSoup(el.get_attribute('outerHTML'), 'lxml')
|
163 | 164 |
|
164 | 165 | self.assertEqual(
|
@@ -211,6 +212,79 @@ def test_initial_state(self):
|
211 | 212 |
|
212 | 213 | self.assertTrue(self.is_console_clean())
|
213 | 214 |
|
| 215 | + def click_undo(self): |
| 216 | + undo_selector = '._dash-undo-redo span:first-child div:last-child' |
| 217 | + undo = self.wait_for_element_by_css_selector(undo_selector) |
| 218 | + self.wait_for_text_to_equal(undo_selector, 'undo') |
| 219 | + undo.click() |
| 220 | + |
| 221 | + def click_redo(self): |
| 222 | + redo_selector = '._dash-undo-redo span:last-child div:last-child' |
| 223 | + self.wait_for_text_to_equal(redo_selector, 'redo') |
| 224 | + redo = self.wait_for_element_by_css_selector(redo_selector) |
| 225 | + redo.click() |
| 226 | + |
| 227 | + def check_undo_redo_exist(self, has_undo, has_redo): |
| 228 | + selector = '._dash-undo-redo span div:last-child' |
| 229 | + els = self.driver.find_elements_by_css_selector(selector) |
| 230 | + texts = (['undo'] if has_undo else []) + (['redo'] if has_redo else []) |
| 231 | + |
| 232 | + self.assertEqual(len(els), len(texts)) |
| 233 | + for el, text in zip(els, texts): |
| 234 | + self.assertEqual(el.text, text) |
| 235 | + |
| 236 | + def test_undo_redo(self): |
| 237 | + app = Dash(__name__, show_undo_redo=True) |
| 238 | + app.layout = html.Div([dcc.Input(id='a'), html.Div(id='b')]) |
| 239 | + |
| 240 | + @app.callback(Output('b', 'children'), [Input('a', 'value')]) |
| 241 | + def set_b(a): |
| 242 | + return a |
| 243 | + |
| 244 | + self.startServer(app) |
| 245 | + |
| 246 | + a = self.wait_for_element_by_css_selector('#a') |
| 247 | + a.send_keys('xyz') |
| 248 | + |
| 249 | + self.wait_for_text_to_equal('#b', 'xyz') |
| 250 | + self.check_undo_redo_exist(True, False) |
| 251 | + |
| 252 | + self.click_undo() |
| 253 | + self.wait_for_text_to_equal('#b', 'xy') |
| 254 | + self.check_undo_redo_exist(True, True) |
| 255 | + |
| 256 | + self.click_undo() |
| 257 | + self.wait_for_text_to_equal('#b', 'x') |
| 258 | + self.check_undo_redo_exist(True, True) |
| 259 | + |
| 260 | + self.click_redo() |
| 261 | + self.wait_for_text_to_equal('#b', 'xy') |
| 262 | + self.check_undo_redo_exist(True, True) |
| 263 | + |
| 264 | + self.percy_snapshot(name='undo-redo') |
| 265 | + |
| 266 | + self.click_undo() |
| 267 | + self.click_undo() |
| 268 | + self.wait_for_text_to_equal('#b', '') |
| 269 | + self.check_undo_redo_exist(False, True) |
| 270 | + |
| 271 | + def test_no_undo_redo(self): |
| 272 | + app = Dash(__name__) |
| 273 | + app.layout = html.Div([dcc.Input(id='a'), html.Div(id='b')]) |
| 274 | + |
| 275 | + @app.callback(Output('b', 'children'), [Input('a', 'value')]) |
| 276 | + def set_b(a): |
| 277 | + return a |
| 278 | + |
| 279 | + self.startServer(app) |
| 280 | + |
| 281 | + a = self.wait_for_element_by_css_selector('#a') |
| 282 | + a.send_keys('xyz') |
| 283 | + |
| 284 | + self.wait_for_text_to_equal('#b', 'xyz') |
| 285 | + toolbar = self.driver.find_elements_by_css_selector('._dash-undo-redo') |
| 286 | + self.assertEqual(len(toolbar), 0) |
| 287 | + |
214 | 288 | def test_array_of_falsy_child(self):
|
215 | 289 | app = Dash(__name__)
|
216 | 290 | app.layout = html.Div(id='nully-wrapper', children=[0])
|
@@ -328,10 +402,9 @@ def update_input(value):
|
328 | 402 | '#react-entry-point').get_attribute('innerHTML'),
|
329 | 403 | 'lxml').select_one('#output > div').contents
|
330 | 404 |
|
331 |
| - self.assertTrue( |
332 |
| - pad_input.attrs == {'type': 'text', 'id': 'sub-input-1', 'value': 'sub input initial value'} |
333 |
| - and pad_input.name == 'input', |
334 |
| - "pad input is correctly rendered") |
| 405 | + self.assertEqual(pad_input.attrs['value'], 'sub input initial value') |
| 406 | + self.assertEqual(pad_input.attrs['id'], 'sub-input-1') |
| 407 | + self.assertEqual(pad_input.name, 'input') |
335 | 408 |
|
336 | 409 | self.assertTrue(
|
337 | 410 | pad_div.text == pad_input.attrs['value']
|
|
0 commit comments