Skip to content

Issue 51524: Allowlist for acceptable types of file upload - automation test#2428

Merged
labkey-danield merged 27 commits intodevelopfrom
fb_allowFileExtensionAutoTest
Jun 10, 2025
Merged

Issue 51524: Allowlist for acceptable types of file upload - automation test#2428
labkey-danield merged 27 commits intodevelopfrom
fb_allowFileExtensionAutoTest

Conversation

@labkey-sweta
Copy link
Copy Markdown
Contributor

@labkey-sweta labkey-sweta commented Apr 28, 2025

Rationale

Add automated tests for the Allowed Files list.

These tests will cover:

Has coverage for:
Issue 53039: Updating an allowed file extension should set a dirty bit on the page.
Issue 53027: Cannot insert a row into a sample type if Allowed File Extensions are set and no file is provided.

TeamCity runs are here.

Related Pull Requests

Changes

  • Add a AllowedFileExtensionAdminPage.
  • Update ShowAdminPage, BaseUpdatePage, FileBrowserHelper
  • Add AllowedFileExtensionAdminTest

@labkey-danield labkey-danield marked this pull request as ready for review May 8, 2025 01:45
@labkey-danield labkey-danield self-assigned this May 8, 2025
…est and into BaseWebDriverTest.

Add AllowedFileExtensionsTest in lims/biologics, add testAllowedFilesInSampleTypes.
Add TestScrubber.clearListOfAllowedFileExtensions.
Add AllowedFileExtensionsTest.testAllowedFilesInWorkflow
waitForPipelineJobsToComplete(pipelineJobs, "Study Reload", expectError);
}

protected void deleteAllAllowedFileExtension() throws IOException, CommandException
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
protected void deleteAllAllowedFileExtension() throws IOException, CommandException
/** Clears any file extensions that are set as the only allowable names, letting users upload any filename they like */
protected void deleteAllAllowedFileExtension() throws IOException, CommandException

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

Comment thread src/org/labkey/test/TestScrubber.java Outdated
}
}

private void clearListOfAllowedFileExtensions() throws IOException, CommandException
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we consolidate this with the copy in BaseWebDriverTest?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed this method. The only place this code should now appear is in AllowedFileExtensionAdminPage.deleteAllAllowedFileExtension.

Comment on lines +490 to +491
// Not sure why we record two exceptions.
checkExpectedErrors(2);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should no longer be needed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

Comment on lines +583 to +584
// Not sure why we record two exceptions.
checkExpectedErrors(2);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should no longer be needed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also gone.

Copy link
Copy Markdown
Member

@labkey-tchad labkey-tchad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The instructions on the admin page say that ".gz" won't allow ".tar.gz" files; should we verify that is true?

