- <%= t('idv.cancel.warnings.warning_1') %>
- <%= t('idv.cancel.warnings.warning_2') %>
- <%= t('idv.cancel.warnings.warning_3', app_name: APP_NAME) %>
diff --git a/app/views/idv/doc_auth/verify.html.erb b/app/views/idv/doc_auth/verify.html.erb
index a921705ab4e..150e0cf4ce7 100644
--- a/app/views/idv/doc_auth/verify.html.erb
+++ b/app/views/idv/doc_auth/verify.html.erb
@@ -64,7 +64,7 @@
url_for,
method: :put,
form: {
- class: 'button_to read-after-submit',
+ class: 'button_to',
data: {
form_steps_wait: '',
error_message: t('idv.failure.exceptions.internal_error'),
diff --git a/app/views/idv/forgot_password/new.html.erb b/app/views/idv/forgot_password/new.html.erb
index edcbfd81e75..056ce94d1de 100644
--- a/app/views/idv/forgot_password/new.html.erb
+++ b/app/views/idv/forgot_password/new.html.erb
@@ -1,21 +1,24 @@
<% title t('titles.idv.reset_password') %>
-<%= image_tag(asset_url('alert/forgot.svg'), width: 54, class: 'margin-bottom-2') %>
+<%= render StatusPageComponent.new(status: :info, icon: :question) do |c| %>
+ <% c.header { t('idv.forgot_password.modal_header') } %>
-<%= render PageHeadingComponent.new.with_content(t('idv.forgot_password.modal_header')) %>
+
+ <% t('idv.forgot_password.warnings').each do |warning| %>
+ - <%= warning %>
+ <% end %>
+
-
+ <% c.action_button(
+ action: ->(**tag_options, &block) do
+ link_to(idv_review_path, **tag_options, &block)
+ end,
+ ) { t('idv.forgot_password.try_again') } %>
-
- - <%= t('idv.forgot_password.warnings.warning_1') %>
- - <%= t('idv.forgot_password.warnings.warning_2') %>
-
-
-
- <%= link_to t('idv.forgot_password.try_again'), idv_review_path,
- class: 'usa-button usa-button--big usa-button--wide' %>
-
-
- <%= button_to t('idv.forgot_password.reset_password'), idv_forgot_password_path,
- method: :post, class: 'usa-button usa-button--big usa-button--wide usa-button--outline' %>
-
+ <% c.action_button(
+ action: ->(**tag_options, &block) do
+ button_to(idv_forgot_password_path, method: :post, **tag_options, &block)
+ end,
+ outline: true,
+ ) { t('idv.forgot_password.reset_password') } %>
+<% end %>
diff --git a/app/views/idv/review/new.html.erb b/app/views/idv/review/new.html.erb
index 74e15e9cd10..31cb2169ed0 100644
--- a/app/views/idv/review/new.html.erb
+++ b/app/views/idv/review/new.html.erb
@@ -20,16 +20,17 @@
MarketingSite.security_url,
) %>
-<%= validated_form_for(
+<%= simple_form_for(
current_user,
url: idv_review_path,
html: { autocomplete: 'off', method: :put, class: 'margin-top-6' },
) do |f| %>
- <%= f.input :password, label: t('idv.form.password'), required: true,
- input_html: { aria: { invalid: false }, class: 'password-toggle' }, wrapper: false %>
-
- <%= t('simple_form.required.text') %>
-
+ <%= render PasswordToggleComponent.new(
+ form: f,
+ label: t('idv.form.password'),
+ required: true,
+ wrapper_html: { class: 'margin-bottom-0' },
+ ) %>
<%= t(
'idv.forgot_password.link_html',
diff --git a/app/views/mfa_confirmation/new.html.erb b/app/views/mfa_confirmation/new.html.erb
index 85113d2590b..8301994ffa2 100644
--- a/app/views/mfa_confirmation/new.html.erb
+++ b/app/views/mfa_confirmation/new.html.erb
@@ -13,7 +13,7 @@
url: reauthn_user_password_path,
html: { autocomplete: 'off', method: 'post', class: 'margin-top-6' },
) do |f| %>
- <%= f.input :password, required: true, input_html: { aria: { invalid: false }, class: 'password-toggle' } %>
+ <%= render PasswordToggleComponent.new(form: f, required: true) %>
<%= f.button :submit, t('forms.buttons.continue'), class: 'display-block margin-y-5 usa-button--big usa-button--wide' %>
<% end %>
<%= render 'shared/cancel', link: account_path %>
diff --git a/app/views/password_capture/new.html.erb b/app/views/password_capture/new.html.erb
index bb8a35d9819..a3926cd5d21 100644
--- a/app/views/password_capture/new.html.erb
+++ b/app/views/password_capture/new.html.erb
@@ -9,8 +9,11 @@
method: :post,
html: { autocomplete: 'off', class: 'margin-top-6' },
) do |f| %>
- <%= f.input :password, label: t('account.index.password'), required: true,
- input_html: { aria: { invalid: false }, class: 'password-toggle' } %>
+ <%= render PasswordToggleComponent.new(
+ form: f,
+ label: t('account.index.password'),
+ required: true,
+ ) %>
<%= f.button :submit, t('forms.buttons.submit.default'), class: 'display-block margin-y-5 usa-button--big usa-button--wide' %>
<% end %>
diff --git a/app/views/shared/_ssn_field.html.erb b/app/views/shared/_ssn_field.html.erb
index 3e9c662b68d..522a2ba6f60 100644
--- a/app/views/shared/_ssn_field.html.erb
+++ b/app/views/shared/_ssn_field.html.erb
@@ -4,11 +4,13 @@ locals:
%>
<%# maxlength set and includes '-' delimiters to work around cleave bug %>
-<%= render ValidatedFieldComponent.new(
+<%= render PasswordToggleComponent.new(
name: :ssn,
form: f,
as: :password,
label: t('idv.form.ssn_label_html'),
+ toggle_label: t('forms.ssn.show'),
+ toggle_position: :bottom,
hint: t('forms.example') + ' 123-45-6789',
required: true,
pattern: '^\d{3}-?\d{2}-?\d{4}$',
diff --git a/app/views/sign_up/passwords/new.html.erb b/app/views/sign_up/passwords/new.html.erb
index 9d798d4225c..94c32bdc1e5 100644
--- a/app/views/sign_up/passwords/new.html.erb
+++ b/app/views/sign_up/passwords/new.html.erb
@@ -11,10 +11,12 @@
method: :post,
html: { autocomplete: 'off' },
) do |f| %>
- <%= f.input :password, required: true,
- label: t('forms.password'),
- input_html: { aria: { invalid: false, describedby: 'password-description' },
- class: 'password-toggle' } %>
+ <%= render PasswordToggleComponent.new(
+ form: f,
+ label: t('forms.password'),
+ required: true,
+ input_html: { aria: { describedby: 'password-description' } },
+ ) %>
<%= render 'devise/shared/password_strength', forbidden_passwords: @forbidden_passwords %>
<%= hidden_field_tag :confirmation_token, @confirmation_token, id: 'confirmation_token' %>
<%= f.input :request_id, as: :hidden, input_html: { value: params[:request_id] || request_id } %>
diff --git a/app/views/two_factor_authentication/webauthn_verification/show.html.erb b/app/views/two_factor_authentication/webauthn_verification/show.html.erb
index 10d57941cf4..d8b494d88d7 100644
--- a/app/views/two_factor_authentication/webauthn_verification/show.html.erb
+++ b/app/views/two_factor_authentication/webauthn_verification/show.html.erb
@@ -11,7 +11,7 @@
url: login_two_factor_webauthn_path,
method: :patch,
html: {
- class: 'margin-bottom-1 read-after-submit',
+ class: 'margin-bottom-1',
id: 'webauthn_form',
},
) do |f| %>
diff --git a/app/views/users/delete/show.html.erb b/app/views/users/delete/show.html.erb
index 2e30b14b4ea..78fec448400 100644
--- a/app/views/users/delete/show.html.erb
+++ b/app/views/users/delete/show.html.erb
@@ -22,12 +22,11 @@
<%= t('users.delete.instructions') %>
- <%= render ValidatedFieldComponent.new(
+ <%= render PasswordToggleComponent.new(
form: f,
name: :password,
label: t('idv.form.password'),
required: true,
- input_html: { class: 'password-toggle' },
) %>
<%= f.button(
diff --git a/app/views/users/passwords/edit.html.erb b/app/views/users/passwords/edit.html.erb
index e1760476231..93f4d845129 100644
--- a/app/views/users/passwords/edit.html.erb
+++ b/app/views/users/passwords/edit.html.erb
@@ -11,8 +11,13 @@
html: { autocomplete: 'off', method: :patch }
) do |f| %>
<%= f.error_notification %>
- <%= f.input :password, label: t('forms.passwords.edit.labels.password'), required: true,
- input_html: { aria: { invalid: false, describedby: 'password-description' }, class: 'password-toggle' } %>
+ <%= render PasswordToggleComponent.new(
+ form: f,
+ name: :password,
+ label: t('forms.passwords.edit.labels.password'),
+ required: true,
+ input_html: { aria: { describedby: 'password-description' } },
+ ) %>
<%= render 'devise/shared/password_strength', forbidden_passwords: @forbidden_passwords %>
<%= f.button :submit, t('forms.buttons.submit.update'), class: 'usa-button--big usa-button--wide margin-top-2 margin-bottom-4' %>
<% end %>
diff --git a/app/views/users/verify_password/new.html.erb b/app/views/users/verify_password/new.html.erb
index d23d668bd37..a5f8b8932a3 100644
--- a/app/views/users/verify_password/new.html.erb
+++ b/app/views/users/verify_password/new.html.erb
@@ -10,8 +10,12 @@
current_user, url: update_verify_password_path,
html: { autocomplete: 'off', method: :put }
) do |f| %>
- <%= f.input :password, label: t('idv.form.password'), required: true,
- input_html: { aria: { invalid: false }, class: 'password-toggle' } %>
+ <%= render PasswordToggleComponent.new(
+ form: f,
+ name: :password,
+ label: t('idv.form.password'),
+ required: true,
+ ) %>
<%= f.button :submit, t('forms.buttons.continue'), class: 'usa-button--big usa-button--wide' %>
<% end %>
diff --git a/app/views/users/webauthn_setup/new.html.erb b/app/views/users/webauthn_setup/new.html.erb
index 5d3b7c10c60..83533c384ca 100644
--- a/app/views/users/webauthn_setup/new.html.erb
+++ b/app/views/users/webauthn_setup/new.html.erb
@@ -13,7 +13,7 @@
url: webauthn_setup_path,
method: :patch,
html: {
- class: 'margin-top-4 margin-bottom-1 read-after-submit',
+ class: 'margin-top-4 margin-bottom-1',
id: 'webauthn_form',
},
) do |f| %>
diff --git a/babel.config.js b/babel.config.js
index c689971aa24..b36b7123923 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -18,6 +18,7 @@ module.exports = (api) => {
],
],
plugins: [
+ ['@babel/plugin-proposal-decorators', { version: 'legacy' }],
[
'polyfill-corejs3',
{
diff --git a/config/initializers/job_configurations.rb b/config/initializers/job_configurations.rb
index bd4cc0ac2fd..bab2298ba18 100644
--- a/config/initializers/job_configurations.rb
+++ b/config/initializers/job_configurations.rb
@@ -69,7 +69,6 @@
cron: cron_24h,
args: -> { [Time.zone.today] },
},
- # Send Sp Success Rate Report to S3
# Proofing Costs Report to S3
proofing_costs: {
class: 'Reports::ProofingCostsReport',
@@ -117,6 +116,12 @@
cron: cron_24h,
args: -> { [Time.zone.today] },
},
+ # Total IAL2 Costs Report to S3
+ total_ial2_costs: {
+ class: 'Reports::TotalIal2CostsReport',
+ cron: cron_24h,
+ args: -> { [Time.zone.today] },
+ },
# SP Active Users Report to S3
sp_active_users_report: {
class: 'Reports::SpActiveUsersReport',
diff --git a/config/locales/components/en.yml b/config/locales/components/en.yml
index be115e26063..fdce36fbd70 100644
--- a/config/locales/components/en.yml
+++ b/config/locales/components/en.yml
@@ -1,12 +1,16 @@
---
en:
components:
+ password_toggle:
+ label: Password
+ toggle_label: Show password
phone_input:
country_code_label: Country code
status_page:
icons:
error: Error
lock: Lock
+ question: Question
warning: Warning
troubleshooting_options:
default_heading: 'Having trouble? Here’s what you can do:'
diff --git a/config/locales/components/es.yml b/config/locales/components/es.yml
index c1007e6480c..84b9e7b8c4c 100644
--- a/config/locales/components/es.yml
+++ b/config/locales/components/es.yml
@@ -1,12 +1,16 @@
---
es:
components:
+ password_toggle:
+ label: Contraseña
+ toggle_label: Mostrar contraseña
phone_input:
country_code_label: Código del país
status_page:
icons:
error: Error
lock: Candado
+ question: Pregunta
warning: Advertencia
troubleshooting_options:
default_heading: '¿Tiene alguna dificultad? Esto es lo que puede hacer:'
diff --git a/config/locales/components/fr.yml b/config/locales/components/fr.yml
index 04fc04e85d8..6dac244aa70 100644
--- a/config/locales/components/fr.yml
+++ b/config/locales/components/fr.yml
@@ -1,12 +1,16 @@
---
fr:
components:
+ password_toggle:
+ label: Mot de passe
+ toggle_label: Afficher le mot de passe
phone_input:
country_code_label: Code pays
status_page:
icons:
error: Erreur
lock: Serrure
+ question: Question
warning: Avertissement
troubleshooting_options:
default_heading: 'Des difficultés? Voici ce que vous pouvez faire:'
diff --git a/config/locales/forms/en.yml b/config/locales/forms/en.yml
index f5e9a1523fd..5701f924f9c 100644
--- a/config/locales/forms/en.yml
+++ b/config/locales/forms/en.yml
@@ -59,7 +59,6 @@ en:
submit: Change password
labels:
password: New password
- show: Show password
personal_key:
alternative: Don’t have your personal key?
confirmation_label: Personal key
@@ -104,7 +103,8 @@ en:
totp_step_4: Enter the temporary code from your app
two_factor:
backup_code: Security code
- code: One-time security code
+ # removed "security code" form labels as they trigger ios credit card reader
+ code: One-time code
personal_key: Personal key
try_again: Use another phone number
two_factor_choice:
diff --git a/config/locales/forms/es.yml b/config/locales/forms/es.yml
index 7fadf7a1eb9..1a43385f069 100644
--- a/config/locales/forms/es.yml
+++ b/config/locales/forms/es.yml
@@ -64,7 +64,6 @@ es:
submit: Cambiar la contraseña
labels:
password: Nueva contraseña
- show: Mostrar contraseña
personal_key:
alternative: '¿No tiene su clave personal?'
confirmation_label: Clave personal
@@ -111,7 +110,8 @@ es:
totp_step_4: Ingrese el código temporal de su aplicación
two_factor:
backup_code: Código de seguridad
- code: Código de seguridad de sólo un uso
+ # removed "security code" form labels as they trigger ios credit card reader
+ code: Código de un solo uso
personal_key: Clave personal
try_again: Use otro número de teléfono.
two_factor_choice:
diff --git a/config/locales/forms/fr.yml b/config/locales/forms/fr.yml
index 5e35632574c..a81b7d5bb73 100644
--- a/config/locales/forms/fr.yml
+++ b/config/locales/forms/fr.yml
@@ -65,7 +65,6 @@ fr:
submit: Changer le mot de passe
labels:
password: Nouveau mot de passe
- show: Afficher le mot de passe
personal_key:
alternative: Vous n’avez pas votre clé personnelle?
confirmation_label: Clé personnelle
@@ -112,7 +111,8 @@ fr:
totp_step_4: Entrez le code temporaire de votre application
two_factor:
backup_code: Code de sécurité
- code: Code de sécurité
+ # removed "security code" form labels as they trigger ios credit card reader
+ code: Code à usage unique
personal_key: Clé personnelle
try_again: Utilisez un autre numéro de téléphone
two_factor_choice:
diff --git a/config/locales/idv/en.yml b/config/locales/idv/en.yml
index 15eb6a5b3c3..e3d652b5a9d 100644
--- a/config/locales/idv/en.yml
+++ b/config/locales/idv/en.yml
@@ -69,9 +69,9 @@ en:
reset_password: Reset password
try_again: Try again
warnings:
- warning_1: If you forgot your password, you’ll need to reset it and fill out the
+ - If you forgot your password, you’ll need to reset it and fill out the
form again.
- warning_2: You’ll have to re-enter your personal information, like your name,
+ - You’ll have to re-enter your personal information, like your name,
state-issued ID, etc.
form:
address1: Address
diff --git a/config/locales/idv/es.yml b/config/locales/idv/es.yml
index 308d4ae7ff1..478e11ee897 100644
--- a/config/locales/idv/es.yml
+++ b/config/locales/idv/es.yml
@@ -76,8 +76,8 @@ es:
reset_password: Restablecer la contraseña
try_again: Inténtalo de nuevo
warnings:
- warning_1: Si olvidó su contraseña, deberá restablecerla y completarla nuevamente.
- warning_2: Tendrá que volver a ingresar su información personal, como su nombre,
+ - Si olvidó su contraseña, deberá restablecerla y completarla nuevamente.
+ - Tendrá que volver a ingresar su información personal, como su nombre,
documento de identidad emitido por el estado, etc.
form:
address1: Dirección
diff --git a/config/locales/idv/fr.yml b/config/locales/idv/fr.yml
index 551dba68c97..c9855f7bfb8 100644
--- a/config/locales/idv/fr.yml
+++ b/config/locales/idv/fr.yml
@@ -79,9 +79,9 @@ fr:
reset_password: Réinitialiser le mot de passe
try_again: Réessayer
warnings:
- warning_1: Si vous avez oublié votre mot de passe, vous devrez le réinitialiser
+ - Si vous avez oublié votre mot de passe, vous devrez le réinitialiser
et remplir à nouveau le formulaire.
- warning_2: Vous devrez ressaisir vos informations personnelles, comme votre nom,
+ - Vous devrez ressaisir vos informations personnelles, comme votre nom,
pièce d’identité officielle, etc.
form:
address1: Adresse
diff --git a/config/routes.rb b/config/routes.rb
index 46cea19738e..2815c0bf86b 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -276,8 +276,6 @@
get '/come_back_later' => 'come_back_later#show'
get '/personal_key' => 'personal_key#show'
post '/personal_key' => 'personal_key#update'
- # Remove this after the next deploy
- get '/download_personal_key' => 'personal_key#download'
get '/forgot_password' => 'forgot_password#new'
post '/forgot_password' => 'forgot_password#update'
get '/otp_delivery_method' => 'otp_delivery_method#new'
diff --git a/package.json b/package.json
index cd977dd0307..2bada0b0363 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
},
"dependencies": {
"@babel/core": "^7.15.5",
+ "@babel/plugin-proposal-decorators": "^7.17.2",
"@babel/preset-env": "^7.15.6",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.16.7",
@@ -56,6 +57,7 @@
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"@types/sinon": "^10.0.11",
+ "@types/sinon-chai": "^3.2.8",
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"chai": "^4.2.0",
diff --git a/spec/components/password_toggle_component_spec.rb b/spec/components/password_toggle_component_spec.rb
new file mode 100644
index 00000000000..36ae51bfec0
--- /dev/null
+++ b/spec/components/password_toggle_component_spec.rb
@@ -0,0 +1,101 @@
+require 'rails_helper'
+
+RSpec.describe PasswordToggleComponent, type: :component do
+ include SimpleForm::ActionViewExtensions::FormHelper
+
+ let(:lookup_context) { ActionView::LookupContext.new(ActionController::Base.view_paths) }
+ let(:view_context) { ActionView::Base.new(lookup_context, {}, controller) }
+ let(:form) { SimpleForm::FormBuilder.new('', {}, view_context, {}) }
+ let(:options) { {} }
+
+ subject(:rendered) { render_inline PasswordToggleComponent.new(form: form, **options) }
+
+ it 'renders default markup' do
+ expect(rendered).to have_css('lg-password-toggle.password-toggle--toggle-top')
+ expect(rendered).to have_field(t('components.password_toggle.label'), type: :password)
+ expect(rendered).to have_field(t('components.password_toggle.toggle_label'), type: :checkbox)
+ end
+
+ it 'renders with accessible linking between toggle and input' do
+ input_id = rendered.css('[type=password]').first.attr('id')
+
+ expect(input_id).to be_present
+ expect(rendered).to have_css("[aria-controls='#{input_id}']")
+ end
+
+ describe '#label' do
+ context 'with custom label' do
+ let(:label) { 'Custom Label' }
+ let(:options) { { label: label } }
+
+ it 'renders custom field label' do
+ expect(rendered).to have_field(label, type: :password)
+ end
+ end
+ end
+
+ describe '#toggle_label' do
+ context 'with custom label' do
+ let(:toggle_label) { 'Custom Toggle Label' }
+ let(:options) { { toggle_label: toggle_label } }
+
+ it 'renders custom field label' do
+ expect(rendered).to have_field(toggle_label, type: :checkbox)
+ end
+ end
+ end
+
+ describe '#toggle_position' do
+ context 'with top toggle position' do
+ let(:options) { { toggle_position: :top } }
+
+ it 'renders modifier class' do
+ expect(rendered).to have_css('lg-password-toggle.password-toggle--toggle-top')
+ end
+ end
+
+ context 'with bottom toggle position' do
+ let(:options) { { toggle_position: :bottom } }
+
+ it 'renders modifier class' do
+ expect(rendered).to have_css('lg-password-toggle.password-toggle--toggle-bottom')
+ end
+ end
+ end
+
+ describe '#toggle_id' do
+ it 'is unique across instances' do
+ toggle_one = PasswordToggleComponent.new(form: form)
+ toggle_two = PasswordToggleComponent.new(form: form)
+
+ expect(toggle_one.toggle_id).to be_present
+ expect(toggle_two.toggle_id).to be_present
+ expect(toggle_one.toggle_id).not_to eq(toggle_two.toggle_id)
+ end
+ end
+
+ describe '#input_id' do
+ it 'is unique across instances' do
+ toggle_one = PasswordToggleComponent.new(form: form)
+ toggle_two = PasswordToggleComponent.new(form: form)
+
+ expect(toggle_one.input_id).to be_present
+ expect(toggle_two.input_id).to be_present
+ expect(toggle_one.input_id).not_to eq(toggle_two.input_id)
+ end
+ end
+
+ describe '#field' do
+ context 'with field options' do
+ let(:options) do
+ { input_html: { class: 'my-custom-field', data: { foo: 'bar' } }, required: true }
+ end
+
+ it 'forwards field options' do
+ expect(rendered).to have_css(
+ '.password-toggle__input.my-custom-field[data-foo="bar"][required]',
+ )
+ end
+ end
+ end
+end
diff --git a/spec/components/status_page_component_spec.rb b/spec/components/status_page_component_spec.rb
index 201d90583bf..0afcf0268c7 100644
--- a/spec/components/status_page_component_spec.rb
+++ b/spec/components/status_page_component_spec.rb
@@ -70,4 +70,10 @@
render_inline StatusPageComponent.new(status: :warning, icon: :foo)
end.to raise_error(ArgumentError)
end
+
+ it 'raises error if no default icon associated with status' do
+ expect do
+ render_inline StatusPageComponent.new(status: :info)
+ end.to raise_error(ArgumentError)
+ end
end
diff --git a/spec/components/validated_field_component_spec.rb b/spec/components/validated_field_component_spec.rb
index d94290780b6..7d9e890620d 100644
--- a/spec/components/validated_field_component_spec.rb
+++ b/spec/components/validated_field_component_spec.rb
@@ -25,6 +25,12 @@
render_inline(described_class.new(**options))
end
+ it 'renders aria-describedby to establish connection between input and error message' do
+ field = rendered.at_css('input')
+
+ expect(field.attr('aria-describedby')).to start_with('validated-field-error-')
+ end
+
describe 'error message strings' do
subject(:strings) do
script = rendered.at_css('script[type="application/json"]')
@@ -59,4 +65,16 @@
end
end
end
+
+ context 'with tag options' do
+ context 'with aria tag option' do
+ let(:tag_options) { { input_html: { aria: { describedby: 'foo' } } } }
+
+ it 'merges aria-describedby with the one applied by the field' do
+ field = rendered.at_css('input')
+
+ expect(field.attr('aria-describedby')).to start_with('foo validated-field-error-')
+ end
+ end
+ end
end
diff --git a/spec/controllers/event_disavowal_controller_spec.rb b/spec/controllers/event_disavowal_controller_spec.rb
index 0856ed63653..e6e7e5174f9 100644
--- a/spec/controllers/event_disavowal_controller_spec.rb
+++ b/spec/controllers/event_disavowal_controller_spec.rb
@@ -41,7 +41,7 @@
event.update!(disavowed_at: Time.zone.now)
expect(@analytics).to receive(:track_event).with(
- Analytics::EVENT_DISAVOWAL_TOKEN_INVALID,
+ 'Event disavowal token invalid',
build_analytics_hash(
success: false,
errors: { event: [t('event_disavowals.errors.event_already_disavowed')] },
@@ -55,7 +55,7 @@
event.update!(disavowed_at: Time.zone.now)
expect(@analytics).to receive(:track_event).with(
- Analytics::EVENT_DISAVOWAL_TOKEN_INVALID,
+ 'Event disavowal token invalid',
build_analytics_hash(
success: false,
errors: { event: [t('event_disavowals.errors.event_already_disavowed')] },
@@ -127,7 +127,7 @@
event.update!(disavowed_at: Time.zone.now)
expect(@analytics).to receive(:track_event).with(
- Analytics::EVENT_DISAVOWAL_TOKEN_INVALID,
+ 'Event disavowal token invalid',
build_analytics_hash(
success: false,
errors: { event: [t('event_disavowals.errors.event_already_disavowed')] },
@@ -150,7 +150,7 @@
it 'errors' do
expect(@analytics).to receive(:track_event).with(
- Analytics::EVENT_DISAVOWAL_TOKEN_INVALID,
+ 'Event disavowal token invalid',
build_analytics_hash(
success: false,
errors: {
diff --git a/spec/controllers/idv/personal_key_controller_spec.rb b/spec/controllers/idv/personal_key_controller_spec.rb
index ed711a1d982..8c4759b2853 100644
--- a/spec/controllers/idv/personal_key_controller_spec.rb
+++ b/spec/controllers/idv/personal_key_controller_spec.rb
@@ -187,45 +187,4 @@ def index
end
end
end
-
- describe '#download' do
- before do
- stub_idv_session
- stub_analytics
- end
-
- it 'allows download of code' do
- subject.idv_session.create_profile_from_applicant_with_password(password)
- code = subject.idv_session.personal_key
-
- get :show
- get :download
-
- expect(response.body).to eq(code + "\r\n")
- expect(response.header['Content-Type']).to eq('text/plain')
- expect(@analytics).to have_logged_event(Analytics::IDV_PERSONAL_KEY_DOWNLOADED, success: true)
- end
-
- it 'recovers pii and verifies personal key digest with the code' do
- get :show
- get :download
-
- code = response.body.chomp
-
- expect(PersonalKeyGenerator.new(user).verify(code)).to eq true
- expect(user.profiles.first.recover_pii(normalize_personal_key(code))).to eq(
- subject.idv_session.pii,
- )
- end
-
- it 'is a bad request when there is no personal_key in the session' do
- get :download
-
- expect(response).to be_bad_request
- expect(@analytics).to have_logged_event(
- Analytics::IDV_PERSONAL_KEY_DOWNLOADED,
- success: false,
- )
- end
- end
end
diff --git a/spec/controllers/redirect/help_center_controller_spec.rb b/spec/controllers/redirect/help_center_controller_spec.rb
index ae752fa2d96..f5bd791df63 100644
--- a/spec/controllers/redirect/help_center_controller_spec.rb
+++ b/spec/controllers/redirect/help_center_controller_spec.rb
@@ -16,7 +16,7 @@
context 'without help center article' do
it 'redirects to the root url' do
expect(response).to redirect_to root_url
- expect(@analytics).not_to have_logged_event(Analytics::EXTERNAL_REDIRECT)
+ expect(@analytics).not_to have_logged_event('External Redirect')
end
end
@@ -26,7 +26,7 @@
it 'redirects to the root url' do
expect(response).to redirect_to root_url
- expect(@analytics).not_to have_logged_event(Analytics::EXTERNAL_REDIRECT)
+ expect(@analytics).not_to have_logged_event('External Redirect')
end
end
@@ -41,7 +41,7 @@
)
expect(response).to redirect_to redirect_url
expect(@analytics).to have_logged_event(
- Analytics::EXTERNAL_REDIRECT,
+ 'External Redirect',
redirect_url: redirect_url,
)
end
@@ -53,7 +53,7 @@
response
expect(@analytics).to have_logged_event(
- Analytics::EXTERNAL_REDIRECT,
+ 'External Redirect',
redirect_url: MarketingSite.help_center_article_url(
category: 'verify-your-identity',
article: 'accepted-state-issued-identification',
diff --git a/spec/controllers/redirect/return_to_sp_controller_spec.rb b/spec/controllers/redirect/return_to_sp_controller_spec.rb
index ff2e0c15772..79574f757b2 100644
--- a/spec/controllers/redirect/return_to_sp_controller_spec.rb
+++ b/spec/controllers/redirect/return_to_sp_controller_spec.rb
@@ -99,8 +99,8 @@
expect(response).to redirect_to('https://sp.gov/failure_to_proof')
expect(@analytics).to have_received(:track_event).with(
- Analytics::RETURN_TO_SP_FAILURE_TO_PROOF,
- redirect_url: 'https://sp.gov/failure_to_proof',
+ 'Return to SP: Failed to proof',
+ hash_including(redirect_url: 'https://sp.gov/failure_to_proof'),
)
end
end
@@ -110,10 +110,12 @@
get 'failure_to_proof', params: { step: 'first', location: 'bottom' }
expect(@analytics).to have_received(:track_event).with(
- Analytics::RETURN_TO_SP_FAILURE_TO_PROOF,
- redirect_url: a_kind_of(String),
- step: 'first',
- location: 'bottom',
+ 'Return to SP: Failed to proof',
+ hash_including(
+ redirect_url: a_kind_of(String),
+ step: 'first',
+ location: 'bottom',
+ ),
)
end
end
diff --git a/spec/controllers/risc/security_events_controller_spec.rb b/spec/controllers/risc/security_events_controller_spec.rb
index 97f834b66ee..b3eadf0ebe6 100644
--- a/spec/controllers/risc/security_events_controller_spec.rb
+++ b/spec/controllers/risc/security_events_controller_spec.rb
@@ -48,7 +48,7 @@
it 'tracks an successful in analytics' do
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::SECURITY_EVENT_RECEIVED,
+ with('RISC: Security event received',
client_id: service_provider.issuer,
error_code: nil,
errors: {},
@@ -77,7 +77,7 @@
it 'tracks an error event in analytics' do
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::SECURITY_EVENT_RECEIVED,
+ with('RISC: Security event received',
client_id: service_provider.issuer,
error_code: SecurityEventForm::ErrorCodes::JWT_AUD,
errors: kind_of(Hash),
diff --git a/spec/controllers/users/forget_all_browsers_controller_spec.rb b/spec/controllers/users/forget_all_browsers_controller_spec.rb
index 28a066ed116..4fa3af9253d 100644
--- a/spec/controllers/users/forget_all_browsers_controller_spec.rb
+++ b/spec/controllers/users/forget_all_browsers_controller_spec.rb
@@ -30,7 +30,7 @@
it 'logs an analytics event for visiting' do
stub_analytics
- expect(@analytics).to receive(:track_event).with(Analytics::FORGET_ALL_BROWSERS_VISITED)
+ expect(@analytics).to receive(:track_event).with('Forget All Browsers Visited')
subject
end
@@ -58,7 +58,7 @@
it 'logs an analytics event for forgetting' do
stub_analytics
- expect(@analytics).to receive(:track_event).with(Analytics::FORGET_ALL_BROWSERS_SUBMITTED)
+ expect(@analytics).to receive(:track_event).with('Forget All Browsers Submitted')
subject
end
diff --git a/spec/controllers/users/rules_of_use_controller_spec.rb b/spec/controllers/users/rules_of_use_controller_spec.rb
index 388a279e4eb..6b20923ba62 100644
--- a/spec/controllers/users/rules_of_use_controller_spec.rb
+++ b/spec/controllers/users/rules_of_use_controller_spec.rb
@@ -33,7 +33,7 @@
it 'logs an analytics event for visiting' do
stub_analytics
- expect(@analytics).to receive(:track_event).with(Analytics::RULES_OF_USE_VISIT)
+ expect(@analytics).to receive(:track_event).with('Rules of Use Visited')
action
end
@@ -64,7 +64,7 @@
it 'logs an analytics event for visiting' do
stub_analytics
- expect(@analytics).to receive(:track_event).with(Analytics::RULES_OF_USE_VISIT)
+ expect(@analytics).to receive(:track_event).with('Rules of Use Visited')
action
end
@@ -117,7 +117,7 @@
it 'logs a successful analytics event' do
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::RULES_OF_USE_SUBMITTED, hash_including(success: true))
+ with('Rules of Use Submitted', hash_including(success: true))
action
end
@@ -147,7 +147,7 @@
it 'logs a failure analytics event' do
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::RULES_OF_USE_SUBMITTED, hash_including(success: false))
+ with('Rules of Use Submitted', hash_including(success: false))
action
end
diff --git a/spec/controllers/users/service_provider_revoke_controller_spec.rb b/spec/controllers/users/service_provider_revoke_controller_spec.rb
index c7049737bda..e72982aef8a 100644
--- a/spec/controllers/users/service_provider_revoke_controller_spec.rb
+++ b/spec/controllers/users/service_provider_revoke_controller_spec.rb
@@ -32,7 +32,7 @@
it 'logs an analytics event for visiting' do
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::SP_REVOKE_CONSENT_VISITED, issuer: service_provider.issuer)
+ with('SP Revoke Consent: Visited', issuer: service_provider.issuer)
subject
end
@@ -75,7 +75,7 @@
it 'logs an analytics event for revoking' do
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::SP_REVOKE_CONSENT_REVOKED, issuer: service_provider.issuer)
+ with('SP Revoke Consent: Revoked', issuer: service_provider.issuer)
subject
end
diff --git a/spec/features/idv/doc_auth/document_capture_step_spec.rb b/spec/features/idv/doc_auth/document_capture_step_spec.rb
index ff7a7072623..8bb5cc04117 100644
--- a/spec/features/idv/doc_auth/document_capture_step_spec.rb
+++ b/spec/features/idv/doc_auth/document_capture_step_spec.rb
@@ -41,7 +41,7 @@
within_window new_window do
expect(fake_analytics).to have_logged_event(
- Analytics::RETURN_TO_SP_FAILURE_TO_PROOF,
+ 'Return to SP: Failed to proof',
step: 'document_capture',
location: 'document_capture_troubleshooting_options',
)
diff --git a/spec/features/idv/doc_auth/welcome_step_spec.rb b/spec/features/idv/doc_auth/welcome_step_spec.rb
index 962d253b052..d0dde031e89 100644
--- a/spec/features/idv/doc_auth/welcome_step_spec.rb
+++ b/spec/features/idv/doc_auth/welcome_step_spec.rb
@@ -28,7 +28,7 @@ def expect_doc_auth_upload_step
click_on t('idv.troubleshooting.options.get_help_at_sp', sp_name: sp_name)
expect(fake_analytics).to have_logged_event(
- Analytics::RETURN_TO_SP_FAILURE_TO_PROOF,
+ 'Return to SP: Failed to proof',
step: 'welcome',
location: 'missing_items',
)
@@ -38,7 +38,7 @@ def expect_doc_auth_upload_step
click_on t('idv.troubleshooting.options.supported_documents')
expect(fake_analytics).to have_logged_event(
- Analytics::EXTERNAL_REDIRECT,
+ 'External Redirect',
step: 'welcome',
location: 'missing_items',
flow: 'idv',
@@ -53,7 +53,7 @@ def expect_doc_auth_upload_step
click_on t('idv.troubleshooting.options.learn_more_address_verification_options')
expect(fake_analytics).to have_logged_event(
- Analytics::EXTERNAL_REDIRECT,
+ 'External Redirect',
step: 'welcome',
location: 'missing_items',
flow: 'idv',
@@ -90,7 +90,7 @@ def expect_doc_auth_upload_step
click_on "‹ #{t('links.back_to_sp', sp: sp_name)}"
expect(fake_analytics).to have_logged_event(
- Analytics::RETURN_TO_SP_FAILURE_TO_PROOF,
+ 'Return to SP: Failed to proof',
step: 'welcome',
location: 'cancel',
)
diff --git a/spec/features/idv/doc_capture/document_capture_step_spec.rb b/spec/features/idv/doc_capture/document_capture_step_spec.rb
index e1c5ee6da59..e27a594a712 100644
--- a/spec/features/idv/doc_capture/document_capture_step_spec.rb
+++ b/spec/features/idv/doc_capture/document_capture_step_spec.rb
@@ -154,7 +154,7 @@
within_window new_window do
expect(fake_analytics).to have_logged_event(
- Analytics::RETURN_TO_SP_FAILURE_TO_PROOF,
+ 'Return to SP: Failed to proof',
step: 'document_capture',
location: 'document_capture_troubleshooting_options',
)
diff --git a/spec/features/users/sign_in_spec.rb b/spec/features/users/sign_in_spec.rb
index 797c7b32f34..3b8ae651141 100644
--- a/spec/features/users/sign_in_spec.rb
+++ b/spec/features/users/sign_in_spec.rb
@@ -218,7 +218,7 @@
scenario 'user can see and use password visibility toggle', js: true do
visit new_user_session_path
- check t('forms.passwords.show')
+ check t('components.password_toggle.toggle_label')
expect(page).to have_css('input.password[type="text"]')
end
diff --git a/spec/features/users/user_profile_spec.rb b/spec/features/users/user_profile_spec.rb
index c7d6ea1ebfa..1e598c120ed 100644
--- a/spec/features/users/user_profile_spec.rb
+++ b/spec/features/users/user_profile_spec.rb
@@ -121,7 +121,7 @@
fill_in t('forms.passwords.edit.labels.password'), with: 'this is a great sentence'
expect(page).to have_content 'Great'
- check t('forms.passwords.show')
+ check t('components.password_toggle.toggle_label')
expect(page).to_not have_css('input.password[type="password"]')
expect(page).to have_css('input.password[type="text"]')
diff --git a/spec/features/visitors/set_password_spec.rb b/spec/features/visitors/set_password_spec.rb
index fa5c5187129..9cffa3706a7 100644
--- a/spec/features/visitors/set_password_spec.rb
+++ b/spec/features/visitors/set_password_spec.rb
@@ -65,7 +65,7 @@
expect(page).to have_css('input.password[type="password"]')
- check t('forms.passwords.show')
+ check t('components.password_toggle.toggle_label')
expect(page).to_not have_css('input.password[type="password"]')
expect(page).to have_css('input.password[type="text"]')
diff --git a/spec/i18n_spec.rb b/spec/i18n_spec.rb
index 0de8b7024e4..a19f6c95957 100644
--- a/spec/i18n_spec.rb
+++ b/spec/i18n_spec.rb
@@ -16,8 +16,9 @@ class BaseTask
ALLOWED_UNTRANSLATED_KEYS = [
{ key: 'account.navigation.menu', locales: %i[fr] }, # "Menu" is "Menu" in French
{ key: 'doc_auth.headings.photo', locales: %i[fr] }, # "Photo" is "Photo" in French
- { key: 'errors.alt.error', locales: %i[es] }, # "Error" is "Error" in Spanish
{ key: 'components.status_page.icons.error', locales: %i[es] }, # "Error" is "Error" in Spanish
+ { key: 'components.status_page.icons.question', locales: %i[fr] }, # "Question" is "Question" in French
+ { key: 'errors.alt.error', locales: %i[es] }, # "Error" is "Error" in Spanish
{ key: /^i18n\.locale\./ }, # Show locale options translated as that language
{ key: /^countries/ }, # Some countries have the same name across languages
{ key: 'links.contact', locales: %i[fr] }, # "Contact" is "Contact" in French
diff --git a/spec/javascripts/packages/document-capture/components/form-error-message-spec.jsx b/spec/javascripts/packages/document-capture/components/form-error-message-spec.jsx
deleted file mode 100644
index b9ab3346bcd..00000000000
--- a/spec/javascripts/packages/document-capture/components/form-error-message-spec.jsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import { I18nContext } from '@18f/identity-react-i18n';
-import FormErrorMessage, {
- RequiredValueMissingError,
- CameraAccessDeclinedError,
-} from '@18f/identity-document-capture/components/form-error-message';
-import { UploadFormEntryError } from '@18f/identity-document-capture/services/upload';
-import { BackgroundEncryptedUploadError } from '@18f/identity-document-capture/higher-order/with-background-encrypted-upload';
-import { render } from '../../../support/document-capture';
-
-describe('document-capture/components/form-error-message', () => {
- it('returns formatted RequiredValueMissingError', () => {
- const { getByText } = render();
-
- expect(getByText('simple_form.required.text')).to.be.ok();
- });
-
- it('returns formatted UploadFormEntryError', () => {
- const { getByText } = render(
- ,
- );
-
- expect(getByText('Field is required')).to.be.ok();
- });
-
- it('returns formatted BackgroundEncryptedUploadError', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- const message = getByText('Sorry, something went wrong on our end. Please try again.');
- expect(message).to.be.ok();
- expect(message.innerHTML.split(' ')).to.deep.equal([
- 'Sorry, something went wrong on our end. Please',
- 'try',
- 'again.',
- ]);
- });
-
- it('returns formatted CameraAccessDeclinedError', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- expect(getByText('Your camera is blocked')).to.be.ok();
- });
-
- it('returns null if error is of an unknown type', () => {
- const { container } = render();
-
- expect(container.childNodes).to.be.empty();
- });
-
- describe('isDetail', () => {
- it('returns formatted CameraAccessDeclinedError', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- expect(getByText('We don’t have permission', { exact: false })).to.be.ok();
- });
- });
-});
diff --git a/spec/jobs/reports/total_ial2_costs_report_spec.rb b/spec/jobs/reports/total_ial2_costs_report_spec.rb
new file mode 100644
index 00000000000..751c32fc192
--- /dev/null
+++ b/spec/jobs/reports/total_ial2_costs_report_spec.rb
@@ -0,0 +1,81 @@
+require 'rails_helper'
+
+RSpec.describe Reports::TotalIal2CostsReport do
+ subject(:report) { described_class.new }
+
+ describe '#perform' do
+ let(:issuer1) { 'issuer1' }
+ let(:issuer2) { 'issuer2' }
+
+ let!(:sp1) { create(:service_provider, issuer: issuer1, friendly_name: issuer1) }
+ let!(:sp2) { create(:service_provider, issuer: issuer2, friendly_name: issuer2) }
+
+ let(:date) { Date.new(2022, 4, 1) }
+ let(:yesterday) { Date.new(2022, 3, 31) }
+ let(:yesterday_utc) { yesterday.in_time_zone('UTC') }
+ let(:too_old) { Date.new(2021, 12, 31) }
+
+ before do
+ SpCost.create(
+ agency_id: 1,
+ issuer: issuer1,
+ cost_type: 'authentication',
+ created_at: yesterday_utc,
+ ial: 2,
+ )
+ SpCost.create(
+ agency_id: 2,
+ issuer: issuer2,
+ cost_type: 'authentication',
+ created_at: yesterday_utc,
+ ial: 2,
+ )
+
+ SpCost.create(
+ agency_id: 1, issuer: issuer1, cost_type: 'sms', created_at: yesterday_utc, ial: 2,
+ )
+
+ # rows that get ignored
+ SpCost.create(
+ agency_id: 2, issuer: issuer2, cost_type: 'user_added', created_at: too_old, ial: 2,
+ )
+ SpCost.create(
+ agency_id: 2, issuer: issuer2, cost_type: 'user_added', created_at: yesterday_utc, ial: 1,
+ )
+ end
+
+ it 'writes a CSV report to S3' do
+ expect(report).to receive(:save_report) do |report_name, body, extension:|
+ expect(report_name).to eq(described_class::REPORT_NAME)
+ expect(extension).to eq('csv')
+
+ csv = CSV.parse(body, headers: true)
+ expect(csv.length).to eq(2)
+
+ row = csv.first
+ expect(row['date']).to eq(yesterday.to_s)
+ expect(row['cost_type']).to eq('authentication')
+ expect(row['ial']).to eq(2.to_s)
+ expect(row['count']).to eq(2.to_s)
+
+ row = csv[1]
+ expect(row['date']).to eq(yesterday.to_s)
+ expect(row['cost_type']).to eq('sms')
+ expect(row['ial']).to eq(2.to_s)
+ expect(row['count']).to eq(1.to_s)
+ end
+
+ report.perform(date)
+ end
+ end
+
+ describe '#good_job_concurrency_key' do
+ let(:date) { Time.zone.today }
+
+ it 'is the job name and the date' do
+ job = described_class.new(date)
+ expect(job.good_job_concurrency_key).
+ to eq("#{described_class::REPORT_NAME}-#{date}")
+ end
+ end
+end
diff --git a/spec/services/db/sp_return_log_spec.rb b/spec/services/db/sp_return_log_spec.rb
index 7d730dfbae6..610b26e457b 100644
--- a/spec/services/db/sp_return_log_spec.rb
+++ b/spec/services/db/sp_return_log_spec.rb
@@ -2,8 +2,7 @@
describe Db::SpReturnLog do
describe '#create_return' do
- # Can be removed after deploy of RC 185
- it 'updates return log if it already exists' do
+ it 'does not fail if row already exists' do
sp_return_log = SpReturnLog.create(
request_id: SecureRandom.uuid,
user_id: 1,
@@ -12,6 +11,7 @@
issuer: 'example.com',
requested_at: Time.zone.now,
)
+
Db::SpReturnLog.create_return(
request_id: sp_return_log.request_id,
user_id: sp_return_log.user_id,
@@ -20,7 +20,8 @@
issuer: sp_return_log.issuer,
requested_at: sp_return_log.requested_at,
)
- expect(sp_return_log.reload.returned_at).to_not be_nil
+
+ expect(SpReturnLog.count).to eq 1
end
end
end
diff --git a/tsconfig.json b/tsconfig.json
index ec4f01ebef0..13ddedd227d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -7,6 +7,7 @@
"strictNullChecks": true,
"jsx": "react-jsx",
"esModuleInterop": true,
+ "experimentalDecorators": true,
"moduleResolution": "node",
"module": "ESNext",
"target": "ESNext",
diff --git a/yarn.lock b/yarn.lock
index 306533df381..bf159f2e42e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -82,6 +82,19 @@
"@babel/helper-replace-supers" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
+"@babel/helper-create-class-features-plugin@^7.17.1":
+ version "7.17.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9"
+ integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-function-name" "^7.16.7"
+ "@babel/helper-member-expression-to-functions" "^7.16.7"
+ "@babel/helper-optimise-call-expression" "^7.16.7"
+ "@babel/helper-replace-supers" "^7.16.7"
+ "@babel/helper-split-export-declaration" "^7.16.7"
+
"@babel/helper-create-regexp-features-plugin@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4"
@@ -314,6 +327,17 @@
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-syntax-class-static-block" "^7.14.5"
+"@babel/plugin-proposal-decorators@^7.17.2":
+ version "7.17.2"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz#c36372ddfe0360cac1ee331a238310bddca11493"
+ integrity sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.17.1"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-replace-supers" "^7.16.7"
+ "@babel/plugin-syntax-decorators" "^7.17.0"
+ charcodes "^0.2.0"
+
"@babel/plugin-proposal-dynamic-import@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c"
@@ -437,6 +461,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"
+"@babel/plugin-syntax-decorators@^7.17.0":
+ version "7.17.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz#a2be3b2c9fe7d78bd4994e790896bc411e2f166d"
+ integrity sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
"@babel/plugin-syntax-dynamic-import@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
@@ -1394,7 +1425,15 @@
"@types/mime" "^1"
"@types/node" "*"
-"@types/sinon@^10.0.11":
+"@types/sinon-chai@^3.2.8":
+ version "3.2.8"
+ resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.8.tgz#5871d09ab50d671d8e6dd72e9073f8e738ac61dc"
+ integrity sha512-d4ImIQbT/rKMG8+AXpmcan5T2/PNeSjrYhvkwet6z0p8kzYtfgA32xzOBlbU0yqJfq+/0Ml805iFoODO0LP5/g==
+ dependencies:
+ "@types/chai" "*"
+ "@types/sinon" "*"
+
+"@types/sinon@*", "@types/sinon@^10.0.11":
version "10.0.11"
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.11.tgz#8245827b05d3fc57a6601bd35aee1f7ad330fc42"
integrity sha512-dmZsHlBsKUtBpHriNjlK0ndlvEh8dcb9uV9Afsbt89QIyydpC7NcR+nWlAhASfy3GHnxTl4FX/aKE7XZUt/B4g==
@@ -2198,6 +2237,11 @@ chalk@^4.0, chalk@^4.0.0, chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
+charcodes@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/charcodes/-/charcodes-0.2.0.tgz#5208d327e6cc05f99eb80ffc814707572d1f14e4"
+ integrity sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==
+
check-error@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"