Coded Ui get past Loading Screen on all browsers - c#

I am using Microsoft Coded Ui on Visual Studio 2015 Update 1.
I am building coded Ui tests for the website am running into a problem on Chrome and Firefox. The website is onboard.passageways.com. There is a a div that has this information:
<div id="loadingOverlay" data-bind="fadeVisible: loading" style="display: none; width: 100%; height: 100%; position: fixed; top: 0px; right: 0px; bottom: 0px; left: 0px; z-index: 9999; background: rgb(204, 204, 204);">
Chrome and Firefox render the page so fast that they see the loadingOverlay when the style is "display: table". This loading overlay is on almost every part of the site.
My question is how do I tell Chrome and Firefox to wait for the loadingOverlay to display none so that it can click on the elements in the background.
I have tried this code but it keeps saying that the collection is at 1.
public static HtmlDiv GetOverlay(UITestControl parent, string id)
{
var div = new HtmlDiv(parent);
div.SearchProperties.Add(HtmlDiv.PropertyNames.Id, id);
GetOverlayProperty(div);
return div;
}
private static UITestControlCollection GetOverlayProperty(HtmlDiv overlay)
{
overlay.SearchProperties.Add(HtmlControl.PropertyNames.ControlDefinition, "display: table",
PropertyExpressionOperator.Contains);
UITestControlCollection collection = overlay.FindMatchingControls();
if (collection.Any())
{
GetOverlay(browser, "loadingOverlay");
}
return collection;
}
My Test Initialize
[TestInitialize]
public void ClassInitializer()
{
BrowserWindow.CurrentBrowser = ConfigurationManager.AppSettings.Get("Browser-Type");
CodedUIUtils.browser = BrowserWindow.Launch(new Uri(ConfigurationManager.AppSettings.Get("Browser-Url")));
CodedUIUtils.browser.CloseOnPlaybackCleanup = false;
CodedUIUtils.browser.Maximized = false;
}
My Login Test
[TestMethod]
public void LoginAndLogout()
{
CodedUIUtils.ClickButton(CodedUIUtils.browser, "PassagewaysLogin");
CodedUIUtils.LoginGuest(CodedUIUtils.browser);
CodedUIUtils.ClickLogon(CodedUIUtils.browser, "Logon");
HtmlDiv overlay = CodedUIUtils.GetOverlay(CodedUIUtils.browser, "loadingOverlay");
overlay.WaitForControlNotExist();
CodedUIUtils.ClickLink(CodedUIUtils.browser, "Log Out");
Playback.Wait(2000);
}
Login Utils
public static class CodedUIUtils
{
public static BrowserWindow browser;
public static void LoginGuest(BrowserWindow browser)
{
EnterText(browser, "Email", "onboardTestUserId+guest#gmail.com");
EnterText(browser, "LoginPassword", "Testing2!");
}
public static void ClickButton(UITestControl parent, string id)
{
var button = new HtmlButton(parent);
button.SearchProperties.Add(HtmlButton.PropertyNames.Id, id);
Mouse.Click(button);
}
public static void EnterText(UITestControl parent, string id, string value)
{
var edit = new HtmlEdit(parent);
edit.SearchProperties.Add(HtmlEdit.PropertyNames.Id, id);
edit.Text = value;
}
public static void ClickLink(UITestControl parent, string innerText)
{
var link = new HtmlHyperlink(parent);
link.SearchProperties.Add(HtmlHyperlink.PropertyNames.InnerText, innerText);
link.WaitForControlReady();
Mouse.Click(link);
}
public static void ClickLogon(UITestControl parent, string value)
{
var logonInput = new HtmlInputButton(parent);
logonInput.SearchProperties.Add(HtmlInputButton.PropertyNames.ValueAttribute, value);
Mouse.Click(logonInput);
}
}

It is a common best practice that when something may have loading time/intro animation or just in general to code with WaitForControlReady or WaitForControlExist Functions.
So unless you specifically really care about the loading overlay, then you can just put the function on the first object that the overlay is affecting you really want to interact with.
[TestMethod]
public void StackOverflow()
{
BrowserWindow browser = BrowserWindow.Launch(new Uri("https://onboard.passageways.com/"));
var _hyper = new HtmlButton(browser);
_hyper.SearchProperties.Add("ID", "PassagewaysLogin");
_hyper.WaitForControlReady();
LoadingOverlay(browser);
Mouse.Click(_hyper);
var _email = new HtmlEdit(browser);
_email.SearchProperties.Add("ID", "Email");
_email.WaitForControlReady();
LoadingOverlay(browser);
Keyboard.SendKeys(_email, "testemail#email.com");
Playback.Wait(10000);
}
public static void LoadingOverlay(BrowserWindow browser)
{
var _image = new HtmlDiv(browser);
_image.SearchProperties.Add("ID", "loadingOverlay");
_image.WaitForControlReady();
}

