使用C#和Selenium在网页的代码镜像文本框中输入多行SQL文本

问题描述

我正在尝试使用Selenium将sql代码输入到“代码镜像”文本框中。针对此问题,我将以http://www.gudusoft.com/sqlflow/#/网站为例。

我的问题:

如果代码包含回车符或换行符,则无法将MSsql sql代码提交到代码文本框中。

作为一种变通方法,在使用JavaScript函数将其写入文本框之前,我将删除所有这些变量,但是最终结果是非常难看的单词包装sql

我也尝试过在Selenium webElement对象上使用SendKeys方法代码发送到文本框中,但是我不确定要“查找”哪个元素。使用SendKeys要求选择文本框,并且当我尝试在该对象上调用Click“和” SendKeys“方法时,我经常会收到一个错误提示该元素不允许用户交互。

如果我能够始终如一地找到可以与之交互的元素(例如TextArea),我将尝试将剪贴板的内容粘贴到其中,而不是将大量的击键发送到文本框。例如,以下内容通常给我“无法与该对象进行交互”的错误,但有时会起作用,具体取决于文本框的当前内容

Clipboard.SetText(sql);
var txtbx = codeMirror.FindElement(By.CssSelector("textarea"));
txtbx.Click();
txtbx.SendKeys(OpenQA.Selenium.Keys.Control + "v");
       

我认为,设置文本的最佳机会是使用Execute脚本方法在CodeMirror对象上执行setValue JavaScript方法,如下所示。再次,如果sql没有CR / LF字符,这是可行的,但是如何更改代码以允许这些字符?

我已经看到很多关于此的文章,但是我的JavaScript知识可能不足以使我达到最终结果。我希望有人可以使用以下代码重构一个有效的示例。这是相对简短的说明。

创建一个C#项目(控制台应用程序,winForms等)并添加以下3个Nuget软件包:

Selenium.Chrome.WebDriver
Selenium.WebDriver
Selenium.WebDriver.ChromeDriver

创建一个“ SeleniumHelperGudusoft”类,并粘贴以下代码

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace sqlSmoke.Classes
{
    public class SeleniumHelperGudusoft
    {
        private IWebDriver driver;

        public SeleniumHelperGudusoft()
        {
            var chromeDriverService = ChromeDriverService.CreateDefaultService();
            chromeDriverService.HideCommandPromptwindow = false;

            ChromeOptions options = new ChromeOptions();
            options.AddAdditionalCapability("useAutomationExtension",false);
            this.driver = new ChromeDriver(chromeDriverService,options);
        }

        public void NavigatetoMain()
        {
            driver.Url = @"http://www.gudusoft.com/sqlflow/#/";
        }

        public void SetLanguagetoMssql()
        {
            string languageButtoncssSelector = "#Root > div > div.Main > div > div.Route.Row.x-start.y-stretch > div.sqlFlowEditor > div.sqlFlowEditorOperations.Row.x-start.y-center > div.Dbvendor > div > div > svg";
            var languageButton = driver.FindElement(By.CssSelector(languageButtoncssSelector));
            languageButton.Click();

            string mssqlCssSelector = "#Root > div > div.Main > div > div.Route.Row.x-start.y-stretch > div.sqlFlowEditor > div.sqlFlowEditorOperations.Row.x-start.y-center > div.Dbvendor > ul > li:nth-child(10)";
            var mssql = driver.FindElement(By.CssSelector(mssqlCssSelector));
            mssql.Click();
        }

        public void SetsqlText(string sql)
        {
            IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
            var codeMirror = driver.FindElement(By.ClassName("CodeMirror"));
            js.ExecuteScript("arguments[0].CodeMirror.setValue(\"" + sql + "\");",codeMirror); //<<<<----Fails here with the error message shown below in my post
        }

        public void ClickVisualizeButton()
        {
            string buttonCssSelector = "#Visualize > div";
            var button = driver.FindElement(By.CssSelector(buttonCssSelector));
            button.Click();
        }
    }
}

