setMinLength(0) ->setTestNames([]); } public function testSetValue() { $field = new ConfirmedPasswordField('Test', 'Testing', 'valueA'); $this->assertEquals('valueA', $field->Value()); $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_Password]')->Value()); $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value()); $field->setValue('valueB'); $this->assertEquals('valueB', $field->Value()); $this->assertEquals('valueB', $field->children->fieldByName($field->getName() . '[_Password]')->Value()); $this->assertEquals('valueB', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value()); } /** * @useDatabase true */ public function testHashHidden() { $field = new ConfirmedPasswordField('Password', 'Password', 'valueA'); $field->setCanBeEmpty(true); $this->assertEquals('valueA', $field->Value()); $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_Password]')->Value()); $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value()); $member = new Member(); $member->Password = "valueB"; $member->write(); /** @skipUpgrade */ $form = new Form(Controller::curr(), 'Form', new FieldList($field), new FieldList()); $form->loadDataFrom($member); $this->assertEquals('', $field->Value()); $this->assertEquals('', $field->children->fieldByName($field->getName() . '[_Password]')->Value()); $this->assertEquals('', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value()); } public function testSetShowOnClick() { //hide by default and display show/hide toggle button $field = new ConfirmedPasswordField('Test', 'Testing', 'valueA', null, true); $fieldHTML = $field->Field(); $this->assertStringContainsString( "showOnClickContainer", $fieldHTML, "Test class for hiding/showing the form contents is set" ); $this->assertStringContainsString( "showOnClick", $fieldHTML, "Test class for hiding/showing the form contents is set" ); //show all by default $field = new ConfirmedPasswordField('Test', 'Testing', 'valueA', null, false); $fieldHTML = $field->Field(); $this->assertStringNotContainsString( "showOnClickContainer", $fieldHTML, "Test class for hiding/showing the form contents is set" ); $this->assertStringNotContainsString( "showOnClick", $fieldHTML, "Test class for hiding/showing the form contents is set" ); } public function testValidation() { $field = new ConfirmedPasswordField( 'Test', 'Testing', [ '_Password' => 'abc123', '_ConfirmPassword' => 'abc123', ] ); $validator = new RequiredFields(); $this->assertTrue( $field->validate($validator), 'Validates when both passwords are the same' ); $field->setName('TestNew'); //try changing name of field $this->assertTrue( $field->validate($validator), 'Validates when field name is changed' ); //non-matching password should make the field invalid $field->setValue([ '_Password' => 'abc123', '_ConfirmPassword' => '123abc', ]); $this->assertFalse( $field->validate($validator), 'Does not validate when passwords differ' ); // Empty passwords should make the field invalid $field->setCanBeEmpty(false); $field->setValue([ '_Password' => '', '_ConfirmPassword' => '', ]); $this->assertFalse( $field->validate($validator), 'Empty passwords should not be allowed when canBeEmpty is false' ); } public function testFormValidation() { /** @skipUpgrade */ $form = new Form( Controller::curr(), 'Form', new FieldList($field = new ConfirmedPasswordField('Password')), new FieldList() ); $form->loadDataFrom([ 'Password' => [ '_Password' => '123', '_ConfirmPassword' => '', ], ]); $this->assertEquals('123', $field->children->first()->Value()); $this->assertEmpty($field->children->last()->Value()); $this->assertNotEquals($field->children->first()->Value(), $field->children->last()->Value()); $form->loadDataFrom([ 'Password' => [ '_Password' => '123', '_ConfirmPassword' => 'abc', ], ]); $this->assertEquals('123', $field->children->first()->Value()); $this->assertEquals('abc', $field->children->last()->Value()); $this->assertNotEquals($field->children->first()->Value(), $field->children->last()->Value()); $form->loadDataFrom([ 'Password' => [ '_Password' => '', '_ConfirmPassword' => 'abc', ], ]); $this->assertEmpty($field->children->first()->Value()); $this->assertEquals('abc', $field->children->last()->Value()); $this->assertNotEquals($field->children->first()->Value(), $field->children->last()->Value()); } /** * @param int|null $minLength * @param int|null $maxLength * @param bool $expectValid * @param string $expectedMessage * @dataProvider lengthValidationProvider */ public function testLengthValidation($minLength, $maxLength, $expectValid, $expectedMessage = '') { $field = new ConfirmedPasswordField('Test', 'Testing', [ '_Password' => 'abc123', '_ConfirmPassword' => 'abc123', ]); $field->setMinLength($minLength)->setMaxLength($maxLength); $validator = new RequiredFields(); $result = $field->validate($validator); $this->assertSame($expectValid, $result, 'Validate method should return its result'); $this->assertSame($expectValid, $validator->getResult()->isValid()); if ($expectedMessage) { $this->assertStringContainsString($expectedMessage, $validator->getResult()->serialize()); } } /** * @return array[] */ public function lengthValidationProvider() { return [ 'valid: within min and max' => [3, 8, true], 'invalid: lower than min with max' => [8, 12, false, 'Passwords must be 8 to 12 characters long'], 'valid: greater than min' => [3, null, true], 'invalid: lower than min' => [8, null, false, 'Passwords must be at least 8 characters long'], 'valid: less than max' => [null, 8, true], 'invalid: greater than max' => [null, 4, false, 'Passwords must be at most 4 characters long'], ]; } public function testStrengthValidation() { $field = new ConfirmedPasswordField('Test', 'Testing', [ '_Password' => 'abc', '_ConfirmPassword' => 'abc', ]); $field->setRequireStrongPassword(true); $validator = new RequiredFields(); $result = $field->validate($validator); $this->assertFalse($result, 'Validate method should return its result'); $this->assertFalse($validator->getResult()->isValid()); $this->assertStringContainsString( 'Passwords must have at least one digit and one alphanumeric character', $validator->getResult()->serialize() ); } public function testCurrentPasswordValidation() { $field = new ConfirmedPasswordField('Test', 'Testing', [ '_Password' => 'abc', '_ConfirmPassword' => 'abc', ]); $field->setRequireExistingPassword(true); $validator = new RequiredFields(); $result = $field->validate($validator); $this->assertFalse($result, 'Validate method should return its result'); $this->assertFalse($validator->getResult()->isValid()); $this->assertStringContainsString( 'You must enter your current password', $validator->getResult()->serialize() ); } public function testMustBeLoggedInToChangePassword() { $field = new ConfirmedPasswordField('Test', 'Testing'); $field->setRequireExistingPassword(true); $field->setValue([ '_CurrentPassword' => 'foo', '_Password' => 'abc', '_ConfirmPassword' => 'abc', ]); $validator = new RequiredFields(); $this->logOut(); $result = $field->validate($validator); $this->assertFalse($result, 'Validate method should return its result'); $this->assertFalse($validator->getResult()->isValid()); $this->assertStringContainsString( 'You must be logged in to change your password', $validator->getResult()->serialize() ); } /** * @useDatabase true */ public function testValidateCorrectPassword() { $this->logInWithPermission('ADMIN'); $field = new ConfirmedPasswordField('Test', 'Testing'); $field->setRequireExistingPassword(true); $field->setValue([ '_CurrentPassword' => 'foo-not-going-to-be-the-correct-password', '_Password' => 'abc', '_ConfirmPassword' => 'abc', ]); $validator = new RequiredFields(); $result = $field->validate($validator); $this->assertFalse($result, 'Validate method should return its result'); $this->assertFalse($validator->getResult()->isValid()); $this->assertStringContainsString( 'The current password you have entered is not correct', $validator->getResult()->serialize() ); } public function testTitle() { $this->assertNull(ConfirmedPasswordField::create('Test')->Title(), 'Should not have it\'s own title'); } public function testSetTitlePropagatesToPasswordField() { /** @var ConfirmedPasswordField $field */ $field = ConfirmedPasswordField::create('Test') ->setTitle('My password'); $this->assertSame('My password', $field->getPasswordField()->Title()); } public function testSetRightTitlePropagatesToChildren() { $field = new ConfirmedPasswordField('Test'); $this->assertCount(2, $field->getChildren()); foreach ($field->getChildren() as $child) { $this->assertEmpty($child->RightTitle()); } $field->setRightTitle('Please confirm'); foreach ($field->getChildren() as $child) { $this->assertSame('Please confirm', $child->RightTitle()); } } public function testSetChildrenTitles() { $field = new ConfirmedPasswordField('Test'); $field->setRequireExistingPassword(true); $field->setChildrenTitles([ 'Current Password', 'Password', 'Confirm Password', ]); $this->assertSame('Current Password', $field->getChildren()->shift()->Title()); $this->assertSame('Password', $field->getChildren()->shift()->Title()); $this->assertSame('Confirm Password', $field->getChildren()->shift()->Title()); } public function testPerformReadonlyTransformation() { $field = new ConfirmedPasswordField('Test', 'Change it'); $result = $field->performReadonlyTransformation(); $this->assertInstanceOf(ReadonlyField::class, $result); $this->assertSame('Change it', $result->Title()); $this->assertStringContainsString('***', $result->Value()); } public function testPerformDisabledTransformation() { $field = new ConfirmedPasswordField('Test', 'Change it'); $result = $field->performDisabledTransformation(); $this->assertInstanceOf(ReadonlyField::class, $result); } public function testSetRequireExistingPasswordOnlyRunsOnce() { $field = new ConfirmedPasswordField('Test', 'Change it'); $this->assertCount(2, $field->getChildren()); $field->setRequireExistingPassword(true); $this->assertCount(3, $field->getChildren(), 'Current password field was not pushed'); $field->setRequireExistingPassword(true); $this->assertCount(3, $field->getChildren(), 'Current password field should not be pushed again'); $field->setRequireExistingPassword(false); $this->assertCount(2, $field->getChildren(), 'Current password field should not be removed'); } }