Switch to at Iframe in selenium java - selenium

I am new using selenium and I am trying to test a web page. This page has as iframe and for the read I need do a switch, the switch I did was:
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame));
But it does not works, maybe somebody should be help me? Here is my code. this code of my page:
public class MainPage extends BasePageObject{
#FindBy(id = "cc-sa-item-logo")
WebElement iconLogin;
private By frame = By.xpath("//iframe[#id='cms']");
public MainPage() {
PageFactory.initElements(driver, this);
waitUntilPageObjectIsLoaded();
}
#Override
public void waitUntilPageObjectIsLoaded() {
wait.until(ExpectedConditions.visibilityOf(iconLogin));
}
public boolean logOutExists() {
boolean res = true;
String parentWindow = driver.getWindowHandle();
try{ wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame));
res = iconLogin.isDisplayed();
}finally {
driver.switchTo().window(parentWindow);
}
return res;
}
and this is the code of page the test:
<iframe id="cms" class="cms" src="/app/s9cea6fcedc36dd82/p430c9b54081c966d/" onload="this.loaded = true;" name="cms">
<!DOCTYPE html>
<html lang="es-ES">
<head>
<body id="page-2281940529" class="body cc-page cc-page-index cc-indexpage j-m-flash-styles j-m-gallery-styles j-m-video-styles j-m-hr-styles j-m-header-styles j-m-text-styles j-m-emotionheader-styles j-m-htmlCode-styles j-m-rss-styles j-m-form-styles-disabled j-m-table-styles j-m-textWithImage-styles j-m-downloadDocument-styles j-m-imageSubtitle-styles j-m-flickr-styles j-m-googlemaps-styles j-m-blogSelection-styles-disabled j-m-comment-styles j-m-jimdo-styles j-m-profile-styles j-m-guestbook-styles j-m-promotion-styles j-m-twitter-styles j-m-hgrid-styles j-m-shoppingcart-styles j-m-catalog-styles j-m-product-styles-disabled j-m-facebook-styles j-m-sharebuttons-styles j-m-externalSource-styles j-m-formnew-styles-disabled j-m-callToAction-styles j-m-turbo-styles j-m-spacing-styles j-m-googleplus-styles j-m-dummy-styles j-footer-styles cc-content-parent" style="background-position: -186px 0px;">
<div class="cc-bs cc-alert-container" ng-controller="cms.common.AlertCtrl"> </div>
<div id="cc-eh" data-display="cms-only">
<div id="cc-nav" class="cc-jimdo ui-draggable" data-display="cms-only">
<script>
<div id="cc-clipboard" class="cc-clipboard-scrolled-left cc-clipboard-scrolled-right cc-clipboard-empty" data-display="cms-only" style="right: 186px; display: block;">
<div id="cc-inner" class="cc-content-parent" style="padding-right: 186px; padding-top: 0px;">
<div id="cc-sa" data-display="cms-only" style="display: block;">
<div id="cc-sa-sidebar" ng-controller="cms.sa.SidebarCtrl">
<div class="cc-sa-sidebar-group cc-sa-sidebar-group--top">
<div class="cc-sa-sidebar-logo-open clear">
<span id="cc-sa-item-logo" class="cc-sa-sidebar-logo" data-params="/app/siteadmin/upgrade/index/,true" data-action="sidebarItem"> </span>
I need find the element of span tag

