Skip to content

Commit 686ebc9

Browse files
test: options_for_get and options_for_create endpoints
1 parent 461f3b9 commit 686ebc9

2 files changed

Lines changed: 141 additions & 0 deletions

File tree

spec/requests/devise/passkeys_controller_spec.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,62 @@
117117
end
118118
end
119119
end
120+
121+
# rubocop:disable RSpec/MultipleExpectations
122+
describe "GET #options_for_get" do
123+
it "returns authentication options and stores the challenge in the session" do
124+
get options_for_get_account_passkeys_path
125+
126+
expect(response).to have_http_status(:ok)
127+
expect(response.media_type).to eq("application/json")
128+
129+
body = response.parsed_body
130+
expect(body).to include("challenge")
131+
expect(session[:authentication_challenge]).to be_present
132+
end
133+
end
134+
135+
describe "GET #options_for_create" do
136+
context "when user is authenticated" do
137+
before do
138+
sign_in user, scope: :account
139+
end
140+
141+
it "returns passkey creation options and stores the challenge in the session" do
142+
get options_for_create_account_passkeys_path
143+
144+
expect(response).to have_http_status(:ok)
145+
expect(response.media_type).to eq("application/json")
146+
147+
body = response.parsed_body
148+
expect(body).to include("challenge")
149+
expect(body.dig("user", "name")).to eq(user.email)
150+
expect(session[:webauthn_challenge]).to be_present
151+
end
152+
153+
it "includes existing passkeys in the excludeCredentials list" do
154+
user.passkeys.create!(
155+
external_id: "existing-external-id",
156+
name: "Existing Passkey",
157+
public_key: "public-key",
158+
sign_count: 0
159+
)
160+
161+
get options_for_create_account_passkeys_path
162+
163+
body = response.parsed_body
164+
exclude_credentials = body["excludeCredentials"] || []
165+
166+
expect(exclude_credentials.size).to eq(user.passkeys.count)
167+
end
168+
end
169+
170+
context "when user is not authenticated" do
171+
it "redirects to the sign-in page" do
172+
get options_for_create_account_passkeys_path
173+
expect(response).to redirect_to(new_account_session_path)
174+
end
175+
end
176+
end
177+
# rubocop:enable RSpec/MultipleExpectations
120178
end

spec/requests/devise/second_factor_webauthn_credentials_controller_spec.rb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,87 @@
121121
end
122122
end
123123
end
124+
125+
# rubocop:disable RSpec/MultipleExpectations
126+
describe "GET #options_for_get" do
127+
before do
128+
user.webauthn_credentials.create!(
129+
external_id: "second-factor-id",
130+
name: "Second Factor Key",
131+
public_key: "pk",
132+
sign_count: 0
133+
)
134+
135+
# rubocop:disable RSpec/AnyInstance
136+
allow_any_instance_of(described_class)
137+
.to receive(:set_resource) do |instance|
138+
instance.instance_variable_set(:@resource, user)
139+
end
140+
# rubocop:enable RSpec/AnyInstance
141+
end
142+
143+
it "returns authentication options and stores the challenge in the session" do
144+
get options_for_get_account_second_factor_webauthn_credentials_path
145+
146+
expect(response).to have_http_status(:ok)
147+
expect(response.media_type).to eq("application/json")
148+
149+
body = response.parsed_body
150+
expect(body).to include("challenge")
151+
expect(body["userVerification"]).to eq("discouraged")
152+
153+
expect(body["allowCredentials"].size).to eq(1)
154+
155+
expect(session[:two_factor_authentication_challenge]).to be_present
156+
end
157+
end
158+
159+
describe "GET #options_for_create" do
160+
context "when user is authenticated" do
161+
before do
162+
sign_in user, scope: :account
163+
end
164+
165+
it "returns security key creation options and stores the challenge in the session" do
166+
get options_for_create_account_second_factor_webauthn_credentials_path
167+
168+
expect(response).to have_http_status(:ok)
169+
expect(response.media_type).to eq("application/json")
170+
171+
body = response.parsed_body
172+
expect(body).to include("challenge")
173+
expect(body.dig("user", "name")).to eq(user.email)
174+
175+
expect(body.dig("authenticatorSelection", "residentKey")).to eq("discouraged")
176+
expect(body.dig("authenticatorSelection", "userVerification")).to eq("discouraged")
177+
178+
expect(session[:webauthn_challenge]).to be_present
179+
end
180+
181+
it "includes existing first-factor credentials in the excludeCredentials list" do
182+
user.webauthn_credentials.create!(
183+
external_id: "existing-id",
184+
name: "Existing Key",
185+
public_key: "pk",
186+
sign_count: 0
187+
)
188+
189+
get options_for_create_account_second_factor_webauthn_credentials_path
190+
191+
body = response.parsed_body
192+
exclude_credentials = body["excludeCredentials"] || []
193+
194+
expect(exclude_credentials.size).to eq(user.webauthn_credentials.count)
195+
end
196+
end
197+
198+
context "when user is not authenticated" do
199+
it "redirects to the sign-in page" do
200+
get options_for_create_account_second_factor_webauthn_credentials_path
201+
202+
expect(response).to redirect_to(new_account_session_path)
203+
end
204+
end
205+
end
206+
# rubocop:enable RSpec/MultipleExpectations
124207
end

0 commit comments

Comments
 (0)