booth 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/LICENSE.md +1 -2
  4. data/README.md +37 -6
  5. data/app/assets/images/booth/browsers/README.md +1 -2
  6. data/app/assets/images/booth/browsers/chrome.svg +1 -1
  7. data/app/assets/images/booth/browsers/edge.svg +1 -1
  8. data/app/assets/images/booth/browsers/firefox.svg +1 -1
  9. data/app/assets/images/booth/browsers/opera.svg +1 -1
  10. data/app/assets/images/booth/browsers/safari.svg +1 -1
  11. data/app/assets/images/booth/fido/passkey_mark_a.svg +10 -0
  12. data/app/assets/images/booth/fido/passkey_mark_a_black.svg +32 -0
  13. data/app/assets/images/booth/fido/passkey_mark_a_reverse.svg +33 -0
  14. data/app/assets/images/booth/fido/passkey_mark_a_white.svg +32 -0
  15. data/app/assets/images/booth/fido/passkey_mark_b_black.svg +1 -0
  16. data/app/assets/images/booth/platforms/android.svg +1 -6
  17. data/app/assets/images/booth/platforms/apple.svg +1 -6
  18. data/app/assets/images/booth/platforms/linux.svg +1 -6
  19. data/app/assets/images/booth/platforms/windows.svg +1 -6
  20. data/app/assets/javascripts/booth/authentication.js +29 -0
  21. data/app/assets/javascripts/booth/authentication.js.map +1 -0
  22. data/app/assets/javascripts/booth/error.js +38 -0
  23. data/app/assets/javascripts/booth/error.js.map +1 -0
  24. data/app/assets/javascripts/booth/form.js +78 -0
  25. data/app/assets/javascripts/booth/form.js.map +1 -0
  26. data/app/assets/javascripts/booth/gui.js +53 -0
  27. data/app/assets/javascripts/booth/gui.js.map +1 -0
  28. data/app/assets/javascripts/booth/registration.js +29 -0
  29. data/app/assets/javascripts/booth/registration.js.map +1 -0
  30. data/app/assets/javascripts/booth/setup.js +14 -0
  31. data/app/assets/javascripts/booth/verification.js +49 -0
  32. data/app/assets/javascripts/booth/verification.js.map +1 -0
  33. data/app/assets/javascripts/declarations/authentication.d.ts +6 -0
  34. data/app/assets/javascripts/declarations/error.d.ts +36 -0
  35. data/app/assets/javascripts/declarations/form.d.ts +8 -0
  36. data/app/assets/javascripts/declarations/gui.d.ts +4 -0
  37. data/app/assets/javascripts/declarations/registration.d.ts +6 -0
  38. data/app/assets/javascripts/declarations/setup.d.ts +3 -0
  39. data/app/assets/javascripts/declarations/verification.d.ts +6 -0
  40. data/app/assets/javascripts/src/authentication.ts +41 -0
  41. data/app/assets/javascripts/src/error.ts +35 -0
  42. data/app/assets/javascripts/src/form.ts +90 -0
  43. data/app/assets/javascripts/src/gui.ts +59 -0
  44. data/app/assets/javascripts/src/registration.ts +44 -0
  45. data/app/assets/javascripts/src/verification.ts +61 -0
  46. data/app/assets/stylesheets/booth/booth.css +3 -0
  47. data/config/importmap.rb +11 -0
  48. data/config/locales/de.yml +14 -38
  49. data/config/locales/en.yml +17 -36
  50. data/data/combined_aaguid.json +1 -0
  51. data/lib/booth/adminland/credentials/create.rb +10 -12
  52. data/lib/booth/adminland/credentials/index.rb +31 -0
  53. data/lib/booth/adminland/onboardings/create.rb +24 -15
  54. data/lib/booth/adminland/onboardings/destroy.rb +8 -4
  55. data/lib/booth/adminland/onboardings/find.rb +52 -45
  56. data/lib/booth/adminland/onboardings/find_unconsumed.rb +61 -0
  57. data/lib/booth/adminland/onboardings/index.rb +6 -3
  58. data/lib/booth/adminland/periodic_cleanup.rb +7 -2
  59. data/lib/booth/adminland.rb +17 -18
  60. data/lib/booth/coercers/domain.rb +11 -0
  61. data/lib/booth/coercers/request.rb +51 -0
  62. data/lib/booth/coercers/scope.rb +11 -0
  63. data/lib/booth/comparisons/domain.rb +38 -0
  64. data/lib/booth/comparisons/scope.rb +38 -0
  65. data/lib/booth/concerns/action.rb +25 -13
  66. data/lib/booth/concerns/transition.rb +5 -2
  67. data/lib/booth/configuration.rb +14 -73
  68. data/lib/booth/configure.rb +3 -10
  69. data/lib/booth/{audits/register → core/audit}/completed_onboarding.rb +8 -6
  70. data/lib/booth/core/audit/credential_created.rb +24 -0
  71. data/lib/booth/core/audit/logout.rb +24 -0
  72. data/lib/booth/core/authenticators/confirm.rb +30 -0
  73. data/lib/booth/core/authenticators/step.rb +24 -0
  74. data/lib/booth/core/cooldowns/distance_of_time.rb +50 -0
  75. data/lib/booth/core/cooldowns/strategies/exponential.rb +88 -0
  76. data/lib/booth/core/cooldowns/strategies/global.rb +66 -0
  77. data/lib/booth/core/cooldowns/strategies/result.rb +27 -0
  78. data/lib/booth/core/credentials/create.rb +32 -0
  79. data/lib/booth/core/credentials/find_by_username.rb +63 -0
  80. data/lib/booth/core/credentials/index.rb +15 -0
  81. data/lib/booth/core/credentials/webauth_challenge.rb +37 -0
  82. data/lib/booth/core/geolocation.rb +25 -0
  83. data/lib/booth/core/onboardings/find.rb +92 -0
  84. data/lib/booth/core/onboardings/step.rb +19 -0
  85. data/lib/booth/core/remotes/get.rb +45 -0
  86. data/lib/booth/core/remotes/respond.rb +82 -0
  87. data/lib/booth/core/remotes/set_for_login.rb +31 -0
  88. data/lib/booth/core/sessions/create_and_login.rb +63 -0
  89. data/lib/booth/core/sessions/historical_locations.rb +22 -0
  90. data/lib/booth/core/sessions/index.rb +66 -0
  91. data/lib/booth/core/sessions/revoke.rb +59 -0
  92. data/lib/booth/core/sessions/revoke_all_others.rb +49 -0
  93. data/lib/booth/core/sessions/to_passport.rb +35 -0
  94. data/lib/booth/core/webauth/authentication_verification.rb +76 -0
  95. data/lib/booth/core/webauth/options_for_create.rb +56 -0
  96. data/lib/booth/core/webauth/options_for_get.rb +30 -0
  97. data/lib/booth/core/webauth/provider.rb +36 -0
  98. data/lib/booth/core/webauth/registration_verification.rb +100 -0
  99. data/lib/booth/credential.rb +35 -0
  100. data/lib/booth/engine.rb +15 -4
  101. data/lib/booth/errors.rb +2 -0
  102. data/lib/booth/hooks/after_fetch.rb +14 -6
  103. data/lib/booth/hooks/before_logout.rb +5 -3
  104. data/lib/booth/hooks/serialize_from_session.rb +13 -5
  105. data/lib/booth/hooks/serialize_into_session.rb +6 -3
  106. data/lib/booth/logging.rb +13 -42
  107. data/lib/booth/models/application_record.rb +3 -0
  108. data/lib/booth/models/audit.rb +10 -11
  109. data/lib/booth/models/authenticator.rb +6 -9
  110. data/lib/booth/models/credential.rb +17 -20
  111. data/lib/booth/models/onboarding.rb +16 -39
  112. data/lib/booth/models/{contest.rb → remote.rb} +13 -14
  113. data/lib/booth/models/remotes/scopes/recently_created.rb +26 -0
  114. data/lib/booth/models/remotes/scopes/recently_responded.rb +35 -0
  115. data/lib/booth/models/session.rb +15 -10
  116. data/lib/booth/models/user_agent.rb +2 -0
  117. data/lib/booth/request.rb +43 -22
  118. data/lib/booth/requests/agent.rb +3 -1
  119. data/lib/booth/requests/authentication.rb +15 -5
  120. data/lib/booth/requests/ip.rb +4 -2
  121. data/lib/booth/requests/return_path.rb +4 -2
  122. data/lib/booth/requests/session.rb +6 -4
  123. data/lib/booth/requests/storage.rb +5 -31
  124. data/lib/booth/requests/storages/login.rb +35 -29
  125. data/lib/booth/requests/storages/registration.rb +2 -0
  126. data/lib/booth/requests/storages/webauth.rb +3 -0
  127. data/lib/booth/requests/sudo.rb +6 -50
  128. data/lib/booth/routes/userland.rb +13 -59
  129. data/lib/booth/syntaxes/domain.rb +46 -0
  130. data/lib/booth/syntaxes/email.rb +11 -8
  131. data/lib/booth/syntaxes/ip.rb +6 -4
  132. data/lib/booth/syntaxes/remote_code.rb +60 -0
  133. data/lib/booth/syntaxes/scope.rb +7 -3
  134. data/lib/booth/syntaxes/secret_key.rb +8 -6
  135. data/lib/booth/syntaxes/username.rb +23 -10
  136. data/lib/booth/syntaxes/uuid.rb +3 -1
  137. data/lib/booth/test.rb +27 -22
  138. data/lib/booth/testing/incorporation_test_case.rb +29 -0
  139. data/lib/booth/testing/shortcuts.rb +77 -0
  140. data/lib/booth/testing/support/assert_all_partials_were_covered.rb +69 -0
  141. data/lib/booth/testing/support/assert_logged_in.rb +68 -0
  142. data/lib/booth/{test → testing}/support/assert_logged_out.rb +7 -4
  143. data/lib/booth/testing/support/assert_partial.rb +56 -0
  144. data/lib/booth/{test → testing}/support/force_login.rb +10 -4
  145. data/lib/booth/{test → testing}/support/get_session_value.rb +8 -6
  146. data/lib/booth/testing/support/scenario.rb +23 -0
  147. data/lib/booth/testing/support/shortcuts/create_and_onboard.rb +56 -0
  148. data/lib/booth/testing/support/shortcuts/login_with_passkey.rb +55 -0
  149. data/lib/booth/testing/support/shortcuts/register_new_passkey.rb +51 -0
  150. data/lib/booth/testing/support/soft_reset_session.rb +24 -0
  151. data/lib/booth/testing/support/virtual_authenticators/create.rb +34 -0
  152. data/lib/booth/testing/support/virtual_authenticators/destroy.rb +20 -0
  153. data/lib/booth/testing/support/virtual_authenticators/enable.rb +24 -0
  154. data/lib/booth/testing/support/virtual_authenticators/load.rb +38 -0
  155. data/lib/booth/testing/support/virtual_authenticators/manager.rb +124 -0
  156. data/lib/booth/testing/support/visit.rb +62 -0
  157. data/lib/booth/testing/userland/login_remotely.rb +100 -0
  158. data/lib/booth/testing/userland/onboarding_first_time.rb +81 -0
  159. data/lib/booth/testing/userland/onboarding_to_reset_passkeys.rb +129 -0
  160. data/lib/booth/testing/userland/registration_with_passkey.rb +93 -0
  161. data/lib/booth/testing/userland/registration_without_passkey.rb +101 -0
  162. data/lib/booth/testing/userland/sessions_manage_behavior.rb +68 -0
  163. data/lib/booth/testing/userland/sessions_revoke_all_others.rb +17 -0
  164. data/lib/booth/testing/userland/sessions_revoke_one.rb +17 -0
  165. data/lib/booth/testing/userland.rb +36 -0
  166. data/lib/booth/to_struct.rb +9 -2
  167. data/lib/booth/userland/extract_flash_messages.rb +10 -3
  168. data/lib/booth/userland/logins/create.rb +8 -6
  169. data/lib/booth/userland/logins/destroy.rb +23 -6
  170. data/lib/booth/userland/logins/new.rb +23 -25
  171. data/lib/booth/userland/logins/transitions/create/choose_username.rb +62 -27
  172. data/lib/booth/userland/logins/transitions/create/skip_remotes.rb +18 -14
  173. data/lib/booth/userland/logins/transitions/create/webauth_authentication_initiation.rb +54 -48
  174. data/lib/booth/userland/logins/transitions/create/webauth_authentication_verification.rb +62 -58
  175. data/lib/booth/userland/logins/transitions/new/already_logged_in.rb +4 -3
  176. data/lib/booth/userland/logins/transitions/new/fallible.rb +4 -0
  177. data/lib/booth/userland/logins/transitions/new/{mode_username_and_password.rb → missing_authenticators.rb} +5 -4
  178. data/lib/booth/userland/logins/transitions/new/mode_username_and_webauth.rb +6 -4
  179. data/lib/booth/userland/logins/transitions/new/no_username_chosen.rb +3 -1
  180. data/lib/booth/userland/logins/transitions/new/remote_session_available.rb +20 -13
  181. data/lib/booth/userland/logins/transitions/new/timed_out.rb +3 -1
  182. data/lib/booth/userland/onboardings/show.rb +65 -39
  183. data/lib/booth/userland/onboardings/update.rb +46 -38
  184. data/lib/booth/userland/registrations/create.rb +51 -20
  185. data/lib/booth/userland/registrations/new.rb +6 -7
  186. data/lib/booth/userland/remotes/show.rb +56 -0
  187. data/lib/booth/userland/{personal_contests → remotes}/update.rb +5 -3
  188. data/lib/booth/userland/sessions/destroy_one_or_other.rb +3 -16
  189. data/lib/booth/userland/sessions/index.rb +4 -2
  190. data/lib/booth/userland/sessions/show.rb +5 -6
  191. data/lib/booth/userland/sessions/transitions/destroy/enter_webauth.rb +8 -6
  192. data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_initiation.rb +8 -6
  193. data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_verification.rb +7 -5
  194. data/lib/booth/userland/sessions/transitions/show/enter_webauth.rb +8 -6
  195. data/lib/booth/userland/webauths/create.rb +20 -17
  196. data/lib/booth/userland/webauths/destroy.rb +6 -16
  197. data/lib/booth/userland/webauths/guards/sudo.rb +10 -5
  198. data/lib/booth/userland/webauths/index.rb +4 -2
  199. data/lib/booth/userland/webauths/new.rb +7 -22
  200. data/lib/booth/userland/webauths/sudo.rb +3 -1
  201. data/lib/booth/userland/webauths/transitions/create/authentication_initiation.rb +8 -11
  202. data/lib/booth/userland/webauths/transitions/create/authentication_verification.rb +11 -13
  203. data/lib/booth/userland/webauths/transitions/create/choose_nickname.rb +8 -5
  204. data/lib/booth/userland/webauths/transitions/create/registration_initiation.rb +15 -14
  205. data/lib/booth/userland/webauths/transitions/create/registration_verification.rb +34 -28
  206. data/lib/booth/userland/webauths/transitions/create/reset.rb +2 -0
  207. data/lib/booth/userland/webauths/transitions/new/step.rb +3 -1
  208. data/lib/booth/userland/webauths/transitions/sudo/authentication_initiation.rb +5 -10
  209. data/lib/booth/userland/webauths/transitions/sudo/authentication_verification.rb +4 -2
  210. data/lib/booth/userland.rb +53 -109
  211. data/lib/booth/version.rb +3 -1
  212. data/lib/booth.rb +6 -236
  213. data/lib/generators/booth/migration/migration_generator.rb +2 -1
  214. data/lib/generators/booth/migration/templates/add_credential_to_users.erb +6 -4
  215. data/lib/generators/booth/migration/templates/create_booth_tables.erb +61 -72
  216. metadata +124 -571
  217. data/app/assets/config/booth_manifest.js +0 -15
  218. data/app/assets/images/booth/browsers/internet_explorer.svg +0 -1
  219. data/app/assets/javascripts/booth/all.js +0 -162
  220. data/app/assets/javascripts/booth/all.js.map +0 -1
  221. data/app/assets/javascripts/booth/booth.ts +0 -194
  222. data/app/assets/javascripts/booth/webauthn-json.ts +0 -99
  223. data/lib/booth/adminland/recoveries/consume.rb +0 -70
  224. data/lib/booth/audits/register/added_otp.rb +0 -22
  225. data/lib/booth/audits/register/changed_otp.rb +0 -22
  226. data/lib/booth/audits/register/correct_otp.rb +0 -42
  227. data/lib/booth/audits/register/correct_password.rb +0 -43
  228. data/lib/booth/audits/register/logout.rb +0 -22
  229. data/lib/booth/audits/register/requested_password_reset.rb +0 -22
  230. data/lib/booth/audits/register/wrong_otp.rb +0 -22
  231. data/lib/booth/audits/register/wrong_password.rb +0 -25
  232. data/lib/booth/authenticators/confirm.rb +0 -34
  233. data/lib/booth/authenticators/credential_mode_after_confirmation.rb +0 -25
  234. data/lib/booth/authenticators/step.rb +0 -19
  235. data/lib/booth/contests/get.rb +0 -36
  236. data/lib/booth/contests/respond.rb +0 -78
  237. data/lib/booth/contests/set_for_login.rb +0 -28
  238. data/lib/booth/cooldowns/distance_of_time.rb +0 -46
  239. data/lib/booth/cooldowns/otp.rb +0 -22
  240. data/lib/booth/cooldowns/password.rb +0 -44
  241. data/lib/booth/cooldowns/password_reset.rb +0 -24
  242. data/lib/booth/cooldowns/strategies/exponential.rb +0 -82
  243. data/lib/booth/cooldowns/strategies/global.rb +0 -62
  244. data/lib/booth/cooldowns/strategies/result.rb +0 -22
  245. data/lib/booth/credentials/create.rb +0 -28
  246. data/lib/booth/credentials/create_with_onboarding.rb +0 -26
  247. data/lib/booth/credentials/find_by_username.rb +0 -45
  248. data/lib/booth/credentials/mode.rb +0 -69
  249. data/lib/booth/credentials/modes/otp_addable.rb +0 -23
  250. data/lib/booth/credentials/modes/otp_changeable.rb +0 -23
  251. data/lib/booth/credentials/modes/otp_manageable.rb +0 -17
  252. data/lib/booth/credentials/modes/otp_removable.rb +0 -23
  253. data/lib/booth/credentials/modes/password_addable.rb +0 -29
  254. data/lib/booth/credentials/modes/password_changeable.rb +0 -31
  255. data/lib/booth/credentials/modes/password_manageable.rb +0 -17
  256. data/lib/booth/credentials/modes/password_removable.rb +0 -24
  257. data/lib/booth/credentials/modes/password_removal_requires_user_verifiable_webauth.rb +0 -16
  258. data/lib/booth/credentials/modes/webauth_addable.rb +0 -26
  259. data/lib/booth/credentials/modes/webauth_manageable.rb +0 -16
  260. data/lib/booth/credentials/modes/webauth_removable.rb +0 -25
  261. data/lib/booth/credentials/otp_authentication.rb +0 -59
  262. data/lib/booth/credentials/password_authentication.rb +0 -72
  263. data/lib/booth/credentials/webauth_challenge.rb +0 -28
  264. data/lib/booth/geolocation.rb +0 -20
  265. data/lib/booth/logger.rb +0 -41
  266. data/lib/booth/method_object.rb +0 -73
  267. data/lib/booth/mode.rb +0 -22
  268. data/lib/booth/models/concerns/modeable.rb +0 -50
  269. data/lib/booth/models/concerns/otpable.rb +0 -37
  270. data/lib/booth/models/concerns/passwordable.rb +0 -58
  271. data/lib/booth/models/contests/scopes/recently_created.rb +0 -23
  272. data/lib/booth/models/contests/scopes/recently_responded.rb +0 -32
  273. data/lib/booth/models/password_reset.rb +0 -41
  274. data/lib/booth/models/recovery.rb +0 -32
  275. data/lib/booth/models/registration.rb +0 -10
  276. data/lib/booth/modes/base.rb +0 -25
  277. data/lib/booth/modes/username_and_password.rb +0 -7
  278. data/lib/booth/modes/username_and_webauth.rb +0 -7
  279. data/lib/booth/modes/username_password_and_otp.rb +0 -7
  280. data/lib/booth/modes/username_password_and_webauth.rb +0 -7
  281. data/lib/booth/onboardings/find.rb +0 -35
  282. data/lib/booth/onboardings/propagate_to_credential.rb +0 -63
  283. data/lib/booth/onboardings/step.rb +0 -68
  284. data/lib/booth/password_resets/create.rb +0 -57
  285. data/lib/booth/password_resets/find.rb +0 -36
  286. data/lib/booth/password_resets/propagate_to_credential.rb +0 -36
  287. data/lib/booth/password_resets/step.rb +0 -18
  288. data/lib/booth/recoveries/create.rb +0 -45
  289. data/lib/booth/requests/storages/otp.rb +0 -54
  290. data/lib/booth/requests/storages/password.rb +0 -49
  291. data/lib/booth/requests/storages/password_reset.rb +0 -35
  292. data/lib/booth/requests/storages/recovery.rb +0 -35
  293. data/lib/booth/sessions/create_and_login.rb +0 -46
  294. data/lib/booth/sessions/historical_locations.rb +0 -18
  295. data/lib/booth/sessions/index.rb +0 -59
  296. data/lib/booth/sessions/revoke.rb +0 -51
  297. data/lib/booth/sessions/revoke_all_others.rb +0 -43
  298. data/lib/booth/sessions/to_passport.rb +0 -51
  299. data/lib/booth/syntaxes/contest_code.rb +0 -58
  300. data/lib/booth/syntaxes/otp.rb +0 -57
  301. data/lib/booth/syntaxes/scope_comparison.rb +0 -28
  302. data/lib/booth/test/helpers.rb +0 -63
  303. data/lib/booth/test/support/assert_all_partials_were_covered.rb +0 -63
  304. data/lib/booth/test/support/assert_logged_in.rb +0 -49
  305. data/lib/booth/test/support/assert_partial.rb +0 -29
  306. data/lib/booth/test/support/otp_code_from_session.rb +0 -30
  307. data/lib/booth/test/support/soft_reset_session.rb +0 -22
  308. data/lib/booth/test/userland/logins/missing_authenticators.rb +0 -72
  309. data/lib/booth/test/userland/logins/missing_onboarding.rb +0 -35
  310. data/lib/booth/test/userland/logins/username_and_password.rb +0 -40
  311. data/lib/booth/test/userland/logins/username_and_webauth.rb +0 -75
  312. data/lib/booth/test/userland/logins/username_password_and_otp.rb +0 -45
  313. data/lib/booth/test/userland/logins/username_password_and_webauth.rb +0 -86
  314. data/lib/booth/test/userland/onboardings/already_logged_in.rb +0 -64
  315. data/lib/booth/test/userland/onboardings/otp.rb +0 -63
  316. data/lib/booth/test/userland/onboardings/password.rb +0 -49
  317. data/lib/booth/test/userland/onboardings/timeout.rb +0 -47
  318. data/lib/booth/test/userland/otps/manage.rb +0 -86
  319. data/lib/booth/test/userland/password_resets/reset.rb +0 -102
  320. data/lib/booth/test/userland.rb +0 -38
  321. data/lib/booth/test/webauthn/disable.rb +0 -17
  322. data/lib/booth/test/webauthn/enable.rb +0 -19
  323. data/lib/booth/test/webauthn/virtual_authenticators/create.rb +0 -38
  324. data/lib/booth/test/webauthn/virtual_authenticators/destroy.rb +0 -20
  325. data/lib/booth/userland/logins/transitions/create/enter_otp.rb +0 -70
  326. data/lib/booth/userland/logins/transitions/create/verify_password.rb +0 -70
  327. data/lib/booth/userland/logins/transitions/new/mode_first_time.rb +0 -20
  328. data/lib/booth/userland/logins/transitions/new/mode_username_password_and_otp.rb +0 -24
  329. data/lib/booth/userland/logins/transitions/new/mode_username_password_and_webauth.rb +0 -24
  330. data/lib/booth/userland/onboardings/transitions/update/choose_mode.rb +0 -58
  331. data/lib/booth/userland/onboardings/transitions/update/choose_password.rb +0 -41
  332. data/lib/booth/userland/onboardings/transitions/update/choose_webauth_nickname.rb +0 -50
  333. data/lib/booth/userland/onboardings/transitions/update/confirm_otp.rb +0 -58
  334. data/lib/booth/userland/onboardings/transitions/update/confirm_password.rb +0 -49
  335. data/lib/booth/userland/onboardings/transitions/update/register_otp.rb +0 -31
  336. data/lib/booth/userland/onboardings/transitions/update/reset_otp.rb +0 -40
  337. data/lib/booth/userland/onboardings/transitions/update/reset_password.rb +0 -35
  338. data/lib/booth/userland/onboardings/transitions/update/reset_webauth.rb +0 -46
  339. data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_initiation.rb +0 -40
  340. data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_verification.rb +0 -59
  341. data/lib/booth/userland/onboardings/transitions/update/webauth_registration_initiation.rb +0 -46
  342. data/lib/booth/userland/onboardings/transitions/update/webauth_registration_verification.rb +0 -56
  343. data/lib/booth/userland/otps/destroy.rb +0 -42
  344. data/lib/booth/userland/otps/edit.rb +0 -72
  345. data/lib/booth/userland/otps/guards/manageable.rb +0 -21
  346. data/lib/booth/userland/otps/guards/sudo.rb +0 -23
  347. data/lib/booth/userland/otps/show.rb +0 -36
  348. data/lib/booth/userland/otps/sudo.rb +0 -51
  349. data/lib/booth/userland/otps/transitions/update/confirm.rb +0 -84
  350. data/lib/booth/userland/otps/transitions/update/register.rb +0 -40
  351. data/lib/booth/userland/otps/transitions/update/reset.rb +0 -31
  352. data/lib/booth/userland/otps/update.rb +0 -34
  353. data/lib/booth/userland/password_resets/create.rb +0 -73
  354. data/lib/booth/userland/password_resets/guards/logged_out.rb +0 -21
  355. data/lib/booth/userland/password_resets/new.rb +0 -57
  356. data/lib/booth/userland/password_resets/show.rb +0 -77
  357. data/lib/booth/userland/password_resets/transitions/update/choose_password.rb +0 -48
  358. data/lib/booth/userland/password_resets/transitions/update/confirm_password.rb +0 -54
  359. data/lib/booth/userland/password_resets/transitions/update/reset_password.rb +0 -29
  360. data/lib/booth/userland/password_resets/update.rb +0 -65
  361. data/lib/booth/userland/passwords/destroy.rb +0 -41
  362. data/lib/booth/userland/passwords/edit.rb +0 -54
  363. data/lib/booth/userland/passwords/guards/manageable.rb +0 -21
  364. data/lib/booth/userland/passwords/guards/removable.rb +0 -21
  365. data/lib/booth/userland/passwords/guards/sudo.rb +0 -21
  366. data/lib/booth/userland/passwords/remove.rb +0 -34
  367. data/lib/booth/userland/passwords/show.rb +0 -32
  368. data/lib/booth/userland/passwords/sudo.rb +0 -55
  369. data/lib/booth/userland/passwords/transitions/remove/step.rb +0 -27
  370. data/lib/booth/userland/passwords/transitions/update/choose_password.rb +0 -62
  371. data/lib/booth/userland/passwords/transitions/update/confirm_password.rb +0 -82
  372. data/lib/booth/userland/passwords/update.rb +0 -33
  373. data/lib/booth/userland/personal_contests/show.rb +0 -60
  374. data/lib/booth/userland/recoveries/create.rb +0 -48
  375. data/lib/booth/userland/recoveries/new.rb +0 -35
  376. data/lib/booth/userland/sessions/transitions/destroy/enter_password.rb +0 -50
  377. data/lib/booth/userland/sessions/transitions/destroy/verify_password.rb +0 -83
  378. data/lib/booth/userland/webauths/guards/manageable.rb +0 -21
  379. data/lib/booth/webauth/authentication_verification.rb +0 -68
  380. data/lib/booth/webauth/demand_user_verification.rb +0 -29
  381. data/lib/booth/webauth/options_for_create.rb +0 -46
  382. data/lib/booth/webauth/options_for_get.rb +0 -29
  383. data/lib/generators/booth/migration/templates/create_booth_mode_types.erb +0 -20
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Booth
2
4
  module Syntaxes
