/// <summary>
        /// Gets the item by class.
        /// </summary>
        /// <param name="className">Name of the class.</param>
        /// <param name="stringComparison">The string comparison.</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public virtual MenuItemComponent GetItemByClass(string className,
                                                        StringComparison stringComparison = StringComparison.Ordinal)
        {
            var menuItemEl = ItemElements.FirstOrDefault(el =>
            {
                return(el
                       .FindElements(itemIconSeletor)
                       .Any(
                           iconEl => iconEl.Classes().Any(
                               @class => String.Equals(
                                   @class,
                                   className,
                                   stringComparison))));
            });

            if (menuItemEl == null)
            {
                throw new NoSuchElementException();
            }

            var cssSelector = WrappedDriver.GetCssSelector(menuItemEl);

            return(pageObjectFactory.PrepareComponent(
                       new MenuItemComponent(
                           cssSelector,
                           pageObjectFactory,
                           WrappedDriver)));
        }
Beispiel #2
0
        /// <summary>
        /// Closes the active panel.
        /// </summary>
        public virtual void ClosePanel()
        {
            if (!accordianComponentOptions.Collaspable)
            {
                throw new Exception("The " +
                                    "AccordianComponentOptions.Collaspable was set to false.");
            }

            if (HasOpenPanel())
            {
                var waiter = WrappedElement.GetEventWaiter("accordionactivate");

                switch (accordianComponentOptions.Event)
                {
                case "click":
                    ActivePanelElement.Click();
                    break;

                case "mouseover":
                    WrappedDriver.CreateActions()
                    .MoveToElement(ActivePanelElement)
                    .Perform();
                    break;

                default:
                    throw new NotImplementedException(accordianComponentOptions.Event);
                }

                waiter.Wait(accordianComponentOptions.AnimationDuration);
            }
        }
        /// <summary>
        /// Locates and selects the format to export to. Will only work when
        /// running tests locally.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="downloadsPath">The downloads path.</param>
        /// <param name="expectedFileName">The expected file name.</param>
        /// <param name="stringComparison">The string comparison.</param>
        /// <exception cref="NoSuchElementException"></exception>
        public virtual void ExportTo(string type,
                                     string downloadsPath,
                                     string expectedFileName,
                                     StringComparison stringComparison = StringComparison.Ordinal)
        {
            var fullPath = Path.Combine(downloadsPath, expectedFileName);
            var element  = ExportDropDownComponent
                           .Expand()
                           .GetEnabledItems()
                           .FirstOrDefault(e => String.Equals(
                                               e.TextHelper().InnerText,
                                               type,
                                               StringComparison.Ordinal));

            if (element == null)
            {
                throw new NoSuchElementException();
            }

            element.Click();

            WrappedDriver
            .Wait(TimeSpan.FromMinutes(5))
            .Until(d => File.Exists(fullPath));
        }
 /// <summary>
 /// Scrolls the specified row into view.  This method should be used to scroll virtualized grid rows into view before interacting with them.
 /// </summary>
 /// <param name="rowIndex">Index of the row.</param>
 public void ScrollGridRowIntoView(int rowIndex)
 {
     //There is a bug where the 'virtualScrollTo' js function won't correctly scroll a row into view, the workaround is to scroll to the first index, wait, then scroll to the real index
     WrappedDriver.ExecuteScript(@"$(arguments[0]).igGrid('virtualScrollTo', arguments[1]);", WrappedElement, 0);
     Thread.Sleep(1000);
     WrappedDriver.ExecuteScript(@"$(arguments[0]).igGrid('virtualScrollTo', arguments[1]);", WrappedElement, rowIndex);
 }
        /// <summary>
        /// Adds the new related product.
        /// </summary>
        /// <param name="productName">Name of the product.</param>
        /// <returns></returns>
        public virtual RelatedProductsComponent AddNewRelatedProduct(string productName)
        {
            var currentPageHandle = WrappedDriver.CurrentWindowHandle;
            var windowHandles     = WrappedDriver.WindowHandles;
            var newWindowHandle   = default(string);

            AddNewRelatedProductElement.Click();

            // Wait for the new window to appear.
            WrappedDriver
            .Wait(TimeSpan.FromSeconds(10))
            .Until(d => newWindowHandle = d.WindowHandles
                                          .Except(windowHandles)
                                          .FirstOrDefault());

            // Switch to the new window.
            WrappedDriver.SwitchTo().Window(newWindowHandle);

            SearchProductPopup.Load();
            SearchProductPopup.SearchForProduct(productName);

            // Switch back.
            WrappedDriver.SwitchTo().Window(currentPageHandle);

            // Wait for the grid to finish loading.
            WrappedDriver
            .Wait(TimeSpan.FromSeconds(10))
            .UntilChain(d => RelatedProductsGrid.IsBusy())
            .UntilChain(d => !RelatedProductsGrid.IsBusy());

            return(this);
        }
