Skip to content

Commit 47233c7

Browse files
committed
Add tests for custom email confirmation UX flow
- Tests the custom flow for both system and SSO sign in - Tests the custom flash messages including the embedded link to the confirmation email request page
1 parent c3075f1 commit 47233c7

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

spec/factories/identifier_schemes.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@
2727
context_count { 1 }
2828
end
2929

30+
# Add a trait for Shibboleth
31+
trait :shibboleth do
32+
name { 'shibboleth' }
33+
context { 11 }
34+
description { 'Institutional Sign In (Shibboleth)' }
35+
logo_url { nil }
36+
identifier_prefix { nil }
37+
active { true }
38+
end
39+
3040
after(:create) do |identifier_scheme, evaluator|
3141
(0..evaluator.context_count - 1).each do |idx|
3242
identifier_scheme.update("#{identifier_scheme.all_context[idx]}": true)

spec/factories/users.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,14 @@
8282
end
8383
end
8484
end
85+
86+
trait :unconfirmed_and_no_confirmation_token do
87+
confirmed_at { nil }
88+
# When using :confirmable, a confirmation_token is generated at the time of user creation
89+
# Setting it to nil allows us to duplicate the attributes of some existing users
90+
after(:create) do |user|
91+
user.update(confirmation_token: nil)
92+
end
93+
end
8594
end
8695
end
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
SSO_SIGN_IN_BUTTON_TEXT = 'Sign in with your institutional credentials'
5+
6+
# For testing the custom email confirmation UX flow for unconfirmed users with no outstanding confirmation_token
7+
RSpec.describe 'Email Confirmation', type: :feature do
8+
include OmniAuthHelper
9+
10+
scenario 'A user attempts to sign in via the "Sign In" button.
11+
However, they are unconfirmed and have no confirmation_token.', :js do
12+
user = create(:user, :unconfirmed_and_no_confirmation_token)
13+
14+
# Sign-in attempt #1 (user is unconfirmed and has no confirmation_token)
15+
sign_in(user)
16+
expectations_for_unconfirmed_user_with_no_confirmation_token_after_sign_in_attempt(user)
17+
18+
# Sign-in attempt #2 (user still unconfirmed but has a confirmation_token)
19+
sign_in(user)
20+
expectations_for_unconfirmed_user_with_confirmation_token_after_sign_in_attempt
21+
22+
# Sign-in attempt #3 (user is now confirmed)
23+
user.confirm
24+
sign_in(user)
25+
# The user is signed in
26+
expect(page).to have_current_path(plans_path)
27+
end
28+
29+
scenario 'A user attempts to sign in via the "Sign in with your institutional credentials"
30+
button. The email is linked to a user account, however the account is
31+
unconfirmed and has no confirmation token.', :js do
32+
user = create(:user, :unconfirmed_and_no_confirmation_token)
33+
scheme = create(:identifier_scheme, :shibboleth)
34+
# Mock the OmniAuth authentication hash for Shibboleth via OmniAuthHelper
35+
OmniAuth.config.mock_auth[:shibboleth] = mock_auth_hash(user, scheme)
36+
# Create a Shibboleth-related Identifier for the user
37+
Identifier.create(identifier_scheme: scheme,
38+
value: OmniAuth.config.mock_auth[:shibboleth].uid,
39+
attrs: OmniAuth.config.mock_auth[:shibboleth],
40+
identifiable: user)
41+
42+
visit root_path
43+
# Sign-in attempt #1 (user is unconfirmed and has no confirmation_token)
44+
click_link SSO_SIGN_IN_BUTTON_TEXT
45+
expectations_for_unconfirmed_user_with_no_confirmation_token_after_sign_in_attempt(user)
46+
47+
visit root_path
48+
# Sign-in attempt #2 (user still unconfirmed but has a confirmation_token)
49+
click_link SSO_SIGN_IN_BUTTON_TEXT
50+
expectations_for_unconfirmed_user_with_confirmation_token_after_sign_in_attempt
51+
52+
# Sign-in attempt #3 (user is now confirmed)
53+
user.confirm
54+
click_link SSO_SIGN_IN_BUTTON_TEXT
55+
# The user is signed in
56+
expect(page).to have_current_path(plans_path)
57+
end
58+
59+
scenario 'A user is unconfirmed but has no confirmation token.
60+
There sign in attempt fails, and a custom flash message
61+
is rendered that can be used to navigate to the confirmation page.', :js do
62+
user = create(:user, confirmed_at: nil)
63+
# Attempt to sign in the unconfirmed user
64+
sign_in(user)
65+
expect(page).to have_current_path(root_path)
66+
# A flash warning is displayed informing the user that they have to confirm their email
67+
within('#notification-area') do
68+
# Click the link embedded in the flash message
69+
find('a.a-orange').click
70+
end
71+
# The user is redirected to the confirmation page
72+
expect(current_path).to eq(new_user_confirmation_path)
73+
end
74+
75+
private
76+
77+
# rubocop:disable Metrics/AbcSize
78+
def expectations_for_unconfirmed_user_with_no_confirmation_token_after_sign_in_attempt(user)
79+
# The user is not signed in
80+
expect(page).to have_current_path(root_path)
81+
# A flash notice is displayed informing the user that a confirmation email has been sent
82+
expect(page).to have_selector('#notification-area',
83+
text: I18n.t('devise.registrations.signed_up_but_unconfirmed'))
84+
# reload the user to check confirmation values
85+
user.reload
86+
# The user remains unconfirmed
87+
expect(user.confirmed?).to be(false)
88+
# A confirmation_token now exists
89+
expect(user.confirmation_token).to be_present
90+
end
91+
# rubocop:enable Metrics/AbcSize
92+
93+
def expectations_for_unconfirmed_user_with_confirmation_token_after_sign_in_attempt
94+
# The user is not signed in
95+
expect(current_path).to eq(root_path)
96+
within('#notification-area') do
97+
# Get the HTML content of the flash message
98+
html_content = find(:xpath, '.').native.attribute('innerHTML')
99+
# A flash warning is displayed informing the user that they have to confirm their email
100+
expect(html_content).to include(I18n.t('devise.failure.unconfirmed'))
101+
end
102+
end
103+
end

0 commit comments

Comments
 (0)