The issue here is that the first thing you do, after initializing the FindBy-annotated fields, is waitUntilPageObjectIsLoaded, which is implicitly calling driver.findElement(By.id("cc-sa-item-logo")).
And here it fails, as you haven't switched to the frame yet at this point, and unfortunately PageFactory is not able to handle that.
Basically you need to wrap each and every call to a FindBy-annotated field with a switchTo().frame/switchTo().defaultContent(). Just like you did in logOutExists.
For convenience, I would model the iframe in a separate page object (class), so as to encapsulate (and automate) the switching back and forth.
public class CmsIframe extends BasePageObject implements AutoCloseable {
#FindBy(id = "cc-sa-item-logo")
WebElement iconLogin;
private By frame = By.xpath("//iframe[#id='cms']");
public CmsIframe() {
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame));
PageFactory.initElements(driver, this);
waitUntilPageObjectIsLoaded();
}
#Override
public void waitUntilPageObjectIsLoaded() {
wait.until(ExpectedConditions.visibilityOf(iconLogin));
}
public boolean logOutExists() {
return iconLogin.isDisplayed();
}
#Override
public void close() {
driver.switchTo().defaultContent();
}
}
MainPage can then be re-written as follows:
public class MainPage extends BasePageObject{
private By frame = By.xpath("//iframe[#id='cms']");
public MainPage() {
PageFactory.initElements(driver, this);
}
public boolean logOutExists() {
try (CmsIframe cmsIframe = new CmsIframe()) {
return cmsIframe.logOutExists();
} // when exiting this try block, the driver will automatically be switched back out of the iframe (as part of CmsIframe#close)
}
}
Please note that thanks to implements AutoCloseable, CmsIframe can be used in a try-with-resources Statement (java > 7 only), which sorts of automates the switching back to the default content.
PS: if you could post the stacktrace with the exception you are getting, that would help help you.

I finally solved my problem, you had reason the problem was that I find the switch in the place incorrect. the solution was:
#Override
public void waitUntilPageObjectIsLoaded() {
String parentWindow = driver.getWindowHandle();
try{
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame));
wait.until(ExpectedConditions.visibilityOf(iconLogin));
}finally {
driver.switchTo().window(parentWindow);
}
}
public boolean logOutExists() {
boolean res = true;
String parentWindow = driver.getWindowHandle();
try{
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame));
res = iconLogin.isDisplayed();
}finally {
driver.switchTo().window(parentWindow);
}
return res;
}

Related

How to update a value on InputText [Blazor NetCore 5.0]

