66import java .net .URL ;
77import java .util .List ;
88import java .util .Map ;
9+ import java .util .Optional ;
910import java .util .stream .Collectors ;
1011
1112import org .openqa .selenium .By ;
1718import com .nordstrom .automation .selenium .annotations .PageUrl ;
1819import com .nordstrom .automation .selenium .core .ByType ;
1920import com .nordstrom .automation .selenium .core .JsUtility ;
21+ import com .nordstrom .automation .selenium .interfaces .DetectsLoadCompletion ;
22+ import com .nordstrom .automation .selenium .model .AlertHandler ;
2023import com .nordstrom .automation .selenium .model .Page ;
2124import com .nordstrom .automation .selenium .model .RobustWebElement ;
2225import com .nordstrom .automation .selenium .servlet .ExamplePageLauncher ;
2629 * This class is the model for the 'Example' page used by Selenium Foundation unit tests.
2730 */
2831@ PageUrl ("/grid/admin/ExamplePageServlet" )
29- public class ExamplePage extends Page {
32+ public class ExamplePage extends Page implements DetectsLoadCompletion {
3033
3134 /** page title */
3235 public static final String TITLE = "Example Page" ;
3336 /** text content of example paragraphs collection */
34- public static final String [] PARAS = {"This is paragraph one." , "This is paragraph two." , "This is paragraph three." };
37+ public static final String [] PARAS =
38+ {"This is paragraph one." , "This is paragraph two." , "This is paragraph three." , /* hidden paragraph */ "" };
3539 /** text content of example table headers collection */
3640 public static final String [] HEADINGS = {"Firstname" , "Lastname" , "Age" };
3741 /** text content of example table rows collection */
@@ -58,6 +62,7 @@ public class ExamplePage extends Page {
5862 */
5963 public ExamplePage (WebDriver driver ) {
6064 super (driver );
65+ alertHandler = new ExampleAlertHandler (this );
6166 }
6267
6368 private FrameComponent frameByLocator ;
@@ -74,7 +79,9 @@ public ExamplePage(WebDriver driver) {
7479 private ShadowRootComponent shadowRootByElement ;
7580 private List <ShadowRootComponent > shadowRootList ;
7681 private Map <Object , ShadowRootComponent > shadowRootMap ;
82+ private final AlertHandler alertHandler ;
7783 private int refreshCount ;
84+ private boolean isLoaded ;
7885
7986 /** identifier for frame 'A' */
8087 protected static final String FRAME_A_ID = "frame-a" ;
@@ -116,7 +123,15 @@ protected enum Using implements ByEnum {
116123 /** shadow root element 'B' */
117124 SHADOW_ROOT_B (By .cssSelector ("div#shadow-root-b" )),
118125 /** division element */
119- FORM_DIV (By .cssSelector ("div#form-div" ));
126+ FORM_DIV (By .cssSelector ("div#form-div" )),
127+ /** alert button */
128+ ALERT (By .cssSelector ("button#alert" )),
129+ /** confirm button */
130+ CONFIRM (By .cssSelector ("button#confirm" )),
131+ /** prompt button */
132+ PROMPT (By .cssSelector ("button#prompt" )),
133+ /** result paragraph */
134+ RESULT (By .cssSelector ("p#result" ));
120135
121136 private final By locator ;
122137
@@ -130,6 +145,39 @@ public By locator() {
130145 }
131146 }
132147
148+ /**
149+ * This enumeration defined alert type constants.
150+ */
151+ public enum ModalType {
152+ /** 'alert' modal */
153+ ALERT ("I am a JS Alert" ),
154+ /** 'confirm' modal */
155+ CONFIRM ("I am a JS Confirm" ),
156+ /** 'prompt' modal */
157+ PROMPT ("I am a JS Prompt" );
158+
159+ private String text ;
160+
161+ ModalType (String text ) {
162+ this .text = text ;
163+ }
164+
165+ /**
166+ * Convert the specified modal text to the corresponding constant.
167+ *
168+ * @param text modal text
169+ * @return modal type constant
170+ * @throws IllegalArgumentException if specified text is unrecognized
171+ */
172+ public static ModalType fromString (String text ) {
173+ if (text == null ) return null ;
174+ for (ModalType type : values ()) {
175+ if (type .text .equals (text )) return type ;
176+ }
177+ throw new IllegalArgumentException ("Unrecognized modal text: " + text );
178+ }
179+ }
180+
133181 /**
134182 * Get the automation component that models frame 'A' via the associated element locator.
135183 *
@@ -436,7 +484,74 @@ public boolean hasXpathOptional() {
436484 public boolean hasBogusOptional () {
437485 return findOptional (By .tagName ("BOGUS" )).hasReference ();
438486 }
487+
488+ /**
489+ * Get the type of the browser modal.
490+ *
491+ * @return {@link ModalType} representing the current modal; {@code null} if modal is not shown
492+ */
493+ public ModalType getModalType () {
494+ return ModalType .fromString (alertHandler .getText ());
495+ }
496+
497+ /**
498+ * Open the {@link ModalType#ALERT ALERT} modal.
499+ */
500+ public void openAlertModal () {
501+ findElement (Using .ALERT ).click ();
502+ }
439503
504+ /**
505+ * Open the {@link ModalType#CONFIRM CONFIRM} modal.
506+ */
507+ public void openConfirmModal () {
508+ findElement (Using .CONFIRM ).click ();
509+ }
510+
511+ /**
512+ * Open the {@link ModalType#PROMPT PROMPT} modal.
513+ */
514+ public void openPromptModal () {
515+ findElement (Using .PROMPT ).click ();
516+ }
517+
518+ /**
519+ * Accept the browser modal.
520+ *
521+ * @return landing page object
522+ */
523+ public Page acceptModal () {
524+ return alertHandler .accept ();
525+ }
526+
527+ /**
528+ * Send the specified keys to the browser modal and accept it.
529+ *
530+ * @param keys keys to send
531+ * @return landing page object
532+ */
533+ public Page sendKeysAndAccept (String keys ) {
534+ return alertHandler .sendKeysAndAccept (keys );
535+ }
536+
537+ /**
538+ * Dismiss the browser modal.
539+ *
540+ * @return landing page object
541+ */
542+ public Page dismissModal () {
543+ return alertHandler .dismiss ();
544+ }
545+
546+ /**
547+ * Get the modal result text.
548+ *
549+ * @return modal result text
550+ */
551+ public String getModalResult () {
552+ return findElement (Using .RESULT ).getText ();
553+ }
554+
440555 /**
441556 * Set the active Grid hub as the base URI for all relative loads of test pages.
442557 *
@@ -464,5 +579,65 @@ public static URI setHubAsTarget() {
464579 }
465580 return targetUri ;
466581 }
582+
583+ /**
584+ * {@inheritDoc}
585+ */
586+ @ Override
587+ public boolean isLoadComplete () {
588+ if (!isLoaded ) {
589+ isLoaded = true ;
590+ return false ;
591+ }
592+ return true ;
593+ }
467594
595+ /**
596+ * This class models the browser alerts of the example page.
597+ */
598+ private static class ExampleAlertHandler extends AlertHandler {
599+ public ExampleAlertHandler (Page parentPage ) {
600+ super (parentPage );
601+ }
602+
603+ /**
604+ * {@inheritDoc}
605+ */
606+ @ Override
607+ public ExamplePage accept () {
608+ return Optional .ofNullable (waitForAlert ())
609+ .map (alert -> {
610+ alert .accept ();
611+ return new ExamplePage (driver );
612+ })
613+ .orElse ((ExamplePage ) parentPage );
614+ }
615+
616+ /**
617+ * {@inheritDoc}
618+ */
619+ @ Override
620+ public ExamplePage sendKeysAndAccept (final String keys ) {
621+ return Optional .ofNullable (waitForAlert ())
622+ .map (alert -> {
623+ alert .sendKeys (keys );
624+ alert .accept ();
625+ return new ExamplePage (driver );
626+ })
627+ .orElse ((ExamplePage ) parentPage );
628+ }
629+
630+ /**
631+ * {@inheritDoc}
632+ */
633+ @ Override
634+ public ExamplePage dismiss () {
635+ return Optional .ofNullable (waitForAlert ())
636+ .map (alert -> {
637+ alert .dismiss ();
638+ return new ExamplePage (driver );
639+ })
640+ .orElse ((ExamplePage ) parentPage );
641+ }
642+ }
468643}
0 commit comments