3
5
  class Username
6
+ include Calls
4
7
  include ::Booth::Logging
5
- include ::Booth::MethodObject
6
8
 
7
9
  param :input
8
10
 
9
11
  def call
10
- # debug { "Checking username #{input.inspect} for valid syntax..." }
12
+ # log { "Checking username #{input.inspect} for valid syntax..." }
11
13
  check_blank.on_success { check_too_short }
12
14
  .on_success { check_too_long }
15
+ .on_success { check_starts_with_letter }
13
16
  .on_success { check_characters }
14
17
  end
15
18
 
@@ -18,7 +21,7 @@ module Booth
18
21
  def check_blank
19
22
  return Tron.success :username_present if input.present?
20
23
 
21
- debug { 'This username is blank.' }
24
+ log { 'This username is blank.' }
22
25
  Tron.failure :blank_username,
23
26
  normalized_username: nil,
24
27
  normalized_invalid_username: normalized_username,
@@ -28,7 +31,7 @@ module Booth
28
31
  def check_too_short
29
32
  return Tron.success :username_not_too_short if input.to_s.length >= min_length
30
33
 
31
- debug { "This username is less than #{min_length} characters long." }
34
+ log { "This username is less than #{min_length} characters long." }
32
35
  Tron.failure :username_is_too_short,
