Skip to content
Merged
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
62 changes: 62 additions & 0 deletions app/javascript/__tests__/password_confirmation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* eslint-env jest */
import { checkPasswordsAndDisplayPopup } from '../src/password_confirmation'

require('jest')

let submitButton, passwordField, confirmationField

beforeEach(() => {
document.body.innerHTML = `
<form action="." method="post" class="test-form">
<div>
<label for="user_password">New Password</label><br>
<input autocomplete="off" class="form-control password-new" minlength="6" type="password" name="user[password]" id="user_password" />
</div>
<div>
<label for="user_password_confirmation">New Password Confirmation</label><br>
<input class="form-control password-confirmation" minlength="6" type="password" name="user[password_confirmation]" id="user_password_confirmation" />
</div>
<input type="submit" name="commit" value="Update Password" class="btn btn-danger submit-password" data-disable-with="Update Password" />
</form>
`
submitButton = document.getElementsByClassName('submit-password')[0]
passwordField = document.getElementsByClassName('password-new')[0]
confirmationField = document.getElementsByClassName('password-confirmation')[0]

submitButton.disabled = true
submitButton.classList.add('disabled')
submitButton.setAttribute('aria-disabled', true)
})

describe('ensure the password field matches the confirmation field on the client side', () => {
function isDisabled (el) {
return el.disabled && el.classList.contains('disabled') && el.hasAttribute('aria-disabled')
}

test('password fields match', () => {
passwordField.value = '123456'
confirmationField.value = '123456'
checkPasswordsAndDisplayPopup(submitButton, passwordField, confirmationField)
expect(isDisabled(submitButton)).toBe(false)
expect(document.getElementsByClassName('swal2-container').length).toBe(0)
})

test("password fields don't match", () => {
passwordField.value = '123456'
confirmationField.value = 'bad'
checkPasswordsAndDisplayPopup(submitButton, passwordField, confirmationField, true)
expect(document.getElementsByClassName('swal2-container').length).toBe(1)
})

test("password fields don't match and pop-up suppressed", () => {
passwordField.value = '123456'
confirmationField.value = 'bad'
checkPasswordsAndDisplayPopup(submitButton, passwordField, confirmationField)
expect(document.getElementsByClassName('swal2-container').length).toBe(0)
})

test('password fields match but are empty', () => {
expect(isDisabled(submitButton)).toBe(true)
expect(document.getElementsByClassName('swal2-container').length).toBe(0)
})
})
1 change: 1 addition & 0 deletions app/javascript/packs/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ require('src/dashboard')
require('src/sidebar')
require('src/readMore')
require('src/tooltip')
require('src/password_confirmation')
require('src/reports')

// Uncomment to copy all static images under ../images to the output folder and
Expand Down
61 changes: 61 additions & 0 deletions app/javascript/src/password_confirmation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* eslint-env jquery */

import Swal from 'sweetalert2'

import { disableBtn, enableBtn } from './casa_case'

const SUBMIT_BUTTON_CLASS = 'submit-password'
const PASSWORD_FIELD_CLASS = 'password-new'
const CONFIRMATION_FIELD_CLASS = 'password-confirmation'

function disableButtonWhenEmptyString (str, button) {
str.length === 0 ? disableBtn(button) : enableBtn(button)
}

// Checks if the password is equivalent to confirmation and has at least 1 character. If not,
// it will disable the button.
// @param {HTMLElement} button - submit button for the form field
// @param {HTMLElement} password - text input form field
// @param {HTMLElement} confirmation - text input form field
// @param {boolean} enablePopup - display popup when field is not in focus
function checkPasswordsAndDisplayPopup (button, password, confirmation, enablePopup = false) {
const passwordText = password.value
const confirmationText = confirmation.value

if (passwordText === confirmationText) {
disableButtonWhenEmptyString(passwordText, button)
} else {
if (enablePopup) {
Swal.fire({
icon: 'error',
title: 'Password Error',
text: 'The password and the confirmation password do not match'
})
}
disableBtn(button)
}
}

// Expects the class name constants above are applied to the correct fields. See
// `app/views/users/edit.html.erb` for usage
$('document').ready(() => {
if ($(`.${SUBMIT_BUTTON_CLASS}`).length > 0) {
const button = $(`.${SUBMIT_BUTTON_CLASS}`)[0]
const password = $(`.${PASSWORD_FIELD_CLASS}`)[0]
const confirmation = $(`.${CONFIRMATION_FIELD_CLASS}`)[0]

disableBtn(button)

$(`.${PASSWORD_FIELD_CLASS}`).on('blur', () => {
checkPasswordsAndDisplayPopup(button, password, confirmation)
})

$(`.${CONFIRMATION_FIELD_CLASS}`).on('blur', () => {
checkPasswordsAndDisplayPopup(button, password, confirmation, true)
})
}
})

export {
checkPasswordsAndDisplayPopup
}
6 changes: 3 additions & 3 deletions app/views/devise/passwords/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class: "form-control", required: true %>
<%= f.password_field :password,
autofocus: true,
autocomplete: "new-password",
class: "form-control",
class: "form-control password-new",
required: true,
minlength: 6 %>
</div>
Expand All @@ -30,13 +30,13 @@ class: "form-control", required: true %>
<%= f.label :password_confirmation, "Confirm new password" %><br>
<%= f.password_field :password_confirmation,
autocomplete: "new-password",
class: "form-control",
class: "form-control password-confirmation",
required: true,
minlength: 6 %>
</div>

<div class="actions">
<%= f.submit "Change my password", class: "btn btn-primary" %>
<%= f.submit "Change my password", class: "btn btn-primary submit-password" %>
</div>
<% end %>
</div>
Expand Down
6 changes: 3 additions & 3 deletions app/views/users/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@
</div>
<div class="field form-group">
<%= f.label :password, "New Password" %><br>
<%= f.password_field :password, autocomplete: "off", class: "form-control", minlength: 6 %>
<%= f.password_field :password, autocomplete: "off", class: "form-control password-new", minlength: 6 %>
</div>
<div class="field form-group">
<%= f.label :password_confirmation, "New Password Confirmation" %><br>
<%= f.password_field :password_confirmation, class: "form-control", minlength: 6 %>
<%= f.password_field :password_confirmation, class: "form-control password-confirmation", minlength: 6 %>
</div>
<div class="action_container">
<%= f.submit "Update Password", class: "btn btn-danger" %>
<%= f.submit "Update Password", class: "btn btn-danger submit-password" %>
</div>
<% end %>
</div>
Expand Down
2 changes: 2 additions & 0 deletions cypress/integration/volunteer/edit_profile.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ context("Logging into cypress as a volunteer", () => {
cy.contains("Change Password").click();
cy.contains("Current Password").should("exist");
cy.contains("New Password").should("exist");
cy.get(".password-new").type("123456")
cy.contains("New Password Confirmation").should("exist");
cy.get(".password-confirmation").type("123456")
cy.contains("Update Profile").click();
cy.contains("Profile was successfully updated.").should("exist");
});
Expand Down