Skip to content

Commit

Permalink
Merge 24.11 to develop
Browse files Browse the repository at this point in the history
  • Loading branch information
labkey-teamcity committed Nov 13, 2024
2 parents b295285 + 66d1a0e commit 05c7c53
Show file tree
Hide file tree
Showing 24 changed files with 152 additions and 144 deletions.
7 changes: 5 additions & 2 deletions src/org/labkey/test/BaseWebDriverTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.labkey.remoteapi.query.ContainerFilter;
import org.labkey.remoteapi.query.Filter;
import org.labkey.remoteapi.query.SelectRowsResponse;
import org.labkey.remoteapi.security.CreateUserResponse;
import org.labkey.serverapi.reader.TabLoader;
import org.labkey.serverapi.writer.PrintWriters;
import org.labkey.test.components.CustomizeView;
Expand Down Expand Up @@ -1946,15 +1947,17 @@ public void setPipelineRootToDefault()
/**
* Create a user with the specified permissions for the specified project
*/
public void createUserWithPermissions(String userName, String projectName, String permissions)
public CreateUserResponse createUserWithPermissions(String userName, String projectName, String permissions)
{
if (projectName == null)
{
projectName = getProjectName();
}
_userHelper.createUser(userName, true);
CreateUserResponse ret = _userHelper.createUser(userName, true);
new ApiPermissionsHelper(this)
.addMemberToRole(userName, permissions, PermissionsHelper.MemberType.user, projectName);

return ret;
}

public ApiPermissionsHelper createSiteDeveloper(String userEmail)
Expand Down
24 changes: 16 additions & 8 deletions src/org/labkey/test/LabKeySiteWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -412,19 +412,25 @@ public void signInShouldFail(String email, String password, String... expectedMe
assertTrue(String.format("Wrong errors.\nExpected: ['%s']\nActual: '%s'", String.join("',\n'", expectedMessages), errorText), missingErrors.isEmpty());
}

protected String setInitialPassword(String user)
@Deprecated // TODO: Call the variant that takes a userId instead
protected String setInitialPassword(String email)
{
return setInitialPassword(_userHelper.getUserId(email));
}

protected String setInitialPassword(int userId)
{
String password = PasswordUtil.getPassword();
SetPasswordForm.goToInitialPasswordForUser(this, user)
.setNewPassword(password)
.clickSubmit();
SetPasswordForm.goToInitialPasswordForUser(this, userId)
.setNewPassword(password)
.clickSubmit();

return password;
}

