Can WatiN handle the CuteWebUI Uploader popup dialog? - dialog

My Background:
I am new to WatiN, but not new to writing automated Web UI tests. At my new job, we are trying to use WatiN for our Web UI tests (thanks to a few CUIT fails).
I've solved this problem in the past using ArtOfTest.WebAii, by using a Win32 mouse click with a magic number offset from the containing element, but I can't seem to find documentation on how to do that in WatiN and I can't figure it out myself :\
My problem:
This dialog appears and I can't seem to find a way for WatiN to click it.
The dialog has the following markup:
<OBJECT style="FILTER: alpha(opacity=1); WIDTH: 329px; HEIGHT: 100px; mozOpacity: 0.01; opacity: 0.01; mozopacity: 0.01" data="data:application/x-oleobject;base64, <a bunch of data>" width=329 height=100 type=application/x-silverlight-2></OBJECT>
<param name="source" value="/CuteWebUI_Uploader_Resource.axd?type=file&file=silverlight.xap&_ver=634334311861475176"/>
<param name="windowless" value="true" object="" <=""/>
my test code:
[TestMethod]
public void SomeTest()
{
Settings.MakeNewIeInstanceVisible = true;
Settings.AutoStartDialogWatcher = true;
Settings.AutoMoveMousePointerToTopLeft = false;
using (IE ie2 = new IE())
{
ie2.GoTo(URL);
ie2.Link(SomeButtonID).Click();
ie2.Image(AnotherButtonID).FireEvent("onclick");
// some debugging code wrapped around the next user action
// which is clicking on the attach file button
var helper = new DialogHandlerHelper();
using (new UseDialogOnce(ie2.DialogWatcher, helper))
{
Thread.Sleep(1 * 1000); // wait for attach button to be "ready"
// Click button that triggers the dialog that states:
// "file browsing dialog has been blocked"
// "please click here and try again"
//
ie2.Button(FileAttachButtonID).FireEvent("onclick");
}
foreach(string dialogHandler in helper.CandidateDialogHandlers)
{
// nothing prints out here :(
Console.Out.WriteLine(dialogHandler);
}
// debug print out all elements with tagname = object
foreach (Element objectElement in ie2.ElementsWithTag("object"))
{
StringBuilder elementInfo = new StringBuilder();
elementInfo.AppendLine("--------------------------------------------");
elementInfo.AppendLine("element.tagname = " + objectElement.TagName);
elementInfo.AppendLine("element.style = " + objectElement.Style);
elementInfo.AppendLine("element.type = " + objectElement.GetAttributeValue("type"));
elementInfo.AppendLine("element.data = " + objectElement.GetAttributeValue("data"));
elementInfo.AppendLine("--------------------------------------------");
Console.Out.WriteLine(elementInfo.ToString());
// none of these clicks make the dialog go away
objectElement.ClickNoWait();
objectElement.Click();
objectElement.DoubleClick();
objectElement.MouseEnter();
objectElement.MouseDown();
Thread.Sleep(500);
objectElement.MouseUp();
}
// wait to see if dialog disappears after click
Thread.Sleep(300 * 1000);
}
}
Any and all help will be very much appreciated.
Thanks!