Related

Blazor (Server) not updating image using StateHasChanged();

I'm creating a blazor server App that should read the Webcam and show the Image, and while the Image generates fine (the base64 is completely valid) it's not updating the image on the Website even when using InvokeAsync(StateHasChanged);
Index.razor:
#page "/"
<PageTitle>Index</PageTitle>
<div style="width: 100%; height: 500px;border: solid green 1px">
<img src="#ImageSource" style="height: 100%; width: 100%; margin: auto; border: solid red 1px;"
/>
</div>
#code
{
public string? ImageSource { get; set; }
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Console.WriteLine("init");
Webcam.Instance?.Init(async bufferScope =>
{
byte[] image = bufferScope.Buffer.ExtractImage();
var ms = new MemoryStream(image);
ImageSource = ToBase64Image(Bitmap.FromStream(ms));
_forceRerender = true;
await InvokeAsync(StateHasChanged);
Console.WriteLine("running again");
}, true);
}
public static string ToBase64Image(Image bmp)
{
var data = GetPng(bmp);
return "data:image/png;base64," + Convert.ToBase64String(data.ToArray());
}
public static byte[] GetPng(Image bitmap)
{
using (var stream = new MemoryStream())
{
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}
bool _forceRerender = false;
protected override bool ShouldRender()
{
if (_forceRerender)
{
_forceRerender = false;
return true;
}
return base.ShouldRender();
}
}
If that helps here is my (rudimentary) webcam class (yes i know the way i have it isn't best practise but i wan't it to at least run):
using FlashCap;
namespace CameraServer.Data
{
public class Webcam
{
public static Webcam? Instance { get; private set; }
private CaptureDeviceDescriptor DeviceDescriptor { get; set; }
public CaptureDevice Device { get; private set; }
public Webcam(CaptureDeviceDescriptor deviceDescriptor)
{
DeviceDescriptor = deviceDescriptor;
Instance = this;
}
public async Task<Webcam?> Init(PixelBufferArrivedDelegate func, bool start = false)
{
Device = await DeviceDescriptor.OpenAsync(DeviceDescriptor.Characteristics[0], func);
if (start)
await Device.StartAsync();
return Instance;
}
//signal webcam to start
public void Start() => Device?.StartAsync();
//stop webcam (videoSource.WaitForStop(); to check)
public void Stop() => Device?.StopAsync();
}
}
If someone has a similar problem: The Issue was solved by changing the render-mode in _Host.cshtml from "ServerPrerendered" to "Server".
Thanks everyone who tried to help!

Teams Tookit Blazor - Unable to use Resize event across multiple tabs