33
36
  normalized_username: nil,
34
37
  normalized_invalid_username: normalized_username,
@@ -38,22 +41,32 @@ module Booth
38
41
  def check_too_long
39
42
  return Tron.success :username_not_too_long if input.to_s.length <= max_length
40
43
 
41
- debug { "This username is more than #{max_length} characters long." }
44
+ log { "This username is more than #{max_length} characters long." }
42
45
  Tron.failure :username_is_too_long,
43
46
  normalized_username: nil,
44
47
  normalized_invalid_username: normalized_username,
45
48
  public_message: I18n.t('booth.username_too_long', maximum: max_length)
46
49
  end
47
50
 
51
+ def check_starts_with_letter
52
+ return Tron.success :starts_with_letter if input.to_s.match?(/\A[a-zA-Z].*/)
53
+
54
+ log { 'This username does not start with a letter.' }
55
+ Tron.failure :username_must_start_with_letter,
56
+ normalized_username: nil,
57
+ normalized_invalid_username: normalized_username,
58
+ public_message: I18n.t('booth.username_must_start_with_letter')
59
+ end
60
+
48
61
  def check_characters
49
62
  if input.to_s.length == normalized_username.length
50
- debug { 'This username has the correct syntax' }
63
+ log { 'This username has the correct syntax' }
51
64
  return Tron.success :valid_username_syntax,