Comment on lines +2510 to +2517
protected void deleteAllAllowedFileExtension() throws IOException, CommandException
{
SimplePostCommand command = new SimplePostCommand("admin", "deleteAllValues");
Map<String, Object> params = new HashMap<>();
params.put("type", "FileExtension");
command.setParameters(params);
command.execute(createDefaultConnection(), "/");
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should go in LabKeySiteWrapper. That would allow TestScrubber to access it.
Alternatively, you could make it a static method in AllowedFileExtensionAdminPage (with a Connection parameter).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved it AllowedFileExtensionsAdminPage and made it static. I think it might be more discoverable there.


public static AllowedFileExtensionAdminPage beginAt(WebDriverWrapper webDriverWrapper)
{
webDriverWrapper.beginAt(WebTestHelper.buildURL("admin", "allowList"));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The allowList page has several flavors, need to specify the FileExtension version.

Suggested change
webDriverWrapper.beginAt(WebTestHelper.buildURL("admin", "allowList"));
webDriverWrapper.beginAt(WebTestHelper.buildURL("admin", "allowList", Map.of("type", "FileExtension")));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

Comment on lines +57 to +71
public String clickSaveExpectingError()
{
String errorText;
elementCache().saveExtension.click();
errorText = waitForElement(Locators.labkeyError).getText();
clearCache();
return errorText;
}

public AllowedFileExtensionAdminPage clickSaveExtension()
{
elementCache().saveExtension.click();
clearCache();
return this;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the buttons (delete, save, and update) trigger a page load, regardless of whether there is an error. These should all wait for a page load and error-free versions should verify that there is no error.

Suggested change
public String clickSaveExpectingError()
{
String errorText;
elementCache().saveExtension.click();
errorText = waitForElement(Locators.labkeyError).getText();
clearCache();
return errorText;
}
public AllowedFileExtensionAdminPage clickSaveExtension()
{
elementCache().saveExtension.click();
clearCache();
return this;
}
private AllowedFileExtensionAdminPage clickButtonNoError(WebElement button)
{
clickAndWait(button);
clearCache();
assertNoLabKeyErrors();
return this;
}
private String clickButtonExpectingError(WebElement button)
{
clickAndWait(button);
clearCache();
return waitForElement(Locators.labkeyError).getText();
}
public String clickSaveExpectingError()
{
return clickButtonExpectingError(elementCache().saveExtension);
}
public AllowedFileExtensionAdminPage clickSaveExtension()
{
return clickButtonNoError(elementCache().saveExtension);
}

And so on for update and delete.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Comment on lines +114 to +128
elementCache().deleteAll.click();

if (acceptAlert)
{
acceptAlert();
shortWait().withMessage("'Delete All' button should have gone away.")
.until(ExpectedConditions.stalenessOf(elementCache().deleteAll));
}
else
{
cancelAlert();
}

clearCache();
return this;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This staleness check will always pass because there is a page load. Need to clear the cache and check the button's visibility.

Suggested change
elementCache().deleteAll.click();
if (acceptAlert)
{
acceptAlert();
shortWait().withMessage("'Delete All' button should have gone away.")
.until(ExpectedConditions.stalenessOf(elementCache().deleteAll));
}
else
{
cancelAlert();
}
clearCache();
return this;
if (acceptAlert)
{
doAndWaitForPageLoad(() -> {
elementCache().deleteAll.click();
acceptAlert();
});
clearCache();
assertFalse("Delete All button should not be present after deleting all extensions", elementCache().deleteAll.isDisplayed());
}
else
{
elementCache().deleteAll.click();
cancelAlert();
assertTrue("Delete All button should be present", elementCache().deleteAll.isDisplayed());
}
return this;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Comment on lines +81 to +84
new PortalHelper(getDriver()).addWebPart("Files");
new PortalHelper(getDriver()).addWebPart("Sample Types");
new PortalHelper(getDriver()).addWebPart("Lists");
new PortalHelper(getDriver()).addWebPart("Messages List");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each addWebPart enters and exits page admin mode. Wrap in doInAdminMode to avoid all the extra navigations.

Suggested change
new PortalHelper(getDriver()).addWebPart("Files");
new PortalHelper(getDriver()).addWebPart("Sample Types");
new PortalHelper(getDriver()).addWebPart("Lists");
new PortalHelper(getDriver()).addWebPart("Messages List");
new PortalHelper(driver).doInAdminMode(ph -> {
ph.addWebPart("Files");
ph.addWebPart("Sample Types");
ph.addWebPart("Lists");
ph.addWebPart("Messages List");
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +244 to +271
allowedFileExtensionAdminPage = goToAdminConsole().clickAllowedFileExtensions();
allowedFileExtensionAdminPage.setExtension("not .an extension");
String expectedValue = "File extension must start with a '.'";
String actualValue = allowedFileExtensionAdminPage.clickSaveExpectingError();
checker().withScreenshot()
.verifyEquals("Incorrect error message for invalid extension.",
expectedValue, actualValue);

allowedFileExtensionAdminPage.setExtension(allowedTypes.get(0));
expectedValue = String.format("'%s' already exists. Duplicate values not allowed.", allowedTypes.get(0));
actualValue = allowedFileExtensionAdminPage.clickSaveExpectingError();
checker().withScreenshot()
.verifyEquals("Incorrect error message for duplicate extension.",
expectedValue, actualValue);

allowedFileExtensionAdminPage.setExtension(allowedTypes.get(1).toUpperCase());
expectedValue = String.format("'%s' already exists. Duplicate values not allowed.", allowedTypes.get(1).toUpperCase());
actualValue = allowedFileExtensionAdminPage.clickSaveExpectingError();
checker().withScreenshot()
.verifyEquals("Incorrect error message for duplicate extension but different case.",
expectedValue, actualValue);

allowedFileExtensionAdminPage.setExtension("");
expectedValue = "File extension must not be blank.";
actualValue = allowedFileExtensionAdminPage.clickSaveExpectingError();
checker().withScreenshot()
.verifyEquals("Incorrect error message for blank extension value.",
expectedValue, actualValue);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving the admin page validation to a separate test case (duplicate extensions, updating extensions, invalid extensions, delete all cancelling, etc.)

Copy link
Copy Markdown
Contributor

@labkey-danield labkey-danield Jun 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved most of the tests cases that check the admin page functionality into a separate class:

  • Check that allowed file extensions are listed in alphabetical order.
  • Canceling out of 'Delete All'.
  • Validate extension value must start with a '.'
  • Validate duplicate extensions are not allowed.
  • Validate blank extension type is not allowed.

I did leave in test cases that validate actions on the admin page behave as expected in the project:

  • Remove an allowed file type and validate files of that type cannot be uploaded.
  • Click 'Delete All' and validate any file type can be uploaded.
  • Edit an allowed extension, .xls to .xlsx, and validate .xlsx files can be uploaded, but .xls cannot.

As a side note it is not possible to test for dirty bit in LKS with selenium. See issue 38785.

Comment on lines +360 to +361
_listHelper.createList(getProjectName(), listName, keyField,
new FieldDefinition(attachmentField, FieldDefinition.ColumnType.Attachment));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create list via API.

Suggested change
_listHelper.createList(getProjectName(), listName, keyField,
new FieldDefinition(attachmentField, FieldDefinition.ColumnType.Attachment));
new IntListDefinition(listName, keyField)
.addField(new FieldDefinition(attachmentField, FieldDefinition.ColumnType.Attachment))
.create(getProjectName(), createDefaultConnection());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +394 to +395
FileInput el = FileInput.FileInput(Locator.name("quf_" + attachmentField), getDriver()).findWhenNeeded();
executeScript("arguments[0].value = '';", el.getComponentElement());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does WebElement.clear work for this?

Suggested change
FileInput el = FileInput.FileInput(Locator.name("quf_" + attachmentField), getDriver()).findWhenNeeded();
executeScript("arguments[0].value = '';", el.getComponentElement());
FileInput el = FileInput.FileInput(Locator.name("quf_" + attachmentField), getDriver()).findWhenNeeded();
el.getComponentElement().clear();

If it does, consider adding a clear method to FileInput.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears to. I've added FileInput.clear.

@labkey-jeckels
Copy link
Copy Markdown
Contributor

The instructions on the admin page say that ".gz" won't allow ".tar.gz" files; should we verify that is true?

This is a good idea - we should cover a "double extension" like this.

@labkey-tchad labkey-tchad self-requested a review May 22, 2025 22:26
Copy link
Copy Markdown
Contributor

@labkey-chrisj labkey-chrisj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have anything pressing to add, looks good to me tho

Move deleteAllAllowedFileExtensions to the AllowedFileExtensionAdminPage
Consolidate button code in AllowedFileExtensionAdminPage
Remove calls to checkExpectedErrors.
Adding FileInput.clear method.
Many other code review feedback as well.
Move deleteAllAllowedFileExtensions to the AllowedFileExtensionAdminPage
Consolidate button code in AllowedFileExtensionAdminPage
Remove calls to checkExpectedErrors.
Adding FileInput.clear method.
Many other code review feedback as well.
@labkey-danield
Copy link
Copy Markdown
Contributor

The instructions on the admin page say that ".gz" won't allow ".tar.gz" files; should we verify that is true?

This is a good idea - we should cover a "double extension" like this.

I've added a tar.gz file to the mix.

… (AllowedFileExtensionsPageTest).

Add a base class that has some shared code.
Cleaned up the biologics AllowedFileExtensionsTest (removed reset errors, used existing methods, updated expected error message).
Added AppRegisterCellLinePage.setColumnValue that takes a file parameter.
Added AppRegisterCellLinePage.clickSubmitExpectingError.
Updated ThreadAttachment.clickRemove to return a confirmation dialog.
Added ThreadEditor.clickCreateBtnExpectingError.
@labkey-danield labkey-danield merged commit 504f0ef into develop Jun 10, 2025
6 checks passed
@labkey-danield labkey-danield deleted the fb_allowFileExtensionAutoTest branch June 10, 2025 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants