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