Beispiel #6
0
        /// <summary>
        /// Views the order. Need to pass in a row from the OrdersGrids.
        /// </summary>
        /// <param name="gridRow">The grid row.</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public virtual Order.IEditPage ViewOrder(IWebElement gridRow)
        {
            if (gridRow == null)
            {
                throw new ArgumentException(nameof(gridRow));
            }

            var hasCorrectTagName = String.Equals(
                gridRow.TagName,
                "tr",
                StringComparison.OrdinalIgnoreCase);

            if (!hasCorrectTagName)
            {
                throw new UnexpectedTagNameException("Expected 'tr' but " +
                                                     $"element had '{gridRow.TagName}' instead.");
            }

            var bttn = gridRow.FindElement(viewButtonSelector);

            WrappedDriver
            .Wait(TimeSpan.FromSeconds(2))
            .UntilPageReloads(bttn, e => e.Click());

            return(pageObjectFactory.PreparePage <Order.IEditPage>());
        }
Beispiel #7
0
        /// <summary>
        /// If overridding this don't forget to call base.Load().
        /// NOTE: Will navigate to the pages url if the current drivers url
        /// is empty.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// If the driver is an EventFiringWebDriver an event listener will
        /// be added to the 'Navigated' event and uses the url to determine
        /// if the page is 'stale'.
        /// </remarks>
        public override ILoadableComponent Load()
        {
            base.Load();

            if (WrappedDriver.FindElements(pagingFilterSelcetor).Any())
            {
                PagingFilterComponent = new CatalogPagingFilterComponent(
                    By.CssSelector(".search-input"),
                    WrappedDriver);

                pageObjectFactory.PrepareComponent(PagingFilterComponent);
            }
            else
            {
                PagingFilterComponent = null;
            }

            if (WrappedDriver.FindElements(pagerSelector).Any())
            {
                PagerComponent = new PagerComponent(
                    By.CssSelector(".pager"),
                    WrappedDriver);

                pageObjectFactory.PrepareComponent(PagerComponent);
            }
            else
            {
                PagerComponent = null;
            }

            return(this);
        }
