Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 16 additions & 20 deletions src/org/labkey/test/LabKeySiteWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.labkey.test.components.ui.navigation.UserMenu;
import org.labkey.test.pages.core.admin.CustomizeSitePage;
import org.labkey.test.pages.core.admin.ShowAdminPage;
import org.labkey.test.pages.core.login.SignInPage;
import org.labkey.test.pages.user.UserDetailsPage;
import org.labkey.test.util.APIUserHelper;
import org.labkey.test.util.ApiPermissionsHelper;
Expand Down Expand Up @@ -156,7 +157,7 @@ public void simpleSignIn()
}
else
{
fillSignInFormAndSubmit();
fillSignInFormAndSubmit("Sign In");

// verify we're signed in now
if (!waitFor(() ->
Expand Down Expand Up @@ -197,14 +198,22 @@ else if (errors.contains("log in and approve the terms of use."))
WebTestHelper.saveSession(PasswordUtil.getUsername(), getDriver());
}

public void fillSignInFormAndSubmit()
public void fillSignInFormAndSubmit(String buttonText)
{
log("Signing in as " + PasswordUtil.getUsername());
fillSignInFormAndSubmit(buttonText, PasswordUtil.getUsername(), PasswordUtil.getPassword());
}

public void fillSignInFormAndSubmit(String buttonText, String username, String password)
{
log(buttonText + " as " + username);
assertElementPresent(Locator.tagWithName("form", "login"));
setFormElement(Locator.name("email"), PasswordUtil.getUsername());
setFormElement(Locator.name("password"), PasswordUtil.getPassword());
setFormElement(Locator.name("email"), username);
setFormElement(Locator.name("password"), password);
acceptTermsOfUse(null, false);
clickButton("Sign In", 0);
WebElement signInButton = Locator.byClass("signin-btn").findElement(getDriver());
if (buttonText != null)
assertEquals("Wrong sign-in button text", buttonText, signInButton.getText());
signInButton.click();
}

/**
Expand Down Expand Up @@ -404,20 +413,7 @@ public void attemptSignIn(String email, String password)
}
}

assertTitleContains("Sign In");

assertElementPresent(Locator.tagWithName("form", "login"));
setFormElement(Locator.id("email"), email);
setFormElement(Locator.id("password"), password);
WebElement signInButton = Locator.button("Sign In").findElement(getDriver());
doAndMaybeWaitForPageToLoad(10_000, () -> {
signInButton.click();
shortWait().until(ExpectedConditions.invisibilityOfElementLocated(Locator.byClass("signing-in-msg")));
shortWait().until(ExpectedConditions.or(
ExpectedConditions.stalenessOf(signInButton), // Successful login
ExpectedConditions.presenceOfElementLocated(Locators.labkeyError.withText()))); // Error during sign-in
return ExpectedConditions.stalenessOf(signInButton).apply(null);
});
new SignInPage(getDriver()).signIn(email, password);
}

public void signInShouldFail(String email, String password, String... expectedMessages)
Expand Down
4 changes: 2 additions & 2 deletions src/org/labkey/test/components/react/ReactDateTimePicker.java
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ protected ElementCache newElementCache()
protected class ElementCache extends Component<?>.ElementCache
{
WebElement inputContainer = Locator.tagWithClass("div", "react-datepicker__input-container")
.findElement(this);
public Input input = new Input(Locator.tag("input").findWhenNeeded(inputContainer), getDriver());
.refindWhenNeeded(this);
public Input input = new Input(Locator.tag("input").refindWhenNeeded(inputContainer), getDriver());

WebElement popup = Locator.xpath(".").followingSibling("div").withClass("react-datepicker__tab-loop")
.refindWhenNeeded(this);
Expand Down
70 changes: 70 additions & 0 deletions src/org/labkey/test/pages/core/login/SignInPage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2026 LabKey Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.labkey.test.pages.core.login;

import org.labkey.test.Locator;
import org.labkey.test.Locators;
import org.labkey.test.pages.LabKeyPage;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

/**
* Page object for the LabKey "Sign In" page. This object assumes the browser is already on the Sign In page; it does
* not handle navigating to it (e.g. clicking a "Sign In" link).
*/
public class SignInPage extends LabKeyPage<SignInPage.ElementCache>
{
public SignInPage(WebDriver driver)
{
super(driver);
}

@Override
protected void waitForPage()
{
waitFor(() -> getDriver().getTitle().contains("Sign In") && isElementPresent(Locator.tagWithName("form", "login")),
"Sign In page did not load in time.", WAIT_FOR_PAGE);
}

public void signIn(String userName, String password)
{
setFormElement(elementCache().emailInput, userName);
setFormElement(elementCache().passwordInput, password);
WebElement signInButton = elementCache().signInButton;
doAndMaybeWaitForPageToLoad(10_000, () -> {
signInButton.click();
shortWait().until(ExpectedConditions.invisibilityOfElementLocated(Locator.byClass("signing-in-msg")));
shortWait().until(ExpectedConditions.or(
ExpectedConditions.stalenessOf(signInButton), // Successful login
ExpectedConditions.presenceOfElementLocated(Locators.labkeyError.withText()))); // Error during sign-in
return ExpectedConditions.stalenessOf(signInButton).apply(null);
});
}

@Override
protected ElementCache newElementCache()
{
return new ElementCache();
}

protected class ElementCache extends LabKeyPage<ElementCache>.ElementCache
{
WebElement emailInput = Locator.id("email").findWhenNeeded(getDriver());
WebElement passwordInput = Locator.id("password").findWhenNeeded(getDriver());
WebElement signInButton = Locator.byClass("signin-btn").findWhenNeeded(getDriver());
}
}
103 changes: 103 additions & 0 deletions src/org/labkey/test/pages/test/TestReauthPage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2018-2026 LabKey Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.labkey.test.pages.test;

import org.apache.hc.core5.http.HttpStatus;
import org.labkey.test.Locator;
import org.labkey.test.WebDriverWrapper;
import org.labkey.test.WebTestHelper;
import org.labkey.test.pages.LabKeyPage;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import java.util.Map;
import java.util.Optional;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

public class TestReauthPage extends LabKeyPage<TestReauthPage.ElementCache>
{
public TestReauthPage(WebDriver driver)
{
super(driver);
}

public static TestReauthPage beginAt(WebDriverWrapper webDriverWrapper)
{
webDriverWrapper.beginAt(WebTestHelper.buildURL("test", "home", "testReauth"));
return new TestReauthPage(webDriverWrapper.getDriver());
}

public static TestReauthPage beginAt(WebDriverWrapper webDriverWrapper, String reauthToken)
{
webDriverWrapper.beginAt(WebTestHelper.buildURL("test", "home", "testReauth", Map.of("reauthToken", reauthToken)));
return new TestReauthPage(webDriverWrapper.getDriver());
}

public String getDescription()
{
if (elementCache().description.isDisplayed())
return elementCache().description.getText();
else
return "";
}

public void clickReauth()
{
clickAndWait(elementCache().reauthLink);
clearCache();
}

public String getReauthToken()
{
return elementCache().reauthTokenInput()
.map(el -> el.getDomProperty("value")).orElse("");
}

public void validateToken()
{
clickAndWait(elementCache().validateButton);
clearCache();
assertNoLabKeyErrors();
assertEquals("Response code", HttpStatus.SC_OK, getResponseCode());
}

public void validateTokenExpectingError()
{
clickAndWait(elementCache().validateButton);
clearCache();
assertNotEquals("Response code", HttpStatus.SC_OK, getResponseCode());
}


@Override
protected ElementCache newElementCache()
{
return new ElementCache();
}

protected class ElementCache extends LabKeyPage<ElementCache>.ElementCache
{
final WebElement description = Locator.id("description").findWhenNeeded(this);
final WebElement reauthLink = Locator.id("link").findWhenNeeded(this);
final Optional<WebElement> reauthTokenInput()
{
return Locator.name("reauthToken").findOptionalElement(this);
}
final WebElement validateButton = Locator.tagWithAttribute("input", "value", "Sign!").findWhenNeeded(this);
}
}
139 changes: 139 additions & 0 deletions src/org/labkey/test/tests/AbstractReauthTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright (c) 2018-2026 LabKey Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.labkey.test.tests;

import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.labkey.test.BaseWebDriverTest;
import org.labkey.test.Locator;
import org.labkey.test.Locators;
import org.labkey.test.pages.test.TestReauthPage;

import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.*;

public abstract class AbstractReauthTest extends BaseWebDriverTest
{
public record User(String email, String password) { }

private final User user1;
private final User user2;

protected AbstractReauthTest(User user1, User user2)
{
this.user1 = user1;
this.user2 = user2;
}

protected abstract void clickSignIn();
protected abstract void authenticate(String email, String password);
protected abstract void authenticateExpectingError(String email, String password);

@Test
public void testReauth()
{
signInAs(user1);

TestReauthPage testReauthPage = TestReauthPage.beginAt(this);
testReauthPage.clickReauth();
authenticate(user1.email, user1.password);
testReauthPage.validateToken();

// Reauth again as the same user to ensure newer token is recognized
testReauthPage = TestReauthPage.beginAt(this);
testReauthPage.clickReauth();
authenticate(user1.email, user1.password);
testReauthPage.validateToken();
}

@Test
public void testReuseReauthToken()
{
signInAs(user1);

TestReauthPage testReauthPage = TestReauthPage.beginAt(this);
testReauthPage.clickReauth();
authenticate(user1.email, user1.password);
String reauthToken = testReauthPage.getReauthToken();
testReauthPage.validateToken();

testReauthPage = TestReauthPage.beginAt(this, reauthToken);
testReauthPage.validateTokenExpectingError();
assertElementPresent(Locator.byClass("labkey-error-heading").withText("Reauthentication validation failed!"));
}

@Test
public void testReauthAsWrongUser()
{
signInAs(user1);

TestReauthPage testReauthPage = TestReauthPage.beginAt(this);
testReauthPage.clickReauth();
authenticate(user2.email, user2.password);
assertElementPresent(Locators.labkeyError.containing("wrong user reauthenticated"));

testReauthPage.clickReauth(); // Try again
authenticate(user1.email, user1.password);
testReauthPage.validateToken();
}

/**
* Test that reauth works when fixing the password after logging in with the wrong password
*/
@Test
public void testReauthWithBadPassword()
{
signInAs(user1);

TestReauthPage testReauthPage = TestReauthPage.beginAt(this);
testReauthPage.clickReauth();
authenticateExpectingError(user1.email, user1.password + "wrong");

authenticate(user1.email, user1.password);
testReauthPage.validateToken();
}

private void signInAs(User user)
{
signOut();
clickSignIn();
authenticate(user.email, user.password);
assertSignedInAs(user);
}

private void assertSignedInAs(User user)
{
Assert.assertEquals("Signed in as", user.email, getCurrentUser());
}

@Override
protected String getProjectName()
{
return null;
}

@Override
public List<String> getAssociatedModules()
{
return Arrays.asList();
}
}
Loading