使用 C# 和 Selenium 在网页上的代码镜像文本框中输入多行 SQL 文本
Using C# and Selenium to enter multi lined SQL text into a Code Mirror textbox on a webpage
我正在尝试使用 Selenium 在代码镜像文本框中输入 SQL 代码。出于这个问题的目的,我将使用站点 http://www.gudusoft.com/sqlflow/#/ 作为示例。
我的问题:
如果代码包含回车 return 或换行,我无法将 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
创建一个class“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();
}
}
}
使用上面的代码 class 尝试粘贴两个不同的 SQLs,一个没有换行符,一个有。
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 中设置值时,您可能需要 re-escape 回车符 return 和换行符:
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 字符串中的任何 double-quotes 也需要转义,以免它们过早结束 JavaScript 字符串:
var sql = @"SELECT foo AS '"bar"'
FROM baz";
var jsString = sql.Replace("\r", "\r")
.Replace("\n", "\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);
我正在尝试使用 Selenium 在代码镜像文本框中输入 SQL 代码。出于这个问题的目的,我将使用站点 http://www.gudusoft.com/sqlflow/#/ 作为示例。
我的问题:
如果代码包含回车 return 或换行,我无法将 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
创建一个class“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();
}
}
}
使用上面的代码 class 尝试粘贴两个不同的 SQLs,一个没有换行符,一个有。
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 中设置值时,您可能需要 re-escape 回车符 return 和换行符:
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 字符串中的任何 double-quotes 也需要转义,以免它们过早结束 JavaScript 字符串:
var sql = @"SELECT foo AS '"bar"'
FROM baz";
var jsString = sql.Replace("\r", "\r")
.Replace("\n", "\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);