diff --git a/.editorconfig b/.editorconfig index 3faf149..5e5b915 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,6 @@ indent_style = tab indent_size = tab tab_width = 4 -[{*.json, *.yaml, *.yml, *.md}] +[*.{json,yaml,yml,md}] indent_style = space indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 12910b6..8f5c55f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,11 +1,11 @@ -# Not archived .docs export-ignore -tests export-ignore +.github export-ignore .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore .travis.yml export-ignore Makefile export-ignore -phpstan.neon export-ignore README.md export-ignore +phpstan.neon export-ignore ruleset.xml export-ignore +tests export-ignore diff --git a/.github/.kodiak.toml b/.github/.kodiak.toml deleted file mode 100644 index 60c34b6..0000000 --- a/.github/.kodiak.toml +++ /dev/null @@ -1,10 +0,0 @@ -version = 1 - -[merge] -automerge_label = "automerge" -blacklist_title_regex = "^WIP.*" -blacklist_labels = ["WIP"] -method = "rebase" -delete_branch_on_merge = true -notify_on_conflict = true -optimistic_updates = false diff --git a/.github/workflows/codesniffer.yml b/.github/workflows/codesniffer.yml index dfc76ff..a58ac4f 100644 --- a/.github/workflows/codesniffer.yml +++ b/.github/workflows/codesniffer.yml @@ -2,6 +2,7 @@ name: "Codesniffer" on: pull_request: + workflow_dispatch: push: branches: ["*"] @@ -12,4 +13,6 @@ on: jobs: codesniffer: name: "Codesniffer" - uses: contributte/.github/.github/workflows/codesniffer.yml@v1 + uses: contributte/.github/.github/workflows/codesniffer.yml@master + with: + php: "8.2" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 121f718..fac01f8 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -2,14 +2,17 @@ name: "Coverage" on: pull_request: + workflow_dispatch: push: branches: ["*"] schedule: - - cron: "0 8 * * 1" + - cron: "0 9 * * 1" jobs: coverage: name: "Nette Tester" - uses: contributte/.github/.github/workflows/nette-tester-coverage.yml@v1 + uses: contributte/.github/.github/workflows/nette-tester-coverage-v2.yml@master + with: + php: "8.2" diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index db3ad34..13ceb07 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -2,14 +2,17 @@ name: "Phpstan" on: pull_request: + workflow_dispatch: push: branches: ["*"] schedule: - - cron: "0 8 * * 1" + - cron: "0 10 * * 1" jobs: phpstan: name: "Phpstan" - uses: contributte/.github/.github/workflows/phpstan.yml@v1 + uses: contributte/.github/.github/workflows/phpstan.yml@master + with: + php: "8.2" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6ca4568..ef17693 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,35 +2,42 @@ name: "Nette Tester" on: pull_request: + workflow_dispatch: push: branches: ["*"] schedule: - - cron: "0 8 * * 1" + - cron: "0 10 * * 1" jobs: - test82: + test85: name: "Nette Tester" - uses: contributte/.github/.github/workflows/nette-tester.yml@v1 + uses: contributte/.github/.github/workflows/nette-tester.yml@master with: - php: "8.2" + php: "8.5" + + test84: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester.yml@master + with: + php: "8.4" - test81: + test83: name: "Nette Tester" - uses: contributte/.github/.github/workflows/nette-tester.yml@v1 + uses: contributte/.github/.github/workflows/nette-tester.yml@master with: - php: "8.1" + php: "8.3" - test80: + test82: name: "Nette Tester" - uses: contributte/.github/.github/workflows/nette-tester.yml@v1 + uses: contributte/.github/.github/workflows/nette-tester.yml@master with: - php: "8.0" + php: "8.2" testlower: name: "Nette Tester" - uses: contributte/.github/.github/workflows/nette-tester.yml@v1 + uses: contributte/.github/.github/workflows/nette-tester.yml@master with: - php: "8.0" + php: "8.2" composer: "composer update --no-interaction --no-progress --prefer-dist --prefer-stable --prefer-lowest" diff --git a/.gitignore b/.gitignore index 83ae570..f0b3670 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,14 @@ -# IDE -/.idea - -# Composer -/vendor -/composer.lock - -# Tests -/tests/_output -/tests/_support -/coverage.xml +# IDE +/.idea + +# Composer +/vendor +/composer.lock + +# Tests +/tests/tmp +/coverage.* +/tests/**/*.log +/tests/**/*.html +/tests/**/*.expected +/tests/**/*.actual diff --git a/Makefile b/Makefile index d919bcf..750fec1 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,11 @@ -.PHONY: install qa cs csf phpstan tests coverage - +.PHONY: install install: composer update +.PHONY: qa qa: phpstan cs +.PHONY: cs cs: ifdef GITHUB_ACTION vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp -q --report=checkstyle src tests | cs2pr @@ -12,18 +13,22 @@ else vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp src tests endif +.PHONY: csf csf: - vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --colors -nsp src tests + vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp src tests +.PHONY: phpstan phpstan: vendor/bin/phpstan analyse -c phpstan.neon +.PHONY: tests tests: - vendor/bin/codecept run + vendor/bin/tester -s -p php --colors 1 -C tests/Cases +.PHONY: coverage coverage: ifdef GITHUB_ACTION - phpdbg -qrr vendor/bin/codecept run --coverage-xml + vendor/bin/tester -s -p php --colors 1 -C --coverage coverage.xml --coverage-src src tests/Cases else - phpdbg -qrr vendor/bin/codecept run --coverage-html + vendor/bin/tester -s -p php --colors 1 -C --coverage coverage.html --coverage-src src tests/Cases endif diff --git a/README.md b/README.md index 4fdba53..b9ec99d 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ For details on how to use this package, check out our [documentation](.docs). | State | Version | Branch | PHP | |-------------|---------|----------|---------| -| dev | `^4.1` | `master` | `>=8.0` | -| stable | `^4.0` | `master` | `>=8.0` | +| dev | `^4.1` | `master` | `>=8.1` | +| stable | `^4.0` | `v4` | `>=8.0` | ## Development diff --git a/codeception.yml b/codeception.yml deleted file mode 100644 index 6ec72ae..0000000 --- a/codeception.yml +++ /dev/null @@ -1,22 +0,0 @@ -actor: Tester - -paths: - # where the tests stored - tests: tests - - # directory for fixture data - data: tests/_data - - # directory for support code - support: tests/_support - - # directory for output - output: tests/_output - -settings: - log: true - -coverage: - enabled: true - include: - - src/** diff --git a/composer.json b/composer.json index 9338bf4..3c93121 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,5 @@ { "name": "contributte/forms-multiplier", - "type": "library", "description": "Multiplier for nette forms", "keywords": [ "nette", @@ -8,20 +7,31 @@ "forms", "multiplier" ], + "type": "library", + "license": "MIT", + "homepage": "https://github.com/contributte/forms-multiplier", + "authors": [ + { + "name": "Milan Felix Sulc", + "homepage": "https://f3l1x.io" + } + ], "require": { - "php": ">=8.0", - "nette/forms": "^3.1.0" + "php": ">=8.2", + "nette/forms": "^3.2.0" }, "require-dev": { - "codeception/codeception": "^4.1.9", - "codeception/module-asserts": "^1.3.1", - "codeception/module-phpbrowser": "^1.0.2", - "nette/application": "^3.1.11", - "nette/di": "^3.1.0", + "contributte/phpstan": "~0.2.0", + "contributte/qa": "~0.4.0", + "contributte/tester": "~0.4.0", "latte/latte": "^3.0.0", - "contributte/qa": "^0.3", - "contributte/phpstan": "^0.1", - "webchemistry/testing-helpers": "~2.0.0" + "nette/application": ">=3.2.0 <3.3.0", + "nette/di": "^3.2.0", + "webchemistry/testing-helpers": "^4.1.1" + }, + "conflict": { + "latte/latte": "<3.0.0", + "nette/component-model": "<3.1.0" }, "autoload": { "psr-4": { @@ -29,12 +39,12 @@ } }, "autoload-dev": { - "classmap": [ - "tests/includes" - ] + "psr-4": { + "Tests\\": "tests" + } }, - "prefer-stable": true, "minimum-stability": "dev", + "prefer-stable": true, "config": { "sort-packages": true, "allow-plugins": { diff --git a/phpstan.neon b/phpstan.neon index 2a23b2d..5fa45d0 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,11 +1,9 @@ includes: - - vendor/phpstan/phpstan-deprecation-rules/rules.neon - - vendor/phpstan/phpstan-nette/extension.neon - - vendor/phpstan/phpstan-nette/rules.neon + - vendor/contributte/phpstan/phpstan.neon parameters: level: 8 - phpVersion: 80000 + phpVersion: 80200 scanDirectories: - src @@ -16,3 +14,48 @@ parameters: paths: - src - .docs + + ignoreErrors: + # https://github.com/phpstan/phpstan-nette/issues/141 + - + message: '#^Parameter \#1 \$array of function array_filter expects array, Iterator\ given\.$#' + identifier: argument.type + count: 4 + path: src/Multiplier.php + + # Strict rules - boolean conditions + - + identifier: if.condNotBoolean + path: src/ComponentResolver.php + - + identifier: if.condNotBoolean + path: src/Multiplier.php + - + identifier: booleanAnd.leftNotBoolean + path: src/Latte/Extension/Node/MultiplierAddNode.php + - + identifier: booleanAnd.leftNotBoolean + path: src/Multiplier.php + - + identifier: booleanAnd.rightNotBoolean + path: src/Multiplier.php + - + identifier: booleanNot.exprNotBoolean + path: src/Latte/Extension/Node/MultiplierRemoveNode.php + - + identifier: booleanNot.exprNotBoolean + path: src/Multiplier.php + - + identifier: ternary.condNotBoolean + path: src/Latte/Extension/Node/MultiplierAddNode.php + - + identifier: ternary.condNotBoolean + path: src/Latte/Extension/Node/MultiplierRemoveNode.php + + # Strict rules - covariance/contravariance + - + identifier: method.childReturnType + path: src/Latte/Extension/MultiplierExtension.php + - + identifier: method.childParameterType + path: src/Multiplier.php diff --git a/ruleset.xml b/ruleset.xml index 8eba5ea..57241ed 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -1,21 +1,22 @@ - - - + + + + + - + - - - /tests + + /tests/tmp diff --git a/src/Buttons/RemoveButton.php b/src/Buttons/RemoveButton.php index df99e56..76ecbe8 100644 --- a/src/Buttons/RemoveButton.php +++ b/src/Buttons/RemoveButton.php @@ -5,6 +5,7 @@ use Contributte\FormMultiplier\Multiplier; use Nette\Forms\Controls\SubmitButton; use Nette\SmartObject; +use Nette\Utils\Html; final class RemoveButton { @@ -14,12 +15,12 @@ final class RemoveButton /** @var callable[] */ public array $onCreate = []; - private ?string $caption = null; + private Html|string|null $caption = null; /** @var string[] */ private array $classes = []; - public function __construct(?string $caption) + public function __construct(Html|string|null $caption) { $this->caption = $caption; } diff --git a/src/Latte/Extension/Node/MultiplierAddNode.php b/src/Latte/Extension/Node/MultiplierAddNode.php index 98a67ba..7026cc6 100644 --- a/src/Latte/Extension/Node/MultiplierAddNode.php +++ b/src/Latte/Extension/Node/MultiplierAddNode.php @@ -35,6 +35,8 @@ public static function create(Tag $tag): self $node->part = new StringNode('1'); } + $tag->parser->stream->tryConsume(','); + $node->attributes = $tag->parser->parseArguments(); return $node; diff --git a/src/Multiplier.php b/src/Multiplier.php index 435bb21..180e506 100644 --- a/src/Multiplier.php +++ b/src/Multiplier.php @@ -4,6 +4,7 @@ use Contributte\FormMultiplier\Buttons\CreateButton; use Contributte\FormMultiplier\Buttons\RemoveButton; +use Generator; use Iterator; use Nette\ComponentModel\IComponent; use Nette\Forms\Container; @@ -11,8 +12,10 @@ use Nette\Forms\Controls\BaseControl; use Nette\Forms\Controls\SubmitButton; use Nette\Forms\Form; +use Nette\InvalidStateException; use Nette\Utils\ArrayHash; use Nette\Utils\Arrays; +use Nette\Utils\Html; use Traversable; class Multiplier extends Container @@ -108,6 +111,9 @@ public static function register(string $name = 'addMultiplier'): void }); } + /** + * @return ($throw is true ? Form : ?Form) + */ public function getForm(bool $throw = true): ?Form { if ($this->form) { @@ -153,7 +159,7 @@ public function getCopyNumber(): int return $this->copyNumber; } - public function addRemoveButton(?string $caption = null): RemoveButton + public function addRemoveButton(Html|string|null $caption = null): RemoveButton { return $this->removeButton = new RemoveButton($caption); } @@ -168,8 +174,7 @@ public function addCreateButton(?string $caption = null, int $copyCount = 1): Cr */ public function validate(?array $controls = null): void { - /** @var Control[] $components */ - $components = $controls ?? iterator_to_array($this->getComponents()); + $components = $controls ?? array_filter($this->getComponents(), fn ($component) => $component instanceof Control || $component instanceof Container); foreach ($components as $index => $control) { foreach ($this->noValidate as $item) { @@ -228,10 +233,12 @@ public function createCopies(): void $this->attachCreateButtons(); } - if ($this->form !== null && $resolver->isRemoveAction() && $this->totalCopies >= $this->minCopies && !$resolver->reachedMinLimit()) { - /** @var RemoveButton $removeButton */ - $removeButton = $this->removeButton; - $this->form->setSubmittedBy($removeButton->create($this)); + if ($this->form !== null && $this->removeButton !== null && $resolver->isRemoveAction() && $this->totalCopies >= $this->minCopies && !$resolver->reachedMinLimit()) { + + // Create dummy remove button. Without this, Nette will validate, + // even though the original button has empty validation scope, + // since the button has actually been removed. + $this->form->setSubmittedBy($this->removeButton->create($this)); $this->resetFormEvents(); @@ -272,23 +279,26 @@ public function resetFormEvents(): void } /** + * @param string|object|bool|null $returnType 'array' for array * @param Control[]|null $controls * @return object|mixed[] - * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint */ - public function getValues($returnType = null, ?array $controls = null): object|array + public function getValues(string|object|bool|null $returnType = null, ?array $controls = null): object|array { if (!$this->resetKeys) { return parent::getValues($returnType, $controls); } /** @var mixed[] $values */ - $values = parent::getValues('array', $controls); + $values = parent::getValues(self::Array, $controls); $values = array_values($values); - $returnType = $returnType === true ? 'array' : $returnType; // @phpstan-ignore-line nette backwards compatibility + if ($returnType === true) { + trigger_error(static::class . '::' . __FUNCTION__ . "(true) is deprecated, use getValues('array').", E_USER_DEPRECATED); + $returnType = self::Array; + } - return $returnType === 'array' ? $values : ArrayHash::from($values); + return $returnType === self::Array ? $values : ArrayHash::from($values); } /** @@ -297,28 +307,30 @@ public function getValues($returnType = null, ?array $controls = null): object|a public function getControls(): Iterator { $this->createCopies(); + $controls = parent::getControls(); - return parent::getControls(); + return (static function () use ($controls): Generator { + yield from $controls; + })(); } /** - * @return Iterator + * @return array */ - public function getContainers(): Iterator + public function getContainers(): iterable { $this->createCopies(); - /** @var Iterator $containers */ - $containers = $this->getComponents(false, Container::class); + $containers = array_filter($this->getComponents(), fn ($component) => $component instanceof Container); return $containers; } /** * @param mixed[]|object $values - * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint + * @internal */ - public function setValues($values, bool $erase = false): self + public function setValues(array|object $values, bool $erase = false, bool $onlyDisabled = false): static { $values = $values instanceof Traversable ? iterator_to_array($values) : (array) $values; @@ -373,19 +385,21 @@ protected function isValidMaxCopies(): bool protected function isFormSubmitted(): bool { - return $this->getForm() !== null && $this->getForm()->isAnchored() && $this->getForm()->isSubmitted(); + return $this->getForm(false) !== null && $this->getForm()->isAnchored() && $this->getForm()->isSubmitted(); } protected function loadHttpData(): void { if ($this->form !== null && $this->isFormSubmitted()) { - $this->httpData = (array) Arrays::get($this->form->getHttpData(), $this->getHtmlName(), []); + /** @var array $httpData The other types from the union can only be returned when the htmlName argument is passed. https://github.com/nette/forms/pull/333 */ + $httpData = $this->form->getHttpData(); + $this->httpData = (array) Arrays::get($httpData, $this->getHtmlName(), []); } } protected function createNumber(): int { - $count = iterator_count($this->getComponents(false, Form::class)); + $count = count(array_filter($this->getComponents(), fn ($component) => $component instanceof Form)); while ($this->getComponent((string) $count, false)) { $count++; } @@ -400,16 +414,17 @@ protected function fillContainer(Container $container): void /** * @return string[] + * @throws InvalidStateException when not attached. */ protected function getHtmlName(): array { - return explode('-', $this->lookupPath(Form::class) ?? ''); + return explode('-', $this->lookupPath(Form::class)); } protected function createContainer(): Container { $control = new Container(); - $control->currentGroup = $this->currentGroup; + $control->setCurrentGroup($this->currentGroup); $this->fillContainer($control); return $control; @@ -420,7 +435,7 @@ protected function createContainer(): Container */ protected function getFirstSubmit(): ?string { - $submits = iterator_to_array($this->getComponents(false, SubmitButton::class)); + $submits = array_filter($this->getComponents(), fn ($component) => $component instanceof SubmitButton); if ($submits) { return reset($submits)->getName(); } @@ -481,7 +496,7 @@ private function createComponents(ComponentResolver $resolver): void $count = $resolver->getCreateNum(); while ($count > 0 && $this->isValidMaxCopies()) { $this->noValidate[] = $containers[] = $container = $this->addCopy(); - $container->setValues($this->createContainer()->getValues('array')); + $container->setValues($this->createContainer()->getValues(self::Array)); $count--; } } diff --git a/tests/.coveralls.yml b/tests/.coveralls.yml deleted file mode 100644 index 740380b..0000000 --- a/tests/.coveralls.yml +++ /dev/null @@ -1,4 +0,0 @@ -# for php-coveralls -service_name: github-actions -coverage_clover: tests/_output/coverage.xml -json_path: tests/_output/coverage.json diff --git a/tests/Cases/Functional/MultiplierExtensionTest.phpt b/tests/Cases/Functional/MultiplierExtensionTest.phpt new file mode 100644 index 0000000..2a9bd9f --- /dev/null +++ b/tests/Cases/Functional/MultiplierExtensionTest.phpt @@ -0,0 +1,68 @@ +|null $multiplierConfig + */ +function initializeContainer(?array $multiplierConfig = null): void +{ + $config = [ + 'services' => [ + 'latte.latteFactory' => ILatteFactory::class, + ], + ]; + + if ($multiplierConfig !== null) { + $config['multiplier'] = $multiplierConfig; + } + + $loader = new ContainerLoader(Environment::getTestDir()); + $class = $loader->load(function (Compiler $compiler) use ($config): void { + $compiler->addExtension('multiplier', new MultiplierExtension()); + $compiler->addConfig($config); + }, md5(serialize($multiplierConfig)) . time()); + $container = new $class(); + $container->initialize(); +} + +// testDefaultConfiguration +Toolkit::test(function (): void { + initializeContainer(); + + $form = new Form(); + $multiplier = $form->addMultiplier('multiplier', function (Container $container, Form $form): void { + }); + Assert::type(Multiplier::class, $multiplier); +}); + +// testAlternativeConfiguration +Toolkit::test(function (): void { + initializeContainer(['name' => 'addMultiplierAlternative']); + + $form = new Form(); + $multiplier = $form->addMultiplierAlternative('multiplier', function (Container $container, Form $form): void { + }); + Assert::type(Multiplier::class, $multiplier); +}); + +// testInvalidConfiguration +Toolkit::test(function (): void { + Assert::exception(function (): void { + initializeContainer(['name' => 0]); + }, InvalidConfigurationException::class); +}); diff --git a/tests/Cases/Unit/CreateButtonTest.phpt b/tests/Cases/Unit/CreateButtonTest.phpt new file mode 100644 index 0000000..cc3793b --- /dev/null +++ b/tests/Cases/Unit/CreateButtonTest.phpt @@ -0,0 +1,139 @@ +form->createRequest( + MultiplierBuilder::create() + ->addCreateButton() + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => ''], + ['bar' => ''], + 'multiplier_creator' => '', + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[2][bar]"]'); +}); + +// testSendCreateOverMaxCopies +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, 2) + ->addCreateButton() + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => ''], + ['bar' => ''], + 'multiplier_creator' => '', + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[2][bar]"]'); +}); + +// testSendCreateButtonWith5Copies +Toolkit::test(function () use ($services): void { + $factory = MultiplierBuilder::create() + ->addCreateButton(5) + ->addCreateButton() + ->addRemoveButton(); + + $response = $services->form->createRequest($factory->createForm())->setPost([ + 'm' => [ + ['bar' => ''], + 'multiplier_creator5' => '', + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[2][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[3][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[4][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[5][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[6][bar]"]'); +}); + +// testCallback +Toolkit::test(function () use ($services): void { + $factory = MultiplierBuilder::create() + ->setMinCopies(1) + ->addRemoveButton(function (SubmitButton $submitter): void { + $submitter->setHtmlAttribute('class', 'delete-btn'); + }) + ->addCreateButton(5, function (Submitter $submitter): void { + $submitter->setHtmlAttribute('class', 'add-btn'); + }); + + $response = $services->form->createRequest($factory->createForm())->setPost([ + 'm' => [ + ['bar' => ''], + ['bar' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input.delete-btn'); + FormAssert::domHas($dom, 'input.add-btn'); +}); + +// testFormEvents +Toolkit::test(function () use ($services): void { + $factory = MultiplierBuilder::create(2) + ->setMinCopies(1) + ->addRemoveButton(function (SubmitButton $submitter): void { + $submitter->setHtmlAttribute('class', 'delete-btn'); + }) + ->addCreateButton(5, function (Submitter $submitter): void { + $submitter->setHtmlAttribute('class', 'add-btn'); + }); + + $called = false; + $factory->formModifier(function ($form) use (&$called): void { + $form->onSuccess[] = $form->onError[] = $form->onSubmit[] = function () use (&$called): void { + $called = true; + }; + }); + + $req = $services->form->createRequest($factory->createForm()); + $response = $req->setPost([ + 'm' => [ + ['bar' => ''], + 'multiplier_creator' => '', + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"]'); + Assert::true($called); +}); diff --git a/tests/Cases/Unit/DefaultValuesTest.phpt b/tests/Cases/Unit/DefaultValuesTest.phpt new file mode 100644 index 0000000..0ae820e --- /dev/null +++ b/tests/Cases/Unit/DefaultValuesTest.phpt @@ -0,0 +1,168 @@ + [ + ['bar' => 'foo'], + ['bar' => 'foo'], + ], +]; + +$defaultNested = [ + 'm' => [ + [ + 'bar' => 'foo1', + 'nested' => [ + ['foo' => 'bar1'], + ['foo' => 'bar2'], + ], + ], + [ + 'bar' => 'foo2', + 'nested' => [ + ['foo' => 'bar3'], + ['foo' => 'bar4'], + ], + ], + ], +]; + +// testRender +Toolkit::test(function () use ($services, $defaults): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, null) + ->addCreateButton() + ->addRemoveButton() + ->setMinCopies(1) + ->setFormDefaults($defaults) + ->createForm() + )->render(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"][value="foo"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"][value="foo"]'); + FormAssert::domNotHas($dom, 'input[name="m[2][bar]"]'); +}); + +// testRenderAndSetDefaultsInAction +Toolkit::test(function () use ($services, $defaults): void { + $response = $services->form->createRequest( + MultiplierBuilder::create() + ->createForm() + )->setActionCallback(function (Form $form) use ($defaults): void { + $form->setDefaults($defaults); + })->render(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"][value="foo"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"][value="foo"]'); + FormAssert::domNotHas($dom, 'input[name="m[2][bar]"]'); +}); + +// testRenderAndSetDefaultsInRender +Toolkit::test(function () use ($services, $defaults): void { + $response = $services->form->createRequest( + MultiplierBuilder::create() + ->createForm() + )->setRenderCallback(function (Form $form) use ($defaults): void { + $form->setDefaults($defaults); + })->render(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"][value="foo"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"][value="foo"]'); + FormAssert::domNotHas($dom, 'input[name="m[2][bar]"]'); +}); + +// testRemoveButtons +Toolkit::test(function () use ($services, $defaults): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, null) + ->addCreateButton() + ->addRemoveButton() + ->setMinCopies(1) + ->setFormDefaults($defaults) + ->createForm() + )->render(); + + $dom = $response->toDomQuery(); + FormAssert::domHas($dom, 'input[name="m[0][' . Multiplier::SUBMIT_REMOVE_NAME . ']"]'); + FormAssert::domHas($dom, 'input[name="m[1][' . Multiplier::SUBMIT_REMOVE_NAME . ']"]'); +}); + +// testDefaultValue +Toolkit::test(function () use ($services, $defaults): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, null) + ->addCreateButton() + ->addRemoveButton() + ->setMinCopies(1) + ->setFormDefaults($defaults) + ->fields(['bar' => 'foo']) + ->createForm() + )->render(); + + $dom = $response->toDomQuery(); + FormAssert::domHas($dom, 'input[name="m[0][bar]"][value="foo"]'); +}); + +// testDefaultValueSend +Toolkit::test(function () use ($services, $defaults): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, null) + ->addCreateButton() + ->addRemoveButton() + ->setMinCopies(1) + ->setFormDefaults($defaults) + ->fields(['bar' => 'foo']) + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => 'bar'], + Multiplier::SUBMIT_CREATE_NAME => '', + ], + ])->send(); + + $dom = $response->toDomQuery(); + FormAssert::domHas($dom, 'input[name="m[0][bar]"][value="bar"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"][value="foo"]'); +}); + +// testNestedMultiplier +Toolkit::test(function () use ($services, $defaultNested): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, null) + ->containerModifier(function (Container $container): void { + $container['nested'] = new Multiplier(function (Container $container): void { + $container->addText('foo'); + }); + }) + ->fields(['bar' => 'foo']) + ->setFormDefaults($defaultNested) + ->createForm() + )->render(); + + $dom = $response->toDomQuery(); + FormAssert::domHas($dom, 'input[name="m[0][bar]"][value="foo1"]'); + FormAssert::domHas($dom, 'input[name="m[0][nested][0][foo]"][value="bar1"]'); + FormAssert::domHas($dom, 'input[name="m[0][nested][1][foo]"][value="bar2"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"][value="foo2"]'); + FormAssert::domHas($dom, 'input[name="m[1][nested][0][foo]"][value="bar3"]'); + FormAssert::domHas($dom, 'input[name="m[1][nested][1][foo]"][value="bar4"]'); +}); diff --git a/tests/Cases/Unit/LatteTest.phpt b/tests/Cases/Unit/LatteTest.phpt new file mode 100644 index 0000000..487478c --- /dev/null +++ b/tests/Cases/Unit/LatteTest.phpt @@ -0,0 +1,35 @@ +addExtension(new FormsExtension()); + $latte->addExtension(new MultiplierExtension()); + + $presenter = new FooPresenter(); + $form = new NetteForm(); + $form['m'] = $m = new Multiplier(function (Container $container): void { + $container->addText('foo'); + }); + $m->addCreateButton('Create one'); + $m->addCreateButton('Create two', 2); + $presenter['m'] = $form; + + $string = $latte->renderToString(__DIR__ . '/templates/macros.latte', ['form' => $form]); + Assert::match('#name="m\[multiplier_creator]"#', $string); + Assert::match('#name="m\[multiplier_creator2]"#', $string); +}); diff --git a/tests/Cases/Unit/MultiplierTest.phpt b/tests/Cases/Unit/MultiplierTest.phpt new file mode 100644 index 0000000..026b23d --- /dev/null +++ b/tests/Cases/Unit/MultiplierTest.phpt @@ -0,0 +1,369 @@ +createForm(); + + Assert::type(Iterator::class, $form['m']->getControls()); +}); + +// testRenderBase +Toolkit::test(function () use ($services): void { + $onCreateParams = []; + $response = $services->form->createRequest( + MultiplierBuilder::create() + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier) use (&$onCreateParams): void { + $multiplier->onCreate[] = function (Container $container) use (&$onCreateParams): void { + $onCreateParams[] = $container; + }; + }) + ->createForm() + )->render(); + + FormAssert::domHas($response->toDomQuery(), 'input[name="m[0][bar]"]'); +}); + +// testSendBase +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create() + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->createForm() + ) + ->setPost($params = [ + 'm' => [ + ['bar' => 'foo'], + ], + ])->send(); + + Assert::true($response->isSuccess()); + Assert::same($params, $response->getValues()); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"][value="foo"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testRenderCopy2 +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2) + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->createForm() + )->render(); + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testSendCopy2 +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2) + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->createForm() + ) + ->setPost($params = [ + 'm' => [ + ['bar' => 'foo'], + ['bar' => 'bar'], + ], + ])->send(); + + Assert::same($params, $response->getValues()); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[1][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[2][bar]"]'); +}); + +// testRenderMaxCopy +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, 1) + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->createForm() + )->render(); + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testSendMaxCopy +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2, 1) + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->createForm() + ) + ->setPost([ + 'm' => [ + ['bar' => 'foo'], + ['bar' => 'bar'], + ], + ])->send(); + + Assert::same([ + 'm' => [ + ['bar' => 'foo'], + ], + ], $response->getValues()); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testNested +Toolkit::test(function () use ($services): void { + $request = $services->form->createRequest( + MultiplierBuilder::create() + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->containerModifier(function (Container $container): void { + $container['m2'] = (new Multiplier(function (Container $container): void { + $container->addText('bar2'); + })); + $container['m2']->addCreateButton('create'); + }) + ->createForm() + ); + + $dom = $request->render()->toDomQuery(); + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input[name="m[0][m2][0][bar2]"]'); + FormAssert::domHas($dom, 'input[name="m[0][m2][' . Multiplier::SUBMIT_CREATE_NAME . ']"]'); +}); + +// testSubmitFilter +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create() + ->fields([]) + ->beforeFormModifier(function (Form $form): void { + $form->addInteger('num'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + $container->addInteger('mnum'); + }; + }) + ->formModifier(function (Form $form): void { + $form->onSuccess[] = $form->onError[] = $form->onSubmit[] = function (): void { + }; + }) + ->createForm() + ) + ->setPost([ + 'num' => '11', + 'm' => [ + ['mnum' => '49'], + ], + ])->send(); + + Assert::true($response->isSuccess()); + Assert::same([ + 'num' => 11, + 'm' => [ + ['mnum' => 49], + ], + ], $response->getValues()); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][mnum]"][value="49"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][mnum]"]'); +}); + +// testGroup +Toolkit::test(function () use ($services): void { + $request = $services->form->createRequest( + MultiplierBuilder::create() + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->createForm() + ); + $dom = $request->render()->toDomQuery(); + FormAssert::domHas($dom, 'fieldset'); + FormAssert::domHas($dom, 'fieldset input[name="m[0][bar]"]'); +}); + +// testGroupManualRenderWithRemovedButtons +Toolkit::test(function () use ($services): void { + $request = $services->form->createRequest( + MultiplierBuilder::create(2) + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + $multiplier->addCreateButton(); + $multiplier->addRemoveButton(); + }) + ->createForm() + ); + $dom = $request->render()->toDomQuery(); + + FormAssert::domNotHas($dom, 'input[name="m[0][multiplier_remover]"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][multiplier_remover]"]'); +}); + +// testGroupManualRenderWithButtons +Toolkit::test(function () use ($services): void { + $request = $services->form->createRequest(MultiplierBuilder::create(2) + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + $multiplier->addCreateButton(); + $multiplier->addRemoveButton(); + $multiplier->setMinCopies(1); + }) + ->createForm()); + $dom = $request->render(__DIR__ . '/templates/group.latte')->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][multiplier_remover]"]'); + FormAssert::domHas($dom, 'input[name="m[1][multiplier_remover]"]'); +}); + +// testOnCreateEvent +Toolkit::test(function () use ($services): void { + $onCreateParams = []; + $request = $services->form->createRequest( + MultiplierBuilder::create() + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier) use (&$onCreateParams): void { + $multiplier->onCreate[] = function (Container $container) use (&$onCreateParams): void { + $onCreateParams[] = $container; + }; + }) + ->createForm() + )->modifyForm(function (Form $form): void { + $form['m']->setValues([ + ['bar' => 'foo'], + ['bar' => 'foo2'], + ]); + }); + $request->render()->toString(); + + Assert::true(count($onCreateParams) > 0); + $values = ['foo', 'foo2']; + foreach ($onCreateParams as $i => $parameter) { + Assert::type(Container::class, $parameter); + Assert::same($values[$i], $parameter['bar']->getValue()); + } +}); + +// testAddDynamic +Toolkit::test(function () use ($services): void { + $request = $services->form->createRequest( + MultiplierBuilder::create() + ->beforeFormModifier(function (Form $form): void { + $form->addGroup('testGroup'); + }) + ->multiplierModifier(function (Multiplier $multiplier): void { + $multiplier->onCreate[] = function (Container $container): void { + }; + }) + ->createForm() + )->modifyForm(function (Form $form): void { + $form['m']->onCreateComponents[] = function (Multiplier $multiplier): void { + $multiplier->addCopy(99)['bar']->setHtmlAttribute('class', 'myClass'); + }; + }); + + $dom = $request->render()->toDomQuery(); + + FormAssert::domHas($dom, '[name="m[99][bar]"]'); + FormAssert::domHas($dom, 'input.myClass'); +}); + +// testPromptSelect +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create() + ->containerModifier(function (Container $container): void { + $container->addSelect('select', null, ['foo' => 'foo']) + ->setPrompt('Select'); + }) + ->addCreateButton() + ->createForm() + ) + ->setPost([ + 'm' => [ + ['select' => '', 'multiplier_creator' => ''], + ], + ])->send(); + + Assert::true($response->isSuccess()); +}); diff --git a/tests/Cases/Unit/RemoveButtonTest.phpt b/tests/Cases/Unit/RemoveButtonTest.phpt new file mode 100644 index 0000000..9ec217b --- /dev/null +++ b/tests/Cases/Unit/RemoveButtonTest.phpt @@ -0,0 +1,229 @@ +form->createRequest( + MultiplierBuilder::create(2) + ->setMinCopies(1) + ->addRemoveButton() + ->addCreateButton() + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => ''], + ['bar' => '', 'multiplier_remover' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testSendRemoveShouldNotValidate +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2) + ->setMinCopies(1) + ->beforeFormModifier(function (Form $form): void { + $form->addInteger('num'); + }) + ->addRemoveButton() + ->createForm() + )->setPost([ + 'num' => '5+1', + 'm' => [ + ['bar' => ''], + ['bar' => '', 'multiplier_remover' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + Assert::false($response->hasErrors()); + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testSendRemoveWithoutButton +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2) + ->setMinCopies(1) + ->addCreateButton() + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => ''], + ['bar' => '', 'multiplier_remover' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testSendRemoveBelowMinCopies +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(1) + ->setMinCopies(1) + ->addRemoveButton() + ->addCreateButton() + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => '', 'multiplier_remover' => ''], + ], + ])->send(); + + FormAssert::domHas($response->toDomQuery(), 'input[name="m[0][bar]"]'); +}); + +// test2Multipliers +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(1) + ->setMinCopies(1) + ->addRemoveButton() + ->addCreateButton() + ->formModifier(function (Form $form): void { + $form['m2'] = new Multiplier(function (Container $container): void { + $container->addText('bar2'); + }); + + $form['m2']->addRemoveButton(); + $form['m2']->addCreateButton(); + }) + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => ''], + ], + 'm2' => [ + ['bar2' => ''], + Multiplier::SUBMIT_CREATE_NAME => '', + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m2[0][multiplier_remover]"]'); + FormAssert::domHas($dom, 'input[name="m2[1][multiplier_remover]"]'); + FormAssert::domNotHas($dom, 'input[name="m[0][multiplier_remover]"]'); +}); + +// testFormEvents +Toolkit::test(function () use ($services): void { + $req = $services->form->createRequest( + MultiplierBuilder::create(2) + ->setMinCopies(1) + ->addRemoveButton() + ->addCreateButton() + ->formModifier(function (Form $form): void { + $form->onSuccess[] = $form->onError[] = $form->onSubmit[] = function (): void { + Assert::fail('Events should not be called'); + }; + }) + ->createForm() + ); + $response = $req->setPost([ + 'm' => [ + ['bar' => ''], + ['bar' => '', 'multiplier_remover' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domNotHas($dom, 'input[name="m[1][bar]"]'); +}); + +// testAddClass +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(2) + ->setMinCopies(1) + ->addRemoveButton(function (SubmitButton $submitter): void { + $submitter->setHtmlAttribute('class', 'btn btn-remove'); + }) + ->addCreateButton() + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => ''], + ['bar' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[0][bar]"]'); + FormAssert::domHas($dom, 'input.btn.btn-remove'); +}); + +// testDeleteLastElementToZero +Toolkit::test(function () use ($services): void { + $response = $services->form->createRequest( + MultiplierBuilder::create(1) + ->setMinCopies(0) + ->addRemoveButton() + ->addCreateButton() + ->createForm() + )->modifyForm(function (Form $form): void { + $form['m']->setValues([ + ['bar' => 'foo'], + ]); + })->setPost([ + 'm' => [ + ['bar' => '', 'multiplier_remover' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + + FormAssert::domHas($dom, 'input[name="m[multiplier_creator]"]'); + FormAssert::domNotHas($dom, 'input[name="m[0][bar]"]'); +}); + +// testOnRemoveEvent +Toolkit::test(function () use ($services): void { + $called = false; + $response = $services->form->createRequest( + MultiplierBuilder::create() + ->setMinCopies(0) + ->addRemoveButton() + ->multiplierModifier(function (Multiplier $multiplier) use (&$called): void { + $multiplier->onRemove[] = function () use (&$called): void { + $called = true; + }; + }) + ->createForm() + )->setPost([ + 'm' => [ + ['bar' => '', 'multiplier_remover' => ''], + ], + ])->send(); + + $dom = $response->toDomQuery(); + + Assert::true($called); + FormAssert::domNotHas($dom, 'input[name="m[0][bar]"]'); +}); diff --git a/tests/unit/templates/group.latte b/tests/Cases/Unit/templates/group.latte similarity index 100% rename from tests/unit/templates/group.latte rename to tests/Cases/Unit/templates/group.latte diff --git a/tests/unit/templates/macros.latte b/tests/Cases/Unit/templates/macros.latte similarity index 100% rename from tests/unit/templates/macros.latte rename to tests/Cases/Unit/templates/macros.latte diff --git a/tests/Helpers/FormAssert.php b/tests/Helpers/FormAssert.php new file mode 100644 index 0000000..a88b0eb --- /dev/null +++ b/tests/Helpers/FormAssert.php @@ -0,0 +1,21 @@ +has($selector), sprintf('Element %s not found in DOM', $selector)); + } + + public static function domNotHas(DomQuery $domQuery, string $selector): void + { + Assert::false($domQuery->has($selector), sprintf('Element %s found in DOM', $selector)); + } + +} diff --git a/tests/includes/MultiplierBuilder.php b/tests/Helpers/MultiplierBuilder.php similarity index 81% rename from tests/includes/MultiplierBuilder.php rename to tests/Helpers/MultiplierBuilder.php index 9c851cc..49f9c4e 100644 --- a/tests/includes/MultiplierBuilder.php +++ b/tests/Helpers/MultiplierBuilder.php @@ -1,40 +1,44 @@ */ + public array $fields = [ 'bar' => '', ]; /** @var callable[] */ - protected $formModifiers = []; + protected array $formModifiers = []; /** @var callable[] */ - protected $beforeFormModifiers = []; + protected array $beforeFormModifiers = []; /** @var callable[] */ - protected $multiplierModifiers = []; + protected array $multiplierModifiers = []; /** @var callable[] */ - protected $containerModifiers = []; + protected array $containerModifiers = []; - /** @var array */ - protected $multiplierArgs = []; + /** @var array */ + protected array $multiplierArgs = []; public function __construct(int $copyNumber = 1, ?int $maxCopies = null) { $this->multiplierArgs = [$copyNumber, $maxCopies]; } + public static function create(int $copyNumber = 1, ?int $maxCopies = null): self + { + return new self($copyNumber, $maxCopies); + } + public function factory(Container $container): void { foreach ($this->fields as $field => $value) { @@ -47,6 +51,9 @@ public function factory(Container $container): void } } + /** + * @param array $fields + */ public function fields(array $fields): self { $this->fields = $fields; @@ -56,9 +63,9 @@ public function fields(array $fields): self public function addRemoveButton(?callable $onCreate = null): self { - $this->multiplierModifiers[] = function (Multiplier $multiplier) use ($onCreate) { + $this->multiplierModifiers[] = function (Multiplier $multiplier) use ($onCreate): void { $btn = $multiplier->addRemoveButton('add'); - if ($onCreate) { + if ($onCreate !== null) { $btn->addOnCreateCallback($onCreate); } }; @@ -68,9 +75,9 @@ public function addRemoveButton(?callable $onCreate = null): self public function addCreateButton(int $copyCount = 1, ?callable $onCreate = null): self { - $this->multiplierModifiers[] = function (Multiplier $multiplier) use ($copyCount, $onCreate) { + $this->multiplierModifiers[] = function (Multiplier $multiplier) use ($copyCount, $onCreate): void { $btn = $multiplier->addCreateButton('add', $copyCount); - if ($onCreate) { + if ($onCreate !== null) { $btn->addOnCreateCallback($onCreate); } }; @@ -78,14 +85,9 @@ public function addCreateButton(int $copyCount = 1, ?callable $onCreate = null): return $this; } - public static function create(int $copyNumber = 1, ?int $maxCopies = null): self - { - return new self($copyNumber, $maxCopies); - } - public function setMinCopies(int $minCopies): self { - $this->multiplierModifiers[] = function (Multiplier $multiplier) use ($minCopies) { + $this->multiplierModifiers[] = function (Multiplier $multiplier) use ($minCopies): void { $multiplier->setMinCopies($minCopies); }; @@ -112,7 +114,8 @@ public function createForm(): Form $form->addSubmit('send'); - $form->onSuccess[] = function(Form $form) {}; + $form->onSuccess[] = function (Form $form): void { + }; return $form; } @@ -145,9 +148,12 @@ public function containerModifier(callable $callback): self return $this; } + /** + * @param array $defaults + */ public function setFormDefaults(array $defaults): self { - $this->formModifiers[] = function (Form $form) use ($defaults) { + $this->formModifiers[] = function (Form $form) use ($defaults): void { $form->setDefaults($defaults); }; diff --git a/tests/Mocks/FooPresenter.php b/tests/Mocks/FooPresenter.php new file mode 100644 index 0000000..f3282a8 --- /dev/null +++ b/tests/Mocks/FooPresenter.php @@ -0,0 +1,15 @@ +initializeContainer(); - - $form = new Form(); - $multiplier = $form->addMultiplier('multiplier', function (Container $container, Form $form) {}); - $this->assertInstanceOf(Multiplier::class, $multiplier); - } - - public function testAlternativeConfiguration() - { - $this->initializeContainer(['name' => 'addMultiplierAlternative']); - - $form = new Form(); - $multiplier = $form->addMultiplierAlternative('multiplier', function (Container $container, Form $form) {}); - $this->assertInstanceOf(Multiplier::class, $multiplier); - } - - public function testInvalidConfiguration() - { - try { - $this->initializeContainer(['name' => 0]); - $e = null; - } catch (InvalidConfigurationException $e) {} - - $this->assertNotNull($e); - } - - protected function _before() - { - FileSystem::createDir(self::TEMP_DIR); - } - - protected function _after() - { - FileSystem::delete(self::TEMP_DIR); - } - - private function initializeContainer(?array $multiplierConfig = null): void - { - $config = [ - 'services' => [ - 'latte.latteFactory' => ILatteFactory::class, - ], - ]; - if ($multiplierConfig !== null) { - $config['multiplier'] = $multiplierConfig; - } - - $loader = new ContainerLoader(self::TEMP_DIR); - $class = $loader->load(function (Compiler $compiler) use ($config) { - $compiler->addExtension('multiplier', new MultiplierExtension()); - $compiler->addConfig($config); - }, md5(serialize($multiplierConfig)) . time()); - $container = new $class(); - $container->initialize(); - } - -} diff --git a/tests/includes/TTest.php b/tests/includes/TTest.php deleted file mode 100644 index 9be0889..0000000 --- a/tests/includes/TTest.php +++ /dev/null @@ -1,65 +0,0 @@ -services = new Services(); - - $parent = get_parent_class($this); - if ($parent !== FALSE && method_exists($parent, 'setUp')) { - parent::setUp(); - } - } - - public function assertThrownException(callable $function, string $class, ?string $message = NULL, $code = NULL): void - { - $this->addToAssertionCount(1); - - $e = NULL; - try { - call_user_func($function); - } catch (\Exception $e) { - } - - if ($e === NULL) { - $this->fail("$class was expected, but none was thrown"); - } elseif (!$e instanceof $class) { - $this->fail("$class was expected but got " . get_class($e) . ($e->getMessage() ? " ({$e->getMessage()})" : '')); - } elseif ($message && $message !== $e->getMessage()) { - $this->fail("$class with a message matching {$message} was expected but got {$e->getMessage()}"); - } elseif ($code !== NULL && $e->getCode() !== $code) { - $this->fail("$class with a code {$code} was expected but got {$e->getCode()}"); - } - } - - public function assertDomHas(DomQuery $domQuery, string $selector): void - { - $this->addToAssertionCount(1); - - if (!$domQuery->has($selector)) { - $this->fail(sprintf('Element %s not found in DOM', $selector)); - } - } - - public function assertDomNotHas(DomQuery $domQuery, string $selector): void - { - $this->addToAssertionCount(1); - - if ($domQuery->has($selector)) { - $this->fail(sprintf('Element %s found in DOM', $selector)); - } - } - -} diff --git a/tests/unit.suite.yml b/tests/unit.suite.yml deleted file mode 100644 index a816494..0000000 --- a/tests/unit.suite.yml +++ /dev/null @@ -1,9 +0,0 @@ -# Codeception Test Suite Configuration -# -# Suite for unit (internal) tests. - -class_name: UnitTester -modules: - enabled: - - Asserts - - \Helper\Unit \ No newline at end of file diff --git a/tests/unit/CreateButtonTest.php b/tests/unit/CreateButtonTest.php deleted file mode 100644 index d84b8bb..0000000 --- a/tests/unit/CreateButtonTest.php +++ /dev/null @@ -1,135 +0,0 @@ -services->form->createRequest( - MultiplierBuilder::create() - ->addCreateButton() - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => ''], - ['bar' => ''], - 'multiplier_creator' => '', - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[2][bar]"]'); - } - - public function testSendCreateOverMaxCopies() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, 2) - ->addCreateButton() - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => ''], - ['bar' => ''], - 'multiplier_creator' => '', - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"]'); - $this->assertDomNotHas($dom, 'input[name="m[2][bar]"]'); - } - - public function testSendCreateButtonWith5Copies() - { - $factory = MultiplierBuilder::create() - ->addCreateButton(5) - ->addCreateButton() - ->addRemoveButton(); - - $response = $this->services->form->createRequest($factory->createForm())->setPost([ - 'm' => [ - ['bar' => ''], - 'multiplier_creator5' => '', - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[2][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[3][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[4][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[5][bar]"]'); - $this->assertDomNotHas($dom, 'input[name="m[6][bar]"]'); - } - - public function testCallback() - { - $factory = MultiplierBuilder::create() - ->setMinCopies(1) - ->addRemoveButton(function (SubmitButton $submitter) { - $submitter->setHtmlAttribute('class', 'delete-btn'); - }) - ->addCreateButton(5, function (Submitter $submitter) { - $submitter->setHtmlAttribute('class', 'add-btn'); - }); - - $response = $this->services->form->createRequest($factory->createForm())->setPost([ - 'm' => [ - ['bar' => ''], - ['bar' => ''], - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input.delete-btn'); - $this->assertDomHas($dom, 'input.add-btn'); - } - - public function testFormEvents() - { - $factory = MultiplierBuilder::create(2) - ->setMinCopies(1) - ->addRemoveButton(function (SubmitButton $submitter) { - $submitter->setHtmlAttribute('class', 'delete-btn'); - }) - ->addCreateButton(5, function (Submitter $submitter) { - $submitter->setHtmlAttribute('class', 'add-btn'); - }); - - $called = false; - $factory->formModifier(function ($form) use (&$called) { - $form->onSuccess[] = $form->onError[] = $form->onSubmit[] = function () use (&$called) { - $called = true; - }; - }); - - $req = $this->services->form->createRequest($factory->createForm()); - $response = $req->setPost([ - 'm' => [ - ['bar' => ''], - 'multiplier_creator' => '', - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"]'); - $this->assertTrue($called); - } - -} diff --git a/tests/unit/DefaultValuesTest.php b/tests/unit/DefaultValuesTest.php deleted file mode 100644 index d9fad31..0000000 --- a/tests/unit/DefaultValuesTest.php +++ /dev/null @@ -1,167 +0,0 @@ - [ - ['bar' => 'foo'], - ['bar' => 'foo'], - ], - ]; - - /** @var array */ - private static $defaultNested = [ - 'm' => [ - [ - 'bar' => 'foo1', - 'nested' => [ - ['foo' => 'bar1'], - ['foo' => 'bar2'], - ], - ], - [ - 'bar' => 'foo2', - 'nested' => [ - ['foo' => 'bar3'], - ['foo' => 'bar4'], - ], - ], - ], - ]; - - public function testRender() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, null) - ->addCreateButton() - ->addRemoveButton() - ->setMinCopies(1) - ->setFormDefaults(self::$defaults) - ->createForm() - )->render(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"][value="foo"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"][value="foo"]'); - $this->assertDomNotHas($dom, 'input[name="m[2][bar]"]'); - } - - public function testRenderAndSetDefaultsInAction() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create() - ->createForm() - )->setActionCallback(function (Form $form) { - $form->setDefaults(self::$defaults); - })->render(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"][value="foo"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"][value="foo"]'); - $this->assertDomNotHas($dom, 'input[name="m[2][bar]"]'); - } - - public function testRenderAndSetDefaultsInRender() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create() - ->createForm() - )->setRenderCallback(function (Form $form) { - $form->setDefaults(self::$defaults); - })->render(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"][value="foo"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"][value="foo"]'); - $this->assertDomNotHas($dom, 'input[name="m[2][bar]"]'); - } - - public function testRemoveButtons() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, null) - ->addCreateButton() - ->addRemoveButton() - ->setMinCopies(1) - ->setFormDefaults(self::$defaults) - ->createForm() - )->render(); - - $dom = $response->toDomQuery(); - $this->assertDomHas($dom, 'input[name="m[0][' . Multiplier::SUBMIT_REMOVE_NAME . ']"]'); - $this->assertDomHas($dom, 'input[name="m[1][' . Multiplier::SUBMIT_REMOVE_NAME . ']"]'); - } - - public function testDefaultValue() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, null) - ->addCreateButton() - ->addRemoveButton() - ->setMinCopies(1) - ->setFormDefaults(self::$defaults) - ->fields(['bar' => 'foo']) - ->createForm() - )->render(); - - $dom = $response->toDomQuery(); - $this->assertDomHas($dom, 'input[name="m[0][bar]"][value="foo"]'); - } - - public function testDefaultValueSend() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, null) - ->addCreateButton() - ->addRemoveButton() - ->setMinCopies(1) - ->setFormDefaults(self::$defaults) - ->fields(['bar' => 'foo']) - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => 'bar'], - Multiplier::SUBMIT_CREATE_NAME => '', - ], - ])->send(); - - $dom = $response->toDomQuery(); - $this->assertDomHas($dom, 'input[name="m[0][bar]"][value="bar"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"][value="foo"]'); - } - - public function testNestedMultiplier() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, null) - ->containerModifier(function (Container $container) { - $container['nested'] = new Multiplier(function (Container $container) { - $container->addText('foo'); - }); - }) - ->fields(['bar' => 'foo']) - ->setFormDefaults(self::$defaultNested) - ->createForm() - )->render(); - - $dom = $response->toDomQuery(); - $this->assertDomHas($dom, 'input[name="m[0][bar]"][value="foo1"]'); - $this->assertDomHas($dom, 'input[name="m[0][nested][0][foo]"][value="bar1"]'); - $this->assertDomHas($dom, 'input[name="m[0][nested][1][foo]"][value="bar2"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"][value="foo2"]'); - $this->assertDomHas($dom, 'input[name="m[1][nested][0][foo]"][value="bar3"]'); - $this->assertDomHas($dom, 'input[name="m[1][nested][1][foo]"][value="bar4"]'); - } - -} diff --git a/tests/unit/LatteTest.php b/tests/unit/LatteTest.php deleted file mode 100644 index 7eeb366..0000000 --- a/tests/unit/LatteTest.php +++ /dev/null @@ -1,53 +0,0 @@ -latte = $latte = new Engine(); - $latte->addExtension(new FormsExtension()); - $latte->addExtension(new MultiplierExtension()); - } - - public function testBtnCreate() - { - $presenter = new FooPresenter(); - $form = new NetteForm(); - $form['m'] = $m = new Multiplier(function (Container $container) { - $container->addText('foo'); - }); - $m->addCreateButton('Create one'); - $m->addCreateButton('Create two', 2); - $presenter['m'] = $form; - - $string = $this->latte->renderToString(__DIR__ . '/templates/macros.latte', ['form' => $form]); - $this->assertRegExp('#name="m\[multiplier_creator]"#', $string); - $this->assertRegExp('#name="m\[multiplier_creator2]"#', $string); - } - -} - -class FooPresenter extends Presenter -{ - - public function link(string $destination, $args = []): string - { - return ''; - } - -} diff --git a/tests/unit/MultiplierTest.php b/tests/unit/MultiplierTest.php deleted file mode 100644 index f6235f6..0000000 --- a/tests/unit/MultiplierTest.php +++ /dev/null @@ -1,392 +0,0 @@ - [], - ]; - - public function testRenderBase() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create() - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - )->render(); - - $this->assertDomHas($response->toDomQuery(), 'input[name="m[0][bar]"]'); - } - - public function testSendBase() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create() - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - ) - ->setPost($params = [ - 'm' => [ - ['bar' => 'foo'], - ], - ])->send(); - - $this->assertTrue($response->isSuccess()); - $this->assertSame($params, $response->getValues()); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"][value="foo"]'); - $this->assertDomNotHas($dom, 'input[name="m[1][bar]"]'); - } - - public function testRenderCopy2() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2) - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - )->render(); - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"]'); - } - - public function testSendCopy2() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2) - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - ) - ->setPost($params = [ - 'm' => [ - ['bar' => 'foo'], - ['bar' => 'bar'], - ], - ])->send(); - - $this->assertSame($params, $response->getValues()); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[1][bar]"]'); - $this->assertDomNotHas($dom, 'input[name="m[2][bar]"]'); - } - - public function testRenderMaxCopy() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, 1) - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - )->render(); - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomNotHas($dom, 'input[name="m[1][bar]"]'); - } - - public function testSendMaxCopy() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2, 1) - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - ) - ->setPost([ - 'm' => [ - ['bar' => 'foo'], - ['bar' => 'bar'], - ], - ])->send(); - - $this->assertSame([ - 'm' => [ - ['bar' => 'foo'], - ], - ], $response->getValues()); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomNotHas($dom, 'input[name="m[1][bar]"]'); - } - - public function testNested() - { - $request = $this->services->form->createRequest( - MultiplierBuilder::create() - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->containerModifier(function (Container $container) { - $container['m2'] = (new Multiplier(function (Container $container) { - $container->addText('bar2'); - })); - $container['m2']->addCreateButton('create'); - }) - ->createForm() - ); - - $dom = $request->render()->toDomQuery(); - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[0][m2][0][bar2]"]'); - $this->assertDomHas($dom, 'input[name="m[0][m2][' . Multiplier::SUBMIT_CREATE_NAME . ']"]'); - } - - public function testSendNested() - { - $request = $this->services->form->createRequest( - MultiplierBuilder::create() - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->containerModifier(function (Container $container) { - $container['m2'] = (new Multiplier(function (Container $container) { - $container->addText('bar2'); - })); - $container['m2']->addCreateButton('create'); - }) - ->createForm() - ); - $request->setPost([ - 'm' => [ - [ - 'bar' => 'foo', - 'm2' => [ - ['bar2' => 'xx'], - ], - ], - ['bar' => 'bar'], - Multiplier::SUBMIT_CREATE_NAME => '', - ], - ]); - - $send = $request->send(); - $dom = $send->toDomQuery(); - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input[name="m[0][m2][0][bar2]"]'); - - $this->assertSame([ - 'm' => [ - [ - 'bar' => 'foo', - 'm2' => [ - ['bar2' => 'xx'], - ], - ], - [ - 'bar' => 'bar', - 'm2' => [], - ], - [ - 'bar' => '', - 'm2' => [], - ], - ], - ], $send->getValues()); - } - - public function testGroup() - { - $request = $this->services->form->createRequest( - MultiplierBuilder::create() - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - ); - $dom = $request->render()->toDomQuery(); - $this->assertDomHas($dom, 'fieldset'); - $this->assertDomHas($dom, 'fieldset input[name="m[0][bar]"]'); - } - - public function testGroupManualRenderWithRemovedButtons() - { - $request = $this->services->form->createRequest( - MultiplierBuilder::create(2) - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - $multiplier->addCreateButton(); - $multiplier->addRemoveButton(); - }) - ->createForm() - ); - $dom = $request->render()->toDomQuery(); - - $this->assertDomNotHas($dom, 'input[name="m[0][multiplier_remover]"]'); - $this->assertDomNotHas($dom, 'input[name="m[1][multiplier_remover]"]'); - } - - public function testGroupManualRenderWithButtons() - { - $request = $this->services->form->createRequest(MultiplierBuilder::create(2) - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - $multiplier->addCreateButton(); - $multiplier->addRemoveButton(); - $multiplier->setMinCopies(1); - }) - ->createForm()); - $dom = $request->render(__DIR__ . '/templates/group.latte')->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][multiplier_remover]"]'); - $this->assertDomHas($dom, 'input[name="m[1][multiplier_remover]"]'); - } - - public function testOnCreateEvent() - { - $this->assertEmpty($this->parameters['onCreate']); - $request = $this->services->form->createRequest( - MultiplierBuilder::create() - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - )->modifyForm(function (Form $form) { - $form['m']->setValues([ - ['bar' => 'foo'], - ['bar' => 'foo2'], - ]); - }); - $request->render()->toString(); - - $this->assertNotEmpty($this->parameters['onCreate']); - $values = ['foo', 'foo2']; - foreach ($this->parameters['onCreate'] as $i => $parameter) { - $this->assertInstanceOf(Container::class, $parameter); - $this->assertSame($values[$i], $parameter['bar']->getValue()); - } - } - - public function testAddDynamic() - { - $request = $this->services->form->createRequest( - MultiplierBuilder::create() - ->beforeFormModifier(function (Form $form) { - $form->addGroup('testGroup'); - }) - ->multiplierModifier(function (Multiplier $multiplier) { - $multiplier->onCreate[] = function (Container $container) { - $this->parameters['onCreate'][] = $container; - }; - }) - ->createForm() - )->modifyForm(function (Form $form) { - $form['m']->onCreateComponents[] = function (Multiplier $multiplier) { - $multiplier->addCopy(99)['bar']->setHtmlAttribute('class', 'myClass'); - }; - }); - - $dom = $request->render()->toDomQuery(); - - $this->assertDomHas($dom, '[name="m[99][bar]"]'); - $this->assertDomHas($dom, 'input.myClass'); - } - - public function testPromptSelect() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create() - ->containerModifier(function (Container $container) { - $container->addSelect('select', null, ['foo' => 'foo']) - ->setPrompt('Select'); - }) - ->addCreateButton() - ->createForm() - ) - ->setPost($params = [ - 'm' => [ - ['select' => '', 'multiplier_creator' => ''], - ], - ])->send(); - - $this->assertTrue($response->isSuccess()); - - $dom = $response->toDomQuery(); - - } - -} diff --git a/tests/unit/RemoveButtonTest.php b/tests/unit/RemoveButtonTest.php deleted file mode 100644 index 17526f9..0000000 --- a/tests/unit/RemoveButtonTest.php +++ /dev/null @@ -1,255 +0,0 @@ -addSubmit('send'); - - return $form; - } - - protected function a_before() - { - $form = $this->services->form; - - $form->addForm('buttons', function ($copyNumber = 2, $maxCopies = null, $removeCallback = null) { - $form = $this->createMultiplier(function (Container $container) { - $container->addText('bar'); - }, $copyNumber, $maxCopies); - - /** @var Multiplier $multiplier */ - $multiplier = $form['m']; - - $multiplier->setMinCopies(1); - $btn = $multiplier->addRemoveButton(); - $multiplier->addCreateButton(); - - if (is_callable($removeCallback)) { - $removeCallback($btn); - } - - return $form; - }); - - $form->addForm('base', function ($copyNumber = 1, $maxCopies = null) { - $form = $this->createMultiplier(function (Container $container) { - $container->addText('bar'); - }, $copyNumber, $maxCopies); - - /** @var Multiplier $multiplier */ - $multiplier = $form['m']; - - $multiplier->addRemoveButton(); - $multiplier->addCreateButton(); - - return $form; - }); - - $form->addForm('2multipliers', function ($copyNumber = 2, $maxCopies = null) { - $form = $this->createMultiplier(function (Container $container) { - $container->addText('bar'); - }, $copyNumber, $maxCopies); - - $form['m2'] = new Multiplier(function (Container $container) { - $container->addText('bar2'); - }); - - /** @var Multiplier $multiplier */ - $multiplier = $form['m']; - - $multiplier->setMinCopies(1); - $multiplier->addRemoveButton(); - $multiplier->addCreateButton(); - - $form['m2']->addRemoveButton(); - $form['m2']->addCreateButton(); - - return $form; - }); - - } - - public function testSendRemove() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2) - ->setMinCopies(1) - ->addRemoveButton() - ->addCreateButton() - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => ''], - ['bar' => '', 'multiplier_remover' => ''], - ], - ])->send(); - - $dom = $response->toDomQuery(); - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomNotHas($dom, 'input[name="m[1][bar]"]'); - } - - public function testSendRemoveBelowMinCopies() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(1) - ->setMinCopies(1) - ->addRemoveButton() - ->addCreateButton() - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => '', 'multiplier_remover' => ''], - ], - ])->send(); - - $this->assertDomHas($response->toDomQuery(), 'input[name="m[0][bar]"]'); - } - - public function test2Multipliers() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(1) - ->setMinCopies(1) - ->addRemoveButton() - ->addCreateButton() - ->formModifier(function (Form $form) { - $form['m2'] = new Multiplier(function (Container $container) { - $container->addText('bar2'); - }); - - $form['m2']->addRemoveButton(); - $form['m2']->addCreateButton(); - }) - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => ''], - ], - 'm2' => [ - ['bar2' => ''], - Multiplier::SUBMIT_CREATE_NAME => '', - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m2[0][multiplier_remover]"]'); - $this->assertDomHas($dom, 'input[name="m2[1][multiplier_remover]"]'); - $this->assertDomNotHas($dom, 'input[name="m[0][multiplier_remover]"]'); - } - - public function testFormEvents() - { - $req = $this->services->form->createRequest( - MultiplierBuilder::create(2) - ->setMinCopies(1) - ->addRemoveButton() - ->addCreateButton() - ->formModifier(function (Form $form) { - $form->onSuccess[] = $form->onError[] = $form->onSubmit[] = function () { - $this->fail('Events called'); - }; - }) - ->createForm() - ); - $response = $req->setPost([ - 'm' => [ - ['bar' => ''], - ['bar' => '', 'multiplier_remover' => ''], - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomNotHas($dom, 'input[name="m[1][bar]"]'); - } - - public function testAddClass() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(2) - ->setMinCopies(1) - ->addRemoveButton(function (SubmitButton $submitter) { - $submitter->setHtmlAttribute('class', 'btn btn-remove'); - }) - ->addCreateButton() - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => ''], - ['bar' => ''], - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[0][bar]"]'); - $this->assertDomHas($dom, 'input.btn.btn-remove'); - } - - // bug #32 - public function testDeleteLastElementToZero() - { - $response = $this->services->form->createRequest( - MultiplierBuilder::create(1) - ->setMinCopies(0) - ->addRemoveButton() - ->addCreateButton() - ->createForm() - )->modifyForm(function (Form $form) { - $form['m']->setValues([ - ['bar' => 'foo'], - ]); - })->setPost([ - 'm' => [ - ['bar' => '', 'multiplier_remover' => ''], - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertDomHas($dom, 'input[name="m[multiplier_creator]"]'); - $this->assertDomNotHas($dom, 'input[name="m[0][bar]"]'); - } - - public function testOnRemoveEvent() - { - $called = false; - $response = $this->services->form->createRequest( - MultiplierBuilder::create() - ->setMinCopies(0) - ->addRemoveButton() - ->multiplierModifier(function (Multiplier $multiplier) use (&$called) { - $multiplier->onRemove[] = function () use (&$called) { - $called = true; - }; - }) - ->createForm() - )->setPost([ - 'm' => [ - ['bar' => '', 'multiplier_remover' => ''], - ], - ])->send(); - - $dom = $response->toDomQuery(); - - $this->assertTrue($called); - $this->assertDomNotHas($dom, 'input[name="m[0][bar]"]'); - } - -}