52
65
  normalized_username:,
53
66
  normalized_invalid_username: normalized_username
54
67
  end
55
68
 
56
- debug { 'This username contains invalid characters' }
69
+ log { 'This username contains invalid characters' }
57
70
  Tron.failure :invalid_username_format,
58
71
  normalized_username: nil,
59
72
  normalized_invalid_username: normalized_username,
@@ -70,15 +83,15 @@ module Booth
70
83
  end
71
84
 
72
85
  def allowed_characters
73
- ::Regexp.escape 'abcdefghijklmnopqrstuvwxyz0123456789@ßöäü_+-,.!?#$%'
86
+ ::Regexp.escape 'abcdefghijklmnopqrstuvwxyz0123456789'
74
87
  end
75
88
 
76
89
  def min_length
77
- 3
90
+ 3 # Like Github
78
91
  end
79
92
 
80
93
  def max_length
81
- 50
94
+ 39 # Like Github
82
95
  end
83
96
  end
84
97
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Booth
2
4
  module Syntaxes
3
5
  class Uuid
4
6
  include ::Booth::Logging
5
- include ::Booth::MethodObject
7
+ include Calls
6
8
 
7
9
  param :input
8
10
  option :raise_if_invalid, default: -> { true }
data/lib/booth/test.rb CHANGED
@@ -1,6 +1,10 @@
1
- # Just in case
1
+ # frozen_string_literal: true
2
+
3
+ # Just in case a developer using Booth makes a mistake.
2
4
  raise 'Requiring `booth/test` is only intended for testing your code' unless Rails.env.test?
