@@ -449,280 +449,43 @@ An example of `python + pytest + selenium` which implemented "**Action Bot**, **
449449
450450A ` pytest ` fixture ` chrome_driver ` .
451451
452- ``` python
453- import pytest
454- from selenium import webdriver
455- from selenium.common import (
456- ElementNotInteractableException,
457- NoSuchElementException,
458- StaleElementReferenceException,
459- )
460- from selenium.webdriver import ActionChains
461- from selenium.webdriver.common.by import By
462- from selenium.webdriver.remote.webelement import WebElement
463- from selenium.webdriver.support import expected_conditions as EC
464- from selenium.webdriver.support.ui import WebDriverWait
465-
466-
467- @pytest.fixture (scope = " function" )
468- def chrome_driver ():
469- with webdriver.Chrome() as driver:
470- driver.set_window_size(1024 , 768 )
471- driver.implicitly_wait(0.5 )
472- yield driver
473- ```
452+ {{< tabpane text=true >}}
453+ {{< tab header="Python" >}}
454+ {{< gh-codeblock path="/examples/python/tests/design_strategy/using_best_practice.py#L6-L26" >}}
455+ {{< /tab >}}
456+ {{< /tabpane >}}
457+
474458
475459"** Action Bot** " implementation.
476460
477- ``` python
478- class ActionBot :
479- def __init__ (self , driver ) -> None :
480- self .driver = driver
481- self .wait = WebDriverWait(
482- driver,
483- timeout = 10 ,
484- poll_frequency = 2 ,
485- ignored_exceptions = [
486- NoSuchElementException,
487- StaleElementReferenceException,
488- ElementNotInteractableException,
489- ],
490- )
491-
492- def element (self , locator : tuple ) -> WebElement:
493- self .wait.until(lambda driver : driver.find_element(* locator))
494- return self .driver.find_element(* locator)
495-
496- def elements (self , locator : tuple ) -> list[WebElement]:
497- return self .driver.find_elements(* locator)
498-
499- def hover (self , locator : tuple ) -> None :
500- element = self .element(locator)
501- ActionChains(self .driver).move_to_element(element).perform()
502-
503- def click (self , locator : tuple ) -> None :
504- element = self .element(locator)
505- element.click()
506-
507- def type (self , locator : tuple , value : str ) -> None :
508- element = self .element(locator)
509- element.clear()
510- element.send_keys(value)
511-
512- def text (self , locator : tuple ) -> str :
513- element = self .element(locator)
514- return element.text
515- ```
461+ {{< tabpane text=true >}}
462+ {{< tab header="Python" >}}
463+ {{< gh-codeblock path="/examples/python/tests/design_strategy/using_best_practice.py#L28-L65" >}}
464+ {{< /tab >}}
465+ {{< /tabpane >}}
516466
517- "** Loadable Component** definition.
518467
519- ``` python
520- class LoadableComponent :
521- def load (self ):
522- raise NotImplementedError (" Subclasses must implement this method" )
468+ "** Loadable Component** definition.
523469
524- def is_loaded (self ):
525- raise NotImplementedError (" Subclasses must implement this method" )
470+ {{< tabpane text=true >}}
471+ {{< tab header="Python" >}}
472+ {{< gh-codeblock path="/examples/python/tests/design_strategy/using_best_practice.py#L67-L80" >}}
473+ {{< /tab >}}
474+ {{< /tabpane >}}
526475
527- def get (self ):
528- if not self .is_loaded():
529- self .load()
530- if not self .is_loaded():
531- raise Exception (" Page not loaded properly." )
532- return self
533- ```
534476
535477"** Loadable Component** and ** Page Object** " implementation.
536478
537- ``` python
538- class TodoPage (LoadableComponent ):
539- url = " https://todomvc.com/examples/react/dist/"
540-
541- new_todo_by = (By.CSS_SELECTOR , " input.new-todo" )
542- count_todo_left_by = (By.CSS_SELECTOR , " span.todo-count" )
543- todo_items_by = (By.CSS_SELECTOR , " ul.todo-list>li" )
544-
545- view_all_by = (By.LINK_TEXT , " All" )
546- view_active_by = (By.LINK_TEXT , " Active" )
547- view_completed_by = (By.LINK_TEXT , " Completed" )
548-
549- toggle_all_by = (By.CSS_SELECTOR , " input.toggle-all" )
550- clear_completed_by = (By.CSS_SELECTOR , " button.clear-completed" )
551-
552- @ staticmethod
553- def build_todo_by (s : str ) -> tuple :
554- p = f " //li[.//label[contains(text(), ' { s} ')]] "
555- return By.XPATH , p
556-
557- @ staticmethod
558- def build_todo_item_label_by (s : str ) -> tuple :
559- p = f " //label[contains(text(), ' { s} ')] "
560- return By.XPATH , p
561-
562- @ staticmethod
563- def build_todo_item_toggle_by (s : str ) -> tuple :
564- by, using = TodoPage.build_todo_item_label_by(s)
565- p = f " { using} /../input[@class='toggle'] "
566- return by, p
567-
568- @ staticmethod
569- def build_todo_item_delete_by (s : str ) -> tuple :
570- by, using = TodoPage.build_todo_item_label_by(s)
571- p = f " { using} /../button[@class='destroy'] "
572- return by, p
573-
574- def build_count_todo_left (self , count : int ) -> str :
575- if count == 1 :
576- return " 1 item left!"
577- else :
578- return f " { count} items left! "
579-
580- def __init__ (self , driver ):
581- self .driver = driver
582- self .bot = ActionBot(driver)
583-
584- def load (self ):
585- self .driver.get(self .url)
586-
587- def is_loaded (self ):
588- try :
589- WebDriverWait(self .driver, 10 ).until(
590- EC .visibility_of_element_located(self .new_todo_by)
591- )
592- return True
593- except :
594- return False
595-
596- # business domain below
597- def count_todo_items_left (self ) -> str :
598- return self .bot.text(self .count_todo_left_by)
599-
600- def todo_count (self ) -> int :
601- return len (self .bot.elements(self .todo_items_by))
602-
603- def new_todo (self , s : str ):
604- self .bot.type(self .new_todo_by, s + " \n " )
605-
606- def toggle_todo (self , s : str ):
607- self .bot.click(self .build_todo_item_toggle_by(s))
608-
609- def hover_todo (self , s : str ) -> None :
610- self .bot.hover(self .build_todo_by(s))
611-
612- def delete_todo (self , s : str ):
613- self .hover_todo(s)
614- self .bot.click(self .build_todo_item_delete_by(s))
615-
616- def clear_completed_todo (self ):
617- self .bot.click(self .clear_completed_by)
618-
619- def toggle_all_todo (self ):
620- self .bot.click(self .toggle_all_by)
621-
622- def view_all_todo (self ):
623- self .bot.click(self .view_all_by)
624-
625- def view_active_todo (self ):
626- self .bot.click(self .view_active_by)
627-
628- def view_completed_todo (self ):
629- self .bot.click(self .view_completed_by)
630- ```
479+ {{< tabpane text=true >}}
480+ {{< tab header="Python" >}}
481+ {{< gh-codeblock path="/examples/python/tests/design_strategy/using_best_practice.py#L82-L172" >}}
482+ {{< /tab >}}
483+ {{< /tabpane >}}
631484
632485Test cases implementation with ` pytest ` .
633486
634- ``` python
635- @pytest.fixture
636- def page (chrome_driver ) -> TodoPage:
637- driver = chrome_driver
638- return TodoPage(driver).get()
639-
640-
641- class TestTodoPage :
642- def test_new_todo (self , page : TodoPage):
643- assert page.todo_count() == 0
644- page.new_todo(" aaa" )
645- assert page.count_todo_items_left() == page.build_count_todo_left(1 )
646-
647- def test_todo_toggle (self , page : TodoPage):
648- s = " aaa"
649- page.new_todo(s)
650- assert page.count_todo_items_left() == page.build_count_todo_left(1 )
651-
652- page.toggle_todo(s)
653- assert page.count_todo_items_left() == page.build_count_todo_left(0 )
654-
655- page.toggle_todo(s)
656- assert page.count_todo_items_left() == page.build_count_todo_left(1 )
657-
658- def test_todo_delete (self , page : TodoPage):
659- s1 = " aaa"
660- s2 = " bbb"
661- page.new_todo(s1)
662- page.new_todo(s2)
663- assert page.count_todo_items_left() == page.build_count_todo_left(2 )
664-
665- page.delete_todo(s1)
666- assert page.count_todo_items_left() == page.build_count_todo_left(1 )
667-
668- page.delete_todo(s2)
669- assert page.todo_count() == 0
670-
671- def test_new_100_todo (self , page : TodoPage):
672- for i in range (100 ):
673- s = f " ToDo { i} "
674- page.new_todo(s)
675- assert page.count_todo_items_left() == page.build_count_todo_left(100 )
676-
677- def test_toggle_all_todo (self , page : TodoPage):
678- for i in range (10 ):
679- s = f " ToDo { i} "
680- page.new_todo(s)
681- assert page.count_todo_items_left() == page.build_count_todo_left(10 )
682- assert page.todo_count() == 10
683-
684- page.toggle_all_todo()
685- assert page.count_todo_items_left() == page.build_count_todo_left(0 )
686- assert page.todo_count() == 10
687-
688- page.toggle_all_todo()
689- assert page.count_todo_items_left() == page.build_count_todo_left(10 )
690- assert page.todo_count() == 10
691-
692- def test_clear_completed_todo (self , page : TodoPage):
693- for i in range (10 ):
694- s = f " ToDo { i} "
695- page.new_todo(s)
696- assert page.count_todo_items_left() == page.build_count_todo_left(10 )
697- assert page.todo_count() == 10
698-
699- for i in range (5 ):
700- s = f " ToDo { i} "
701- page.toggle_todo(s)
702- assert page.count_todo_items_left() == page.build_count_todo_left(5 )
703- assert page.todo_count() == 10
704-
705- page.clear_completed_todo()
706- assert page.count_todo_items_left() == page.build_count_todo_left(5 )
707- assert page.todo_count() == 5
708-
709- def test_view_todo (self , page : TodoPage):
710- for i in range (10 ):
711- s = f " ToDo { i} "
712- page.new_todo(s)
713- for i in range (4 ):
714- s = f " ToDo { i} "
715- page.toggle_todo(s)
716-
717- page.view_all_todo()
718- assert page.count_todo_items_left() == page.build_count_todo_left(6 )
719- assert page.todo_count() == 10
720-
721- page.view_active_todo()
722- assert page.count_todo_items_left() == page.build_count_todo_left(6 )
723- assert page.todo_count() == 6
724-
725- page.view_completed_todo()
726- assert page.count_todo_items_left() == page.build_count_todo_left(6 )
727- assert page.todo_count() == 4
728- ```
487+ {{< tabpane text=true >}}
488+ {{< tab header="Python" >}}
489+ {{< gh-codeblock path="/examples/python/tests/design_strategy/using_best_practice.py#L174-" >}}
490+ {{< /tab >}}
491+ {{< /tabpane >}}
0 commit comments