I am currently trying to re-register an event I am using upon switching tabs.
The JS is:
window.resizeListener = function (dotnethelper) {
$(window).resize(() => {
let browserWidth = $(window).innerWidth();
let browserHeight = $(window).innerHeight();
dotnethelper.invokeMethodAsync('SetBrowserDimensions', browserWidth, browserHeight).then(() => {
// success, do nothing
}).catch(error => {
console.log("Error during browser resize: " + error);
});
});
}
window.getWindowDimensions = function () {
return {
width: window.innerWidth,
height: window.innerHeight
};
};`
I created the following Class:
using Microsoft.JSInterop;
namespace DevBlazor.Data
{
public class BrowserService
{
private IJSRuntime JS = null;
public event EventHandler<GetDimensions> Resize;
public async void Init(IJSRuntime js)
{
// enforce single invocation
if (JS == null)
{
this.JS = js;
_ = await JS.InvokeAsync<string>("resizeListener", DotNetObjectReference.Create(this));
}
}
[JSInvokable]
public void SetBrowserDimensions(int jsBrowserWidth, int jsBrowserHeight)
{
// For simplicity, we're just using the new width
this.Resize?.Invoke(this, new GetDimensions() { Width = jsBrowserWidth, Height = jsBrowserHeight });
}
}
public class GetDimensions
{
public int Width { get; set; }
public int Height { get; set; }
}
}
added as singleton in program.cs: builder.Services.AddSingleton<BrowserService>();
Then I use it in each tab:
private static Boolean bigWindowSize = true;
protected void UpdatedBrowserWidth(object sender, GetDimensions getDimensions)
{
wd = getDimensions;
Console.WriteLine("Width: " + wd.Width + Environment.NewLine + "Height: " + wd.Height);
if (wd.Width >= wd.Height)
{
bigWindowSize = true;
base.StateHasChanged();
}
else
{
bigWindowSize = false;
base.StateHasChanged();
}
}
async Task CreateSizeDimensions()
{
//just used to create an initial non-null starting value
wd = await JsRuntime.InvokeAsync<GetDimensions>("getWindowDimensions");
Console.WriteLine("Init Width: " + wd.Width + Environment.NewLine + "Init Height: " + wd.Height);
if (wd.Width >= wd.Height)
bigWindowSize = true;
else
bigWindowSize = false;
Browser.Init(JsRuntime);
Browser.Resize += UpdatedBrowserWidth;
}
Standard Init:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
isInTeams = await MicrosoftTeams.IsInTeams();
if (isInTeams)
{
await CreateSizeDimensions();
}
StateHasChanged();
}
}
I have tried:
Adding an IDisposable
Can't find a way to make it register more globally via the TabConfig.razor file, couldn't find ways to call the variables.
Make the main variables static on Welcome.razor and use them on another tab.
Make all main variables connected to this in each tab privately static since I can't make a global page to call from.
I am just trying to make the Resize event more of a global registration somehow with the Teams Tookit Tab app.
There were multiple problems.
JS == null was causing it to run 1 time no matter what so it would never invoke again.
After removing all statics and un-registering the event with IDisposable, no memory leaks should be left.
Issue is now resolved and loads/unloads on each tab.

Unable to locate element -- OpenQA.Selenium.NoSuchElementException

I am trying to automate a test case through Specflow, by using the Gherkin format, but I keep getting the error:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"xpath","selector":"./ancestor-or-self::form"}
The button that cannot be located is commented in the AddCart Page below.
The website that I am testing is: http://automationpractice.com/index.php
What I am trying to achieve is as seen below:
Feature: Adding products in the cart
Scenario Outline: Adding a product of the HomePage in the cart and continue shopping
Given That the user is on the HomePage
When User clicks the Add to cart button
And User clicks the Continue shopping button
Then The user will stay on the HomePage
The code of the Step Definition is:
namespace WebsiteTestingSpecflow.Steps
{
[Binding]
public sealed class AddingCartContinueStep
{
AddCartPage addcart = null;
[Given(#"That the user is on the HomePage")]
public void GivenThatTheUserIsOnTheHomePage()
{
IWebDriver webDriver = new ChromeDriver();
webDriver.Navigate().GoToUrl("http://automationpractice.com/index.php");
addcart = new AddCartPage(webDriver);
}
[When(#"User clicks the Add to cart button")]
public void WhenUserClicksTheAddToCartButton()
{
addcart.AddCart();
}
[When(#"User clicks the Continue shopping button")]
public void WhenUserClicksTheContinueShoppingButton()
{
addcart.ContinueShopping();
}
[Then(#"The user will stay on the HomePage")]
public void ThenTheUserWillStayOnTheHomePage()
{
addcart.Verifyelement();
}
}
}
The code of the AddCart Page is:
namespace WebsiteTestingSpecflow.Pages
{
public class AddCartPage
{
private readonly WebDriverWait wait;
public IWebDriver Webdriver { get; }
public AddCartPage(IWebDriver webDriver)
{
Webdriver = webDriver;
wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(30));
}
public IWebElement BtnAddCart => Webdriver.FindElement(By.CssSelector("#homefeatured > .ajax_block_product:nth-child(1) .button:nth-child(1) > span"));
// This is the button that I keep getting error.
public IWebElement btnContinueCart => Webdriver.FindElement(By.CssSelector(".continue > span"));
public void AddCart() {
BtnAddCart.Submit();
}
public void ContinueShopping() {
wait.Until(ExpectedConditions.ElementToBeClickable(By.CssSelector(".continue > span")));
btnContinueCart.Submit();
}
public void Verifyelement() => Webdriver.FindElement(By.CssSelector(".sfHover > .sf-with-ul"));
}
}
The CSS Selector of that button is as mentioned in the AddCart Page, but it still unable to locate the element.
May anyone know how can I fix this problem?
Thank you in advance.
Looks like you are trying to find element at the moment when it's not visible yet, because it will be visible only when you click to Add to cart and only then that element can be reached.
Try code below and also consider using Page Object model
public void ContinueShopping() {
IWebElement btnContinueCart => Webdriver.FindElement(By.CssSelector(".continue > span"));
wait.Until(ExpectedConditions.ElementToBeClickable(By.CssSelector(".continue > span")));
btnContinueCart.Submit();
}
You need to incorporate Actions into your code since this button is not visible unless you hover over it. Also add a wait condition around it
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
Actions action = new Actions(driver);
var btn = wait.Until(ExpectedConditions.ElementIsVisible(By.CssSelector("#homefeatured > .ajax_block_product:nth-child(1) .button:nth-child(1) > span")));
action.MoveToElement(driver.FindElement(By.CssSelector("#homefeatured > .ajax_block_product:nth-child(1) .button:nth-child(1) > span"))).Build().Perform();
btn.Click();
Add the following to the top:
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.UI;

Access Shared Resources from Tag Helper

I'm trying to access Shared Resources in a Tag Helper, but it doesn't return the value from the resource file even though I know it exists, only ResourceNotFound. I use IHtmlLocalizer to access shared resources in some of my views and it works fine so everything should be configured correctly.
Tag Helper:
[HtmlTargetElement("lc:buy-button", Attributes = "product", TagStructure = TagStructure.WithoutEndTag)]
public class BuyButtonTagHelper : BaseTagHelper
{
private readonly IStringLocalizer<SharedResources> _localizer;
public BuyButtonTagHelper(AppHelper app, IStringLocalizer<SharedResources> localizer) : base(app)
{
_localizer = localizer;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
.........
base.Process(context, output);
}
private string ProcessHtml(string html)
{
string result = html.Replace("{?productId?}", this.Product.ToString());
result = result.Replace("{?subscribeText?}", _localizer["SubscribeButtonText"].Value);
return result;
}
[HtmlAttributeName("product")]
public int Product { get; set; } = -1;
}
Solved it by installing the nuget package Microsoft.AspNetCore.Mvc.Localization

How to pass string from android render page to PCL page?

How to pass string value to android render page to PCL page.
I want to send token of eventArgs.Account.Properties["access_token"] to PCL page.
how can i do ?Please help.
[assembly: ExportRenderer(typeof(LoginPage), typeof(LoginRender))]
namespace TestApp.Droid.Renderers
{
public class LoginRender : PageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
// this is a ViewGroup - so should be able to load an AXML file and FindView<>
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "", // your OAuth2 client id
scope: "user_about_me", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri("https://www.facebook.com/dialog/oauth"), // the auth URL for the service
redirectUrl: new Uri("https://www.facebook.com/connect/login_success.html")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
if (eventArgs.IsAuthenticated)
{
Toast.MakeText(this.Context, eventArgs.Account.Properties["access_token"], ToastLength.Long).Show();
App.SuccessfulLoginAction.Invoke();
App.SaveToken(eventArgs.Account.Properties["access_token"]);
}
else
{
// The user cancelled
}
};
activity.StartActivity(auth.GetUI(activity));
}
}
}
App.cs
public class App
{
static NavigationPage _NavPage;
public static Page GetMainPage()
{
var profilePage = new ProfilePage();
_NavPage = new NavigationPage(profilePage);
return _NavPage;
}
public static bool IsLoggedIn
{
get { return !string.IsNullOrWhiteSpace(_Token); }
}
static string _Token;
public static string Token
{
get { return _Token; }
}
public static void SaveToken(string token)
{
_Token = token;
}
public static Action SuccessfulLoginAction
{
get
{
return new Action(() => {
_NavPage.Navigation.PopModalAsync();
});
}
}
}
above is my App.cs file code. static method can't return token.
ProfilePage.cs in PCL
public class ProfilePage : BaseContentPage
{
public ProfilePage()
{
string tk = App.Token;
var lbltoken = new Label()
{
FontSize = 20,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Text = tk,
};
var stack = new StackLayout
{
VerticalOptions = LayoutOptions.StartAndExpand,
Children = { lbltoken },
};
Content = stack;
}
}
I'm presuming that you have followed this example here: How to login to facebook in Xamarin.Forms
In that case you can use it in your PCL by calling App.Token
If that isn't working create a static property of the field you are using by calling App.SaveToken(eventArgs.Account.Properties["access_token"]);
With the edits you have made it is apparent that you set the value of your Label before the App.Token has a value.
A quick fix here could be to hook in to the Page.Appearing event, like so;
public class ProfilePage : BaseContentPage
{
private Label _lbltoken;
public ProfilePage()
{
Appearing += (object s, EventArgs a) => {
_lbltoken.Text = App.Token;
};
string tk = App.Token;
_lbltoken = new Label()
{
FontSize = 20,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Text = tk,
};
var stack = new StackLayout
{
VerticalOptions = LayoutOptions.StartAndExpand,
Children = { _lbltoken },
};
Content = stack;
}
}
I've made your Label control a private variable so we can easily refer to it from elsewhere, and create a Event-handler for when your ProfilePage appears.
So every time you Page appears, it will set the value of App.Token in your Label.
This should work. However you would probably be better of checking out techniques like MVVM.

Categories