Looking for direction in why program is not functioning properly
This is kind of a long question but I'm completely stumped on why my
program isn't working, and how I can begin to troubleshoot it.
I have a program that accesses "Scenarios" from a XML database and runs
tests on them. What's neat about the program is that if runs these tests
in WebBrowser control embedded in a Windows Form, so it can act as a
screensaver when the user is idle. That way, even idle computers are still
running unit tests in scenarios.
When the screensaver form loads, I call GetScenarios(). GetScenarios()
does a number of things:
Login to a portal.
Connects to the SQL DB
Starts up a SQLDataReader while loop to loop through the Scenarios in the
database
Inside of the while loop, it runs a test function on the scenarios, and
inserts the results into another database.
The main problem I have been trying to solve throughout this project has
been how to Navigate on a WebBrowser and read the DOM and inject
Javascript all inside of this global while loop, without anything being
interrupted. I'm really close to it working, but I'm still encountering a
number of problems.
Program (relevant code):
public void GetScenarios()
{
// Login to portal
PortalLogin();
using (SqlConnection conn = new
SqlConnection(Properties.Settings.Default.DBConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT * FROM
Scenarios WHERE IsEnabled='1'", conn))
{
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
// Store scenario ID/initialize variables
int Id = (int)reader["ScenarioID"];
int[] results = { 0, 0 };
var screenshot = new Byte[] { };
// Start reading XML Data
string Url = "";
/* Perform a test on the selected scenario
* (can do different types of tests)
* Update HasSucceeded and successes/failures
* */
results = TestScenarios(reader, cmd, Url,
results);
// Take screenshot
TakeScreenshot(screenshot);
// Insert result data into Results table
InsertResults(Id, results, screenshot);
// Mark IsEnabled as false (disable the scenario)
DisableScenario(Id);
}
reader.Close();
//MessageBox.Show("All scenarios have been marked
as disabled.");
Application.Exit();
}
else
{
//MessageBox.Show("All scenarios have been marked
as disabled.");
Application.Exit();
}
}
}
}
/// <summary>
/// Login to the portal
/// </summary>
public void PortalLogin()
{
string portalUrl = "URL";
string portalEmail = "EMAIL";
string portalPassword = "PASSWORD";
// Run when page finishes navigating
webBrowser2.DocumentCompleted += (s, e) =>
{
HtmlElement head =
webBrowser2.Document.GetElementsByTagName("head")[0];
HtmlElement testScript =
webBrowser2.Document.CreateElement("script");
IHTMLScriptElement element =
(IHTMLScriptElement)testScript.DomElement;
element.text = "function PortalLogin() {
document.getElementById('EMAIL').value = '" + portalEmail
+ "'; document.getElementById('PASSWORD').value = '" +
portalPassword + "';
document.getElementById('LOGINFORM').submit(); }";
head.AppendChild(testScript);
webBrowser2.Document.InvokeScript("PortalLogin");
};
// Navigate to O365 portal
webBrowser2.Navigate(portalUrl);
while (this.webBrowser2.ReadyState !=
WebBrowserReadyState.Complete)
{
Application.DoEvents();
Thread.Sleep(100);
}
}
/// <summary>
/// Goes to specified Url
/// Performs a test on the selected scenario
/// </summary>
public int[] TestScenarios(SqlDataReader reader, SqlCommand cmd,
string Url, int[] results)
{
// Initialize variables
string testType = "";
string testElement = "";
string expected = "";
string formElem = "";
string emailElem = "";
string passwordElem = "";
string testEmail = "";
string testPassword = "";
// Open SQLXML reader
SqlXml sqlXml = reader.GetSqlXml(1);
using (var xmlreader = sqlXml.CreateReader())
{
// Start looping through scenario steps
var document = XDocument.Load(xmlreader);
foreach (XElement step in document.Descendants("Step"))
{
// Get scenario Url
Url = step
.Attribute("Url")
.Value;
// Start looping through scenario checks
foreach (XElement substep in step.Descendants())
{
// Get type of test
testType = substep
.Attribute("Type")
.Value;
// Run when page finishes navigating
webBrowser2.DocumentCompleted += (s, e) =>
{
// If/else to determine type of test
if (testType == "ContentPresent")
{
expected = substep
.Attribute("Expected")
.Value;
HtmlAgilityPack.HtmlDocument doc = new
HtmlAgilityPack.HtmlDocument();
WebClient client = new WebClient();
string html = client.DownloadString(Url);
doc.LoadHtml(html);
var foo = (from bar in
doc.DocumentNode.DescendantNodes()
where
bar.GetAttributeValue("id",
null) == expected
select bar).FirstOrDefault();
if (foo != null)
{
results[0]++;
}
else
{
results[1]++;
}
}
else if (testType == "Click")
{
testElement = substep
.Attribute("Element")
.Value;
expected = substep
.Attribute("Expected")
.Value;
webBrowser2.Invoke(new Action(() =>
{
HtmlElement head =
webBrowser2.Document.GetElementsByTagName("head")[0];
HtmlElement testScript =
webBrowser2.Document.CreateElement("script");
IHTMLScriptElement element =
(IHTMLScriptElement)testScript.DomElement;
element.text = "FUNCTION TO INJECT JS";
head.AppendChild(testScript);
webBrowser2.Document.InvokeScript("TestClick");
}));
string TestUrl = webBrowser2.Url.AbsoluteUri;
if (TestUrl.Equals(expected))
{
results[0]++;
}
else
{
results[1]++;
}
}
else if (testType == "Login")
{
formElem = substep
.Attribute("FormElem")
.Value;
emailElem = substep
.Attribute("EmailElem")
.Value;
passwordElem = substep
.Attribute("PasswordElem")
.Value;
testEmail = substep
.Attribute("TestEmail")
.Value;
testPassword = substep
.Attribute("TestPassword")
.Value;
expected = substep
.Attribute("Expected")
.Value;
webBrowser2.Invoke(new Action(() =>
{
HtmlElement head =
webBrowser2.Document.GetElementsByTagName("head")[0];
HtmlElement testScript =
webBrowser2.Document.CreateElement("script");
IHTMLScriptElement element =
(IHTMLScriptElement)testScript.DomElement;
element.text = "FUNCTION TO SIMULATE
LOGIN";
head.AppendChild(testScript);
webBrowser2.Document.InvokeScript("TestLogin");
}));
string TestUrl = webBrowser2.Url.AbsoluteUri;
if (TestUrl.Equals(expected))
{
results[0]++;
}
else
{
results[1]++;
}
}
else
{
MessageBox.Show("Test type not valid");
}
};
// Navigate to page
webBrowser2.Navigate(Url);
while (this.webBrowser2.ReadyState !=
WebBrowserReadyState.Complete)
{
Application.DoEvents();
Thread.Sleep(100);
}
}
}
}
return results;
}
XML Data:
1st Scenario: (only XML part)
<Scenario Name="LogoPresent" Feature="Navbar">
<Steps>
<Step Url="URL">
<Check Type="ContentPresent" Expected="ELEM_ID" />
<Check Type="ContentPresent" Expected="ELEM_ID2" />
</Step>
<Step Url="URL2">
<Check Type="ContentPresent" Expected="ELEM_ID3" />
</Step>
</Steps>
</Scenario>
2nd Scenario: (only XML part)
<Scenario>
<Steps>
<Step Url="URL1">
<Check Type="ContentPresent" Expected="ELEM_ID"></Check>
</Step>
</Steps>
</Scenario>
As you can see, I've been trying to use DocumentCompleted to handle the
Navigate running asynchronously, but the output of my code is still a bit
buggy.
Expected Result:
The expected result of this program is for TestScenarios() to output a
results array of [2, 0] for the first scenario and [1,0] for the second
scenario (which means 2 successes, 0 failures, and 1 success, 0 failures,
respectively). If there is a problem with my JS injection (which I don't
think there is, because when I input it directly into the Chrome/IE
console it returns true), than it should return [0, 2] and [0, 1]
respectively.
Actual Result:
However, the actual result is a little different. For some reason, the
program always outputs a results array of [0, 6] and [0, 1], which doesn't
make sense because there are only 2 XML checks in the first scenario, so
why are 6 failures being outputted?
Interestingly, when I debug the program, it appears to run fine: the
portal appears and is logged into with the JS, and then the 3 separate
webpages appear one after another, and then the program closes.
Brainstorming what the problem is:
I've been trying to brainstorm what the problem could be and have come
across a couple of ideas:
The tests are occurring before the page is fully loaded, so they are
continually returning failures. I'm not sure if this could be the case
though, because usually an exception is thrown if the DOM is accessed
without the element having been loaded.
The nested foreach loops are not looping through the XML <Check> elements
correctly (however I asked this in another question and it seems like they
were).
The while loop is interrupting the TestScenario checks somehow...
Overall- any ideas/direction/tips are really useful, and if this question
is too large/out of scope I can delete it and try to narrow down what my
problem is.
No comments:
Post a Comment