Skip to content

Commit

Permalink
Merge pull request #58 from daniel-frak/e2e_forgotten_password
Browse files Browse the repository at this point in the history
End-to-end test the forgotten password flow after user is migrated
  • Loading branch information
daniel-frak authored May 8, 2022
2 parents 9e65e9c + 3047da9 commit 4897795
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 45 deletions.
9 changes: 9 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,20 @@ services:
environment:
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
DB_VENDOR: h2
ports:
- "8024:8080"
networks:
- internal

mailhog:
image: mailhog/mailhog
ports:
- 1025:1025 # smtp server
- 8025:8025 # web ui
networks:
- internal

legacy-system-example:
build:
context: legacy-system-example
Expand Down
3 changes: 2 additions & 1 deletion docker/e2e/cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"retries": {
"runMode": 2,
"openMode": 0
}
},
"mailHogUrl": "http://localhost:8025"
}
217 changes: 175 additions & 42 deletions docker/e2e/cypress/integration/migrating_users.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,43 @@
// check out the link below and learn how to write your first test:
// https://on.cypress.io/writing-first-test

const REST_CLIENT_URI = "http://legacy-system-example:8080/user-migration-support";
const quotedPrintable = require('quoted-printable');

const LEGACY_SYSTEM_URL = "http://legacy-system-example:8080/user-migration-support";

const SMTP_HOST = "mailhog";
const SMTP_PORT = "1025";
const SMTP_FROM = "admin@example.com";

const ADMIN_USERNAME = "admin";
const ADMIN_PASSWORD = "admin";
const ADMIN_EMAIL = 'admin@example.com';

const LEGACY_USER_USERNAME = "lucy";
const LEGACY_USER_PASSWORD = "password";
const LEGACY_USER_EMAIL = 'lucy@example.com';
const LEGACY_USER_FIRST_NAME = 'Lucy';
const LEGACY_USER_LAST_NAME = 'Brennan';

