diff --git a/pom.xml b/pom.xml
index fd85c81b6a..055196ee7a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -492,6 +492,10 @@ and
-Djdk.net.URLClassPath.disableClassPathURLCheck=true
+
+
+ target/credentials.hpi
+
@@ -765,6 +769,12 @@ and
${jenkins.version}
war
+
+ org.jenkins-ci.plugins
+ credentials
+ 1561.v172b_32e210ef
+ hpi
+
${project.build.directory}
true
diff --git a/src/main/java/org/jenkinsci/test/acceptance/junit/WithCredentials.java b/src/main/java/org/jenkinsci/test/acceptance/junit/WithCredentials.java
index 7a60279306..110c300e4f 100644
--- a/src/main/java/org/jenkinsci/test/acceptance/junit/WithCredentials.java
+++ b/src/main/java/org/jenkinsci/test/acceptance/junit/WithCredentials.java
@@ -15,7 +15,6 @@
import org.jenkinsci.test.acceptance.plugins.credentials.UserPwdCredential;
import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshPrivateKeyCredential;
import org.jenkinsci.test.acceptance.po.Jenkins;
-import org.junit.AssumptionViolatedException;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -107,19 +106,13 @@ private boolean enterCredentials(WithCredentials wp) {
* @param sshKeyPath path to the ssh key
*/
private void addSshUsernamePrivateKeyCredentials(String username, String sshKeyPath, String id) {
- try {
- CredentialsPage cp = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
- cp.open();
- SshPrivateKeyCredential sc = cp.add(SshPrivateKeyCredential.class);
- sc.username.set(username);
- sc.selectEnterDirectly()
- .privateKey
- .set(resource(sshKeyPath).asText());
- maybeSetId(sc, id);
- cp.create();
- } catch (Exception ex) {
- throw new AssumptionViolatedException("@WithCredentials requires credentials@2.0.7.", ex);
- }
+ CredentialsPage cp = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
+ cp.open();
+ SshPrivateKeyCredential sc = cp.add(SshPrivateKeyCredential.class);
+ sc.username.set(username);
+ sc.selectEnterDirectly().privateKey.set(resource(sshKeyPath).asText());
+ maybeSetId(sc, id);
+ cp.create();
}
/**
@@ -128,17 +121,13 @@ private void addSshUsernamePrivateKeyCredentials(String username, String sshKeyP
* @param password password
*/
private void addUsernamePasswordCredentials(String username, String password, String id) {
- try {
- CredentialsPage c = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
- c.open();
- final UserPwdCredential upc = c.add(UserPwdCredential.class);
- upc.username.set(username);
- upc.password.set(password);
- maybeSetId(upc, id);
- c.create();
- } catch (Exception ex) {
- throw new AssumptionViolatedException("@WithCredentials requires credentials@2.0.7.", ex);
- }
+ CredentialsPage c = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
+ c.open();
+ final UserPwdCredential upc = c.add(UserPwdCredential.class);
+ upc.username.set(username);
+ upc.password.set(password);
+ maybeSetId(upc, id);
+ c.create();
}
private void maybeSetId(BaseStandardCredentials creds, String id) {
diff --git a/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/AbstractCredentialsTest.java b/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/AbstractCredentialsTest.java
index f758cc7540..b46ae527dc 100644
--- a/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/AbstractCredentialsTest.java
+++ b/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/AbstractCredentialsTest.java
@@ -110,6 +110,7 @@ protected T createCredentials(
SshPrivateKeyCredential castedCred = (SshPrivateKeyCredential) cred;
castedCred.description.set(CRED_DSCR);
if (scope != null) {
+ waitFor(by.option(scope));
castedCred.scope.select(scope);
}
castedCred.username.set(CRED_USER);
@@ -126,7 +127,7 @@ private void navigateToCreateCredentials() {
tryCredentialsClick();
waitFor(by.href("/user/" + CREATED_USER + "/credentials/store/user")).click();
waitFor(by.href("domain/_")).click();
- waitFor(by.href("newCredentials")).click();
+ waitFor(by.button("Add Credentials")).click();
waitFor(by.name("_.id"));
}
diff --git a/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/Credential.java b/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/Credential.java
index eddf49240c..be89f7de93 100644
--- a/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/Credential.java
+++ b/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/Credential.java
@@ -29,11 +29,11 @@ protected Credential(PageArea area, String relativePath) {
*/
public void add() {
WebElement dialog = find(by.id("credentials-dialog-form"));
- WebElement we = find(submitButton());
+ WebElement we = find(by.id("cr-dialog-submit"));
we.click();
// wait for the form to be removed from the UI
waitFor(driver).until(ExpectedConditions.invisibilityOf(dialog));
- // the notification bar can place itslef over other elements
+ // the notification bar can place itself over other elements
// so wait for it to be added and then disappear
waitFor(waitFor(By.id("notification-bar"))).until(bar -> !bar.isDisplayed());
}
diff --git a/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/CredentialsPage.java b/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/CredentialsPage.java
index f60d26f84e..dfca558b1b 100644
--- a/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/CredentialsPage.java
+++ b/src/main/java/org/jenkinsci/test/acceptance/plugins/credentials/CredentialsPage.java
@@ -10,7 +10,9 @@
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.Folder;
import org.jenkinsci.test.acceptance.po.Jenkins;
+import org.jenkinsci.test.acceptance.selenium.Scroller;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
public class CredentialsPage extends ConfigurablePageObject {
public final Control addButton = control(by.xpath("//select[contains(@class, 'setting-input dropdownList')] | "
@@ -22,26 +24,41 @@ public class CredentialsPage extends ConfigurablePageObject {
* Create a new Credential
*/
public CredentialsPage(Jenkins j, String domainName) {
- super(j, j.url("credentials/store/system/domain/" + domainName + "/newCredentials"));
+ super(j, j.url("credentials/store/system/domain/" + domainName));
}
/**
* Create a new Credential scoped to a Folder
*/
public CredentialsPage(Folder f, String domainName) {
- super(f, f.url("credentials/store/folder/domain/" + domainName + "/newCredentials"));
+ super(f, f.url("credentials/store/folder/domain/" + domainName));
}
/**
* Create a new personal Credential
*/
public CredentialsPage(Jenkins j, String domainName, String userName) {
- super(j, j.url(String.format("user/%s/credentials/store/user/domain/%s/newCredentials", userName, domainName)));
+ super(j, j.url(String.format("user/%s/credentials/store/user/domain/%s", userName, domainName)));
}
public T add(Class type) {
- addButton.selectDropdownMenuAlt(type);
- String path = find(by.name("credentials")).getAttribute("path");
+ WebElement radio = findCaption(type, caption -> {
+ for (WebElement webElement : all(by.css(".jenkins-choice-list__item__label"))) {
+ if (webElement.getText().equals(caption)) {
+ webElement.click();
+ return webElement.findElement(by.xpath("./../input"));
+ }
+ }
+ return null;
+ });
+
+ String path = radio.getAttribute("path");
+
+ WebElement nextButton = find(by.id("cr-dialog-next"));
+ nextButton.click();
+ waitFor(by.id("cr-dialog-submit"));
+ new Scroller(driver).disableStickyElements();
+
return newInstance(type, this, path);
}
@@ -56,7 +73,7 @@ public void setConfigUrl(String url) throws MalformedURLException {
}
public void create() {
- find(by.name("Submit")).click();
+ find(by.id("cr-dialog-submit")).click();
assertThat(driver, not(hasContent("This page expects a form submission")));
}
@@ -72,9 +89,10 @@ public void delete() {
@Override
public WebDriver open() {
WebDriver wd = super.open();
- // wait for default form fields to be present to avoid possible race
- // condition when changing credentials type too fast (happens rarely)
- waitFor(by.name("_.id"));
+
+ clickButton("Add Credentials");
+ // Selenium will execute the next step before the options have loaded if we don't wait for them
+ waitFor(by.css(".jenkins-choice-list__item__label"));
return wd;
}
diff --git a/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_credentials/SshCredentialDialog.java b/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_credentials/SshCredentialDialog.java
index 95c4533e72..2394742ec5 100644
--- a/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_credentials/SshCredentialDialog.java
+++ b/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_credentials/SshCredentialDialog.java
@@ -1,7 +1,6 @@
package org.jenkinsci.test.acceptance.plugins.ssh_credentials;
import org.jenkinsci.test.acceptance.plugins.credentials.BaseStandardCredentials;
-import org.jenkinsci.test.acceptance.plugins.credentials.Credential;
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.PageObject;
@@ -16,19 +15,4 @@ public class SshCredentialDialog extends BaseStandardCredentials {
public SshCredentialDialog(PageObject context, String path) {
super(context, path);
}
-
- /**
- * Selects the credential type and bind the controls to the page area.
- */
- public T select(Class type) {
-
- findCaption(type, new Resolver() {
- @Override
- protected void resolve(String caption) {
- kind.select(caption);
- }
- });
-
- return newInstance(type, getPage(), getPath());
- }
}
diff --git a/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_slaves/SshSlaveLauncher.java b/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_slaves/SshSlaveLauncher.java
index 540dd04b74..4a68fd3576 100644
--- a/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_slaves/SshSlaveLauncher.java
+++ b/src/main/java/org/jenkinsci/test/acceptance/plugins/ssh_slaves/SshSlaveLauncher.java
@@ -4,14 +4,16 @@
import edu.umd.cs.findbugs.annotations.CheckForNull;
import java.time.Duration;
+import org.jenkinsci.test.acceptance.plugins.credentials.Credential;
import org.jenkinsci.test.acceptance.plugins.credentials.UserPwdCredential;
-import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshCredentialDialog;
import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshPrivateKeyCredential;
import org.jenkinsci.test.acceptance.po.ComputerLauncher;
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.Describable;
import org.jenkinsci.test.acceptance.po.PageObject;
+import org.jenkinsci.test.acceptance.selenium.Scroller;
import org.jenkinsci.test.acceptance.selenium.UselessFileDetectorReplacement;
+import org.openqa.selenium.WebElement;
/**
* @author Kohsuke Kawaguchi
@@ -32,14 +34,31 @@ public SshSlaveLauncher(PageObject context, String path) {
super(context, path);
}
- public SshCredentialDialog addCredential() {
+ public T addCredential(Class type) {
find(by.button("Add")).click();
- find(by.css(".jenkins-dropdown"))
- .findElement(by.button("Jenkins Credentials Provider"))
- .click();
+ find(by.css(".jenkins-dropdown")).findElement(by.button("Global")).click();
- return new SshCredentialDialog(getPage(), "/credentials");
+ // Selenium will execute the next step before the options have loaded if we don't wait for them
+ waitFor(by.css(".jenkins-choice-list__item__label"));
+
+ WebElement radio = findCaption(type, caption -> {
+ for (WebElement webElement : all(by.css(".jenkins-choice-list__item__label"))) {
+ if (webElement.getText().equals(caption)) {
+ webElement.click();
+ return webElement.findElement(by.xpath("./../input"));
+ }
+ }
+ return null;
+ });
+
+ String path = radio.getAttribute("path");
+
+ WebElement nextButton = find(by.id("cr-dialog-next"));
+ nextButton.click();
+ waitFor(by.id("cr-dialog-submit"));
+ new Scroller(driver).disableStickyElements();
+ return newInstance(type, getPage(), path);
}
public void setJavaPath(String jvmPath) {
@@ -55,6 +74,8 @@ public SshSlaveLauncher port(int port) {
}
private void ensureAdvancedOpen() {
+ new Scroller(driver).disableStickyElements();
+
control("advanced-button").click();
}
@@ -66,8 +87,7 @@ private void ensureAdvancedOpen() {
* @return the SshSlaveLauncher to be configured
*/
public SshSlaveLauncher pwdCredentials(String username, String password) {
- final SshCredentialDialog dia = this.addCredential();
- final UserPwdCredential cred = dia.select(UserPwdCredential.class);
+ final UserPwdCredential cred = this.addCredential(UserPwdCredential.class);
cred.username.set(username);
cred.password.set(password);
// credentials are identified by their id. Set username as id so it can be found by it
@@ -86,8 +106,7 @@ public SshSlaveLauncher pwdCredentials(String username, String password) {
* @return the SshSlaveLauncher to be configured
*/
public SshSlaveLauncher pwdCredentials(String username, String password, String id) {
- final SshCredentialDialog dia = this.addCredential();
- final UserPwdCredential cred = dia.select(UserPwdCredential.class);
+ final UserPwdCredential cred = this.addCredential(UserPwdCredential.class);
cred.username.set(username);
cred.password.set(password);
// credentials are identified by their id.
@@ -105,8 +124,7 @@ public SshSlaveLauncher pwdCredentials(String username, String password, String
* @return the SshSlaveLauncher to be configured
*/
public SshSlaveLauncher keyCredentials(String username, String key, @CheckForNull String passphrase) {
- final SshCredentialDialog dia = this.addCredential();
- final SshPrivateKeyCredential cred = dia.select(SshPrivateKeyCredential.class);
+ final SshPrivateKeyCredential cred = this.addCredential(SshPrivateKeyCredential.class);
cred.username.set(username);
if (passphrase != null) {
cred.passphrase.set(passphrase);
diff --git a/src/main/resources/org/jenkinsci/test/acceptance/selenium/disable-sticky-elements.js b/src/main/resources/org/jenkinsci/test/acceptance/selenium/disable-sticky-elements.js
index 525c2f3f17..51766d73c1 100644
--- a/src/main/resources/org/jenkinsci/test/acceptance/selenium/disable-sticky-elements.js
+++ b/src/main/resources/org/jenkinsci/test/acceptance/selenium/disable-sticky-elements.js
@@ -7,6 +7,20 @@ const bottomAppBar = document.getElementById("bottom-sticker");
// https://github.com/jenkinsci/jenkins/commit/6481e78d20a0c689859058da5a029489e8b5072c introduced a shadow on a different div!?
const bottomShadow = document.querySelector(".jenkins-bottom-app-bar__shadow")
+document.querySelectorAll(".bottom-sticker-inner")
+ .forEach(element => {
+ // there can be multiple bottom stickers (e.g. in a dialog) but there's no class on the actual element
+ const bottomSticker = element.parentNode
+ if (bottomSticker) {
+ bottomSticker.style.position = "relative";
+ }
+ })
+
+document.querySelectorAll(".jenkins-bottom-app-bar__shadow")
+ .forEach(element => {
+ element.style.position = "initial";
+ })
+
if (header) {
header.style.position = "relative";
}
diff --git a/src/test/java/plugins/SshSlavesPluginTest.java b/src/test/java/plugins/SshSlavesPluginTest.java
index aa7ed5f69d..c75bc37bce 100644
--- a/src/test/java/plugins/SshSlavesPluginTest.java
+++ b/src/test/java/plugins/SshSlavesPluginTest.java
@@ -41,7 +41,6 @@
import org.jenkinsci.test.acceptance.junit.WithPlugins;
import org.jenkinsci.test.acceptance.plugins.credentials.CredentialsPage;
import org.jenkinsci.test.acceptance.plugins.credentials.ManagedCredentials;
-import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshCredentialDialog;
import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshPrivateKeyCredential;
import org.jenkinsci.test.acceptance.plugins.ssh_slaves.SshSlaveLauncher;
import org.jenkinsci.test.acceptance.po.Control;
@@ -96,14 +95,13 @@ public void newAgent() {
// ignore
}
- SshCredentialDialog f = l.addCredential();
+ SshPrivateKeyCredential sc = l.addCredential(SshPrivateKeyCredential.class);
{
- SshPrivateKeyCredential sc = f.select(SshPrivateKeyCredential.class);
sc.description.set(description);
sc.username.set(username);
sc.selectEnterDirectly().privateKey.set(privateKey);
+ sc.add();
}
- f.add();
l.credentialsId.select(String.format("%s (%s)", username, description));
}