锻炼上面类中的代码,尝试粘贴两种不同的sql,一种不带换行符,另一种不带换行符。

string sql;

var lineageHelper = new SeleniumHelperGudusoft();
lineageHelper.NavigatetoMain();
lineageHelper.SetLanguagetoMssql();

sql = "SELECT COL1,nCOL2 FROM TABLE1"; //all on one line works
lineageHelper.SetsqlText(sql);
lineageHelper.ClickVisualizeButton();
                    
sql = "SELECT COL1,\r\nCOL2 FROM TABLE1"; 
lineageHelper.SetsqlText(sql); //<<<----- Fails here with the following error message
lineageHelper.ClickVisualizeButton();

在第二次调用该行的SetsqlText方法时出现以下错误

js.ExecuteScript("arguments[0].CodeMirror.setValue(\"" + sql + "\");",codeMirror);

Message "javascript error: Invalid or unexpected token\n  (Session info: chrome=84.0.4147.105)" string

如何修改示例以使第二个查询输入到CodeMirror文本框中?

更新

代码镜像文档在这里找到: https://codemirror.net/doc/manual.html

这是错误的完整调用堆栈:

OpenQA.Selenium.WebDriverException
  HResult=0x80131500
  Message=javascript error: Invalid or unexpected token
  (Session info: chrome=84.0.4147.105)
  Source=WebDriver
  StackTrace:
   at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse)
   at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute,Dictionary`2 parameters)
   at OpenQA.Selenium.Remote.RemoteWebDriver.ExecuteScriptCommand(String script,String commandName,Object[] args)
   at OpenQA.Selenium.Remote.RemoteWebDriver.ExecuteScript(String script,Object[] args)
   at MyNAME.Selenium.SeleniumHelperGudusoft.SetsqlText(String sql) in C:\Users\MYLANID\Desktop\sqlSmoke Code\MyNAME.Selenium\SeleniumHelper.cs:line 41
   at MyNAME.Selenium.Form1.button3_Click(Object sender,EventArgs e) in C:\Users\MYLANID\Desktop\sqlSmoke Code\MyNAME.Selenium\Form1.cs:line 201
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.onmouseup(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m,MouseButtons button,Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.dispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.imsoComponentManager.FPushMessageLoop(IntPtr dwComponentID,Int32 reason,Int32 pvLoopData)
   at System.Windows.Forms.Application.threadcontext.RunMessageLoopInner(Int32 reason,ApplicationContext context)
   at System.Windows.Forms.Application.threadcontext.RunMessageLoop(Int32 reason,ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at MyNAME.Selenium.Program.Main() in C:\Users\MYLANID\Desktop\sqlSmoke Code\MyNAME.Selenium\Program.cs:line 19

解决方法

在JavaScript中设置值时,您可能需要重新转义回车符和换行符:

var sql = @"SELECT foo
FROM bar";
var jsString = sql.Replace("\r","\\r")
                  .Replace("\n","\\n");

js.ExecuteScript("arguments[0].CodeMirror.setValue(\"" + jsString + "\");",codeMirror);

生成的JavaScript行将为:

arguments[0].CodeMirror.setValue("SELECT foo\n\rFROM bar")

请注意,SQL字符串中的所有双引号也需要转义,以免它们过早地结束JavaScript字符串:

var sql = @"SELECT foo AS '"bar"'
FROM baz";
var jsString = sql.Replace("\r","\\n")
                  .Replace("\"","\\\"");

js.ExecuteScript("arguments[0].CodeMirror.setValue(\"" + jsString + "\");",codeMirror);

因此,生成的JavaScript为:

arguments[0].CodeMirror.setValue("SELECT foo AS '\"bar\"'\n\rFROM baz");
,

为避免错误,只需提供SQL字符串作为参数即可:

js.ExecuteScript("arguments[0].CodeMirror.setValue(arguments[1]);",codeMirror,sql);

或使用反引号:

js.ExecuteScript("arguments[0].CodeMirror.setValue(`" + sql + "`);",codeMirror);