Unable to use Console.Log() within a WebBrowser Control - javascript

So I'm writing a Javascript coding UI using C# Windows Forms. This is my code for when the "Run" button is pressed, in case it helps:
//If the button in the upper-right corner is clicked
private void run_Click(object sender, EventArgs e)
{
//If the program isn't running
if (!running)
{
//Show the web browser
webBrowser1.Visible = true;
richTextBox1.Visible = false;
//Set the label to Running
status.Text = "Running";
//Set the html text to this below
webBrowser1.DocumentText = "<!DOCTYPE html><html><body><script>\n" + richTextBox1.Text + "\n</script></body></html>";
//Set the "run" button to "stop"
run.Text = "Stop";
//Set the status to running
running = true;
}
//otherwise
else
{
//Show the text box
webBrowser1.Visible = false;
richTextBox1.Visible = true;
//Set the label to Ready
status.Text = "Ready";
//Go to nothingness
webBrowser1.Navigate("about:blank");
//Set the "stop" button to "run"
run.Text = "Run";
//Set the status to not running
running = false;
}
}
I run the program, and for the most part, everything works fine. However, when I try to use the console.log() command, the following error appears:
'console' is undefined
I also try Console.Log (I actually don't know Javascript; just trying my best) but that returns the same error, that 'Console' is undefined.
Also, once I get console.log working, how do I open the console on the WebBrowser control? I've tried searching the internet, but nothing has come up on either of these questions.

You can get JavaScript console output from within Visual Studio.
By default the webBrowser1 control uses IE7 to render it's output. IE7 does not have a console.log() function. In order to get the console.log() function to work, you need to add the following meta tag:
<meta http-equiv="X-UA-Compatible" content="IE=11">
'IE=8' or greater should make the console.log() available to you.
When you debug a Windows Forms application it debugs using the .NET Managed Code debugger. In order to debug differently, instead of pressing 'Play' to debug, try selecting "Debug" > "Start without Debugging". Now once your application is running, go to "Debug" > "Attach to Process" and find your WindowsFormsApplication.exe, attach to it using the Script Code Debugger instead of the .NET Managed Code debugger.
Now, in Visual Studio:
You can open "Debug" > "Windows" > "JavaScript Console"
You can also open "Debug" > "Windows" > "DOM Explorer"

Yes, Console class is not available in your browser control, but you can create a logger class like this
[ComVisible(true)]
public class Logger
{
public void log(string s)
{
Console.WriteLine(s);
}
}
and use it in your browser control
webBrowser1.ObjectForScripting = new Logger();
webBrowser1.DocumentText = "<script>external.log('TEST');</script>";

Related

Open a Browser Window with Javascript on Xamarin.Forms

I have a Xamarin.Forms app. It includes a button like this:
<Button x:Name="Buy_Button" Text="Satın Al" FontAttributes="Bold" TextColor="#e2e2e2" BackgroundColor="#2A52BE" FontFamily="Segoe UI" Grid.Column="2" Grid.ColumnSpan="1" Grid.RowSpan="1" CornerRadius="5" VerticalOptions="Start" HorizontalOptions="Center" FontSize="15.667" Grid.Row="0" Margin="0,10,10,0" Clicked="Buy_Button_ClickedAsync" CommandParameter="{Binding Buy_URL}" />
I'm sending a URL link to click event for opening specific web page. Code is:
private async void Buy_Button_ClickedAsync(object sender, EventArgs e)
{
Button btn = (Button)sender; // Coming button from click event handler.
var buylink = btn.CommandParameter.ToString(); // Get the CommandParameter.
// await DisplayAlert("Satın alma linki", buylink, "Anladım"); // Show the link.
try // Uwp & iOS & Android
{
await Browser.OpenAsync(new Uri(buylink), BrowserLaunchMode.SystemPreferred); // Open url in-app browser for iOS & Android- native in UWP
}
catch (NotImplementedInReferenceAssemblyException ex) //Wasm falls here because lack of Xamarin.Essentials.
{
// await DisplayAlert("Hata", ex.Message, "Anladım"); // Show the info about exception.
// Jint - nt is a Javascript interpreter for .NET which provides full ECMA 5.1 compliance and can run on any .NET platform.
//Because it doesn't generate any .NET bytecode nor use the DLR it runs relatively small scripts faster.
//https://github.com/sebastienros/jint
var engine = new Engine();
engine.SetValue("log", new Action<object>(Console.WriteLine));
engine.Execute(#"function openurl() { log('" + buylink + "'); }; openurl(); ");
}
}
In UWP, Xamarin.iOS and Xamarin. Android this code is running via Xamarin.Esssentials:
await Browser.OpenAsync(new Uri(buylink), BrowserLaunchMode.SystemPreferred); // Open url in-app browser for iOS & Android- native in UWP
However, my Xamarin.Forms app projected to WebAssembly code with Uno Platform, so this code block not running. As a result. I install Jint to Xamarin.Forms app. This catch block prints the link to Browser console, but no window.open function track in API reference:
catch (NotImplementedInReferenceAssemblyException ex) //Wasm falls here because lack of Xamarin.Essentials.
{
// await DisplayAlert("Hata", ex.Message, "Anladım"); // Show the info about exception.
// Jint - nt is a Javascript interpreter for .NET which provides full ECMA 5.1 compliance and can run on any .NET platform.
//Because it doesn't generate any .NET bytecode nor use the DLR it runs relatively small scripts faster.
//https://github.com/sebastienros/jint
var engine = new Engine();
engine.SetValue("log", new Action<object>(Console.WriteLine));
engine.Execute(#"function openurl() { log('" + buylink + "'); }; openurl(); ");
}
}
How can I open WebBrowser page on WASM via Javascript form Xamarin.Forms C# code? Thanks.
2 things:
1. Use the browser!
On Wasm, you're running in a webassembly environment, which is running in a javascript virtual machine (that's not totally accurate, but close enough for my point). That means you can directly invoke the javascript of the running environment (browser).
Making a call to native javascript...
WebAssemblyRuntime
.InvokeJS("(function(){location.href=\"https://www.wikipedia.com/\";})();");
In your case, since you want to open a browser window, it's required to use this approach, because Jint can't access anything from the browser itself.
2. You can still call Jint anyway (but not to open a new window)
If you still want to call code using Jint (because you can!!), you need to exclude the Jint.dll assembly from the linking process. Probably because it's using reflection to operate. Again, it won't work to open a window as you're asking, but if you need to call Jint for any other reason, it will work as on other platforms!
Add this to your LinkerConfig.xml (in the Wasm project):
<assembly fullname="Jint" />
Also... You gave me an idea and I did something cool with Jint...
I put the entire solution there: https://github.com/carldebilly/TestJint
It works, even on Wasm:
Interesting code:
https://github.com/carldebilly/TestJint/blob/master/TestJint/TestJint.Shared/MainPage.xaml.cs#L18-L40
private void BtnClick(object sender, RoutedEventArgs e)
{
void Log(object o)
{
output.Text = o?.ToString() ?? "<null>";
}
var engine = new Engine()
.SetValue("log", new Action<object>(Log));
engine.Execute(#"
function hello() {
log('Hello World ' + new Date());
};
hello();
");
#if __WASM__
output2.Text =
WebAssemblyRuntime.InvokeJS("(function(){return 'Hello World ' + new Date();})();");
#else
output2.Text = "Not supported on this platform.";
#endif
}
Final Note
On UWP/WinUI XAML, you can directly put a <Hyperlink /> in your XAML. I'm not familiar enough with Xamarin Forms to know if there's an equivalent.
I am using Device.OpenUri and it works in WASM with Xamarin.Forms
Device.OpenUri(new Uri("https://www.bing.com"));

Synchronization problems with automated testing Angular website with Selenium and testing issues with Internet Explorer.

I am trying to write an automated test program for one of my website using Selenium WEbDriver. I am having some problems when doing the test on Internet Explorer. The website that I am trying to test is built in AngularJS. I will explain my problems in detail.
Here, is the code that waits until Angular has finished processing.
private static ExpectedCondition angularHasFinishedProcessing() {
return (ExpectedCondition<Boolean>) driver -> {
String hasAngularFinishedScript = "var callback = arguments[arguments.length - 1];\n" +
"var el = document.querySelector('html');\n" +
"if (!window.angular) {\n" +
" callback('false')\n" +
"}\n" +
"if (angular.getTestability) {\n" +
" angular.getTestability(el).whenStable(function(){callback('true')});\n" +
"} else {\n" +
" if (!angular.element(el).injector()) {\n" +
" callback('false')\n" +
" }\n" +
" var browser = angular.element(el).injector().get('$browser');\n" +
" browser.notifyWhenNoOutstandingRequests(function(){callback('true')});\n" +
"}";
JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
assert javascriptExecutor != null;
String isProcessingFinished = javascriptExecutor.executeAsyncScript(hasAngularFinishedScript).toString();
return Boolean.valueOf(isProcessingFinished);
};
}
private void waitForAngular() {
WebDriverWait wait = new WebDriverWait(driver, 15, 100);
wait.until(angularHasFinishedProcessing());
}
And here is the code that instantiates WebDriver for Internet Explorer.
System.setProperty("webdriver.ie.driver",
new File("H:/libraries/webdrivers/IEDriverServer.exe").getAbsolutePath());
DesiredCapabilities d = DesiredCapabilities.internetExplorer();
// To bypasse the Protected Mode settings of IE
d.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
driver = new InternetExplorerDriver(d);
driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
driver.manage().window().maximize();
driver.get("https://arandomangularjsapp.com"); // Let's suppose this
I had to bypass the Protected Mode settings (shown in above code) because I was constantly getting this Exception
Caused by: org.openqa.selenium.WebDriverException: Unexpected error launching Internet
Explorer. Protected Mode must be set to the same value (enabled or disabled) for all
zones. (WARNING: The server did not provide any stacktrace information)
though I made sure that protected mode was enabled and same values were set for all zones.
Now comes the real issue I am having. Look at this block of code,
waitForAngular();
WebElement el = driver.findElement(By.xpath("//div[#class='events-list__event-info' and #id='48040']" +
"//following-sibling::div[#class='events-list__event-buy']/a"));
if(driver.toString().toUpperCase().contains("INTERNETEXPLORER"))
el.sendKeys(Keys.ENTER);
else
el.click();
waitForAngular();
webElement = driver.findElement(By.xpath("(//div[#class='ticket u-cf ng-scope'])[1]//select"));
select = new Select(webElement);
select.selectByIndex(1);
My first question, the way I am trying to wait for Angular app to get ready by calling waitForAngular(), is it a good way? In my program I even had to use Thread.sleep() so many times in order to let elements to properly render before I could invoke actions on them. It would be great if you guys can suggest me a proper way to use Selenium WebDriver along with Angular App.
Now let's talk about my second issue. I had to completely disable Protected Mode from Internet Explorer's options in order to run the program. Otherwise, I would get this exception,
Caused by: org.openqa.selenium.JavascriptException: JavaScript error in async script. (WARNING: The server did not provide any stacktrace information)
I get this exception when trying to execute waitForAngular(). What could be causing this? Is there any way by which I could keep the Protected Mode enabled and still be able to execute that script inside angularHasFinishedProcessing() method?
Finally, my third problem is related to click action not being triggered. Forget about the previous issues for a second. I disabled IE's Protected Mode, so my program starts IE without throwing any exception. The program successfully finds the first element as shown in the code above. But, the click action is not triggered, browser thus doesn't navigate to next page, and the program fails to find the second element. As a workaround I even tried el.sendKeys(Keys.ENTER); but it didn't work.** So, am I having this problem because I bypassed/disabled Protected Mode? Or, is there something else that I am not being able to see?**
I run tests on IE, Opera, Chrome and Firefox and the problem seems to occur only in IE. Any sort of help, suggestions or guidelines are highly appreciated.
Thank You.

programmatically print a web page

I am making a program to automatically go to a website and print a page, Can't seem to make it work, I tried selenium chrome driver, problem is it doesn't work. i tried action.sendkeys keys ctrl + shift + p to no avail, the biggest problem is print preview pop-up.
I tried sending JavaScript command: window.print(), but the print preview in chrome stands in my way, because you need to press enter. Is there a way in JavaScript to simulate the pressing of the ENTER key? Help would be appreciated.
Well, after a bit of research, I found this video, if you can add these switches: "--kiosk --kiosk-printing", to the chrome driver start, it would automatically skip the print preview prompt, just as shown in the video.
also, I tested this on the latest version of SRWare iron(fork of chromium), and it worked.
If you are using C# to make your program, then there is an easier solution:
private void Button1_Click(object sender, EventArgs e)
{
PrintHelpPage();
}
private void PrintHelpPage()
{
// Create a WebBrowser instance.
WebBrowser webBrowserForPrinting = new WebBrowser();
// Add an event handler that prints the document after it loads.
webBrowserForPrinting.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(PrintDocument);
// Set the Url property to load the document.
webBrowserForPrinting.Url = new Uri(#"http://www.google.com"); //This is what you want to change
}
private void PrintDocument(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).Print();
// Dispose the WebBrowser now that the task is complete.
((WebBrowser)sender).Dispose();
}
Found the answer in Here, this uses the WebBrowser control to navigate to a specific Url, can be a local url or from the internet, and prints it using your default printer.
Maybe you could you use this approach that doesn't require windows forms, worked like a charm for me:
With C# use Chrome to covert HTML to PDF
var process = new System.Diagnostics.Process();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
var chrome = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), #"Google\Chrome\Application\chrome.exe");
// use powershell
process.StartInfo.FileName = "powershell";
// set the Chrome path as local variable in powershell and run
process.StartInfo.Arguments = "$chrome='" + chrome + #"'; & $chrome --headless --print-to-pdf='c:\Users\" + Environment.UserName + #"\desktop\myReport.pdf' https://google.com";
process.Start();

Suppress Script errors in WebBrowser control but still allow popups

I am getting vaious script errors when I use a WebBrowser Control to view web pages in my WPF application. To supress these I used the 'Silent' method as outlined in this link: http://social.msdn.microsoft.com/Forums/vstudio/en-US/4f686de1-8884-4a8d-8ec5-ae4eff8ce6db/new-wpf-webbrowser-how-do-i-suppress-script-errors?forum=wpf
void wbMain_Navigated(object sender, NavigationEventArgs e)
{
SetSilent(WebBrowser, true);
}
public static void SetSilent(WebBrowser browser, bool silent)
{
if (browser == null)
throw new ArgumentNullException("browser");
FieldInfo webBrowserInfo = browser.GetType().GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
object comWebBrowser = null;
if (webBrowserInfo != null)
comWebBrowser = webBrowserInfo.GetValue(browser);
if (comWebBrowser != null)
comWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, comWebBrowser, new object[] { silent });
}
But the problem now is that because the "Silent" property has been set none of my web pages right click options work. (There are many right click options on my flash website that pop up various menus).
If I don't use the workaround above then the right click action brings up script error:
"An error has occurred in the script on this page"
How can I get around this?