describe('user migration plugin', () => {
beforeEach(() => {

before(() => {
signOutViaUrl();
deleteTestUserIfExists();
});
signInAsAdmin();
configureLoginSettings();
configureMigrationPlugin();
configureEmails();
signOutViaUI();
})

function signOutViaUrl() {
cy.visit('http://localhost:8024/auth/realms/master/protocol/openid-connect/logout' +
'?redirect_uri=http%3A%2F%2Flocalhost%3A8024%2Fauth%2Frealms%2Fmaster%2Faccount%2F');
}

function deleteTestUserIfExists() {
signInAsAdmin();
cy.visit('/admin/master/console/#/realms/master/users');
cy.intercept('GET', '/auth/admin/realms/master/users*').as("userGet");
cy.get('#viewAllUsers').click();
cy.wait('@userGet');

cy.get('body').then($body => {
if ($body.find('td:contains("lucy@localhost.com")').length > 0) {
cy.contains('lucy@localhost.com').parent().contains('Delete').click();
cy.get('.modal-dialog button').contains('Delete').click();
cy.get('.alert').should('contain', "Success");
}
signOutViaUI();
});
}

function signInAsAdmin() {
cy.visit('/admin');
submitCredentials("admin", "admin");
submitCredentials(ADMIN_USERNAME, ADMIN_PASSWORD);
}

function submitCredentials(user, password) {
Expand All @@ -50,36 +54,38 @@ describe('user migration plugin', () => {
cy.get('a').contains('Sign Out').click({force: true});
}

it('should migrate users', () => {
signInAsAdmin();
visitUserFederationPage();
configureMigrationPlugin();
signOutViaUI();
signInAsLegacyUser();
updateAccountInformation();
cy.get('#landingLoggedInUser').should('contain', 'Lucy Brennan');
});
function configureLoginSettings() {
cy.visit('/admin/master/console/#/realms/master/login-settings');

function visitUserFederationPage() {
cy.intercept('GET',
'/auth/admin/realms/master/components?parent=master&type=org.keycloak.storage.UserStorageProvider')
.as('storageProviders');
cy.visit('/admin/master/console/#/realms/master/user-federation/');
cy.wait('@storageProviders');
cy.contains("Forgot password").parent().find('[type="checkbox"]')
.uncheck({force: true})
.check({force: true});

cy.get('button').contains('Save').click();
}

function configureMigrationPlugin() {
visitUserFederationPage();
cy.wait(1000);
let providerDropdownSelector = '.blank-slate-pf-main-action select[ng-model="selectedProvider"]';
cy.get(providerDropdownSelector)
.then($providerDropdown => {
goToPluginSettings($providerDropdown, providerDropdownSelector);
cy.get('.form-group.ng-scope').contains('Rest client URI (required)').parent().within(() => {
cy.get('input').clear().type(REST_CLIENT_URI);
cy.get('input').clear().type(LEGACY_SYSTEM_URL);
});
cy.get('button').filter(':visible').contains('Save').click();
});
}

function visitUserFederationPage() {
cy.intercept('GET',
'/auth/admin/realms/master/components?parent=master&type=org.keycloak.storage.UserStorageProvider')
.as('storageProviders');
cy.visit('/admin/master/console/#/realms/master/user-federation/');
cy.wait('@storageProviders');
}

function goToPluginSettings($providerDropdown, providerDropdownSelector) {
if ($providerDropdown.is(':visible')) {
cy.get(providerDropdownSelector)
Expand All @@ -89,16 +95,143 @@ describe('user migration plugin', () => {
}
}

function configureEmails() {
configureAdminPersonalInfo();
configureSmtpSettings();
}

function configureAdminPersonalInfo() {
cy.intercept('GET', '/auth/realms/master/account/')
.as("accountDetails");
cy.visit('/realms/master/account/#/personal-info');
cy.wait('@accountDetails');

// Wait a while, otherwise Keycloak overrides the inputs randomly
cy.wait(5000);

cy.get('#email-address').clear().type(ADMIN_EMAIL);
cy.get('#first-name').clear().type(ADMIN_USERNAME);
cy.get('#last-name').clear().type(ADMIN_USERNAME);

cy.get('button').contains('Save').click();

cy.get('.pf-c-alert').should('contain', "Your account has been updated");
}

function configureSmtpSettings() {
cy.visit('/admin/master/console/#/realms/master/smtp-settings');

cy.get('#smtpHost').clear().type(SMTP_HOST);
cy.get('#smtpPort').clear().type(SMTP_PORT);
cy.get('#smtpFrom').clear().type(SMTP_FROM);

cy.get('a').contains('Test connection').click();
cy.get('.alert').should('contain', "SMTP connection successful. E-mail was sent!");

cy.get('button').contains('Save').click();
}

beforeEach(() => {
deleteEmails();
deleteTestUserIfExists();
});

function deleteEmails() {
cy.mhDeleteAll();
cy.mhGetAllMails()
.should('have.length', 0);
}

function deleteTestUserIfExists() {
signInAsAdmin();
cy.visit('/admin/master/console/#/realms/master/users');
cy.intercept('GET', '/auth/admin/realms/master/users*').as("userGet");
cy.get('#viewAllUsers').click();
cy.wait('@userGet');

cy.get('body').then($body => {
if ($body.find('td:contains("' + LEGACY_USER_EMAIL + '")').length > 0) {
cy.contains(LEGACY_USER_EMAIL).parent().contains('Delete').click();
cy.get('.modal-dialog button').contains('Delete').click();
cy.get('.alert').should('contain', "Success");
}
signOutViaUI();
});
}

it('should migrate users', () => {
signInAsLegacyUser();
updateAccountInformation();
assertIsLoggedInAsLegacyUser();
});

function signInAsLegacyUser() {
cy.visit('/realms/master/account');
cy.get('button').contains('Sign In').click();
submitCredentials("lucy", "password");
submitCredentials(LEGACY_USER_USERNAME, LEGACY_USER_PASSWORD);
}

function updateAccountInformation() {
cy.get('#email').should('have.value', 'lucy@localhost.com');
cy.get('#firstName').should('have.value', 'Lucy');
cy.get('#lastName').should('have.value', 'Brennan');
cy.get('#email').should('have.value', LEGACY_USER_EMAIL);
cy.get('#firstName').should('have.value', LEGACY_USER_FIRST_NAME);
cy.get('#lastName').should('have.value', LEGACY_USER_LAST_NAME);
cy.get("input").contains("Submit").click();
}

function assertIsLoggedInAsLegacyUser() {
cy.get('#landingLoggedInUser').should('contain', LEGACY_USER_FIRST_NAME + ' ' + LEGACY_USER_LAST_NAME);
}

it('should reset password after inputting wrong credentials', () => {
attemptLoginWithWrongPassword();
triggerPasswordReset();

cy.mhGetMailsBySubject('Reset password')
.should('have.length', 1);

cy.mhGetMailsBySubject('Reset password').mhFirst().mhGetBody()
.then(bodyQuotedPrintable => {
clickPasswordResetLink(bodyQuotedPrintable);
updateAccountInformation();
inputNewPassword();
assertIsLoggedInAsLegacyUser();
});
});

function attemptLoginWithWrongPassword() {
cy.visit('/realms/master/account');
cy.get('button').contains('Sign In').click();
submitCredentials(LEGACY_USER_USERNAME, "wrongPassword");
}

function triggerPasswordReset() {
cy.intercept('GET', '/auth/realms/master/login-actions/reset-credentials*')
.as('resetCredentials');
cy.get("a").contains("Forgot Password?").click();
cy.wait('@resetCredentials');
cy.get('#username').clear().type(LEGACY_USER_EMAIL);
cy.get('input[type=submit]').click();
cy.get('body').should('contain.text',
'You should receive an email shortly with further instructions.');
}

function clickPasswordResetLink(bodyQuotedPrintable) {
const body = quotedPrintable.decode(bodyQuotedPrintable);
const resetPassUrl = getUrlFromLink(body, 'Link to reset credentials');

cy.visit(resetPassUrl);
}

function getUrlFromLink(body, linkText) {
const linkPattern = new RegExp('<a href="([^"]*).+' + linkText + '.*?<\\/a>');
return linkPattern.exec(body)[1]
.toString()
.replace(/(\r\n|\n|\r)/gm, "");
}

function inputNewPassword() {
cy.get('#password-new').type(LEGACY_USER_PASSWORD);
cy.get('#password-confirm').type(LEGACY_USER_PASSWORD);
cy.get('input[type=submit]').click();
}
});
2 changes: 2 additions & 0 deletions docker/e2e/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

import 'cypress-mailhog';
18 changes: 18 additions & 0 deletions docker/e2e/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion docker/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"description": "",
"main": "index.js",
"dependencies": {
"cypress": "^9.6.0"
"cypress": "^9.6.0",
"cypress-mailhog": "^1.4.0",
"quoted-printable": "^1.0.1"
},
"devDependencies": {},
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ private User generateUser(String name, String lastName) {

return User.builder()
.username(username)
.email(username + "@localhost.com")
.email(username + "@example.com")
.firstName(name)
.lastName(lastName)
.password("password")
Expand Down

0 comments on commit 4897795

Please sign in to comment.