Beispiel #8
0
        /// <summary>
        /// Will click an element that will close the collapsable if not
        /// already closed and wait for the animation to finish.
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public virtual CollapsableComponent <T> Close(IWebElement element = null)
        {
            if (!IsExpanded())
            {
                if (element == null)
                {
                    if (CloseElements.Any())
                    {
                        CloseElements.First().Click();
                    }
                    else if (ToggleElements.Any())
                    {
                        ToggleElements.First().Click();
                    }
                    else
                    {
                        throw new NoSuchElementException("Failed to locate " +
                                                         "any elements to collpase the collapsable element.");
                    }
                }
                else
                {
                    element.Click();
                }

                WrappedDriver
                .Wait(animationData.AnimationDuration + TimeSpan.FromSeconds(2))
                .Until(d => !IsCurrentlyAnimating());
            }

            return(this);
        }
        /// <summary>
        /// If overridding this don't forget to call base.Load().
        /// NOTE: Will navigate to the pages url if the current drivers url
        /// is empty.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// If the driver is an EventFiringWebDriver an event listener will
        /// be added to the 'Navigated' event and uses the url to determine
        /// if the page is 'stale'.
        /// </remarks>
        public override ILoadableComponent Load()
        {
            base.Load();
            basePage.Load();

            pageObjectFactory.PrepareComponent(CategoriesComponent);
            pageObjectFactory.PrepareComponent(ManufacturersComponent);
            pageObjectFactory.PrepareComponent(PopularTagsComponent);

            // Verify this is displayed before loading it.
            if (WrappedDriver.FindElements(recentlyViewedProductsSelector).Any())
            {
                RecentlyViewProductsComponent = new CatalogBlockComponent(
                    recentlyViewedProductsSelector,
                    WrappedDriver);

                pageObjectFactory.PrepareComponent(RecentlyViewProductsComponent);
            }
            else
            {
                // Assign to null if not loaded.
                RecentlyViewProductsComponent = null;
            }

            return(this);
        }
        /// <summary>
        /// Retrieves the viewmodel.
        /// </summary>
        /// <returns></returns>
        public virtual HeaderLinksModel ViewModel()
        {
            var wait = WrappedDriver.Wait(TimeSpan.FromSeconds(30));

            var isLoggedIn           = wait.Exists(LogoutSelector.ToString());
            var hasShoppingCartItems = wait.Exists(ShoppingCartSelector);
            var hasPrivateMessages   = wait.Exists(PrivateMessagesSelector);
            var hasWishList          = WrappedDriver.FindElements(WishListSelector).Any();

            var model = new HeaderLinksModel
            {
                IsAuthenticated = isLoggedIn,
                CustomerName    = isLoggedIn
                    ? CustomerInfoElement.Text
                    : null,
                ShoppingCartEnabled = hasShoppingCartItems,
                ShoppingCartItems   = hasShoppingCartItems
                    ? ShoppingCartQtyElement.TextHelper().ExtractInteger()
                    : 0,
                AllowPrivateMessages  = hasPrivateMessages,
                UnreadPrivateMessages = hasPrivateMessages
                    ? PrivateMessageLabelElement.Text
                    : null,
                WishlistEnabled = hasWishList,
                WishlistItems   = hasWishList
                    ? WishListQtyElement.TextHelper().ExtractInteger()
                    : 0,
                Currency = CurrencyElement.SelectedOption.TextHelper().InnerText,
                Language = LanguageElement.SelectedOption.TextHelper().InnerText
            };

            return(model);
        }
        public void Navigate(string url)
        {
            bool tryAgain = false;

            try
            {
                WrappedDriver.Navigate().GoToUrl(url);
            }
            catch (Exception)
            {
                tryAgain = true;
            }

            if (tryAgain)
            {
                try
                {
                    WrappedDriver.Navigate().GoToUrl(url);
                }
                catch (Exception ex)
                {
                    throw new Exception($"Navigation to page {url} has failed after two attempts. Error was: {ex.Message}");
                }
            }
        }
Beispiel #12
0
        /// <summary>
        /// Finalizes and confirms the order.
        /// </summary>
        /// <param name="resolve">Called if</param>
        /// <param name="reject"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public virtual bool TryConfirm(Action <ICompletedPage> resolve,
                                       Action <ICheckoutPage> reject)
        {
            // Check if on right step.
            if (GetCurrentStepName() != "Confirm order")
            {
                throw new Exception("Not on correct step.");
            }

            ConfirmElement.Click();

            // Wait until the please wait message appears and then either
            // dissapears or becomes null.
            var result = WrappedDriver
                         .Wait(TimeSpan.FromSeconds(60 * 5))
                         .TrySequentialWait(
                out var exc,
                d => ConfirmPleaseWaitElement?.Displayed ?? true,
                d => !ConfirmPleaseWaitElement?.Displayed ?? true);

            if (result)
            {
                var completedPage = pageObjectFactory
                                    .PreparePage <ICompletedPage>();
                resolve(completedPage);
            }
            else
            {
                reject(this);
            }

            return(result);
        }
Beispiel #13
0
 private bool HasExistingShippingAddresses()
 {
     // If the element exists then there are existing addresses.
     return(WrappedDriver
            .FindElements(shippingAddressDropDownSelector)
            .Any());
 }
Beispiel #14
0
        /// <summary>
        /// Tries the go to step.
        /// </summary>
        /// <param name="stepName">Name of the step.</param>
        /// <param name="resolve">The resolve.</param>
        /// <param name="reject">The reject.</param>
        /// <param name="stringComparison">The string comparison.</param>
        /// <returns>
        /// The operation success status.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// resolve
        /// or
        /// reject
        /// </exception>
        /// <exception cref="NotImplementedException"></exception>
        public virtual bool TryGoToStep(string stepName,
                                        Action <ICheckoutStepPage> resolve = null,
                                        Action <ICheckoutStepPage> reject  = null,
                                        StringComparison stringComparison  = StringComparison.Ordinal)
        {
            if (String.IsNullOrEmpty(stepName))
            {
                throw new ArgumentNullException(stepName);
            }

            var indexOfStep = GetAllStepNames().IndexOf(
                name => String.Equals(
                    name,
                    stepName,
                    stringComparison));

            var result = TryGoToStep(indexOfStep, resolve, reject);

            if (result)
            {
                // For unknown reasons the step is changing correctly but the
                // step name is being a bit slow to update.
                WrappedDriver
                .Wait(TimeSpan.FromSeconds(1))
                .Until(d =>
                {
                    return(String.Equals(
                               GetCurrentStepName(),
                               stepName,
                               stringComparison));
                });
            }

            return(result);
        }
Beispiel #15
0
        /// <summary>
        /// Adds to cart and calls resolve/reject if the product was or wasn't
        /// added to the cart.
        /// </summary>
        /// <param name="resolve">The resolve.</param>
        /// <param name="reject">The reject.</param>
        /// <returns></returns>
        public virtual IBaseProductPage AddToCart(
            Action <IBaseProductPage> resolve,
            Action <IBaseProductPage> reject)
        {
            AddToCartButtonElement.Click();

            WrappedDriver
            .Wait(TimeSpan.FromSeconds(30))
            .Until(d => HasNotifications());

            HandleNotification(el =>
            {
                var hasError = el.Classes().Contains("error");

                DismissNotifications();

                if (hasError)
                {
                    reject(this);
                }
                else
                {
                    resolve(this);
                }
            });

            return(this);
        }
        /// <summary>
        /// Searches for product.
        /// </summary>
        /// <param name="productName">Name of the product.</param>
        public virtual void SearchForProduct(string productName)
        {
            var currentWindowHandle = WrappedDriver.CurrentWindowHandle;

            ProductNameElement.SetValue(productName);
            SearchElement.Click();

            WrappedDriver
            .Wait(TimeSpan.FromSeconds(2))
            .Until(d => !ProductsGrid.IsBusy());

            var firstCheckbox = ProductsGrid
                                .GetCell(0, 0)
                                .FindElement(By.TagName("input"));

            var checkbox = new CheckboxElement(firstCheckbox);

            checkbox.Check(true);
            SaveElement.Click();

            // Wait for the page to close.
            WrappedDriver
            .Wait(TimeSpan.FromSeconds(10))
            .Until(d => !d.WindowHandles.Contains(currentWindowHandle));
        }
        /// <summary>
        /// Gets the item by text.
        /// </summary>
        /// <param name="itemName">Name of the item.</param>
        /// <param name="stringComparison">The string comparison.</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public virtual MenuItemComponent GetItemByText(string itemName,
                                                       StringComparison stringComparison = StringComparison.Ordinal)
        {
            var menuItemEl = ItemElements.FirstOrDefault(el =>
            {
                return(el.FindElements(itemNameSelector)
                       .Any(name => String.Equals(
                                el.TextHelper().InnerText,
                                itemName,
                                stringComparison)));
            });

            if (menuItemEl == null)
            {
                throw new NoSuchElementException();
            }

            var cssSelector = WrappedDriver.GetCssSelector(menuItemEl);

            return(pageObjectFactory.PrepareComponent(
                       new MenuItemComponent(
                           cssSelector,
                           pageObjectFactory,
                           WrappedDriver)));
        }
        /// <summary>
        /// Since kendo events aren't compatible with native js events use this
        /// method to listen for kendo events.
        /// </summary>
        /// <param name="eventName">Name of the event to listen for.</param>
        protected virtual PromiseBody GetPromiseForKendoEvent(
            string eventName)
        {
            var script =
                "var callback = {resolve};" +
                "var $el = $({args}[0]);" +
                "var dropdown = $el.data().kendoDropDownList;" +
                "var unbindCallback = function () {" +
                $"dropdown.unbind('{eventName}', unbindCallback);" +
                "callback();" +
                "};" +
                $"dropdown.bind('{eventName}', unbindCallback);";

            var promise = new PromiseBody(WrappedDriver)
            {
                Arguments = new JavaScriptValue[]
                {
                    new JavaScriptValue(WrappedElement)
                },
                Script = script
            };

            promise.Execute(WrappedDriver.JavaScriptExecutor());

            return(promise);
        }