protected String getPasswordResetUrl(String username)
protected String getPasswordResetUrl(int userId)
{
beginAt(buildURL("security", "showResetEmail", Map.of("email", username)));
beginAt(buildURL("security", "showResetEmail", Map.of("userId", userId)));

WebElement resetLink = Locator.xpath("//a[contains(@href, 'setPassword.view')]").findElement(getDriver());
shortWait().until(ExpectedConditions.elementToBeClickable(resetLink));
Expand Down Expand Up @@ -608,8 +614,10 @@ private void checkForUpgrade()
refresh(); // Clear form

log("Testing bad email addresses");
verifyInitialUserError(null, null, null, "Invalid email address");
verifyInitialUserError("bogus@bogus@bogus", null, null, "Invalid email address: bogus@bogus@bogus");
verifyInitialUserError(null, null, null, "email: '' is not a valid email address. Please enter an email address in this form: user@domain.tld");
verifyInitialUserError("bogus@bogus@bogus", null, null, "email: 'bogus@bogus@bogus' is not a valid email address. Please enter an email address in this form: user@domain.tld");
// In the past, email address was getting double encoded
verifyInitialUserError("<>\"&%", null, null, "email: '<>\"&%' is not a valid email address. Please enter an email address in this form: user@domain.tld");

log("Testing bad passwords");
verifyInitialUserError(email, null, null, "You must enter a password.");
Expand Down
46 changes: 44 additions & 2 deletions src/org/labkey/test/components/core/ApiKeyDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Arrays;

public class ApiKeyDialog extends ModalDialog
{
Expand Down Expand Up @@ -42,8 +44,48 @@ public ApiKeyDialog copyKey()

public String getClipboardContent() throws IOException, UnsupportedFlavorException
{
return (String) Toolkit.getDefaultToolkit().getSystemClipboard()
.getData(DataFlavor.stringFlavor);
DataFlavor[] flavors = Toolkit.getDefaultToolkit().getSystemClipboard().getAvailableDataFlavors();
Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);

// Adding debug info for TeamCity run.
// Windows is not giving DataFlavor (MIME Type) for the data on the clipboard.
getWrapper().log("Available flavors: " + Arrays.stream(flavors).toList());
getWrapper().log("Best flavor: " + DataFlavor.selectBestTextFlavor(flavors));

if (t != null)
{

// Adding debug info for TeamCity run.
getWrapper().log("Is DataFlavor.imageFlavor supported? " + t.isDataFlavorSupported(DataFlavor.imageFlavor));
getWrapper().log("Is DataFlavor.allHtmlFlavor supported? " + t.isDataFlavorSupported(DataFlavor.allHtmlFlavor));
getWrapper().log("Is DataFlavor.fragmentHtmlFlavor supported? " + t.isDataFlavorSupported(DataFlavor.fragmentHtmlFlavor));
getWrapper().log("Is DataFlavor.selectionHtmlFlavor supported? " + t.isDataFlavorSupported(DataFlavor.selectionHtmlFlavor));
getWrapper().log("Is DataFlavor.javaFileListFlavor supported? " + t.isDataFlavorSupported(DataFlavor.javaFileListFlavor));
getWrapper().log("Is DataFlavor.stringFlavor supported? " + t.isDataFlavorSupported(DataFlavor.stringFlavor));

DataFlavor[] transferFlavors = t.getTransferDataFlavors();
getWrapper().log("Transferable supported data flavors: " + Arrays.stream(transferFlavors).toList());

if (flavors.length > 0)
{
getWrapper().log("Best Text Flavor: " + DataFlavor.selectBestTextFlavor(flavors));
return (String) Toolkit.getDefaultToolkit().getSystemClipboard()
.getData(DataFlavor.selectBestTextFlavor(flavors));
}
else
{
getWrapper().log("There are no DataFlavors to use.");
// Return a value to indicate something is on the clipboard but no DataFlavor was provided.
return "There are no DataFlavors to use.";
}

}
else
{
getWrapper().log("The clipboard is empty.");
return "";
}

}

public boolean isCopyButtonDisplayed()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public SetPasswordForm(WebDriver driver)
}