In my .razor page I have an InputText, what I want is to update that number as soon as it is being typed, specifically is to put a space every 4 characters, how am I trying to do it?
<InputText #bind-Value="oPagos.NumeroEnTarjeta" #onkeydown="#Tecleando" type="number"
onchange="()=>NumberChanged()" id="card-number" placeholder="1111 2222 3333 4444" class="input" maxlength="16" />
Then,
public void Tecleando(KeyboardEventArgs e)
{
//Console.WriteLine(e.Key);
oPagos.NumeroEnTarjeta = generateSpaces(oPagos.NumeroEnTarjeta);
Console.WriteLine(oPagos.NumeroEnTarjeta);
}
I have a function where I plan to take all the value from the bind, ie: oPayments.NumberOnCard, and every 4 spaces generate a space.
This does not work for me for two reasons.
the first number that I type is taken from the #Onkeydown event but the variable oPagos.NumeroEnTarjeta is empty.
I don't know how to update the value of the InputText, as I show in the following image I effectively modify the variable oPagos.NumeroEnTarjeta, but I can't get the user to see it rendered in the text box.
Should I take another way or how do I fix what I have? Thank you.
Update
I succeeded in doing something similar, but with two different events, onblur and onfocus.
I use onfocus to remove the spaces and I use onblur to add my spaces, however, what I would like to do is while I'm writing
I got some Problems with Dynamic Data using Bind-Value / Bind so i started using Blazorise and solve my problems, a possible solution is this one:
<Field>
<TextEdit Text="#opagos.NumeroEnTarjeta" TextChanged="#MethodThatBringSpaces"></TextEdit>
<Field>
Then in #code
Task MethodThatBringSpaces(string value){
opagos.NumeroEnTarjeta = generateSpaces(value);
}
Also you can use the data that you want (i use string in this case) and you can add the same things than blazor (id,placeholder,etc.)
Here's a set of code which I think does basically what you want. It was written to answer a similar question on here a few months ago! I've used dashes instead of spaces to show the space being filled. It's was coded in Net6.0 but should be Ok in Net5.0.
You will probably need to tweak it a little to fit your exact needs:
CreditCardCode.razor
#namespace StackOverflowAnswers.Components
#inherits InputBase<string>
<input #attributes="AdditionalAttributes"
class="#CssClass"
value="#stringValue"
#oninput="OnInput"
#onchange="this.OnValueChanged"
#onfocus="OnFocus"
#onblur="OnBlur"
/>
CreditCardCode.razor.cs
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using System.Text.RegularExpressions;
namespace StackOverflowAnswers.Components;
public partial class CreditCardCode : InputBase<string>
{
private string stringValue = String.Empty;
private string _currentValue = String.Empty;
// Sets up the initial value of the input
protected override void OnInitialized()
{
_currentValue = this.Value ?? string.Empty;
this.stringValue = this.GetCodeValue(_currentValue);
base.OnInitialized();
}
private async Task OnInput(ChangeEventArgs e)
{
var rawValue = e.Value?.ToString();
stringValue = "";
await Task.Yield();
_currentValue = this.GetCodeValue(rawValue ?? string.Empty);
this.stringValue = this.FormatValueAsString(_currentValue);
}
private async Task OnFocus(FocusEventArgs e)
{
stringValue = "";
await Task.Yield();
this.stringValue = this.FormatValueAsString(_currentValue);
}
private async Task OnBlur(FocusEventArgs e)
{
stringValue = "";
await Task.Yield();
this.stringValue = this.GetCodeValue(_currentValue);
}
// We set the base CurrentValueAsString to let it handle all the EditContext changes and validation process
private void OnValueChanged(ChangeEventArgs e)
=> this.CurrentValueAsString = e.Value?.ToString() ?? string.Empty;
// Necessary override for InputBase
protected override bool TryParseValueFromString(string? value, out string result, out string validationErrorMessage)
{
result = value ?? string.Empty;
if (!string.IsNullOrEmpty(value) && value.Length == 19)
{
validationErrorMessage = string.Empty;
return true;
}
else
{
validationErrorMessage = "Value must be nnnn-nnnn-nnnn-nnnn";
return false;
}
}
protected override string FormatValueAsString(string? value)
=> value ?? string.Empty;
private string GetCodeValue(string value)
{
value = new string(value.Where(c => char.IsDigit(c)).ToArray());
value = value.Length > 16
? value.Substring(0, 16)
: value;
var reg = new Regex(#"([0-9]{1,4})");
var matches = reg.Matches(value);
var outvalue = string.Empty;
if (matches.Count > 0)
{
foreach (Match match in matches)
{
outvalue = $"{outvalue}-{match.Value}";
}
outvalue = outvalue.Trim('-');
return outvalue;
}
return string.Empty;
}
}
Test Page
#page "/"
#using StackOverflowAnswers.Components
<h3>EditForm</h3>
<div class="container-fluid">
<EditForm EditContext=editContext>
<div class="row">
<div class="col-2">
Credit Card No:
</div>
<div class="col-4">
<CreditCardCode class="form-control" #bind-Value="this.model.CreditCardNo"/>
</div>
<div class="col-4">
<ValidationMessage For="() => this.model.CreditCardNo" />
</div>
</div>
</EditForm>
<div class="row">
<div class="col-2">
Credit Card No:
</div>
<div class="col-4">
#model.CreditCardNo
</div>
</div>
</div>
#code {
private EditContext? editContext;
private ModelData model = new ModelData();
protected override Task OnInitializedAsync()
{
this.editContext = new EditContext(model);
return Task.CompletedTask;
}
class ModelData
{
public string CreditCardNo { get; set; } = string.Empty;
}
}

Accessing ViewData in Layout for page with partial view not working