Beispiel #19
0
        /// <summary>
        /// Prints the order details.
        /// </summary>
        public virtual void Print()
        {
            var tabHelper   = WrappedDriver.TabHelper();
            var initialTabs = tabHelper.GetTabHandles().ToList();
            var initialTab  = WrappedDriver.CurrentWindowHandle;

            WrappedDriver
            .Wait(TimeSpan.FromSeconds(30))
            .Until(
                d => tabHelper.GetTabHandles().Count() > initialTabs.Count);

            WrappedDriver
            .SwitchTo()
            .Window(tabHelper
                    .GetTabHandles()
                    .Except(initialTabs)
                    .First());

            var printWindowHandle = WrappedDriver.CurrentWindowHandle;

            WrappedDriver.WaitForUserSignal(TimeSpan.FromMinutes(5));

            // Close the tab if it's still open.
            if (WrappedDriver.CurrentWindowHandle == printWindowHandle)
            {
                WrappedDriver.Close();
            }

            // Switch back to the initial window handle.
            WrappedDriver.SwitchTo().Window(initialTab);
        }
        /// <summary>
        /// Gets the DataSource for an individual series.  The igDataChart supports defining a single dataSource for all series, or individual data sources for each series.
        /// If the series does not has a DataSource explicitly defined then this method will return null, and you should call GetDataSource instead.
        /// </summary>
        /// <typeparam name="T">The object type for each item in the DataSource.</typeparam>
        /// <param name="seriesTitle">The title of the series you want to retrieve.</param>
        /// <returns>The DataSource as an IEnumerable of T.</returns>
        public IEnumerable <T> GetSeriesDataSource <T>(string seriesTitle)
        {
            string scriptString =
                @"var result;
                var series = $(arguments[0]).igDataChart('option', 'series');
	            for (var x = 0; x < series.length; x++) {
		            if (series[x].title == arguments[1] && series[x].hasOwnProperty('dataSource')) {
			            result = series[x].dataSource;
                        break;
		            }
	            }
                if (result != null)
                    return JSON.stringify(result);
                else
                    return null;";

            scriptString = Regex.Replace(scriptString, @"\t|\n|\r", ""); //I kept the script string in a readable format in the C# code, this line makes it a valid js script format
            var             jsResult   = WrappedDriver.ExecuteScript(scriptString, WrappedElement, seriesTitle) as string;
            IEnumerable <T> dataSource = null;

            if (jsResult != null)
            {
                dataSource = JsonConvert.DeserializeObject <IEnumerable <T> >(jsResult);
            }
            return(dataSource);
        }
        private void UpdateIntegrationMode()
        {
            if (TinyMCEContainerElement.FindElements(By.TagName("iframe")).Any())
            {
                // Only classic mode uses iframes.
                IntegrationMode = IntegrationMode.Classic;
            }
            else
            {
                // Could be either classic or distraction free.
                var script =
                    "var el = arguments[0];" +
                    "var editor = tinyMCEUtilities.getEditor(el);" +
                    "if (editor == null) {" +
                    "return false;" +
                    "} else {" +
                    "return editor.getParam('theme') === 'inlite';" +
                    "}";

                script = AddTinyMCEUtilities(script);

                var isDistractionFreeMode = (bool)WrappedDriver
                                            .JavaScriptExecutor()
                                            .ExecuteScript(script, WrappedElement);

                IntegrationMode = isDistractionFreeMode
                    ? IntegrationMode.DistractionFree
                    : IntegrationMode.Inline;
            }
        }
        private void WaitForInitalization()
        {
            var wait      = WrappedDriver.Wait(TimeSpan.FromSeconds(10));
            var timeoutMS = wait.Timeout.TotalMilliseconds;
            var pollingMS = wait.PollingInterval.TotalMilliseconds;

            var script =
                AddTinyMCEUtilities(String.Empty) +
                "var el = {args}[0];" +
                "var editor = tinyMCEUtilities.getEditor(el);" +
                "tinyMCEUtilities.waitForInitialization(editor," +
                $"{timeoutMS}," +
                $"{pollingMS}," +
                "{resolve}," +
                "{reject});";

            script = JavaScript.RemoveComments(script);
            script = JavaScript.Clean(script);

            var waiter = new PromiseBody(WrappedDriver)
            {
                Arguments = new[] { new JavaScriptValue(WrappedElement) },
                Script    = script
            };

            // Condense the script.
            waiter.Format();

            waiter.Execute(WrappedDriver.JavaScriptExecutor());
            wait.Until(d => waiter.Finished);
            waiter.Wait(TimeSpan.FromSeconds(10));
        }