// Don't use this unless you're actually testing authentication functionality
public static SetPasswordForm goToInitialPasswordForUser(WebDriverWrapper wrapper, String email)
public static SetPasswordForm goToInitialPasswordForUser(WebDriverWrapper wrapper, int userId)
{
wrapper.beginAt(WebTestHelper.buildURL("security", "showRegistrationEmail", Map.of("email", email)));
wrapper.beginAt(WebTestHelper.buildURL("security", "showRegistrationEmail", Map.of("userId", userId)));
// Get setPassword URL from notification email.
WebElement resetLink = Locator.linkWithHref("setPassword.view").findElement(wrapper.getDriver());

Expand Down
30 changes: 19 additions & 11 deletions src/org/labkey/test/components/domain/DomainFormPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
import org.labkey.test.components.ui.grids.ResponsiveGrid;
import org.labkey.test.params.FieldDefinition;
import org.labkey.test.selenium.WebElementWrapper;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
Expand Down Expand Up @@ -518,16 +520,16 @@ public WebElement getPanelErrorWebElement()
*/
public String getPanelAlertText()
{
WebElement alertEl = getPanelAlertWebElement();
if (alertEl != null)
return alertEl.getText();

return "";
return getPanelAlertText(0);
}

public String getPanelAlertText(int index)
{
return getPanelAlertWebElement(index).getText();
WebElement panelAlertWebElement = getPanelAlertWebElement(index);
if (panelAlertWebElement != null)
return panelAlertWebElement.getText();
else
return "";
}

public List<String> getPanelAlertTexts()
Expand All @@ -546,17 +548,23 @@ public WebElement getPanelAlertWebElement()

public WebElement getPanelAlertWebElement(int index)
{
return getPanelAlertElements().get(index);
List<WebElement> panelAlertElements = getPanelAlertElements();
if (panelAlertElements.size() > index)
return panelAlertElements.get(index);
else
return null;
}

public List<WebElement> getPanelAlertElements()
{
if (!WebDriverWrapper.waitFor(() -> BootstrapLocators.infoBanner.existsIn(this), 1000))
try
{
return null;
return BootstrapLocators.infoBanner.waitForElements(this, 1000);
}
catch (NoSuchElementException nothing)
{
return Collections.emptyList();
}

return BootstrapLocators.infoBanner.findElements(this);
}

@Override
Expand Down
16 changes: 6 additions & 10 deletions src/org/labkey/test/components/ui/entities/EntityInsertPanel.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.labkey.test.components.ui.entities;

import org.junit.Assert;
import org.labkey.test.Locator;
import org.labkey.test.WebDriverWrapper;
import org.labkey.test.components.Component;
Expand Down Expand Up @@ -156,18 +157,14 @@ public EntityInsertPanel addRecords(List<Map<String, Object>> records)
showGrid();
elementCache().grid.addRows(records.size());

List<Integer> rowIndices = elementCache().grid.getEditableRowIndices();

if(rowIndices.size() < records.size())
{
throw new IllegalStateException("Trying to add more records than there are rows. Number of records to create: " + records.size() + " number of available rows: " + rowIndices.size());
}
Assert.assertFalse(String.format("Trying to add more records than there are rows. Number of records to create: %d number of available rows: %d",
records.size(), elementCache().grid.getRowCount()),
elementCache().grid.getRowCount() < records.size());

int index = 0;

for(Map<String, Object> record : records)
{
setRecordValues(record, rowIndices.get(index));
setRecordValues(record, index);
index++;
}

Expand All @@ -176,8 +173,7 @@ public EntityInsertPanel addRecords(List<Map<String, Object>> records)

public EntityInsertPanel setRecordValues(Map<String, Object> columnValues)
{
int insertRowIndex = getEditableGrid().getEditableRowIndices().get(0);
return setRecordValues(columnValues, insertRowIndex);
return setRecordValues(columnValues, 0);
}

public EntityInsertPanel setRecordValues(Map<String, Object> columnValues, int row)
Expand Down
4 changes: 2 additions & 2 deletions src/org/labkey/test/components/ui/grids/DetailTableEdit.java
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,8 @@ public DetailDataPanel clickSave()
elementCache().saveButton.click();

// If save causes some update, wait until it is completed.
WebDriverWrapper.waitFor(()->!BootstrapLocators.loadingSpinner.existsIn(getDriver()),
"Save has taken too long to complete.", 15_000);
getWrapper().longWait().withMessage("Update took too long to complete.")
.until(ExpectedConditions.stalenessOf(elementCache().saveButton));

return new DetailDataPanel.DetailDataPanelFinder(getDriver()).withTitle(title).waitFor();
}
Expand Down
53 changes: 0 additions & 53 deletions src/org/labkey/test/components/ui/grids/EditableGrid.java
Original file line number Diff line number Diff line change
Expand Up @@ -318,59 +318,6 @@ public int getRowCount()
return getRows().size();
}

/**
* As best as possible get a list of row indices from the grid for editable rows. That is rows where the values can
* be entered or changed.
*
* @return A list of indices (0 based) for rows that can be edited.
*/
public List<Integer> getEditableRowIndices()
{
return getRowTypes().get(0);
}

/**
* Some EditableGrids have read only rows. These are rows in the grid that display data but cannot be updated. As
* best as possible return a list of those rows.
*
* @return A list of indices (0 based) of rows that cannot be edited.
*/
public List<Integer> getReadonlyRowIndices()
{
return getRowTypes().get(1);
}

private List<List<Integer>> getRowTypes()
{
List<Integer> unPopulatedRows = new ArrayList<>();
List<Integer> populatedRows = new ArrayList<>();

// Need to look at an attribute of a cell to see if it has pre-populated data.
// But this info will not be in the select or row-number cells, so we'll use the last column
// (CSS selector is 1-based not 0-based).
int checkColumn = getColumnNames().size();
int rowCount = 0;

for (WebElement row : getRows())
{
String classAttribute = row.findElement(By.cssSelector("td:nth-child(" + checkColumn + ") > div"))
.getAttribute("class");

if ((!classAttribute.contains("cell-selection")) && (!classAttribute.contains("cell-read-only")))
{
unPopulatedRows.add(rowCount);
}
else
{
populatedRows.add(rowCount);
}

rowCount++;
}

return new ArrayList<>(Arrays.asList(unPopulatedRows, populatedRows));
}

