I am writing Se tests for an Ext JS 3.x website. This is a very old framework from Sencha. It is not HTML 5 compliant and deeply nests elements that need to be tested.
One case is an object with 70 dates. In debug, the tests will run. In Run mode, there isn't time for the list to populate and by the time its elements are needed, the error 'Sequence contains no elements' is thrown.
Incorporating all the code needed to drill into this list into its own browser test fixture still falls prey to the same issue.
Here is the HTML for the list, showing the detail into the first element of the list:
<?xml version="1.0" encoding="utf-8" ?>
<div id="programmaticWindow" class=" x-window x-window-plain" style="position: absolute; z-index: 9003; visibility: visible; left: 278px; top: 246px; width: 600px; display: block;">
<div class="x-window-tl">
<div class="x-window-tr">
<div class="x-window-tc">
<div class="x-window-header x-unselectable x-window-draggable" id="ext-gen286">
<div class="x-tool x-tool-close" id="ext-gen292"> </div>
<span class="x-window-header-text" id="ext-gen298">Programmatic Dates</span>
</div>
</div>
</div>
</div>
<div class="x-window-bwrap" id="ext-gen287">
<div class="x-window-ml">
<div class="x-window-mr">
<div class="x-window-mc" id="ext-gen291">
<div class="x-window-body x-border-layout-ct" id="ext-gen288" style="width: 588px; height: 345px;">
<div id="ext-comp-1217" class=" x-panel x-panel-noborder x-border-panel" style="padding: 5px; width: 190px; left: 0px; top: 0px;">
<div class="x-panel-bwrap" id="ext-gen304">
<div class="x-panel-body x-panel-body-noheader x-panel-body-noborder" id="ext-gen305" style="width: 190px; height: 335px;">
<div id="ext-comp-1214" class=" x-panel x-panel-noborder x-grid-panel" style="width: 190px;">
<div class="x-panel-bwrap" id="ext-gen308">
<div class="x-panel-body x-panel-body-noheader x-panel-body-noborder" id="ext-gen309" style="height: 335px; width: 190px;">
<div class="x-grid3" hidefocus="true" id="ext-gen310" style="width: 190px; height: 335px;">
<div class="x-grid3-viewport" id="ext-gen311">
<div class="x-grid3-header" id="ext-gen312">
<div class="x-grid3-header-inner" id="ext-gen314" style="width: 190px;">
<div class="x-grid3-header-offset" style="width:190px;">
<table border="0" cellspacing="0" cellpadding="0" style="width: 174px;">
<thead>
<tr class="x-grid3-hd-row">
<td class="x-grid3-hd x-grid3-cell x-grid3-td-FormattedDate x-grid3-cell-first " style="width: 100px;">
<div class="x-grid3-hd-inner x-grid3-hd-FormattedDate" unselectable="on" style="">
Programmatic Date<img alt="" class="x-grid3-sort-icon" src="/pdpdev/scripts/ext/resources/images/default/s.gif">
</div>
</td>
<td class="x-grid3-hd x-grid3-cell x-grid3-td-isActiveDate x-grid3-cell-last" style="width: 74px;text-align: center;">
<div class="x-grid3-hd-inner x-grid3-hd-isActiveDate" unselectable="on" style="">
Active<img alt="" class="x-grid3-sort-icon" src="/pdpdev/scripts/ext/resources/images/default/s.gif">
</div>
</td>
</tr>
</thead>
</table>
</div>
</div>
<div class="x-clear"></div>
</div>
<div class="x-grid3-scroller" id="ext-gen313" style="width: 190px; height: 311px;">
<div class="x-grid3-body" style="width:174px;" id="ext-gen315">
<div class="x-grid3-row x-grid3-row-first" style="width:174px;">
<table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="width:174px;">
<tbody>
<tr>
<td class="x-grid3-col x-grid3-cell x-grid3-td-FormattedDate x-grid3-cell-first " style="width: 100px;" tabindex="0">
<div class="x-grid3-cell-inner x-grid3-col-FormattedDate" unselectable="on">11/21/2025</div>
</td>
<td class="x-grid3-col x-grid3-cell x-grid3-td-isActiveDate x-grid3-cell-last " style="width: 74px;text-align: center;" tabindex="0">
<div class="x-grid3-cell-inner x-grid3-col-isActiveDate" unselectable="on">
<input type="checkbox" disabled="disabled" class="noauto" checked="checked">
</div>
</td>
</tr>
</tbody>
</table>
</div>
Here are screens shot of the dialog window, with HTML containing the list:
There are 70 containing divs, using the x-grid3-row class element to group them.
The div containing elements (70) must be drilled into in a for-each loop to get if they're checked or not, and the date value.
Use cases for this dialog depend on access to the list itself. A date must be selected for it to be shown in the Programmatic Date textbox, for example.
From there it can be activated (checked) and so on.
'Programmatic' in this sense means a date that will be used as a milestone. These are in turn tied to projects.
Solutions I've tried:
Here is the code for attempt 4. The idea here is the Setup() method, called from the constructor, pops the ProgrammaticDatesList and this done, its value is passed into its own property which should have the full list.
This should be part of setup. But it isn't happening.
The same error as having the code directly in the [Fact] is happening, the 'Sequence contains no elements' error.
private static ReadOnlyCollection<IWebElement> ProgrammaticDatesList =>
AdminManageProgrammaticDatesDialog.FindElement(
By.XPath(CommonXpathStrings.adminManageProgrammaticDialogDateList))
.FindElements(By.XPath(
CommonXpathStrings.adminManageProgrammaticDialogDateListItems));
private static ReadOnlyCollection<IWebElement> myElements = null;
#endregion
#region Methods
public static ReadOnlyCollection<IWebElement> ReturnProgrammaticDatesList()
{
return myElements;
}
private void SetupBrowser()
{
EdgeDriver.Manage().Window.Size = new Size(1520, 1080);
EdgeDriver.Navigate().GoToUrl(CommonStrings.localhostDevRoot);
HomePageClickHereLoginAsAdmin();
Thread.Sleep(3000);
EdgeDriver.SwitchTo().Window(EdgeDriver.CurrentWindowHandle);
CommonMethods.WaitElementByIdVisibleEdge(
EdgeDriver, 3000, CommonXpathStrings.profilePageToolbarId);
ClickMenuDropDownSignedIn();
ClickMenuManageProgrammaticAsAdmin();
GetProgrammaticDateList();
}
Thanks for any suggestions.
=========== Jeff, as requested, we start withthe GetProgrammaticDateList() method. I created an unused method and put the full xpath strings in it:
private void ExpandedGetProgrammaticDateList()
{
IReadOnlyCollection<IWebElement> ProgrammaticDatesList =
EdgeDriver.FindElement(By.Id("programmaticWindow"))
.FindElement(
By.XPath(@"div[contains(@class, 'x-window-bwrap')]
/div/div/div/div/div/div/div/div/div/div/div/div[contains(@class, 'x-grid3-viewport')]
/div[contains(@class, 'x-grid3-scroller')]
/div[contains(@class, 'x-grid3-body')]"))
.FindElements(By.XPath(@"div[contains(@class, 'x-grid3-row')]"));
}
The HTML for this is already included, above. Let me know if this will work. I'm here until 3:30ish, EST.
I don't know all of your use cases but I would do something like this...
WebDriverWait
. This may need to be tweaked if it doesn't work as written below. If we know there's always 70 dates, we can wait for that. We can also wait for JS/jQuery to finish in the background, etc. The hard part may be figuring out what specifically to wait for.I replaced all your chained XPaths, etc. and reduced them all to a simple CSS selector.
NOTE: I store the dates as a DateOnly
type. This makes it much easier to deal with dates if you need to add/subtract days, do comparisons, etc. If you don't need that "power", you can just replace DateOnly
with string
.
The refactored method
private Dictionary<DateTime, bool> GetProgrammaticDateList()
{
Dictionary<DateTime, bool> dateList = new Dictionary<DateTime, bool>();
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60)); // adjust to whatever time you need for the full table to load
ReadOnlyCollection<IWebElement> rows = wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.CssSelector("#programmaticWindow table.x-grid3-row-table tr")));
foreach (IWebElement row in rows)
{
dateList.Add(DateTime.Parse(row.FindElement(By.CssSelector("div.x-grid3-col-FormattedDate")).Text), row.FindElement(By.CssSelector("input")).Selected);
}
return dateList;
}
The test code to call and use it. I added a few different examples of how to use the dictionary of date/bool values.
// navigate to the URL, log in as admin, etc. goes here
Dictionary<DateTime, bool> dateList = GetProgrammaticDateList();
// assert some values
Assert.AreEqual(dateList[new DateTime(2025, 11, 21)], true);
Assert.AreEqual(dateList[new DateTime(2025, 11, 22)], false);
// print all values
foreach (KeyValuePair<DateTime, bool> date in dateList)
{
Console.WriteLine($"{date.Key.ToString("MM/dd/yy")}, {date.Value}");
}
NOTE: This works on the HTML you posted so I'm assuming it will work on the full HTML. If it doesn't I'll need more HTML... probably a few rows of dates to fix my locator(s).