diff --git a/Makefile b/Makefile
index ee1c06d68c3..c3e18730b32 100644
--- a/Makefile
+++ b/Makefile
@@ -177,7 +177,7 @@ brakeman: ## Runs brakeman code security check
(bundle exec brakeman) || (echo "Error: update code as needed to remove security issues. For known exceptions already in brakeman.ignore, use brakeman to interactively update exceptions."; exit 1)
public/packs/manifest.json: yarn.lock $(shell find app/javascript -type f) ## Builds JavaScript assets
- yarn build
+ yarn build:js
browsers.json: yarn.lock .browserslistrc ## Generates browsers.json browser support file
yarn generate-browsers-json
diff --git a/app/components/block_link_component.rb b/app/components/block_link_component.rb
index 9878ee58641..34f25d68654 100644
--- a/app/components/block_link_component.rb
+++ b/app/components/block_link_component.rb
@@ -1,11 +1,11 @@
class BlockLinkComponent < BaseComponent
- attr_reader :url, :action, :new_tab, :tag_options
+ attr_reader :url, :action, :new_tab, :tag_options, :component
alias_method :new_tab?, :new_tab
- def initialize(url:, action: tag.method(:a), new_tab: false, **tag_options)
- @action = action
+ def initialize(url: '#', component: nil, new_tab: false, **tag_options)
@url = url
+ @component = component
@new_tab = new_tab
@tag_options = tag_options
end
@@ -21,11 +21,11 @@ def target
end
def wrapper(&block)
- wrapper = action.call(**tag_options, href: url, class: css_class, target:, &block)
- if wrapper.respond_to?(:render_in)
- render wrapper, &block
+ if component
+ render component.new(href: url, class: css_class), &block
else
- wrapper
+ action = tag.method(:a)
+ action.call(**tag_options, href: url, class: css_class, target:, &block)
end
end
end
diff --git a/app/components/form_link_component.html.erb b/app/components/form_link_component.html.erb
new file mode 100644
index 00000000000..3e72713c616
--- /dev/null
+++ b/app/components/form_link_component.html.erb
@@ -0,0 +1,3 @@
+
<%= t('devise.registrations.close_window') %>
-<%= simple_form_for @resend_email_confirmation_form, - html: { class: 'margin-bottom-2' }, - url: sign_up_register_path do |f| %> - <%= f.input :email, as: :hidden %> - <%= f.input :resend, as: :hidden %> -<%= t('notices.signed_up_but_unconfirmed.no_email_sent_explanation_start') %> - <%= f.button :button, t('links.resend'), class: 'usa-button--unstyled margin-left-05' %>
- -- <%= t( - 'notices.use_diff_email.text_html', - link_html: link_to(t('notices.use_diff_email.link'), sign_up_email_path), - ) %> -
-<%= t('devise.registrations.close_window') %>
+<%= render TroubleshootingOptionsComponent.new do |c| %> + <% c.with_header { t('components.troubleshooting_options.default_heading') } %> + <% c.with_option(component: FormLinkComponent) do %> + <%= t('notices.signed_up_but_unconfirmed.resend_confirmation_email') %> + <%= simple_form_for @resend_email_confirmation_form, + html: { class: 'display-none' }, + url: sign_up_register_path do |f| %> + <%= f.input :email, as: :hidden %> + <%= f.input :resend, as: :hidden %> + <%= f.button :button, t('notices.signed_up_but_unconfirmed.resend_confirmation_email') %> + <% end %> + <% end %> + <% c.with_option( + url: sign_up_email_path, + ).with_content(t('notices.use_diff_email.link').upcase_first) %> +<% end %> - <% if FeatureManagement.enable_load_testing_mode? && EmailAddress.find_with_email(email) %> - <%= link_to( - 'CONFIRM NOW', - sign_up_create_email_confirmation_url(confirmation_token: EmailAddress.find_with_email(email).confirmation_token), - id: 'confirm-now', - ) %> - <% end %> +<% if FeatureManagement.enable_load_testing_mode? && EmailAddress.find_with_email(email) %> + <%= link_to( + 'CONFIRM NOW', + sign_up_create_email_confirmation_url(confirmation_token: EmailAddress.find_with_email(email).confirmation_token), + id: 'confirm-now', + ) %> <% end %> diff --git a/config/locales/notices/en.yml b/config/locales/notices/en.yml index c621d34246d..a617bb02aa9 100644 --- a/config/locales/notices/en.yml +++ b/config/locales/notices/en.yml @@ -35,7 +35,7 @@ en: first_paragraph_end: with a link to confirm your email address. Follow the link to continue creating your account. first_paragraph_start: We sent an email to - no_email_sent_explanation_start: Didn’t receive an email? + resend_confirmation_email: Resend the confirmation email timeout_warning: partially_signed_in: continue: Continue sign in diff --git a/config/locales/notices/es.yml b/config/locales/notices/es.yml index 180544da64e..3fae3ca377b 100644 --- a/config/locales/notices/es.yml +++ b/config/locales/notices/es.yml @@ -37,7 +37,7 @@ es: first_paragraph_end: con un enlace para confirmar su email. Siga el enlace para continuar creando su cuenta. first_paragraph_start: Enviamos un email a - no_email_sent_explanation_start: '¿No recibió un email?' + resend_confirmation_email: Reenviar el correo electrónico de confirmación timeout_warning: partially_signed_in: continue: Continuar el inicio de sesión diff --git a/config/locales/notices/fr.yml b/config/locales/notices/fr.yml index 0e366e5db32..9ed9eb1a3cc 100644 --- a/config/locales/notices/fr.yml +++ b/config/locales/notices/fr.yml @@ -37,7 +37,7 @@ fr: first_paragraph_end: avec un lien pour confirmer votre adresse courriel. Suivez le lien pour continuer à créer votre compte. first_paragraph_start: Nous avons envoyé un courriel à - no_email_sent_explanation_start: Vous n’avez pas reçu d’e-mail? + resend_confirmation_email: Renvoyer le courriel de confirmation timeout_warning: partially_signed_in: continue: Continuer la connexion diff --git a/config/locales/telephony/en.yml b/config/locales/telephony/en.yml index c8a6b95d05c..b6a9a6e0808 100644 --- a/config/locales/telephony/en.yml +++ b/config/locales/telephony/en.yml @@ -1,6 +1,7 @@ --- en: telephony: + account_deleted_notice: This text message confirms you have deleted your %{app_name} account. account_reset_cancellation_notice: Your request to delete your %{app_name} account has been cancelled. account_reset_notice: As requested, your %{app_name} account will be deleted in %{interval}. Don't want to delete your account? Sign in to your diff --git a/config/locales/telephony/es.yml b/config/locales/telephony/es.yml index 37a022203a2..eb830e07212 100644 --- a/config/locales/telephony/es.yml +++ b/config/locales/telephony/es.yml @@ -1,6 +1,7 @@ --- es: telephony: + account_deleted_notice: Este SMS confirma que ha eliminado su cuenta de %{app_name}. account_reset_cancellation_notice: Su solicitud para eliminar su cuenta de %{app_name} ha sido cancelada. account_reset_notice: Según lo solicitado, su cuenta %{app_name} se eliminará en %{interval}. ¿No quieres eliminar tu cuenta? Inicie sesión en su cuenta diff --git a/config/locales/telephony/fr.yml b/config/locales/telephony/fr.yml index 013d8e60358..e29117bc63c 100644 --- a/config/locales/telephony/fr.yml +++ b/config/locales/telephony/fr.yml @@ -1,6 +1,7 @@ --- fr: telephony: + account_deleted_notice: Cet SMS confirme que vous avez supprimé votre compte %{app_name}. account_reset_cancellation_notice: Votre demande de suppression de votre compte %{app_name} a été annulée. account_reset_notice: Comme demandé, votre compte %{app_name} sera supprimé dans les %{interval}. Vous ne voulez pas supprimer votre compte? Connectez-vous diff --git a/db/primary_migrate/20240215212318_add_vtr_and_acrvalues_to_identities.rb b/db/primary_migrate/20240215212318_add_vtr_and_acrvalues_to_identities.rb new file mode 100644 index 00000000000..3cdf60f9ec1 --- /dev/null +++ b/db/primary_migrate/20240215212318_add_vtr_and_acrvalues_to_identities.rb @@ -0,0 +1,6 @@ +class AddVtrAndAcrvaluesToIdentities < ActiveRecord::Migration[7.1] + def change + add_column :identities, :vtr, :string + add_column :identities, :acr_values, :string + end +end diff --git a/db/primary_migrate/20240216184124_drop_monthly_auth_counts.rb b/db/primary_migrate/20240216184124_drop_monthly_auth_counts.rb new file mode 100644 index 00000000000..7c47e069de5 --- /dev/null +++ b/db/primary_migrate/20240216184124_drop_monthly_auth_counts.rb @@ -0,0 +1,17 @@ +class DropMonthlyAuthCounts < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def up + drop_table :monthly_auth_counts + end + + def down + create_table :monthly_auth_counts do |t| + t.string :issuer, null: false + t.string :year_month, null: false + t.integer :user_id, null: false + t.integer :auth_count, default: 1, null: false + end + add_index :monthly_auth_counts, %i[issuer year_month user_id], algorithm: :concurrently, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 8cdcaf3f109..4c3a718d4d5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_01_10_142935) do +ActiveRecord::Schema[7.1].define(version: 2024_02_16_184124) do # These are extensions that must be enabled in order to support this database enable_extension "citext" enable_extension "pg_stat_statements" @@ -288,6 +288,8 @@ t.datetime "deleted_at", precision: nil t.integer "aal" t.text "requested_aal_value" + t.string "vtr" + t.string "acr_values" t.index ["access_token"], name: "index_identities_on_access_token", unique: true t.index ["session_uuid"], name: "index_identities_on_session_uuid", unique: true t.index ["user_id", "service_provider"], name: "index_identities_on_user_id_and_service_provider", unique: true @@ -362,14 +364,6 @@ t.index ["ftp_at"], name: "index_letter_requests_to_usps_ftp_logs_on_ftp_at" end - create_table "monthly_auth_counts", force: :cascade do |t| - t.string "issuer", null: false - t.string "year_month", null: false - t.integer "user_id", null: false - t.integer "auth_count", default: 1, null: false - t.index ["issuer", "year_month", "user_id"], name: "index_monthly_auth_counts_on_issuer_and_year_month_and_user_id", unique: true - end - create_table "notification_phone_configurations", force: :cascade do |t| t.bigint "in_person_enrollment_id", null: false t.text "encrypted_phone", null: false, comment: "Encrypted phone number to send notifications to" diff --git a/docs/local-development.md b/docs/local-development.md index bc560e8533f..344db74541b 100644 --- a/docs/local-development.md +++ b/docs/local-development.md @@ -65,7 +65,7 @@ asked to consent to share their information with the partner before being sent b To simulate a true end-to-end user experience, you can either... - Use the built-in test controller for SAML logins at http://localhost:3000/test/saml/login or OIDC logins at http://localhost:3000/test/oidc/login - + Note: to update service provider configurations, run the command `rake db:seed` or `make setup`. - Or, run a sample partner application, which is configured by default to run with your local IdP instance: - OIDC: https://github.com/18F/identity-oidc-sinatra @@ -125,8 +125,8 @@ $ SKIP_BUILD=true bundle exec rspec spec/features Since the automatic build is meant to act as a safeguard to prevent stale assets from being used, disabling it will mean you're responsible for running the build any time JavaScript or Sass source -files are changed. You can do this by running `yarn build` for JavaScript, or `yarn build:css` for -stylesheets. +files are changed. You can do this by running `yarn build:js` for JavaScript, or `yarn build:css` +for stylesheets. ### Viewing email messages diff --git a/lib/cleanup/destroyable_records.rb b/lib/cleanup/destroyable_records.rb index 08cf370a4f4..47746e7ba6b 100644 --- a/lib/cleanup/destroyable_records.rb +++ b/lib/cleanup/destroyable_records.rb @@ -26,7 +26,7 @@ def print_data stdout.puts '********' stdout.puts 'Integration:' - if integration.nil? + if integration.blank? stdout.puts 'No associated integration' else stdout.puts integration.attributes.to_yaml @@ -46,7 +46,7 @@ def print_data stdout.puts '*******' stdout.puts 'These are the IAA orders that will be affected: \n' - if iaa_orders.nil? + if iaa_orders.blank? stdout.puts 'No IAA orders will be affected' else stdout.puts 'These are the IAA orders that will be affected: \n' @@ -79,11 +79,11 @@ def destroy_records private def integration_usages - integration&.integration_usages + integration&.integration_usages || [] end def iaa_orders - integration&.iaa_orders + integration&.iaa_orders || [] end def in_person_enrollments diff --git a/lib/telephony.rb b/lib/telephony.rb index d8d5eb7a2c6..ac43d2f3698 100644 --- a/lib/telephony.rb +++ b/lib/telephony.rb @@ -80,6 +80,7 @@ def self.alert_sender :send_doc_auth_link, :send_personal_key_regeneration_notice, :send_personal_key_sign_in_notice, + :send_account_deleted_notice, :send_account_reset_notice, :send_account_reset_cancellation_notice, :send_notification diff --git a/lib/telephony/alert_sender.rb b/lib/telephony/alert_sender.rb index b202e5bbfc1..adc2a149af7 100644 --- a/lib/telephony/alert_sender.rb +++ b/lib/telephony/alert_sender.rb @@ -2,6 +2,13 @@ module Telephony class AlertSender SMS_MAX_LENGTH = 160 + def send_account_deleted_notice(to:, country_code:) + message = I18n.t('telephony.account_deleted_notice', app_name: APP_NAME) + response = adapter.deliver(message: message, to: to, country_code: country_code) + log_response(response, context: __method__.to_s.gsub(/^send_/, '')) + response + end + def send_account_reset_notice(to:, country_code:, interval:) message = I18n.t( 'telephony.account_reset_notice', app_name: APP_NAME, diff --git a/package.json b/package.json index 13abe4113f6..2fba5d67906 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "generate-browsers-json": "./scripts/generate-browsers-json.js", "clean": "rm -rf public/packs/*", "prebuild": "yarn run clean", - "build": "webpack && yarn generate-browsers-json", + "build": "yarn build:js", + "build:js": "concurrently 'yarn:webpack' 'make browsers.json'", "build:css": "build-sass app/assets/stylesheets/*.css.scss app/components/*.scss --load-path=app/assets/stylesheets --out-dir=app/assets/builds" }, "dependencies": { @@ -31,6 +32,7 @@ "babel-plugin-polyfill-corejs3": "^0.5.2", "browserslist": "^4.22.3", "cleave.js": "^1.6.0", + "concurrently": "^8.2.2", "core-js": "^3.21.1", "fast-glob": "^3.2.7", "foundation-emails": "^2.3.1", diff --git a/spec/components/block_link_component_spec.rb b/spec/components/block_link_component_spec.rb index f3b9ece14a2..4ead0f748c6 100644 --- a/spec/components/block_link_component_spec.rb +++ b/spec/components/block_link_component_spec.rb @@ -29,26 +29,22 @@ end end - context 'with custom renderer' do - # rubocop:disable RSpec/LeakyConstantDeclaration - class ExampleBlockLinkCustomRendererComponent < BaseComponent - def initialize(href:, **) - @href = href - end - - def call - content_tag(:button, "Example #{content.strip}", data: { href: @href }) - end + context 'with a component' do + before do + stub_const( + 'TestComponent', Class.new(BaseComponent) do + def call + content_tag(:div, 'from test component', class: 'style') + end + end + ) end - # rubocop:enable RSpec/LeakyConstantDeclaration - it 'renders using the custom renderer' do - rendered = render_inline BlockLinkComponent.new( - url: '/', - action: ExampleBlockLinkCustomRendererComponent.method(:new), - ).with_content('Link Text') + it 'renders using the specified component' do + rendered = render_inline(BlockLinkComponent.new(component: TestComponent)) - expect(rendered).to have_css('button[data-href="/"]', text: 'Example Link Text') + expect(rendered).to have_css('.style') + expect(rendered).to have_text('from test component') end end end diff --git a/spec/components/form_link_component_spec.rb b/spec/components/form_link_component_spec.rb new file mode 100644 index 00000000000..f6d11807824 --- /dev/null +++ b/spec/components/form_link_component_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe FormLinkComponent, type: :component do + let(:options) { { href: '/', method: :post } } + let(:content) { 'Title' } + + subject(:rendered) do + render_inline(described_class.new(**options).with_content(content)) + end + + it 'renders custom element with link' do + expect(rendered).to have_css('lg-form-link a[href="/"]', text: content) + end +end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 11d7a7cc266..72a9aa0a6db 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -473,6 +473,19 @@ def index expect(result.aal2?).to eq(true) expect(result.identity_proofing?).to eq(true) end + + context 'without an SP' do + it 'returns a no-SP result' do + sp = nil + sp_session = {} + allow(controller).to receive(:current_sp).and_return(sp) + allow(controller).to receive(:sp_session).and_return(sp_session) + + result = subject.resolved_authn_context_result + + expect(result).to eq(Vot::Parser::Result.no_sp_result) + end + end end describe '#sp_session_request_url_with_updated_params' do diff --git a/spec/controllers/frontend_log_controller_spec.rb b/spec/controllers/frontend_log_controller_spec.rb index 6a3ce372296..9ca398cedbb 100644 --- a/spec/controllers/frontend_log_controller_spec.rb +++ b/spec/controllers/frontend_log_controller_spec.rb @@ -31,10 +31,9 @@ end context 'with invalid event name' do - it 'logs with warning' do + it 'responds as unsuccessful' do action - expect(fake_analytics).to have_logged_event('Frontend (warning): Custom Event') expect(response).to have_http_status(:bad_request) expect(json[:success]).to eq(false) expect(json[:error_message]).to eq('invalid event') @@ -239,10 +238,9 @@ end context 'with invalid event name' do - it 'logs with warning' do + it 'responds as unsuccessful' do action - expect(fake_analytics).to have_logged_event('Frontend (warning): Custom Event') expect(response).to have_http_status(:bad_request) expect(json[:success]).to eq(false) expect(json[:error_message]).to eq('invalid event') diff --git a/spec/controllers/users/delete_controller_spec.rb b/spec/controllers/users/delete_controller_spec.rb index 4f3007cb5e9..e61186248db 100644 --- a/spec/controllers/users/delete_controller_spec.rb +++ b/spec/controllers/users/delete_controller_spec.rb @@ -74,7 +74,14 @@ allow(UserMailer).to receive(:account_delete_submitted).and_call_original stub_signed_in_user delete - expect(UserMailer).not_to have_received(:account_delete_submitted) + expect(ActionMailer::Base.deliveries.count).to eq 1 + end + + it 'text user of account deletion' do + allow(Telephony).to receive(:send_account_deleted_notice).and_call_original + stub_signed_in_user + delete + expect(Telephony).to have_received(:send_account_deleted_notice) end it 'logs a succesful submit' do @@ -114,6 +121,7 @@ def stub_signed_in_user user = create( :user, :fully_registered, + :with_phone, email: 'old_email@example.com', password: ControllerHelper::VALID_PASSWORD, ) diff --git a/spec/factories/auth_app_configurations.rb b/spec/factories/auth_app_configurations.rb index 473d945bd32..8413405d69d 100644 --- a/spec/factories/auth_app_configurations.rb +++ b/spec/factories/auth_app_configurations.rb @@ -2,7 +2,7 @@ Faker::Config.locale = :en factory :auth_app_configuration do - name { Faker::Lorem.word } + name { Faker::Lorem.unique.words.join(' ') } otp_secret_key { SecureRandom.hex(16) } user end diff --git a/spec/factories/piv_cac_configurations.rb b/spec/factories/piv_cac_configurations.rb index f2b5c9bb0de..68c73f0b22b 100644 --- a/spec/factories/piv_cac_configurations.rb +++ b/spec/factories/piv_cac_configurations.rb @@ -2,7 +2,7 @@ Faker::Config.locale = :en factory :piv_cac_configuration do - name { Faker::Lorem.word } + name { Faker::Lorem.unique.words.join(' ') } x509_dn_uuid { 'helloworld' } user end diff --git a/spec/features/idv/doc_auth/document_capture_spec.rb b/spec/features/idv/doc_auth/document_capture_spec.rb index 9141c0d592d..525886c37ba 100644 --- a/spec/features/idv/doc_auth/document_capture_spec.rb +++ b/spec/features/idv/doc_auth/document_capture_spec.rb @@ -58,16 +58,15 @@ attach_images( Rails.root.join( 'spec', 'fixtures', - 'ial2_test_credential_barcode_attention_no_dob.yml' + 'ial2_test_credential_barcode_attention_no_address.yml' ), ) submit_images - expect(page).to have_content(t('doc_auth.errors.barcode_attention.heading')) - click_idv_continue - - # should show try again + expect(page).to have_content(t('doc_auth.errors.alerts.address_check')) expect(page).to have_current_path(idv_document_capture_path) + + click_try_again attach_images submit_images expect(page).to have_current_path(idv_ssn_path) diff --git a/spec/features/visitors/email_confirmation_spec.rb b/spec/features/visitors/email_confirmation_spec.rb index 9e86c14bc27..2a9ac6680ac 100644 --- a/spec/features/visitors/email_confirmation_spec.rb +++ b/spec/features/visitors/email_confirmation_spec.rb @@ -46,7 +46,7 @@ it 'sends the confirmation email again' do sign_up_with('test@example.com') - expect { click_on t('links.resend') }. + expect { click_on t('notices.signed_up_but_unconfirmed.resend_confirmation_email') }. to change { ActionMailer::Base.deliveries.count }.by(1) expect(last_email.html_part.body).to have_content( diff --git a/spec/fixtures/ial2_test_credential_barcode_attention_no_address.yml b/spec/fixtures/ial2_test_credential_barcode_attention_no_address.yml new file mode 100644 index 00000000000..c32bbceb669 --- /dev/null +++ b/spec/fixtures/ial2_test_credential_barcode_attention_no_address.yml @@ -0,0 +1,14 @@ +document: + first_name: Jane + last_name: Doe + middle_name: Q + city: Bayside + state: NY + zipcode: '11364' + dob: 10/06/1938 + phone: +1 314-555-1212 + state_id_jurisdiction: 'NY' + state_id_number: 'S59397998' +failed_alerts: + - name: 2D Barcode Read + result: Attention \ No newline at end of file diff --git a/spec/lib/cleanup/destroyable_records_spec.rb b/spec/lib/cleanup/destroyable_records_spec.rb index d425b780ebf..269379bf495 100644 --- a/spec/lib/cleanup/destroyable_records_spec.rb +++ b/spec/lib/cleanup/destroyable_records_spec.rb @@ -106,6 +106,16 @@ expect(iaa_order.integrations.include? integration).to be false end + describe 'integration without usages or iaa_orders' do + let!(:empty_integration) { create(:integration) } + let!(:service_provider) { empty_integration.service_provider } + + it 'destroys the integration' do + deleted_int = Agreements::Integration.find_by(id: empty_integration.id) + expect(deleted_int).to be nil + end + end + it 'does not delete unrelated objects' do iu2.reload iaa_order.reload diff --git a/spec/lib/telephony/alert_sender_spec.rb b/spec/lib/telephony/alert_sender_spec.rb index 01616c6e797..7430cdc73ad 100644 --- a/spec/lib/telephony/alert_sender_spec.rb +++ b/spec/lib/telephony/alert_sender_spec.rb @@ -10,6 +10,18 @@ Telephony::Test::Message.clear_messages end + describe 'send_account_deleted_notice' do + it 'sends the correct message' do + subject.send_account_deleted_notice(to: recipient, country_code: 'US') + + last_message = Telephony::Test::Message.messages.last + expect(last_message.to).to eq(recipient) + expect(last_message.body).to eq( + I18n.t('telephony.account_deleted_notice', app_name: APP_NAME), + ) + end + end + describe 'send_account_reset_notice' do it 'sends the correct message' do subject.send_account_reset_notice(to: recipient, country_code: 'US', interval: interval) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 3d64d596206..04b0c431cdd 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -79,8 +79,7 @@ class Analytics # rubocop:enable Style/GlobalVars # rubocop:disable Rails/Output print ' Bundling JavaScript and stylesheets... ' - system 'WEBPACK_PORT= yarn build > /dev/null 2>&1' - system 'yarn build:css > /dev/null 2>&1' + system 'WEBPACK_PORT= yarn concurrently "yarn:build:*" > /dev/null 2>&1' puts '✨ Done!' # rubocop:enable Rails/Output end diff --git a/spec/services/frontend_logger_spec.rb b/spec/services/frontend_logger_spec.rb index 2d146bf1d85..545ea9f4a4f 100644 --- a/spec/services/frontend_logger_spec.rb +++ b/spec/services/frontend_logger_spec.rb @@ -37,16 +37,14 @@ def example_method_handler(ok:, **rest) context 'with unknown event' do let(:name) { :test_event } - it 'logs unknown event with warning' do - call - - expect(analytics).to have_logged_event('Frontend (warning): test_event') - end + it { expect(call).to eq(false) } end context 'with method handler' do let(:name) { 'method' } + it { expect(call).to eq(true) } + it 'calls method with attributes based on signature' do call @@ -57,6 +55,8 @@ def example_method_handler(ok:, **rest) context 'with proc handler' do let(:name) { 'proc' } + it { expect(call).to eq(true) } + it 'calls the method and passes analytics and attributes' do call diff --git a/spec/services/reporting/total_user_count_report_spec.rb b/spec/services/reporting/total_user_count_report_spec.rb index bf3f2bb503d..b67f7111bb6 100644 --- a/spec/services/reporting/total_user_count_report_spec.rb +++ b/spec/services/reporting/total_user_count_report_spec.rb @@ -10,6 +10,13 @@ [ ['Metric', 'All Users', 'Verified users', 'Time Range Start', 'Time Range End'], ['All-time count', expected_total_count, expected_verified_count, '-', Date.new(2021, 3, 1)], + [ + 'All-time fully registered', + expected_total_fully_registered, + '-', + '-', + Date.new(2021, 3, 1), + ], [ 'New users count', expected_new_count, @@ -44,6 +51,7 @@ before { create(:user) } let(:expected_total_count) { 1 } let(:expected_verified_count) { 0 } + let(:expected_total_fully_registered) { 0 } let(:expected_new_count) { 1 } let(:expected_new_verified_count) { 0 } let(:expected_annual_count) { expected_total_count } @@ -58,6 +66,7 @@ let(:expected_total_count) { 2 } let(:expected_verified_count) { 0 } + let(:expected_total_fully_registered) { 0 } let(:expected_new_count) { 1 } let(:expected_new_verified_count) { 0 } let(:expected_annual_count) { 1 } @@ -75,6 +84,7 @@ end let(:expected_total_count) { 2 } let(:expected_verified_count) { 1 } + let(:expected_total_fully_registered) { 0 } let(:expected_new_count) { 2 } let(:expected_new_verified_count) { 1 } let(:expected_annual_count) { expected_total_count } @@ -92,6 +102,7 @@ # A suspended user is still a total user: let(:expected_total_count) { 1 } let(:expected_verified_count) { 0 } + let(:expected_total_fully_registered) { 0 } let(:expected_new_count) { 1 } let(:expected_new_verified_count) { 0 } let(:expected_annual_count) { 1 } @@ -106,6 +117,7 @@ # A user with a fraud rejection is still a total user let(:expected_total_count) { 1 } let(:expected_verified_count) { 0 } + let(:expected_total_fully_registered) { 1 } let(:expected_new_count) { 1 } let(:expected_new_verified_count) { 0 } let(:expected_annual_count) { 1 } @@ -113,5 +125,23 @@ it_behaves_like 'a report with the specified counts' end + + context 'with fully registered user' do + before do + create(:user) + create_list(:user, 2).each do |user| + RegistrationLog.create(user: user, registered_at: user.created_at) + end + end + let(:expected_total_count) { 3 } + let(:expected_verified_count) { 0 } + let(:expected_total_fully_registered) { 2 } + let(:expected_new_count) { 3 } + let(:expected_new_verified_count) { 0 } + let(:expected_annual_count) { 3 } + let(:expected_annual_verified_count) { 0 } + + it_behaves_like 'a report with the specified counts' + end end end diff --git a/spec/support/features/session_helper.rb b/spec/support/features/session_helper.rb index b5754b5dc38..70f3ba3a267 100644 --- a/spec/support/features/session_helper.rb +++ b/spec/support/features/session_helper.rb @@ -490,7 +490,7 @@ def submit_form_with_valid_but_wrong_email end def click_link_to_use_a_different_email - click_link t('notices.use_diff_email.link') + click_link t('notices.use_diff_email.link').upcase_first end def submit_form_with_valid_email(email = 'test@test.com') diff --git a/spec/views/sign_up/emails/show.html.erb_spec.rb b/spec/views/sign_up/emails/show.html.erb_spec.rb index b51b5daf051..b8f2e9f22d7 100644 --- a/spec/views/sign_up/emails/show.html.erb_spec.rb +++ b/spec/views/sign_up/emails/show.html.erb_spec.rb @@ -19,10 +19,14 @@ expect(rendered).to have_selector('h1', text: t('headings.verify_email')) end - it 'contains link to resend confirmation page' do + it 'contains a form link to resend confirmation page' do render - expect(rendered).to have_button(t('links.resend')) + expect(rendered).to have_selector('lg-form-link') + expect(rendered).to have_link(href: '#', class: ['usa-link', 'block-link']) + expect(rendered). + to have_button(t('notices.signed_up_but_unconfirmed.resend_confirmation_email')) + expect(rendered).to have_css("form[action='#{sign_up_register_path}']") end context 'when enable_load_testing_mode? is true and email address found' do diff --git a/yarn.lock b/yarn.lock index 6f4fc7cd765..16b74664e85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -985,12 +985,12 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.9", "@babel/runtime@^7.8.4": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" - integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== +"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.9", "@babel/runtime@^7.21.0", "@babel/runtime@^7.8.4": + version "7.23.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650" + integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw== dependencies: - regenerator-runtime "^0.13.4" + regenerator-runtime "^0.14.0" "@babel/template@^7.15.4", "@babel/template@^7.20.7", "@babel/template@^7.22.15": version "7.22.15" @@ -2483,7 +2483,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: +chalk@^4.0, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2673,6 +2673,21 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +concurrently@^8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.2.tgz#353141985c198cfa5e4a3ef90082c336b5851784" + integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg== + dependencies: + chalk "^4.1.2" + date-fns "^2.30.0" + lodash "^4.17.21" + rxjs "^7.8.1" + shell-quote "^1.8.1" + spawn-command "0.0.2" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.2" + confusing-browser-globals@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" @@ -2836,6 +2851,13 @@ data-urls@^4.0.0: whatwg-mimetype "^3.0.0" whatwg-url "^12.0.0" +date-fns@^2.30.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -4655,10 +4677,10 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libphonenumber-js@^1.10.55: - version "1.10.55" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.55.tgz#ec864e369bf7babde02021d06b5f2433d7e9c78e" - integrity sha512-MrTg2JFLscgmTY6/oT9vopYETlgUls/FU6OaeeamGwk4LFxjIgOUML/ZSZICgR0LPYXaonVJo40lzMvaaTJlQA== +libphonenumber-js@^1.10.56: + version "1.10.56" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.56.tgz#96d9d64c31888ec363ed99fbf77cf4ad12117aa4" + integrity sha512-d0GdKshNnyfl5gM7kZ9rXjGiAbxT/zCXp0k+EAzh8H4zrb2R7GXtMCrULrX7UQxtfx6CLy/vz/lomvW79FAFdA== lightningcss-darwin-arm64@1.23.0: version "1.23.0" @@ -5811,6 +5833,11 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regenerator-transform@^0.14.2: version "0.14.5" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" @@ -5954,10 +5981,10 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.4.0, rxjs@^7.5.5: - version "7.8.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" - integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== +rxjs@^7.4.0, rxjs@^7.5.5, rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" @@ -6347,6 +6374,11 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spawn-command@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== + spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -6779,6 +6811,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + trim-newlines@^4.0.2: version "4.1.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.1.1.tgz#28c88deb50ed10c7ba6dc2474421904a00139125" @@ -7351,7 +7388,7 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.3.1: +yargs@^17.3.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==