Access is denied error in Windows Store App using Javascript

I'm trying to launch a save dialog in my windows RT app when someone tries to close a file which has not been saved. However, I keep getting a 0x80070005 - JavaScript runtime error: Access is denied error
This is the code I'm using the launch the message dialog. When "Don't Save" is chosen (and BlankFile() is run) everything runs ok. However when you choose "Save File" it throws the access denied error when it tries to run .pickSaveFileAsync()
function createNewFile()
{
if (editedSinceSave)
{
// Create the message dialog and set its content
var msg = new Windows.UI.Popups.MessageDialog("Save this file?",
"Save Changes");
// Add commands
msg.commands.append(new Windows.UI.Popups.UICommand("Don't Save",
function (command) {
BlankFile();
}));
msg.commands.append(new Windows.UI.Popups.UICommand("Save File",
function (command) {
//saveFile(true, true);
testPop("test");
}));
// Set the command that will be invoked by default
msg.defaultCommandIndex = 2;
// Show the message dialog
msg.showAsync();
}
}
function testPop(text) {
var msg = new Windows.UI.Popups.MessageDialog(text, "");
msg.showAsync();
}
Your core problem is you are tying to show a message dialog ontop of another. I discuss the details, and the solution here:
What is the alternative to `alert` in metro apps?
However, you flow naturally needs this is to happen -- I suggest looking at building a different type of flow rather than stacking dialogs.
The way around this seems to be to set a command id and catch it in the done() function of showAsync(), like so
function createNewFile()
{
if (editedSinceSave)
{
// Add commands and set their CommandIds
msg.commands.append(new Windows.UI.Popups.UICommand("Dont Save", null, 1));
msg.commands.append(new Windows.UI.Popups.UICommand("Save File", null, 2));
// Set the command that will be invoked by default
msg.defaultCommandIndex = 1;
// Show the message dialog
msg.showAsync().done(function (command) {
if (command) {
if (command.id == 1){
BlankFile();
}
else {
saveFile(true, true);
}
}
});
}
}
This doesn't throw any errors. I don't know why doing it the other way throws errors as it doesn't seem to be any different!

Categories