diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4127d4c0..a1202972 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,12 +13,15 @@ jobs: runs-on: ubuntu-latest strategy: max-parallel: 12 + fail-fast: false matrix: php: ['7.4', '8.0', '8.1', '8.2'] package-release: [dist] steps: - name: Checkout repository uses: actions/checkout@v3 + with: + fetch-depth: 2 - name: Setup PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 @@ -28,7 +31,7 @@ jobs: - name: Get user-level Composer cache id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Setup Composer cache uses: actions/cache@v3 @@ -50,5 +53,5 @@ jobs: - name: Upload to Scrutinizer continue-on-error: true run: | - wget https://scrutinizer-ci.com/ocular.phar - php ocular.phar code-coverage:upload --format=php-clover coverage.clover + composer global require scrutinizer/ocular + ~/.composer/vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover diff --git a/.gitignore b/.gitignore index 4fb34c2a..37dc081e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,7 @@ composer.lock coverage *.taskpaper NOTES.md -.phpunit.result.cache +/.phpunit.result.cache +/.phpunit.cache/ +/phpunit.xml.bak +/coverage.clover diff --git a/composer.json b/composer.json index 8ce7ce6c..80d14d8e 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "illuminate/validation": "^6 || ^7 || ^8 || ^9 || ^10" }, "require-dev": { - "orchestra/testbench": "^6.13 || ^7.0" + "orchestra/testbench": "^6.13 || ^7.0 || ^8" }, "extra": { "branch-alias": { @@ -35,13 +35,15 @@ "psr-0": { "Kris\\LaravelFormBuilder": "src/" }, - "classmap": [ - "tests/FormBuilderTestCase.php" - ], "files": [ "src/helpers.php" ] }, + "autoload-dev": { + "classmap": [ + "tests/" + ] + }, "minimum-stability": "dev", "prefer-stable": true } diff --git a/phpunit.xml b/phpunit.xml index a631ba06..0545ef35 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,20 +1,22 @@ - + ./tests/ ./tests/resources/views/ + ./tests/resources/lang/ + ./tests/Fixtures/ + ./tests/FormBuilderTestCase.php diff --git a/tests/Fields/ButtonGroupTypeTest.php b/tests/Fields/ButtonGroupTypeTest.php index f01f2abc..b18cbaeb 100644 --- a/tests/Fields/ButtonGroupTypeTest.php +++ b/tests/Fields/ButtonGroupTypeTest.php @@ -104,4 +104,4 @@ public function it_handles_buttons(): void $this->assertSame($buttons, $buttongroup->getOption('buttons')); } -} \ No newline at end of file +} diff --git a/tests/Fields/CheckableTypeTest.php b/tests/Fields/CheckableTypeTest.php index da1d9a73..3a54156d 100644 --- a/tests/Fields/CheckableTypeTest.php +++ b/tests/Fields/CheckableTypeTest.php @@ -108,4 +108,4 @@ public function it_handles_checked(): void $this->assertTrue($checkable->getValue()); $this->assertTrue($checkable->getOption('checked')); } -} \ No newline at end of file +} diff --git a/tests/Fields/FormFieldTest.php b/tests/Fields/FormFieldTest.php index bbfc8da4..4a039cb0 100644 --- a/tests/Fields/FormFieldTest.php +++ b/tests/Fields/FormFieldTest.php @@ -21,9 +21,7 @@ public function it_use_set_rendered() /** @test */ public function it_uses_the_template_prefix() { - $viewStub = $this->getMockBuilder('Illuminate\View\Factory')->setMethods(['make', 'with', 'render'])->disableOriginalConstructor()->getMock(); - $viewStub->method('make')->willReturn($viewStub); - $viewStub->method('with')->willReturn($viewStub); + $viewStub = $this->getViewFactoryMock(); $helper = new FormHelper($viewStub, $this->translator, $this->config); @@ -212,7 +210,7 @@ public function it_translates_the_label_if_translation_exists() $this->plainForm->setLanguageName('validation')->add('accepted', 'text'); $this->assertEquals( - 'The :attribute must be accepted.', + 'The :attribute field must be accepted.', $this->plainForm->accepted->getOption('label') ); } @@ -225,7 +223,7 @@ public function it_translates_the_label_using_translation_templates() $this->plainForm->setTranslationTemplate('validation.{name}')->add('accepted', 'text'); $this->assertEquals( - 'The :attribute must be accepted.', + 'The :attribute field must be accepted.', $this->plainForm->accepted->getOption('label') ); } @@ -479,7 +477,7 @@ public function label_template() 'options' => [ 'label' => 'Text Field #1', 'label_show' => true, - 'label_template' => 'laravel-form-builder-test::test-label', + 'label_template' => 'laravel-form-builder-test::test-label', ] ], [ @@ -488,10 +486,10 @@ public function label_template() 'options' => [ 'label' => 'Textarea Field #1', 'label_show' => true, - 'label_template' => 'laravel-form-builder-test::test-label', + 'label_template' => 'laravel-form-builder-test::test-label', ] ], - + ]; foreach ($fieldsOptions as $config) { diff --git a/tests/Fields/RepeatedTypeTest.php b/tests/Fields/RepeatedTypeTest.php index d96b5f25..e1a2b805 100644 --- a/tests/Fields/RepeatedTypeTest.php +++ b/tests/Fields/RepeatedTypeTest.php @@ -1,9 +1,7 @@ assertFalse($valid); $errors = [ - 'password' => ['The Password and password confirmation must match.'], + 'password' => [ + 'The Password field must match password confirmation.', + ], ]; $this->assertEquals($errors, $plainForm->getErrors()); @@ -65,7 +65,7 @@ public function handles_validation_rules_properly() 'rules' => 'required|min:5', ]); $plainForm->renderForm(); - + $rules = ['password' => ['required', 'min:5', 'same:password_confirmation']]; $this->assertEquals($rules, $plainForm->getRules()); @@ -74,8 +74,8 @@ public function handles_validation_rules_properly() $errors = [ 'password' => [ - 'The Password must be at least 5 characters.', - 'The Password and password confirmation must match.', + 'The Password field must be at least 5 characters.', + 'The Password field must match password confirmation.', ] ]; $this->assertEquals($errors, $plainForm->getErrors()); @@ -95,9 +95,9 @@ public function handles_validation_rules_properly() $errors = [ 'password' => [ - 'The Password must be at least 5 characters.', - 'The Password and password confirmation must match.', - ] + 'The Password field must be at least 5 characters.', + 'The Password field must match password confirmation.', + ] ]; $this->assertEquals($errors, $plainForm->getErrors()); @@ -117,9 +117,9 @@ public function handles_validation_rules_properly() $errors = [ 'password' => [ - 'The Password must be at least 5 characters.', - 'The Password and password confirmation must match.', - ] + 'The Password field must be at least 5 characters.', + 'The Password field must match password confirmation.', + ] ]; $this->assertEquals($errors, $plainForm->getErrors()); } diff --git a/tests/FormBuilderTestCase.php b/tests/FormBuilderTestCase.php index f4a4f7ae..84f27d5c 100644 --- a/tests/FormBuilderTestCase.php +++ b/tests/FormBuilderTestCase.php @@ -186,6 +186,9 @@ public function setUp(): void parent::setUp(); $this->withoutDeprecationHandling(); + + $this->app['path.lang'] = __DIR__ . '/resources/lang'; + // add views for testing $this->app['view']->addNamespace('laravel-form-builder-test', __DIR__ . '/resources/views'); @@ -267,4 +270,16 @@ protected function assertIdentical($one, $two): void { self::assertThat($one, new IsIdentical($two)); } + + protected function getViewFactoryMock() + { + $mock = $this->getMockBuilder('Illuminate\View\Factory') + ->onlyMethods(['make']) + ->addMethods(['with', 'render']) + ->disableOriginalConstructor() + ->getMock(); + $mock->method('make')->willReturn($mock); + $mock->method('with')->willReturn($mock); + return $mock; + } } diff --git a/tests/FormTest.php b/tests/FormTest.php index f51fd5c6..7a488e08 100644 --- a/tests/FormTest.php +++ b/tests/FormTest.php @@ -91,7 +91,7 @@ public function it_fails_validation() $errors = [ 'name' => ['The Name field is required.'], - 'description' => ['The Description must not be greater than 10 characters.'] + 'description' => ['The Description field must not be greater than 10 characters.'] ]; $this->assertEquals($errors, $this->plainForm->getErrors()); @@ -153,7 +153,7 @@ public function it_can_automatically_redirect_back_when_failing_verification() $errorBag = $response->getSession()->get('errors'); $this->assertTrue($errorBag->has('description')); $this->assertTrue($errorBag->has('name')); - $this->assertEquals('The Description must not be greater than 10 characters.', $errorBag->first('description')); + $this->assertEquals('The Description field must not be greater than 10 characters.', $errorBag->first('description')); } } @@ -191,7 +191,7 @@ public function it_can_automatically_redirect_to_a_specified_destination_when_fa $errorBag = $response->getSession()->get('errors'); $this->assertTrue($errorBag->has('description')); $this->assertTrue($errorBag->has('name')); - $this->assertEquals('The Description must not be greater than 10 characters.', $errorBag->first('description')); + $this->assertEquals('The Description field must not be greater than 10 characters.', $errorBag->first('description')); } } @@ -233,7 +233,7 @@ public function it_overrides_default_rules_and_messages() $errors = [ 'name' => ['Name field must be numeric.'], - 'description' => ['The Description must not be greater than 10 characters.'], + 'description' => ['The Description field must not be greater than 10 characters.'], 'age' => ['The age field is a must.'], 'email' => ['The email is very required.'] ]; @@ -1109,9 +1109,7 @@ public function it_stores_a_template_prefix() /** @test */ public function it_uses_the_template_prefix() { - $viewStub = $this->getMockBuilder('Illuminate\View\Factory')->setMethods(['make', 'with', 'render'])->disableOriginalConstructor()->getMock(); - $viewStub->method('make')->willReturn($viewStub); - $viewStub->method('with')->willReturn($viewStub); + $viewStub = $this->getViewFactoryMock(); $helper = new FormHelper($viewStub, $this->translator, $this->config); diff --git a/tests/resources/lang/en/validation.php b/tests/resources/lang/en/validation.php new file mode 100644 index 00000000..99f7c611 --- /dev/null +++ b/tests/resources/lang/en/validation.php @@ -0,0 +1,184 @@ + 'The :attribute field must be accepted.', + 'accepted_if' => 'The :attribute field must be accepted when :other is :value.', + 'active_url' => 'The :attribute field must be a valid URL.', + 'after' => 'The :attribute field must be a date after :date.', + 'after_or_equal' => 'The :attribute field must be a date after or equal to :date.', + 'alpha' => 'The :attribute field must only contain letters.', + 'alpha_dash' => 'The :attribute field must only contain letters, numbers, dashes, and underscores.', + 'alpha_num' => 'The :attribute field must only contain letters and numbers.', + 'array' => 'The :attribute field must be an array.', + 'ascii' => 'The :attribute field must only contain single-byte alphanumeric characters and symbols.', + 'before' => 'The :attribute field must be a date before :date.', + 'before_or_equal' => 'The :attribute field must be a date before or equal to :date.', + 'between' => [ + 'array' => 'The :attribute field must have between :min and :max items.', + 'file' => 'The :attribute field must be between :min and :max kilobytes.', + 'numeric' => 'The :attribute field must be between :min and :max.', + 'string' => 'The :attribute field must be between :min and :max characters.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute field confirmation does not match.', + 'current_password' => 'The password is incorrect.', + 'date' => 'The :attribute field must be a valid date.', + 'date_equals' => 'The :attribute field must be a date equal to :date.', + 'date_format' => 'The :attribute field must match the format :format.', + 'decimal' => 'The :attribute field must have :decimal decimal places.', + 'declined' => 'The :attribute field must be declined.', + 'declined_if' => 'The :attribute field must be declined when :other is :value.', + 'different' => 'The :attribute field and :other must be different.', + 'digits' => 'The :attribute field must be :digits digits.', + 'digits_between' => 'The :attribute field must be between :min and :max digits.', + 'dimensions' => 'The :attribute field has invalid image dimensions.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'doesnt_end_with' => 'The :attribute field must not end with one of the following: :values.', + 'doesnt_start_with' => 'The :attribute field must not start with one of the following: :values.', + 'email' => 'The :attribute field must be a valid email address.', + 'ends_with' => 'The :attribute field must end with one of the following: :values.', + 'enum' => 'The selected :attribute is invalid.', + 'exists' => 'The selected :attribute is invalid.', + 'file' => 'The :attribute field must be a file.', + 'filled' => 'The :attribute field must have a value.', + 'gt' => [ + 'array' => 'The :attribute field must have more than :value items.', + 'file' => 'The :attribute field must be greater than :value kilobytes.', + 'numeric' => 'The :attribute field must be greater than :value.', + 'string' => 'The :attribute field must be greater than :value characters.', + ], + 'gte' => [ + 'array' => 'The :attribute field must have :value items or more.', + 'file' => 'The :attribute field must be greater than or equal to :value kilobytes.', + 'numeric' => 'The :attribute field must be greater than or equal to :value.', + 'string' => 'The :attribute field must be greater than or equal to :value characters.', + ], + 'image' => 'The :attribute field must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field must exist in :other.', + 'integer' => 'The :attribute field must be an integer.', + 'ip' => 'The :attribute field must be a valid IP address.', + 'ipv4' => 'The :attribute field must be a valid IPv4 address.', + 'ipv6' => 'The :attribute field must be a valid IPv6 address.', + 'json' => 'The :attribute field must be a valid JSON string.', + 'lowercase' => 'The :attribute field must be lowercase.', + 'lt' => [ + 'array' => 'The :attribute field must have less than :value items.', + 'file' => 'The :attribute field must be less than :value kilobytes.', + 'numeric' => 'The :attribute field must be less than :value.', + 'string' => 'The :attribute field must be less than :value characters.', + ], + 'lte' => [ + 'array' => 'The :attribute field must not have more than :value items.', + 'file' => 'The :attribute field must be less than or equal to :value kilobytes.', + 'numeric' => 'The :attribute field must be less than or equal to :value.', + 'string' => 'The :attribute field must be less than or equal to :value characters.', + ], + 'mac_address' => 'The :attribute field must be a valid MAC address.', + 'max' => [ + 'array' => 'The :attribute field must not have more than :max items.', + 'file' => 'The :attribute field must not be greater than :max kilobytes.', + 'numeric' => 'The :attribute field must not be greater than :max.', + 'string' => 'The :attribute field must not be greater than :max characters.', + ], + 'max_digits' => 'The :attribute field must not have more than :max digits.', + 'mimes' => 'The :attribute field must be a file of type: :values.', + 'mimetypes' => 'The :attribute field must be a file of type: :values.', + 'min' => [ + 'array' => 'The :attribute field must have at least :min items.', + 'file' => 'The :attribute field must be at least :min kilobytes.', + 'numeric' => 'The :attribute field must be at least :min.', + 'string' => 'The :attribute field must be at least :min characters.', + ], + 'min_digits' => 'The :attribute field must have at least :min digits.', + 'missing' => 'The :attribute field must be missing.', + 'missing_if' => 'The :attribute field must be missing when :other is :value.', + 'missing_unless' => 'The :attribute field must be missing unless :other is :value.', + 'missing_with' => 'The :attribute field must be missing when :values is present.', + 'missing_with_all' => 'The :attribute field must be missing when :values are present.', + 'multiple_of' => 'The :attribute field must be a multiple of :value.', + 'not_in' => 'The selected :attribute is invalid.', + 'not_regex' => 'The :attribute field format is invalid.', + 'numeric' => 'The :attribute field must be a number.', + 'password' => [ + 'letters' => 'The :attribute field must contain at least one letter.', + 'mixed' => 'The :attribute field must contain at least one uppercase and one lowercase letter.', + 'numbers' => 'The :attribute field must contain at least one number.', + 'symbols' => 'The :attribute field must contain at least one symbol.', + 'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.', + ], + 'present' => 'The :attribute field must be present.', + 'prohibited' => 'The :attribute field is prohibited.', + 'prohibited_if' => 'The :attribute field is prohibited when :other is :value.', + 'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.', + 'prohibits' => 'The :attribute field prohibits :other from being present.', + 'regex' => 'The :attribute field format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_array_keys' => 'The :attribute field must contain entries for: :values.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_if_accepted' => 'The :attribute field is required when :other is accepted.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values are present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute field must match :other.', + 'size' => [ + 'array' => 'The :attribute field must contain :size items.', + 'file' => 'The :attribute field must be :size kilobytes.', + 'numeric' => 'The :attribute field must be :size.', + 'string' => 'The :attribute field must be :size characters.', + ], + 'starts_with' => 'The :attribute field must start with one of the following: :values.', + 'string' => 'The :attribute field must be a string.', + 'timezone' => 'The :attribute field must be a valid timezone.', + 'unique' => 'The :attribute has already been taken.', + 'uploaded' => 'The :attribute failed to upload.', + 'uppercase' => 'The :attribute field must be uppercase.', + 'url' => 'The :attribute field must be a valid URL.', + 'ulid' => 'The :attribute field must be a valid ULID.', + 'uuid' => 'The :attribute field must be a valid UUID.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap our attribute placeholder + | with something more reader friendly such as "E-Mail Address" instead + | of "email". This simply helps us make our message more expressive. + | + */ + + 'attributes' => [], + +];