3
5
 
6
+ # raise "Only require 'booth/test' when running incorporation test" if ENV['BOOTH_SKIP_INCORPORATION']
7
+
4
8
  def try_to_load_gem(gem_name, require_name = nil)
5
9
  require_name = gem_name if require_name.nil?
6
10
  require require_name
@@ -9,45 +13,46 @@ rescue LoadError => e
9
13
  end
10
14
 
11
15
  # Gems
16
+ try_to_load_gem 'capybara', 'capybara/dsl'
12
17
  try_to_load_gem 'capybara-lockstep'
13
- try_to_load_gem 'rack_session_access'
18
+ try_to_load_gem 'rack_session_access', 'rack_session_access/capybara'
14
19
  try_to_load_gem 'selenium-devtools', 'selenium/devtools'
15
20
  try_to_load_gem 'selenium-webdriver'
16
- require 'rack_session_access/capybara'
21
+ try_to_load_gem 'minitest'
22
+
23
+ require 'active_support/testing/time_helpers'
17
24
 
18
- # Internal Helpers
19
- require_relative 'test/helpers'
20
- require_relative 'test/support/force_login'
25
+ # Support
26
+ # require_relative 'test/support/virtual_authenticators/manager'
27
+ # require_relative 'test/support/virtual_authenticators/create'
28
+
29
+ # # Internal Helpers
30
+ require_relative 'testing/shortcuts'
31
+ # # require_relative 'test/support/force_login'
32
+ require_relative 'testing/incorporation_test_case'
21
33
 