Your control is a silverlight component which can't be automated with WatiN. Fortunately this you can combine WatiN and White to get the job done.
Following code is created and published by Leo Bartnik so ALL the credits go to him! Have a look at his blog post here. The following code in the comments:
He used the following versions.
watin-2.0.50.1179.zip from 2011-02-08 http://sourceforge.net/projects/watin/files/WatiN%202.x/2.0%20Final/
white 0.20 Binaries http://white.codeplex.com/releases/view/29694
public void WatiN_and_White_join_forces()
{
// Navigate to your webpage with WatiN
string url = "http://localhost[port#]/WatinWhiteTestLandingPage.aspx";
WatiN.Core.IE watin = new WatiN.Core.IE(url);
watin.Link(Find.ByText("click here)).Click();
// Attach the IE instance used by WatiN to White
InternetExplorerFactory.Plugin();
string title = "[browser title here]"; // will be something like "WatinWhiteHybrid - Internet Explorer provided by ..."
var ie = (InternetExplorerWindow)Application.Attach(watin.ProcessID).GetWindow(title);
White.WebBrowser.Silverlight.SilverlightDocument sl = ie.SilverlightDocument;
// Click the button in the silverlight control using White
sl.Get(SearchCriteria.ByAutomationId("ClickMeId")).Click();
}
btw don't know why the formating of this code is so way off....

So this was my hack solution:
Use Microsoft's Coded UI Test to click on the Silverlight dialog. However, CUIT is inferior to WatiN, so I run my test in WatiN and load CUIT for one, magical, click.
Additionally, I was not able to easily find the Silverlight object using CUIT, so I find the window behind it, find the window's center pixel and force a Microsoft.VisualStudio.TestTools.UITesting.Mouse.Click(). Yes, a hack inside of a hack, I am a very bad person, but I ran out of time and just needed something working.
If anyone has a more elegant solution, please share.
My solution code:
FileUploadDialogHandler helper = new FileUploadDialogHandler(attachmentPath);
using (new UseDialogOnce(ie.DialogWatcher, helper))
{
Thread.Sleep(1 * 1000); // wait for attach button to be "ready"
ie.Button(browseButtonID).FireEvent("onclick");
// When automating a file upload, there is a Silverlight popup in IE that forces an extra click
// before opening the file open dialog. WatiN does not support Silverlight automation
// and the popup element was acting quirky in Microsoft's Coded UI Test, so we find the
// dialog box UNDERNEATH the Silverlight popup and force one, lovely, mouse click.
//===== Entering Coded UI Test land, beware! =====================================
// initialize Coded UI Test
Playback.Initialize();
BrowserWindow.CurrentBrowser = "IE";
Process watinBrowserProcess = Process.GetProcessById(ie.ProcessID);
BrowserWindow cuitBrowser = BrowserWindow.FromProcess(watinBrowserProcess); // attach Coded UI Test to the IE browser WatiN initialized
// get the window underneath the Silverlight popup
UITestControl modalUnderSilverlightPopup = new UITestControl(cuitBrowser.CurrentDocumentWindow);
modalUnderSilverlightPopup.SearchProperties.Add("id", windowElementUnderPopupID);
// get the X and Y pixel center of the window
int centerX = modalUnderSilverlightPopup.BoundingRectangle.X + modalUnderSilverlightPopup.BoundingRectangle.Width / 2;
int centerY = modalUnderSilverlightPopup.BoundingRectangle.Y + modalUnderSilverlightPopup.BoundingRectangle.Height / 2;
// Click!
Mouse.Click(new Point(centerX, centerY));
// Shutdown Coded UI Test
Playback.Cleanup();
//===== End Coded UI Test land, you survived! yay! ============================
}

Related

SPFx solution with 2 pages / web-parts communicating

I am replacing a server side solution that allowed a master application page to fire headless window that talk to the originating page.
Now I am doing it in SPO with SPFx and so far I just used one page and web part with a big dialog that can't get out of the sending page.
My users want to be able to put the dialog on the second monitor so I think I have to do it in a different window / web part. I am planning a version 2.0 and collection ideas how to do it.
So far I think I will use "broadcast-channel" for communicating between the parent page/web part and the child page/web part.
I still need to figure out the following:
How to create a sharepoint page containing just a SPFx web part without all the side and top bla bla. (safe to hide by CSS?)
How to pass the spfxContext from parent to child
how to debug 2 separate SPFx projects at the same time while building the solution.
Any suggestion is welcomed. Samples even more 😘 
Thank you in advance.
Try to use an extension:
export default class CssInjectApplicationCustomizer
extends BaseApplicationCustomizer<ICssInjectApplicationCustomizerProperties> {
#override
public onInit(): Promise<void> {
const cssUrl: string = '/SiteAssets/inject.css';
const head: any = document.getElementsByTagName("head")[0] || document.documentElement;
let customStyle: HTMLLinkElement = document.createElement("link");
customStyle.href = cssUrl;
customStyle.rel = "stylesheet";
customStyle.type = "text/css";
head.insertAdjacentElement("beforeEnd", customStyle);
return Promise.resolve();
}
}
inject.css:
/* Hide header */
#SuiteNavPlaceHolder, .od-SuiteNav{
display:none !Important;
}
/** Hide options header **/
div[class^="sideActionsWrapper-"],
.sideActionsWrapper-53 .ms-searchux-searchbox {
display: none;
}
/** Hide header lists**/
.CanvasSection .ms-DetailsList-headerWrapper,
.CanvasSection div[class^="itemsViewDetailsListCommandBar_"]{
display: none;
}
/** Hide Header page **/
div[class^="detailsListContainer_"],
.ControlZoneEmphasisBackground,
.root-63,
.root-76{
background-color:transparent;
}

SharePoint WebPart Context Menu is going inside div (please see picture)

I have created MasterPage and page layout. Then I created a page using page layout. Then by editing the page, I added content editor web part but there was one issue that web part context menu was going inside div. Kindly see attached image.
your response would be highly appreacited.
Thanksenter image description here
it may helped somebody that I managed it programmatically using javascript.
when icon will be clicked then javascript function will be fired which will check the height of context menu and if the height is greater than the height of the web part then it will increase the height of the zone height. please see code below.
var menulistheight;
var zoneid;
jQuery('.js-webpart-menuCell').click(function (e) {
if (!menulistheight) {
var dd = jQuery('.ms-core-menu-list');
dd = dd.height();
menulistheight = dd;
}
var zone = $(e.target).closest("#MSOZone")[0];
var id = jQuery(zone).attr("zoneid");
var zHeight = jQuery(zone).height();
if (zHeight < menulistheight) {
jQuery(zone).css("height", zHeight + menulistheight - 100 + "px");
}
});

LWUIT move all commands from the form to the "slide context menu"

I am trying to make a calculator for nokia 501 asha and i want all my buttons to fit on the the screen so that i don't have to scroll the form to access all buttons.
Apparently adding commands like exit,about and help are mandatory to your app.
Now when i add these commands one of the commands appear as a button and occupy a lot of screen space which i don't want.
I want my commands to appear like this i.e all commands on the slide context menu.
But instead there's an unnecessary button on the screen.
The code that i have used to add commands is as follows:
Form a = new Form("form");
a.addCommand(new Command("exit"),0);
a.addCommand(new Command("HELP"),1);
a.addCommand(new Command("ABOUT"),2);
a.setEnabled(true);
a.show();
So, what modifications i need to make in that code so that all my commands appear on the slide context menu ?
I am looking the Asha UI Component Demos, in the Menu section, options menu. I find this code to add the Commands:
// The rest appear in menu
Command menuCommand1 = new Command("Command 2", Command.SCREEN, 1);
addCommand(menuCommand1);
Command menuCommand2 = new Command("Command 3", Command.SCREEN, 2);
addCommand(menuCommand2);
Command menuCommand3 = new Command("Command 4", Command.SCREEN, 3);
addCommand(menuCommand3);
Try to put this Command.SCREEN parameter.
This answer will help to someone. The following code is working in 501.
protected void startApp() throws MIDletStateChangeException {
// TODO Auto-generated method stub
Display.init(this);
// For hide the form title bar. It is working in Nokia asha 501.
Display.getInstance().setForceFullScreen(true);
Display.setObjectTrait(Display.getInstance().getImplementation(), "nokia.ui.canvas.status_zone", Boolean.TRUE);
Form a = new Form("form");
a.addCommand(new Command("exit"),0);
a.addCommand(new Command("HELP"),1);
a.addCommand(new Command("ABOUT"),2);
a.setEnabled(true);
a.show();
}

Paste as plain text Contenteditable div & textarea (word/excel...)

I would like the to paste text in a contenteditable div, but reacting as a textarea.
Note that I want to keep the formatting as I would paste it in my textarea (from word, excel...).
So.
1) Paste text in contenteditable div
2) I get the text from clipboard
3) I push my value from clipboard to my textarea, (dont know how??)
4) Get value from my textarea and place it in my contenteditable div
Any suggestions?
I'm CKEditor's core developer and by coincidence for last 4 months I was working on clipboard support and related stuff :) Unfortunately I won't be able to describe you the entire way how pasting is handled, because the tales of the impl are too tricky for me even after writing impl by myself :D
However, here're some hints that may help you:
Don't write wysiwyg editor - use one that exists. It's going to consume all your time and still your editor will be buggy. We and guys from other... two main editors (guess why only three exist) are working on this for years and we still have full bugs lists ;).
If you really need to write your own editor check out http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/clipboard/plugin.js - it's the old impl, before I rewrote it, but it works everywhere where it's possible. The code is horrible... but it may help you.
You won't be possible to handle all browsers by just one event paste. To handle all ways of pasting we're using both - beforepaste and paste.
There's number (huge number :D) of browsers' quirks that you'll need to handle. I can't to describe you them, because even after few weeks I don't remember all of them. However, small excerpt from our docs may be useful for you:
Paste command (used by non-native paste - e.g. from our toolbar)
* fire 'paste' on editable ('beforepaste' for IE)
* !canceled && execCommand 'paste'
* !success && fire 'pasteDialog' on editor
Paste from native context menu & menubar
(Fx & Webkits are handled in 'paste' default listner.
Opera cannot be handled at all because it doesn't fire any events
Special treatment is needed for IE, for which is this part of doc)
* listen 'onpaste'
* cancel native event
* fire 'beforePaste' on editor
* !canceled && getClipboardDataByPastebin
* execIECommand( 'paste' ) -> this fires another 'paste' event, so cancel it
* fire 'paste' on editor
* !canceled && fire 'afterPaste' on editor
The rest of the trick - On IEs we listen for both paste events, on the rest only for paste. We need to prevent some events on IE, because since we're listening for both sometimes this may cause doubled handling. This is the trickiest part I guess.
Note that I want to keep the formatting as I would paste it in my textarea (from word, excel...).
Which parts of formatting do you want to keep? Textarea will keep only basic ones - blocks formatting.
See http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js#L120 up to line 123 - this is the last part of the task - inserting content into selection.
Current solution works perfect in IE/SAF/FF
But still i need a fix for "non" keyboard events, when pasting with mouse click...
Current solution for keyboard "paste" events:
$(document).ready(function() {
bind_paste_textarea();
});
function bind_paste_textarea(){
var activeOnPaste = null;
$("#mypastediv").keydown(function(e){
var code = e.which || e.keyCode;
if((code == 86)){
activeOnPaste = $(this);
$("#mytextarea").val("").focus();
}
});
$("#mytextarea").keyup(function(){
if(activeOnPaste != null){
$(activeOnPaste).focus();
activeOnPaste = null;
}
});
}
<h2>DIV</h2>
<div id="mypastediv" contenteditable="true" style="width: 400px; height: 400px; border: 1px solid orange;">
</div>
<h2>TEXTAREA</h2>
<textarea id="mytextarea" style="width: 400px; height: 400px; border: 1px solid red;"></textarea>
I have achieved this using rangy library to save and restore selections.
I also perform some other work using the library in the same functions, which I have stripped out of this example, so this is not optimal code.
HTML
<div><div id="editor"contenteditable="true" type="text"></div><div>
Javascript
var inputArea = $element.find('#editor');
var debounceInterval = 200;
function highlightExcessCharacters() {
// Bookmark selection so we can restore it later
var sel = rangy.getSelection();
var savedSel = sel.saveCharacterRanges(editor);
// Strip HTML
// Prevent images etc being pasted into textbox
inputArea.text(inputArea[0].innerText);
// Restore the selection
sel.restoreCharacterRanges(editor, savedSel);
}
// Event to handle checking of text changes
var handleEditorChangeEvent = (function () {
var timer;
// Function to run after timer passed
function debouncer() {
if (timer) {
timer = null;
}
highlightExcessCharacters();
}
return function () {
if (timer) {
$timeout.cancel(timer);
}
// Pass the text area we want monitored for exess characters into debouncer here
timer = $timeout(debouncer, debounceInterval);
};
})();
function listen(target, eventName, listener) {
if (target.addEventListener) {
target.addEventListener(eventName, listener, false);
} else if (target.attachEvent) {
target.attachEvent("on" + eventName, listener);
}
}
// Start up library which allows saving of text selections
// This is useful for when you are doing anything that might destroy the original selection
rangy.init();
var editor = inputArea[0];
// Set up debounced event handlers
var editEvents = ["input", "keydown", "keypress", "keyup", "cut", "copy", "paste"];
for (var i = 0, eventName; eventName = editEvents[i++];) {
listen(editor, eventName, handleEditorChangeEvent);
}

