@@ -430,6 +430,7 @@ describe('Form re-categorizes inputs', () => {
430
430
const deviceInterface = InterfacePrototype . default ( ) ;
431
431
deviceInterface . settings . setFeatureToggles ( {
432
432
unknown_username_categorization : true ,
433
+ password_variant_categorization : true ,
433
434
} ) ;
434
435
describe ( 'Should recategorize' , ( ) => {
435
436
test ( 'when form has unknown input and has username data available' , ( ) => {
@@ -735,3 +736,114 @@ describe('site specific fixes', () => {
735
736
} ) ;
736
737
} ) ;
737
738
} ) ;
739
+
740
+ describe ( 'Password variant recategorization' , ( ) => {
741
+ test ( 'recategorizes first password field to current-password when there are 3 new-password fields' , ( ) => {
742
+ attachAndReturnGenericForm ( `
743
+ <form>
744
+ <input id="old-password" type="password" value="oldPassword" />
745
+ <input id="new-password" type="password" value="newPassword" autocomplete="new-password" />
746
+ <input id="confirm-password" type="password" value="confirmPassword" autocomplete="new-password" />
747
+ <button type="submit">Change Password</button>
748
+ </form>` ) ;
749
+
750
+ // Create a device interface with password_variant_categorization enabled
751
+ const deviceInterface = InterfacePrototype . default ( ) ;
752
+ deviceInterface . settings . setFeatureToggles ( {
753
+ password_variant_categorization : true ,
754
+ } ) ;
755
+
756
+ createScanner ( deviceInterface ) . findEligibleInputs ( document ) ;
757
+
758
+ // Query password inputs by their IDs
759
+ const oldPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'old-password' ) ) ;
760
+ const newPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'new-password' ) ) ;
761
+ const confirmPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'confirm-password' ) ) ;
762
+
763
+ // The first password field should be recategorized to current-password
764
+ expect ( oldPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.current' ) ;
765
+ // The other password fields should remain as new-password
766
+ expect ( newPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
767
+ expect ( confirmPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
768
+ } ) ;
769
+
770
+ test ( 'does not recategorize when there are less than 3 new-password fields' , ( ) => {
771
+ attachAndReturnGenericForm ( `
772
+ <form>
773
+ <input id="new-password" type="password" value="newPassword" autocomplete="new-password" />
774
+ <input id="confirm-password" type="password" value="confirmPassword" autocomplete="new-password" />
775
+ <button type="submit">Create Account</button>
776
+ </form>` ) ;
777
+
778
+ const deviceInterface = InterfacePrototype . default ( ) ;
779
+ deviceInterface . settings . setFeatureToggles ( {
780
+ password_variant_categorization : true ,
781
+ } ) ;
782
+
783
+ createScanner ( deviceInterface ) . findEligibleInputs ( document ) ;
784
+
785
+ // Query password inputs by their IDs
786
+ const newPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'new-password' ) ) ;
787
+ const confirmPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'confirm-password' ) ) ;
788
+
789
+ // Both password fields should remain as new-password
790
+ expect ( newPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
791
+ expect ( confirmPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
792
+ } ) ;
793
+
794
+ test ( 'does not recategorize when there is already a current-password field' , ( ) => {
795
+ attachAndReturnGenericForm ( `
796
+ <form>
797
+ <input id="current-password" type="password" value="oldPassword" autocomplete="current-password" />
798
+ <input id="new-password" type="password" value="newPassword" autocomplete="new-password" />
799
+ <input id="confirm-password" type="password" value="confirmPassword" autocomplete="new-password" />
800
+ <button type="submit">Change Password</button>
801
+ </form>` ) ;
802
+
803
+ const deviceInterface = InterfacePrototype . default ( ) ;
804
+ deviceInterface . settings . setFeatureToggles ( {
805
+ password_variant_categorization : true ,
806
+ } ) ;
807
+
808
+ createScanner ( deviceInterface ) . findEligibleInputs ( document ) ;
809
+
810
+ // Query password inputs by their IDs
811
+ const currentPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'current-password' ) ) ;
812
+ const newPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'new-password' ) ) ;
813
+ const confirmPasswordInput = /** @type {HTMLInputElement } */ ( document . getElementById ( 'confirm-password' ) ) ;
814
+
815
+ // The first password should remain as current-password
816
+ expect ( currentPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.current' ) ;
817
+ // The other password fields should remain as new-password
818
+ expect ( newPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
819
+ expect ( confirmPasswordInput . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
820
+ } ) ;
821
+
822
+ test ( 'does not recategorize when feature toggle is disabled' , ( ) => {
823
+ attachAndReturnGenericForm ( `
824
+ <form>
825
+ <input id="password1" type="password" value="oldPassword" autocomplete="new-password" />
826
+ <input id="password2" type="password" value="newPassword" autocomplete="new-password" />
827
+ <input id="password3" type="password" value="confirmPassword" autocomplete="new-password" />
828
+ <button type="submit">Change Password</button>
829
+ </form>` ) ;
830
+
831
+ // Create a device interface with password_variant_categorization disabled
832
+ const deviceInterface = InterfacePrototype . default ( ) ;
833
+ deviceInterface . settings . setFeatureToggles ( {
834
+ password_variant_categorization : false ,
835
+ } ) ;
836
+
837
+ createScanner ( deviceInterface ) . findEligibleInputs ( document ) ;
838
+
839
+ // Query password inputs by their IDs
840
+ const password1 = /** @type {HTMLInputElement } */ ( document . getElementById ( 'password1' ) ) ;
841
+ const password2 = /** @type {HTMLInputElement } */ ( document . getElementById ( 'password2' ) ) ;
842
+ const password3 = /** @type {HTMLInputElement } */ ( document . getElementById ( 'password3' ) ) ;
843
+
844
+ // All password fields should remain as new-password
845
+ expect ( password1 . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
846
+ expect ( password2 . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
847
+ expect ( password3 . getAttribute ( constants . ATTR_INPUT_TYPE ) ) . toBe ( 'credentials.password.new' ) ;
848
+ } ) ;
849
+ } ) ;
0 commit comments