22
34
  # Tests
23
- require_relative 'test/userland/logins/missing_authenticators'
24
- require_relative 'test/userland/logins/missing_onboarding'
25
- require_relative 'test/userland/logins/username_and_password'
26
- require_relative 'test/userland/logins/username_and_webauth'
27
- require_relative 'test/userland/logins/username_password_and_otp'
28
- require_relative 'test/userland/logins/username_password_and_webauth'
29
- require_relative 'test/userland/onboardings/already_logged_in'
30
- require_relative 'test/userland/onboardings/otp'
31
- require_relative 'test/userland/onboardings/password'
32
- require_relative 'test/userland/onboardings/timeout'
33
- require_relative 'test/userland/otps/manage'
34
- require_relative 'test/userland/password_resets/reset'
35
35
 
36
36
  # Public API
37
- require_relative 'test/userland'
37
+ require_relative 'testing/userland'
38
38
 
39
39
  module Booth
40
40
  module Test
41
- def self.middleware
42
- ::RackSessionAccess::Middleware
41
+ module Userland
42
+ def self.scenarios(...)
43
+ Booth::Testing::Userland.scenarios(...)
44
+ end
43
45
  end
44
46
 
45
47
  def self.force_login(...)
46
- ::Booth::Test::Support::ForceLogin.call(...)
48
+ ::Booth::Testing::Support::ForceLogin.call(...)
47
49
  end
48
50
  end
49
51
  end
50
52
 
51
53
  Capybara.configure do |config|
52
54
  config.test_id = 'data-booth' # How Booth interacts with your HTML elements.
55
+ config.default_max_wait_time = 20 if ENV['CHROME'] # For manual debugging
53
56
  end
