diff --git a/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.spec.tsx b/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.spec.tsx
index 828de0d5291..67616a4a328 100644
--- a/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.spec.tsx
+++ b/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.spec.tsx
@@ -49,6 +49,17 @@ describe('PersonalKeyInput', () => {
expect(input.value).to.equal('1234-1234-1234-1234');
});
+ it('allows the user to paste the personal key from their clipboard', async () => {
+ const { getByRole } = render();
+
+ const input = getByRole('textbox') as HTMLInputElement;
+
+ input.focus();
+ await userEvent.paste('1234-1234-1234-1234');
+
+ expect(input.value).to.equal('1234-1234-1234-1234');
+ });
+
it('validates the input value against the expected value (case-insensitive, crockford)', async () => {
const { getByRole } = render();
diff --git a/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.tsx b/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.tsx
index 03d2a835c3f..21b7bde05a0 100644
--- a/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.tsx
+++ b/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-input.tsx
@@ -1,10 +1,18 @@
import { forwardRef, useCallback } from 'react';
import type { ForwardedRef } from 'react';
import Cleave from 'cleave.js/react';
+import type { ReactInstanceWithCleave } from 'cleave.js/react/props';
import { t } from '@18f/identity-i18n';
import { ValidatedField } from '@18f/identity-validated-field';
import type { ValidatedFieldValidator } from '@18f/identity-validated-field';
+/**
+ * Internal Cleave.js React instance API methods.
+ */
+interface CleaveInstanceInternalAPI {
+ updateValueState: () => void;
+}
+
interface PersonalKeyInputProps {
/**
* The correct personal key to validate against.
@@ -42,6 +50,9 @@ function PersonalKeyInput(
return (
{
+ (owner as ReactInstanceWithCleave & CleaveInstanceInternalAPI).updateValueState();
+ }}
options={{
blocks: [4, 4, 4, 4],
delimiter: '-',
diff --git a/spec/support/shared_examples_for_personal_keys.rb b/spec/support/shared_examples_for_personal_keys.rb
index 67c32ad0010..fbaa47105a5 100644
--- a/spec/support/shared_examples_for_personal_keys.rb
+++ b/spec/support/shared_examples_for_personal_keys.rb
@@ -1,3 +1,5 @@
+require 'rbconfig'
+
shared_examples_for 'personal key page' do
include PersonalKeyHelper
include JavascriptDriverHelper
@@ -36,6 +38,14 @@
copied_text = page.evaluate_async_script('navigator.clipboard.readText().then(arguments[0])')
expect(copied_text).to eq(scrape_personal_key)
+
+ click_continue
+ mod = mac? ? :meta : :control
+ page.find(':focus').send_keys [mod, 'v']
+
+ path_before_submit = current_path
+ within('[role=dialog]') { click_on t('forms.buttons.continue') }
+ expect(current_path).not_to eq path_before_submit
end
it 'validates as case-insensitive, crockford-normalized, length-limited, dash-flexible' do
@@ -61,4 +71,8 @@
expect(current_path).not_to eq path_before_submit
end
end
+
+ def mac?
+ RbConfig::CONFIG['host_os'].match? 'darwin'
+ end
end