Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3f07f66
Switch back to main window after system maintenance (#2598)
labkey-tchad Aug 4, 2025
c29e288
Add selenium test for importing attachment as string values (#2597)
XingY Aug 4, 2025
637dc78
Add more informative errors for null ElementCache (#2600)
labkey-tchad Aug 4, 2025
5f14c73
Merge 25.7 to 25.8
labkey-danield Aug 5, 2025
ace1198
Update EditableGrid and EditableGridTest to handle long field names (…
labkey-tchad Aug 7, 2025
8a64dac
Handle double spaces in some error messages (#2607)
labkey-tchad Aug 7, 2025
eb13dfc
More helpers for tricky characters (#2612)
labkey-tchad Aug 8, 2025
06681d7
Fix blocked clicks for editable grid operations (#2613)
labkey-tchad Aug 9, 2025
06c4adc
AuditLogHelper: return null instead of index error (#2610)
labkey-nicka Aug 11, 2025
435a498
Wait for system maintenance page to load when rerunning the task (#2615)
labkey-tchad Aug 11, 2025
ffd5c3d
Wait for panel visibility in ShowAdminPage (#2620)
labkey-tchad Aug 11, 2025
0a44bcb
Merge 25.7 to 25.8
cnathe Aug 12, 2025
04a40f5
Add support for generating random text choice data (#2616)
labkey-tchad Aug 13, 2025
7c88338
Fix WebDriverWrapper.isTextPresent usages (#2618)
labkey-tchad Aug 13, 2025
976df85
Update 'doAndWaitForWindow' to actually wait for the window (#2623)
labkey-tchad Aug 13, 2025
3cee692
Issue 53699: BufferUnderflow and length validator test case (#2632)
labkey-nicka Aug 15, 2025
4324a20
Fix tab management and random data generation (#2631)
labkey-tchad Aug 15, 2025
6e967ad
Helper to create dataset categories with retry (#2626)
labkey-tchad Aug 15, 2025
3a1bb0b
BackPort sample type test fix (#2636)
labkey-danield Aug 18, 2025
36e1370
Merge 25.7 to 25.8
labkey-danield Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/org/labkey/test/LabKeySiteWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ public void signInShouldFail(String email, String password, String... expectedMe
errorText = getText(Locator.tagWithClass("div", "auth-form-body").childTag("p"));
}

List<String> missingErrors = getMissingTexts(new TextSearcher(errorText), expectedMessages);
List<String> missingErrors = new TextSearcher(errorText).getMissingTexts(expectedMessages);
assertTrue(String.format("Wrong errors.\nExpected: ['%s']\nActual: '%s'", String.join("',\n'", expectedMessages), errorText), missingErrors.isEmpty());
}

Expand Down
91 changes: 51 additions & 40 deletions src/org/labkey/test/WebDriverWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
Expand Down Expand Up @@ -62,6 +61,7 @@
import org.labkey.test.util.RelativeUrl;
import org.labkey.test.util.TestLogger;
import org.labkey.test.util.TextSearcher;
import org.labkey.test.util.TextSearcher.TextTransformers;
import org.labkey.test.util.Timer;
import org.labkey.test.util.selenium.ScrollUtils;
import org.labkey.test.util.selenium.WebDriverUtils;
Expand All @@ -76,6 +76,7 @@
import org.openqa.selenium.Keys;
import org.openqa.selenium.NoAlertPresentException;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.NoSuchWindowException;
import org.openqa.selenium.ScriptTimeoutException;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.StaleElementReferenceException;
Expand Down Expand Up @@ -148,6 +149,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -167,6 +169,7 @@
import static org.labkey.test.TestProperties.isWebDriverLoggingEnabled;
import static org.labkey.test.WebTestHelper.makeRelativeUrl;
import static org.labkey.test.components.html.RadioButton.RadioButton;
import static org.labkey.test.util.LabKeyExpectedConditions.windowIsPresent;
import static org.openqa.selenium.chrome.ChromeDriverService.CHROME_DRIVER_LOG_PROPERTY;
import static org.openqa.selenium.chrome.ChromeDriverService.CHROME_DRIVER_VERBOSE_LOG_PROPERTY;
import static org.openqa.selenium.firefox.GeckoDriverService.GECKO_DRIVER_LOG_PROPERTY;
Expand Down Expand Up @@ -1620,31 +1623,27 @@ public void assertLabKeyErrorPresent()
fail("No errors found");
}

public static String encodeText(String unencodedText)
/**
* Check whether all the specified text is present on the page
* @param texts un-encoded text to search for
* @return true if all the specified texts are present on the page
*/
public boolean isTextPresent(String... texts)
{
return unencodedText
.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;");
return new TextSearcher(this).areAllTextsPresent(texts);
}

public boolean isTextPresent(String... texts)
/**
* Check whether the HTML-encoded text is in the page source
* @param htmlFragments encoded html fragments to search for
* @return true if all the specified texts are present on the page
*/
public boolean isHtmlPresent(String... htmlFragments)
{
final MutableBoolean present = new MutableBoolean(true);

TextSearcher.TextHandler handler = (htmlSource, text) -> {
// Not found... stop enumerating and return false
if (htmlSource == null || !htmlSource.contains(text))
present.setFalse();

return present.getValue();
};
TextSearcher searcher = new TextSearcher(this);
searcher.setSearchTransformer(TextSearcher.TextTransformers.IDENTITY);
searcher.setSourceTransformer(TextSearcher.TextTransformers.IDENTITY);
searcher.searchForTexts(handler, Arrays.asList(texts));
searcher.setSearchTransformer(TextTransformers.IDENTITY);

return present.getValue();
return searcher.areAllTextsPresent(htmlFragments);
}

public List<String> getTextOrder(TextSearcher searcher, String... texts)
Expand All @@ -1667,11 +1666,6 @@ public List<String> getTextOrder(TextSearcher searcher, String... texts)
return orderedTexts;
}

public List<String> getMissingTexts(TextSearcher searcher, String... texts)
{
return searcher.getMissingTexts(Arrays.asList(texts));
}

public String getText(Locator elementLocator)
{
WebElement el = elementLocator.findElement(getDriver());
Expand Down Expand Up @@ -1700,7 +1694,7 @@ public void assertTextPresent(String... texts)

public void assertTextPresent(TextSearcher searcher, String... texts)
{
List<String> missingTexts = getMissingTexts(searcher, texts);
List<String> missingTexts = searcher.getMissingTexts(texts);

if (!missingTexts.isEmpty())
{
Expand All @@ -1717,7 +1711,7 @@ public void assertTextPresentCaseInsensitive(String... texts)
{
TextSearcher searcher = new TextSearcher(this);

searcher.setSearchTransformer((text) -> encodeText(text).toLowerCase());
searcher.setSearchTransformer(TextTransformers.ENCODE_HTML.andThen(String::toLowerCase));

searcher.setSourceTransformer(String::toLowerCase);

Expand All @@ -1729,18 +1723,7 @@ public void assertTextPresentCaseInsensitive(String... texts)
*/
public boolean isAnyTextPresent(String... texts)
{
final MutableBoolean found = new MutableBoolean(false);

TextSearcher.TextHandler handler = (htmlSource, text) -> {
if (htmlSource.contains(text))
found.setTrue();

return !found.getValue(); // stop searching if any value is found
};
TextSearcher searcher = new TextSearcher(this);
searcher.searchForTexts(handler, Arrays.asList(texts));

return found.getValue();
return new TextSearcher(this).isAnyTextPresent(texts);
}

/**
Expand Down Expand Up @@ -1900,7 +1883,7 @@ public static void assertTextNotPresent(TextSearcher searcher, String... texts)
public void assertTextNotPresent(String... texts)
{
TextSearcher searcher = new TextSearcher(this);
searcher.setSearchTransformer((text) -> encodeText(text).replace("&nbsp;", " "));
searcher.setSearchTransformer(TextTransformers.ENCODE_HTML.andThen(t -> t.replace("&nbsp;", " ")));

assertTextNotPresent(searcher, texts);
}
Expand Down Expand Up @@ -2140,6 +2123,34 @@ public long doAndMaybeWaitForPageToLoad(int msWait, Supplier<Boolean> action)
return loadTimer.elapsed().toMillis();
}

public long doAndWaitForWindow(Runnable action, String windowName)
{
String initialWindow = getDriver().getWindowHandle();
AtomicBoolean targetWindowExists = new AtomicBoolean(false);
try
{
getDriver().switchTo().window(windowName);
targetWindowExists.set(true);
}
catch (NoSuchWindowException e)
{
targetWindowExists.set(false);
}

// Call doAndMaybeWaitForPageToLoad with target window in focus (if present)
// Then it will correctly detect the page load in that window
return doAndMaybeWaitForPageToLoad(10_000, () -> {
if (targetWindowExists.get())
getDriver().switchTo().window(initialWindow);

action.run();

new WebDriverWait(getDriver(), Duration.ofSeconds(5)).until(windowIsPresent(windowName));

return targetWindowExists.get();
});
}

public long doAndAcceptUnloadAlert(Runnable func, String partialAlertText)
{
return doAndWaitForPageToLoad(() ->
Expand Down
13 changes: 8 additions & 5 deletions src/org/labkey/test/components/Component.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.labkey.test.components;

import org.apache.commons.lang3.NotImplementedException;
import org.jetbrains.annotations.NotNull;
import org.labkey.test.Locator;
import org.labkey.test.selenium.RefindingWebElement;
import org.labkey.test.util.TestLogger;
Expand All @@ -27,6 +28,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

Expand All @@ -43,13 +45,13 @@ public String toString()
}

@Override
public WebElement findElement(By by)
public @NotNull WebElement findElement(@NotNull By by)
{
return getComponentElement().findElement(by);
}

@Override
public List<WebElement> findElements(By by)
public @NotNull List<WebElement> findElements(@NotNull By by)
{
return getComponentElement().findElements(by);
}
Expand All @@ -69,8 +71,9 @@ protected EC elementCache()
// Pass if element doesn't exist. Might be checking if component is visible.
}

_elementCache = newElementCache();
_elementCache = Objects.requireNonNull(newElementCache());
waitForReady();
Objects.requireNonNull(_elementCache, "waitForReady() cleared the element cache");
}
return _elementCache;
}
Expand Down Expand Up @@ -103,13 +106,13 @@ protected ElementCache()
}

@Override
public List<WebElement> findElements(By by)
public @NotNull List<WebElement> findElements(@NotNull By by)
{
return getComponentElement().findElements(by);
}

@Override
public WebElement findElement(By by)
public @NotNull WebElement findElement(@NotNull By by)
{
return getComponentElement().findElement(by);
}
Expand Down
33 changes: 23 additions & 10 deletions src/org/labkey/test/components/ui/Pager.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,41 @@ public int getCurrentPage() // only works on GridPanel

public Pager selectPageSize(String pageSize) // only works on GridPanel
{
int currentPageSize = getPageSize();
if(currentPageSize != Integer.parseInt(pageSize))
{
_pagedComponent.doAndWaitForUpdate(() -> elementCache().jumpToDropdown.clickSubMenu(false, pageSize));
}
pageSize(pageSize);
return this;
}

public int getPageSize() // only works on GridPanel
{
// Changing the jumpToDropdown button from the deprecated DropdownButtonGroup class to a MultiMenu type has changed
// the way that various text from the control is gathered. Getting the current page size now requires that the dropdown
return pageSize(null);
}

/**
* Sets the page size if required (pageSize is specified and doesn't match the current page size)
* @return returns the initial page size
*/
private int pageSize(String pageSize) // only works on GridPanel
{
// Getting the current page size requires that the dropdown
// be expanded and the selected page size found in the list.
elementCache().jumpToDropdown.expand();

// Find the selected li element in the page size list
WebElement activeLi = Locator.byClass("active").findElement(elementCache().jumpToDropdown);

int size = Integer.parseInt(activeLi.getText());
elementCache().jumpToDropdown.collapse();
int initialSize = Integer.parseInt(activeLi.getText());

if (pageSize != null && initialSize != Integer.parseInt(pageSize))
{
_pagedComponent.doAndWaitForUpdate(() -> elementCache().jumpToDropdown.clickSubMenu(false, pageSize));
}
else
{
// Tooltip sometimes blocks button. Click active option to dismiss menu.
activeLi.click();
}

return size;
return initialSize;
}

/**
Expand Down
Loading