57
+
58
+ Rails.application.config.middleware.use RackSessionAccess::Middleware
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booth
4
+ module Testing
5
+ class IncorporationTestCase
6
+ include ::Calls
7
+ include ::Capybara::DSL
8
+ include ::Minitest::Assertions
9
+ include ::ActiveSupport::Testing::TimeHelpers
10
+ include ::Booth::Testing::Shortcuts
11
+
12
+ option :host, default: -> { 'localhost' }
13
+ option :scope
14
+ option :routing_namespace
15
+ option :before_test, default: -> {}
16
+ option :after_credential, default: -> { ->(credential_id:) {} }
17
+
18
+ private
19
+
20
+ def virtual_authenticators
21
+ @virtual_authenticators ||= ::Booth::Testing::Support::VirtualAuthenticators::Manager.new
22
+ end
23
+
24
+ # So that `Minitest::Assertions` can be included
25
+ def assertions = 0
26
+ attr_writer :assertions
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booth
4
+ module Testing
5
+ # Shortcuts and Assertions for System tests.
6
+ module Shortcuts
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ include ActiveSupport::Testing::TimeHelpers
11
+ end
12
+
13
+ def visit_namespaced(controller:, action:, params: {})
14
+ ::Booth::Testing::Support::Visit.call(routing_namespace:, controller:, action:, params:)
15
+ end
16
+
17
+ def create_and_onboard(username:)
18
+ ::Booth::Testing::Support::Shortcuts::CreateAndOnboard.call(routing_namespace:,
19
+ scope:,
20
+ username:,
21
+ after_credential:)
22
+ end
23
+
24
+ def register_new_passkey(username:)
25
+ ::Booth::Testing::Support::Shortcuts::RegisterNewPasskey.call(routing_namespace:,
26
+ scope:,
27
+ username:)
28
+ end
29
+
30
+ def login_with_passkey(username:)
31
+ ::Booth::Testing::Support::Shortcuts::LoginWithPasskey.call(routing_namespace:,
32
+ scope:,
33
+ username:)
34
+ end
35
+
36
+ def assert_logged_out
37
+ ::Booth::Testing::Support::AssertLoggedOut.call(scope:)
38
+ end
39
+
40
+ def assert_logged_in(credential: Dry::Initializer::UNDEFINED, username: Dry::Initializer::UNDEFINED)
41
+ ::Booth::Testing::Support::AssertLoggedIn.call(scope:, credential:, username:)
42
+ end
43
+
44
+ def assert_userland_view(controller:, step:)
45
+ ::Booth::Testing::Support::AssertPartial.call(namespace: :userland, controller:, step:)
46
+ end
47
+
48
+ def soft_reset_session
49
+ ::Booth::Testing::Support::SoftResetSession.call
50
+ end
51
+
52
+ def virtual_authenticators
53
+ @virtual_authenticators ||= ::Booth::Testing::Support::VirtualAuthenticators::Manager.new
54
+ end
55
+ # def debug
56
+ # puts
57
+ # puts
58
+ # puts Nokogiri::XML(page.html, &:noblanks)
59
+ # puts
60
+ # end
61
+
62
+ # def respond_to_remote
63
+ # visit userland_remote_login_path
64
+
65
+ # credential = ::Booth::Models::Session.sorted_scope.first.credential
66
+ # code = ::Booth::Core::Remotes::Get.call(credential_id: credential.id).formatted_code
67
+
68
+ # fill_in 'Code', with: code
69
+ # click_on 'Continue'
70
+
71
+ # assert_content 'logged in on the other device'
72
+ # assert_content 'solved your challenge'
73
+ # end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booth
4
+ module Testing
5
+ module Support
6
+ class AssertAllPartialsWereCovered
7
+ include ::Minitest::Assertions
8
+ include ::Calls
9
+
10
+ # cd test/dummy
11
+ # ls app/views/community -R
12
+ EXPECTED_PARTIALS = %w[
13
+ userland/logins/enter_username
14
+ userland/logins/enter_webauth
15
+ userland/logins/no_authenticators
16
+ userland/logins/remote_session_available
17
+ userland/logins/remote_session_expired
18
+ userland/onboardings/already_used
19
+ userland/onboardings/blocked
20
+ userland/onboardings/not_found
21
+ userland/onboardings/not_needed
22
+ userland/onboardings/redeem
23
+ userland/onboardings/success
24
+ userland/onboardings/timed_out
25
+ userland/onboardings/wrong_user
26
+ userland/registrations/already_logged_in
27
+ userland/registrations/choose_username
28
+ userland/remote_logins/no_remote
29
+ userland/remote_logins/remote_login
30
+ userland/remote_logins/remote_solved
31
+ userland/sessions/index
32
+ userland/webauths/choose_nickname
33
+ userland/webauths/completed
34
+ userland/webauths/confirm
35
+ userland/webauths/index
36
+ userland/webauths/register
37
+ userland/webauths/sudo
38
+ userland/sessions/enter_webauth_to_destroy
39
+ userland/sessions/enter_webauth_to_destroy_all_others
40
+ ].freeze
41
+
42
+ def call
43
+ assert_empty superfluous_partials, 'These partials were rendered but not anticipated'
44
+ assert_empty missing_partials, 'These partials were not rendered in any test'
45
+ end
46
+
47
+ private
48
+
49
+ def missing_partials
50
+ (EXPECTED_PARTIALS - covered_partials)
51
+ end
52
+
53
+ def superfluous_partials
54
+ (covered_partials - EXPECTED_PARTIALS)
55
+ end
56
+
57
+ def covered_partials
58
+ Booth::Testing::Support::AssertPartial.asserted_partials.to_a
59
+ end
60
+
61
+ # So that `Minitest::Assertions` can be included
62
+ def assertions
63
+ 0
64
+ end
65
+ attr_writer :assertions
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booth
4
+ module Testing
5
+ module Support
6
+ class AssertLoggedIn
7
+ class AssertionFailedError < StandardError; end
8
+ include ::Calls
9
+ include ::Capybara::DSL
10
+ include ::Booth::Logging
11
+
12
+ option :scope
13
+ option :credential, as: :manual_credential, optional: true
14
+ option :username, optional: true
15
+
16
+ def call
17
+ # tries ||= 0
18
+ ::Capybara::Lockstep.synchronize
19
+
20
+ browser_session_id = nil
21
+ active_sessions.each do |session|
22
+ browser_session_id = ::Booth::Testing::Support::GetSessionValue.call(key:)
23
+ return true if browser_session_id == session.id.to_s
24
+ end
25
+
26
+ attributes = {
27
+ expected_username: credential.username,
28
+ expected_credential_id: credential.id,
29
+ expected_session_ids: active_sessions.map(&:id),
30
+ actual_session_id: browser_session_id,
31
+ }
32
+ raise AssertionFailedError, "Expected to be logged in. #{attributes}"
33
+ # "Expected Credential `#{credential.id}` to be logged in with a session of: #{active_sessions.map(&:id)}"
34
+
35
+ # With the Webauth pingpong it sometimes takes a little longer.
36
+ # And Capybara Lockstep doesn't seem to be able to detect that.
37
+ # rescue AssertionFailedError
38
+ # if (tries += 1) < 3
39
+ # log { 'Trying again...' }
40
+ # sleep 1
41
+ # retry
42
+ # end
43
+
44
+ # raise
45
+ end
46
+
47
+ private
48
+
49
+ def active_sessions
50
+ credential.sessions.active_scope.sorted_scope
51
+ end
52
+
53
+ def credential
54
+ if @credential == Dry::Initializer::UNDEFINED &&
55
+ @username == Dry::Initializer::UNDEFINED
56
+ raise 'Must provide either `credential:` or `username:`'
57
+ end
58
+
59
+ manual_credential || ::Booth::Models::Credential.find_by(username:)
60
+ end
61
+
62
+ def key
63
+ "warden.user.#{scope}.key"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Booth
2
- module Test
4
+ module Testing
3
5
  module Support