From a partial view, I want to include scripts or styles and have them rendered into the header or footer (instead of inline) so I have a taghelper and htmlextension that works when I used TempData in the htmlextensions, but if I use ViewData, it doesn't work. Any ideas why?
Partial view:
<style asp-resource-location="Header">
.partial1 {
background-color: red;
}
</style>
<h2>Test Partial</h2>
<script asp-resource-location="Footer">
alert("Partial1");
</script>
Htmlextensions:
public static IHtmlContent InlineScripts(this IHtmlHelper html, Enums.ResourceLocation location)
{
var result = new StringBuilder();
var scripts = html.ViewData.ContainsKey(location.ToString()) ? html.ViewData[location.ToString()] as List<string> : new List<string>();
foreach (var script in scripts)
{
result.Append(script);
}
var tag = new TagBuilder(location == Enums.ResourceLocation.Header ? "style" : "script");
tag.InnerHtml.SetHtmlContent(result.ToString());
return tag;
}
public static void AddInlineScriptParts(this IHtmlHelper html, Enums.ResourceLocation location, string script)
{
var scripts = html.ViewData.ContainsKey(location.ToString()) ? html.ViewData[location.ToString()] as List<string> : new List<string>();
scripts.Add(script);
html.ViewData[location.ToString()] = scripts;
}
Layout page:
#Html.InlineScripts(Enums.ResourceLocation.Header)
Style Taghelper:
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (Location != Enums.ResourceLocation.Header)
return;
var viewContextAware = _htmlHelper as IViewContextAware;
viewContextAware?.Contextualize(ViewContext);
var style = output.GetChildContentAsync().Result.GetContent();
_htmlHelper.AddInlineScriptParts(Location, style);
output.SuppressOutput();
}
I used ViewContext.HttpContext.Items and it works. I figured it would be better to use than TempData which uses session. If anyone has any reason why I shouldn't use this, please let me know. And if anyone knows why ViewData doesn't work, I would be interested to know also.

Selenium IE Page title is not working. Tried IWebDriver.Title