/**
* <p>
* For a given column, 'columnNameToSet', set the lookup cell in the first row where the value in column 'columnNameToSearch'
Expand Down
6 changes: 6 additions & 0 deletions src/org/labkey/test/pages/query/QueryMetadataEditorPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Map;

import static org.labkey.test.WebDriverWrapper.WAIT_FOR_JAVASCRIPT;
import static org.labkey.test.WebDriverWrapper.waitFor;

/**
* Automates the platform component defined in: query/src/client/QueryMetadataEditor/QueryMetadataEditor.tsx
Expand All @@ -34,6 +35,11 @@ public static QueryMetadataEditorPage beginAt(WebDriverWrapper webDriverWrapper,
{
webDriverWrapper.beginAt(WebTestHelper.buildURL("query", containerPath, "metadataQuery",
Map.of("schemaName", schemaName, "query.queryName", queryName)));

// Wait for domain editor rows to show up.
waitFor(()->!Locator.tagWithClass("div", "domain-field-row domain-row-border-default").findElements(webDriverWrapper.getDriver()).isEmpty(),
"Query Metadata Editor Page did not load in time.", 5_000);

return new QueryMetadataEditorPage(webDriverWrapper.getDriver());
}

Expand Down
5 changes: 2 additions & 3 deletions src/org/labkey/test/tests/AdminConsoleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.labkey.test.util.ApiPermissionsHelper;
import org.labkey.test.util.LogMethod;
import org.labkey.test.util.PermissionsHelper;
import org.openqa.selenium.WebElement;

import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -331,8 +330,8 @@ protected void doCleanup(boolean afterTest) throws TestTimeoutException

private void createTestUser()
{
_userHelper.createUser(APP_ADMIN_USER, true, false);
setInitialPassword(APP_ADMIN_USER);
int userId = _userHelper.createUser(APP_ADMIN_USER, true, false).getUserId();
setInitialPassword(userId);

ApiPermissionsHelper apiPermissionsHelper = new ApiPermissionsHelper(this);
apiPermissionsHelper.addMemberToRole(APP_ADMIN_USER, "Application Admin", PermissionsHelper.MemberType.user, "/");
Expand Down
4 changes: 2 additions & 2 deletions src/org/labkey/test/tests/SecurityApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ public void createUsers(){
apiPermissionsHelper.setPermissions(GROUP_2, "Reader");

// Create the admin user that will be used to call the APIs.
_userHelper.createUserAndNotify(ADMIN_USER);
setInitialPassword(ADMIN_USER);
int userId = _userHelper.createUserAndNotify(ADMIN_USER).getUserId();
setInitialPassword(userId);
apiPermissionsHelper.addUserToSiteGroup(ADMIN_USER, "Site Administrators");

}
Expand Down
12 changes: 6 additions & 6 deletions src/org/labkey/test/tests/UserDetailsPermissionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ private void doSetup()
domainFormPanel.addField(CUSTOM_USER_COLUMN).setType(FieldDefinition.ColumnType.String);
domainDesignerPage.clickFinish();

_userHelper.createUser(ADMIN_USER, true, true);
_userHelper.createUser(USER_INFO_VIEWER, true, true);
_userHelper.createUser(IMPERSONATED_USER, true, true);
int adminId = _userHelper.createUser(ADMIN_USER, true, true).getUserId();
int userInfoId = _userHelper.createUser(USER_INFO_VIEWER, true, true).getUserId();
int impersonatedId = _userHelper.createUser(IMPERSONATED_USER, true, true).getUserId();
_userHelper.createUser(CHECKED_USER, true, true);
setInitialPassword(ADMIN_USER);
setInitialPassword(USER_INFO_VIEWER);
setInitialPassword(IMPERSONATED_USER);
setInitialPassword(adminId);
setInitialPassword(userInfoId);
setInitialPassword(impersonatedId);

_containerHelper.createProject(getProjectName(), null);

Expand Down
Loading

0 comments on commit 05c7c53

Please sign in to comment.