4
6
  class AssertLoggedOut
5
- include ::Booth::MethodObject
7
+ include ::Calls
8
+ include ::Capybara::DSL
9
+ include ::Booth::Logging
6
10
 
7
- option :page
8
11
  option :scope
9
12
 
10
13
  def call
@@ -18,7 +21,7 @@ module Booth
18
21
  private
19
22
 
20
23
  def logged_in?
21
- ::Booth::Test::Support::GetSessionValue.call(page:, key:)
24
+ ::Booth::Testing::Support::GetSessionValue.call(key:)
22
25
  end
23
26
 
24
27
  def key
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booth
4
+ module Testing
5
+ module Support
6
+ class AssertPartial
7
+ include ::Calls
8
+ include ::Capybara::DSL
9
+ include ::Booth::Logging
10
+
11
+ cattr_accessor :asserted_partials, instance_accessor: false, default: Set.new
12
+
13
+ option :namespace
14
+ option :controller
15
+ option :step
16
+
17
+ def call
18
+ ::Capybara::Lockstep.synchronize
19
+ log { "Looking for view `#{partial}`" }
20
+
21
+ assert_selector 'template', visible: false
22
+
23
+ content = page.html.match(%r{<template>([^<]+)</template>})[1].strip
24
+
25
+ raise "Expected view '#{partial}' but got '#{content}'" unless content == partial
26
+
27
+ log { "The expected view `#{partial}` was rendered." }
28
+ self.class.asserted_partials << partial
29
+ nil
30
+ end
31
+
32
+ def expected_tag
33
+ "<template>#{partial}</template>"
34
+ end
35
+
36
+ def actual_tag
37
+ page.html.scan(%r{<template>[^/]+/[^/]+/[^/]+</template>}).uniq.first.presence ||
38
+ page.text
39
+ end
40
+
41
+ def partial
42
+ "#{namespace}/#{controller}/#{step}"
43
+ end
44
+
45
+ def test_file_and_line_number
46
+ # Called from e.g. `::Booth::Testing::Userland::LoginRemotely`.
47
+ candidate = caller[3].split(':in ').first
48
+ return candidate unless candidate.include?('calls')
49
+
50
+ # Called from e.g. `::Booth::Testing::Support::RegisterNewPasskey`.
51
+ caller[2].split(':in ').first
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,14 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Booth
2
- module Test
4
+ module Testing
3
5
  module Support
4
6
  class ForceLogin
5
- include ::Booth::MethodObject
7
+ include Calls
6
8
 
7
9
  option :credential_id
8
- option :request, ::Booth::Request
10
+ option :request
9
11
 
10
12
  def call
11
- ::Booth::Sessions::CreateAndLogin.call(credential:, request:)
13
+ login = ::Booth::Core::Sessions::CreateAndLogin.call(domain: request.host, scope:,
14
+ credential:, request:)
15
+ raise login.inspect if login.failure?
16
+
17
+ nil
12
18
  end
13
19
 
14
20
  delegate :scope, to: :credential
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Booth
2
- module Test
4
+ module Testing
3
5
  module Support
4
6
  class GetSessionValue
5
- include ::Booth::MethodObject
7
+ include ::Calls
8
+ include ::Capybara::DSL
6
9
  include ::Booth::Logging
7
10
 
8
- option :page
9
11
  option :key
10
12
 
11
13
  def call
@@ -16,7 +18,7 @@ module Booth
16
18
  result = page.get_rack_session[key]
17
19
  end
18
20
 
19
- debug { "session[#{key.inspect}] is: #{result.inspect}" }
21
+ log { "session[#{key.inspect}] is: #{result.inspect}" }
20
22
 
21
23
  ::Capybara::Lockstep.synchronize
22
24
  result
@@ -25,8 +27,8 @@ module Booth
25
27
  private
26
28
 
27
29
  def in_new_window(&)
28
- window = page.open_new_window
29
- page.within_window(window, &)
30
+ window = open_new_window
31
+ within_window(window, &)
30
32
  window.close
31
33
  end
32
34
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booth
4
+ module Testing
5
+ module Support
6
+ class Scenario
7
+ attr_accessor :routing_namespace, :scope, :before_test, :after_credential
8
+
9
+ def initialize(klass)
10
+ @klass = klass
11
+ end
12
+
13
+ def name
14
+ @klass.to_s.underscore.parameterize(separator: '_')
15
+ end
16
+
17
+ def call
18
+ @klass.call routing_namespace:, scope:, before_test:, after_credential:
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booth
4
+ module Testing
5
+ module Support
6
+ module Shortcuts
7
+ # Create a Credential and use an Onboarding link to login.
8
+ class CreateAndOnboard
9
+ include ::Calls
10
+ include ::Capybara::DSL
11
+
12
+ option :routing_namespace
13
+ option :scope
14
+ option :username
15
+ option :after_credential
16
+
17
+ def call
18
+ Visit.call(routing_namespace:,
19
+ controller: :onboardings,
20
+ action: :show,
21
+ params: { id: onboarding.secret_key })
22
+
23
+ AssertPartial.call(namespace: :userland, controller: :onboardings, step: :redeem)
24
+
25
+ click_on :submit
26
+
27
+ AssertLoggedIn.call(scope:, credential:)
28
+
29
+ nil
30
+ end
31
+
32
+ private
33
+
34
+ def onboarding
35
+ @onboarding ||= ::Booth::Models::Onboarding.create!(
36
+ credential_id: credential.id,
37
+ )
38
+ end
39
+
40
+ def credential
41
+ return @credential if defined?(@credential)
42
+
43
+ @credential = ::Booth::Models::Credential.create!(
44
+ domain: ::Capybara.app_host.remove('http://'),
45
+ username:,
46
+ scope:,
47
+ )
48
+
49
+ after_credential&.call(credential_id: @credential.id)
50
+ @credential
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end