Can't prevent ModalDialog to close in SharePoint Web Part

I am calling SP.UI.ModalDialog.showModalDialog() in a javascript function of my Web Part (SharePoint 2010) but the dialog appears for one second, then closes itself.
Originally, I wanted to call a sharepoint page (in Layouts folder) but I am testing with a simple dialog to make sure it isn't an error in my sharepoint page.
In the Web Part, I have a table where each first cell row is a LinkButton. I have set the OnClientClick to call a javascript function :
linkButton.OnClientClick = string.Format("OpenNotationCurveDialog('{0}');",
notation.code);
In the script block of the web part ASCX, I have :
function OpenNotationCurveDialog(notationCode) {
var htmlElement = document.createElement('p');
var helloWorldNode = document.createTextNode('Hello world!');
htmlElement.appendChild(helloWorldNode);
var options = {
title: "Add item",
allowMaximize: true,
showClose: true,
width: 800,
height: 600,
html: htmlElement,
dialogReturnValueCallback: CurveDialog_ClosedCallback
};
SP.UI.ModalDialog.showModalDialog(options);
return false;
}
function CurveDialog_ClosedCallback(result, value) {
console.log('!! CurveDialog_ClosedCallback !!');
}
The function CurveDialog_ClosedCallback is never called.
In the same Web Part, I have added an element to the Web Part menu that calls the javascript function SP.UI.ModalDialog.showModalDialog() : it is working perfectly. I don't understand why it is working when calling showModalDialog() from the menu and not working from the LinkButton client event.
Any idea how to solve this very annoying behavior ?
thx
What probably happens is that the linkbutton performs a postback so that the page reloads, causing the dialog to disappear Try using a simple anchor-tag instead.

Resources