Beispiel #23
0
        /// <summary>
        /// Selects the tag.
        /// </summary>
        /// <param name="tagText">The tag text.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public virtual TagEditorComponent <T> SelectTag(string tagText)
        {
            if (String.IsNullOrEmpty(tagText))
            {
                throw new ArgumentException($"{nameof(tagText)} cannot be " +
                                            $"null or empty.");
            }

            var selectedTags = SelectedTagElements;

            if (selectedTags.Any())
            {
                var lastActiveEl = selectedTags.Last();
                var width        = lastActiveEl.Size.Width;

                WrappedDriver.CreateActions()
                .MoveToElement(lastActiveEl)
                .MoveByOffset(width, 0)
                .Click()
                .SendKeys(tagText + Keys.Enter)
                .Perform();
            }
            else
            {
                WrappedDriver.CreateActions()
                .MoveToElement(TagEditorContainerElement)
                .Click()
                .SendKeys(tagText + Keys.Enter)
                .Perform();
            }

            return(this);
        }
Beispiel #24
0
        public void AddCookie(string cookieName, string cookieValue, string path = "/")
        {
            cookieValue = Uri.UnescapeDataString(cookieValue);
            var cookie = new Cookie(cookieName, cookieValue, path);

            WrappedDriver.Manage().Cookies.AddCookie(cookie);
        }
Beispiel #25
0
 public void SwitchToFrame(Frame frame)
 {
     if (frame.WrappedElement != null)
     {
         WrappedDriver.SwitchTo().Frame(frame.WrappedElement);
     }
 }
Beispiel #26
0
        /// <summary>
        /// Checks if a user is logged in.
        /// </summary>
        /// <returns></returns>
        public virtual bool IsLoggedIn()
        {
            var hasNopCookie = WrappedDriver.Manage().Cookies
                               .GetCookieNamed("NOPCOMMERCE.AUTH");

            return(hasNopCookie != null);
        }
Beispiel #27
0
        /// <summary>
        /// Begins the impersonation session.
        /// </summary>
        /// <returns></returns>
        public virtual Public.Home.IHomePage PlaceOrder()
        {
            WrappedDriver
            .Wait(TimeSpan.FromSeconds(10))
            .UntilPageReloads(PlaceOrderElement, e => e.Click());

            return(pageObjectFactory.PreparePage <Public.Home.IHomePage>());
        }
 private void _Write(string content)
 {
     WrappedDriver.CreateActions()
     .MoveToElement(EditableBodyElement)
     .Click()
     .SendKeys(content)
     .Perform();
 }
 private void _HighlightAllText()
 {
     WrappedDriver.CreateActions()
     .MoveToElement(EditableBodyElement)
     .Click()
     .SendKeys(Keys.LeftControl + "a")
     .Perform();
 }
        /// <summary>
        /// Saves the customer and continues to edit them on the
        /// <see cref="T:ApertureLabs.Selenium.NopCommerce.PageObjects.Shared.Admin.Customers.IEditPage" />.
        /// </summary>
        /// <returns></returns>
        public virtual IEditPage SaveAndContinue()
        {
            WrappedDriver
            .Wait(TimeSpan.FromSeconds(2))
            .UntilPageReloads(SaveAndContinueElement, el => el.Click());

            return(pageObjectFactory.PreparePage <IEditPage>());
        }