I asked this question last week and someone marked it as a duplicate. However the duplicate reference did not answer or give solution to my question.
I am trying to get the page title to a complicated html page. I am trying to get the 'By' locator used to find an element. This is the HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="ctl00_Head1"><title>
Smart Tracking System
</title><meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" /><link rel="shortcut icon" type="image/x-icon" href="../images/desktopicon.ico" /><link href="../App_Themes/appthemes/appstyles.css" type="text/css" rel="stylesheet" /><link href="../App_Themes/appthemes/calendarstyles.css" type="text/css" rel="stylesheet" /><link href="../App_Themes/appthemes/tabsstyles.css" type="text/css" rel="stylesheet" /></head>
<body>
When I copy the xpath from Firefox source code, it says the xpath is:
/html/head/title
I am using C# code to do the validation but I keep getting "LoadableComponentException..."
This is my C# code:
public class AccountsOverviewPage : CVALoadableComponent<AccountsOverviewPage>
{
private IWebDriver _driver;
private By textlabelPageHeader = By.XPath("//head[#class='title' and text()='Smart Tracking System']");
public AccountsOverviewPage()
{
_driver = ScenarioContext.Current.Get<IWebDriver>();
}
protected override void ExecuteLoad()
{
}
protected override bool EvaluateLoadedStatus()
{
if (!CVAElements.WaitForElementOnPageLoad(_driver, textlabelPageHeader))
{
UnableToLoadMessage = "Could not load Accounts Overview page within the designated timeout period";
return false;
}
return true;
}
public bool IsAt()
{
return CVAElements.CheckElementIsVisible(_driver, textlabelPageHeader);
}
}
I have even tried doing the validation by Id, and this time I used an element Id that I am sure is there:
private By textlabelPageHeader = By.Id("ctl00_Head1");
and still the validation failed. What am I not doing?? Please any assistance will be greatly appreciated.
UPDATE
This is how I am using the Driver.Title method:
public class AccountsOverviewPage : CVALoadableComponent<AccountsOverviewPage>
{
private IWebDriver _driver;
// error happens on this line:
string textlabelPageHeader = _driver.Title;
public string TextlabelPageHeader
{
get
{
return textlabelPageHeader;
}
set
{
textlabelPageHeader = value;
}
}
public AccountsOverviewPage()
{
_driver = ScenarioContext.Current.Get<IWebDriver>();
}
protected override void ExecuteLoad()
{
}
protected override bool EvaluateLoadedStatus()
{
if (!CVAElements.WaitForElementOnPageLoad(_driver, TextlabelPageHeader))
{
UnableToLoadMessage = "Could not load Accounts Overview page within the designated timeout period";
return false;
}
return true;
}
public bool IsAt()
{
return CVAElements.CheckElementIsVisible(_driver, TextlabelPageHeader);
}
and I getting error: "A field initializer cannot reference the non-static field, method, or property" here
string textlabelPageHeader = _driver.Title;
What you're trying to access - a page title - is not a web element. It's a property of the web page itself. In Selenium, you access the page title by:
String pageTitle = _driver.getTitle();
I program in Java, so that might not be the correct syntax for C#

Aurelia Custom element with dialog

I am having trouble with creating a custom element that will be used like
<shimmy-dialog type="video" href="/test">Hi</shimmy-dialog>
The custim element will replace this code with a href that when clicked should popup a dialog of a particular type.
Everything seems to work up until the point I try to open the dialog.
This is when I get the error
Unhandled rejection TypeError: Cannot set property 'bindingContext' of null
I do sometimes find the Aurelia errors a little cyptic.
I suspect it has something todo with the element not having a view.
The code is as follows
enum DialogType {
video = 1,
iframe
};
#inject(Bcp, DialogController)
export class ShimmyDialogModel {
private type : DialogType;
constructor(private bcp: Bcp, private controller : DialogController){
console.log("here");
}
async activate(state){
this.type = state['type'];
}
get isVideo() : boolean {
return this.type == DialogType.video;
}
get isIframe() : boolean {
return this.type == DialogType.iframe;
}
}
#noView
#processContent(false)
#customElement('shimmy-dialog')
#inject(Element, App, Bcp, DialogService)
export class ShimmyDialog {
#bindable public type : string;
#bindable public href;
#bindable public name;
private originalContent : string;
constructor(private element: Element, private app: App, private bcp: Bcp,
private dialogService: DialogService) {
this.originalContent = this.element.innerHTML;
}
bind() {
this.element.innerHTML = '' + this.originalContent + '';
}
attached() {
let self = this;
this.type = this.element.getAttribute("type");
let dialogType = DialogType[this.type];
this.element.children[0].addEventListener("click", function(){
if(dialogType == DialogType.iframe) {
self.dialogService.open({ viewModel: ShimmyDialogModel, model: {'type' : dialogType}}).then(response => {
});
}
else if(dialogType == DialogType.video) {
self.dialogService.open({ viewModel: ShimmyDialogModel, model: {'type' : dialogType}}).then(response => {
});
}
return false;
});
}
async typeChanged(newValue) {
this.type = newValue;
}
async hrefChanged(newValue) {
this.href = newValue;
}
}
The template for the dialog is below.
<template>
<require from="materialize-css/bin/materialize.css"></require>
<ai-dialog>
<ai-dialog-header>
</ai-dialog-header>
<ai-dialog-body>
<div if.bind="isVideo">
Video
</div>
<div if.bind="isIframe">
IFrame
</div>
</ai-dialog-body>
<ai-dialog-footer>
<button click.trigger="controller.cancel()">Close</button>
</ai-dialog-footer>
</ai-dialog>
</template>
Thanks for any help.
I solved this by seperating the classes into their own files.
Aurelia did no like having two export classes there.

composing html file in aurelia

I'd like to achieve something similar as "include" in android but in aurelia:
How to inject a plain html file content into my view, with binding evaluated within the parent View, and without using a custom element?
Binding innerhtml is not enough as, according to the doc, the bindings expressions are bypassed.
As already said by Ashley, using <compose view="./your-view.html"></compose> element will work with an existing HTML file and it will inherit the parent context.
If you want to compose HTML dynamically (from a file, database, or built-up programmatically) then using the ViewCompiler will give you the best performance and flexibility, as this is one layer less than compose compared to how aurelia builds custom elements internally.
I gave a similar answer to a different (but related) question here:
Aurelia dynamic binding
You'd use the text plugin to load your HTML file as text into a variable, and then pass that to the ViewCompiler. I have a custom element for this which, in terms of performance, is probably not better than compose but it does allow for more control when working with raw html as input and you could do your own performance optimizations specific to your situation as needed:
import * as markup from "text!./your-element.html";
export class SomeViewModel {
constructor() {
this.markup = markup;
}
}
And the view:
<template>
<dynamic-html html.bind="markup"></dynamic-html>
</template>
For completeness sake, here is the custom element I encapsulated the ViewCompiler in:
import {
customElement,
TaskQueue,
bindable,
ViewCompiler,
ViewSlot,
View,
ViewResources,
Container,
ViewFactory,
inlineView,
inject,
DOM
} from "aurelia-framework";
#customElement("dynamic-html")
#inlineView("<template><div></div></template>")
#inject(DOM.Element, TaskQueue, Container, ViewCompiler)
export class DynamicHtml {
#bindable()
public html: string;
public element: HTMLElement;
private tq: TaskQueue;
private container: Container;
private viewCompiler: ViewCompiler;
private runtimeView: View;
private runtimeViewSlot: ViewSlot;
private runtimeViewFactory: ViewFactory;
private runtimeViewAnchor: HTMLDivElement;
constructor(element, tq, container, viewCompiler) {
this.element = <HTMLElement>element;
this.tq = tq;
this.container = container;
this.viewCompiler = viewCompiler;
}
public bindingContext: any;
public overrideContext: any;
public bind(bindingContext: any, overrideContext: any): void {
this.bindingContext = bindingContext;
this.overrideContext = overrideContext;
if (this.html) {
this.htmlChanged(this.html, undefined);
}
}
public unbind(): void {
this.disposeView();
this.bindingContext = null;
this.overrideContext = null;
}
public needsApply: boolean = false;
public isAttached: boolean = false;
public attached(): void {
this.runtimeViewAnchor = <HTMLDivElement>this.element.firstElementChild;
this.isAttached = true;
if (this.needsApply) {
this.needsApply = false;
this.apply();
}
}
public detached(): void {
this.isAttached = false;
this.runtimeViewAnchor = null;
}
private htmlChanged(newValue: string, oldValue: void): void {
if (newValue) {
if (this.isAttached) {
this.tq.queueMicroTask(() => {
this.apply();
});
} else {
this.needsApply = true;
}
} else {
if (this.isApplied) {
this.disposeView();
}
}
}
private isApplied: boolean = false;
private apply(): void {
if (this.isApplied) {
this.disposeView();
}
this.compileView();
}
private disposeView(): void {
if (this.runtimeViewSlot) {
this.runtimeViewSlot.unbind();
this.runtimeViewSlot.detached();
this.runtimeViewSlot.removeAll();
this.runtimeViewSlot = null;
}
if (this.runtimeViewFactory) {
this.runtimeViewFactory = null;
}
if (this.runtimeView) {
this.runtimeView = null;
}
this.isApplied = false;
}
private compileView(): void {
this.runtimeViewFactory = createViewFactory(this.viewCompiler, this.container, this.html);
this.runtimeView = createView(this.runtimeViewFactory, this.container);
this.runtimeViewSlot = createViewSlot(this.runtimeViewAnchor);
this.runtimeViewSlot.add(this.runtimeView);
this.runtimeViewSlot.bind(this.bindingContext, this.overrideContext);
this.runtimeViewSlot.attached();
this.isApplied = true;
}
}
function createViewFactory(viewCompiler: ViewCompiler, container: Container, html: string): ViewFactory {
if (!html.startsWith("<template>")) {
html = `<template>${html}</template>`;
}
let viewResources: ViewResources = container.get(ViewResources);
let viewFactory = viewCompiler.compile(html, viewResources);
return viewFactory;
}
function createView(viewFactory: ViewFactory, container: Container): View {
let childContainer = container.createChild();
let view = viewFactory.create(childContainer);
return view;
}
function createViewSlot(containerElement: Element): ViewSlot {
let viewSlot = new ViewSlot(containerElement, true);
return viewSlot;
}