From 9f30bb4ef15fbaa95d4e1189161753d1e12ec501 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 2 Dec 2022 16:44:06 -0500 Subject: [PATCH 1/9] initial text and toggle tests --- tests/Tags/Concerns/RendersFormsTest.php | 118 +++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/tests/Tags/Concerns/RendersFormsTest.php b/tests/Tags/Concerns/RendersFormsTest.php index fc17195ee0f..1bdfd692c28 100644 --- a/tests/Tags/Concerns/RendersFormsTest.php +++ b/tests/Tags/Concerns/RendersFormsTest.php @@ -3,12 +3,15 @@ namespace Tests\Tags\Concerns; use Statamic\Facades\Antlers; +use Statamic\Fields\Field; use Statamic\Tags\Concerns; use Statamic\Tags\Tags; use Tests\TestCase; class RendersFormsTest extends TestCase { + const MISSING = 'field is missing from request'; + public function setUp(): void { parent::setUp(); @@ -89,6 +92,121 @@ public function it_minifies_space_between_field_html_elements() $this->assertEquals($expected, $this->tag->minifyFieldHtml($fields)); } + + /** + * @test + * @dataProvider renderTextProvider + */ + public function renders_text_fields($value, $default, $old, $expected) + { + $config = ['type' => 'text']; + + if ($default) { + $config['default'] = $default; + } + + $field = new Field('test', $config); + $field->setValue($value); + + if ($old !== self::MISSING) { + session()->flashInput(['test' => $old]); + $this->get('/'); // create a request so the session works. + } + + $rendered = $this->tag->getRenderableField($field); + + $this->assertSame($expected, $rendered['value']); + $this->assertStringContainsString('value="'.$rendered['value'].'"', $rendered['field']); + } + + public function renderTextProvider() + { + return [ + 'no value, missing' => ['value' => null, 'default' => null, 'old' => self::MISSING, 'expectedValue' => null], + 'no value, filled' => ['value' => null, 'default' => null, 'old' => 'old', 'expectedValue' => 'old'], + 'no value, empty' => ['value' => null, 'default' => null, 'old' => null, 'expectedValue' => null], + + 'value, missing' => ['value' => 'existing', 'default' => null, 'old' => self::MISSING, 'expectedValue' => 'existing'], + 'value, filled' => ['value' => 'existing', 'default' => null, 'old' => 'old', 'expectedValue' => 'old'], + 'value, empty' => ['value' => 'existing', 'default' => null, 'old' => null, 'expectedValue' => null], + + 'no value, default, missing' => ['value' => null, 'default' => 'default', 'old' => self::MISSING, 'expectedValue' => 'default'], + 'no value, default, filled' => ['value' => null, 'default' => 'default', 'old' => 'old', 'expectedValue' => 'old'], + 'no value, default, empty' => ['value' => null, 'default' => 'default', 'old' => null, 'expectedValue' => null], + + 'value, default, missing' => ['value' => 'existing', 'default' => 'default', 'old' => self::MISSING, 'expectedValue' => 'existing'], + 'value, default, filled' => ['value' => 'existing', 'default' => 'default', 'old' => 'old', 'expectedValue' => 'old'], + 'value, default, empty' => ['value' => 'existing', 'default' => 'default', 'old' => null, 'expectedValue' => null], + ]; + } + + /** + * @test + * @dataProvider renderToggleProvider + */ + public function renders_toggles($value, $default, $old, $expected) + { + $config = ['type' => 'toggle']; + + if ($default) { + $config['default'] = $default; + } + + $field = new Field('test', $config); + $field->setValue($value); + + if ($old !== self::MISSING) { + session()->flashInput(['test' => $old]); + $this->get('/'); // create a request so the session works. + } + + $rendered = $this->tag->getRenderableField($field); + + $this->assertSame($expected, (bool) $rendered['value']); + + if ($expected) { + $this->assertStringContainsString('checked', $rendered['field']); + } else { + $this->assertStringNotContainsString('checked', $rendered['field']); + } + } + + public function renderToggleProvider() + { + return [ + 'no value, missing' => ['value' => null, 'default' => null, 'old' => self::MISSING, 'expectedValue' => false], + 'no value, checked' => ['value' => null, 'default' => null, 'old' => '1', 'expectedValue' => true], + 'no value, unchecked' => ['value' => null, 'default' => null, 'old' => '0', 'expectedValue' => false], + + 'value true, missing' => ['value' => true, 'default' => null, 'old' => self::MISSING, 'expectedValue' => true], + 'value true, checked' => ['value' => true, 'default' => null, 'old' => '1', 'expectedValue' => true], + 'value true, unchecked' => ['value' => true, 'default' => null, 'old' => '0', 'expectedValue' => false], + + 'value false, missing' => ['value' => false, 'default' => null, 'old' => self::MISSING, 'expectedValue' => false], + 'value false, checked' => ['value' => false, 'default' => null, 'old' => '1', 'expectedValue' => true], + 'value false, unchecked' => ['value' => false, 'default' => null, 'old' => '0', 'expectedValue' => false], + + 'no value, default true, missing' => ['value' => null, 'default' => true, 'old' => self::MISSING, 'expectedValue' => true], + 'no value, default true, checked' => ['value' => null, 'default' => true, 'old' => '1', 'expectedValue' => true], + 'no value, default true, unchecked' => ['value' => null, 'default' => true, 'old' => '0', 'expectedValue' => false], + + 'no value, default false, missing' => ['value' => null, 'default' => false, 'old' => self::MISSING, 'expectedValue' => false], + 'no value, default false, checked' => ['value' => null, 'default' => false, 'old' => '1', 'expectedValue' => true], + 'no value, default false, unchecked' => ['value' => null, 'default' => false, 'old' => '0', 'expectedValue' => false], + + 'value true, default true, missing' => ['value' => true, 'default' => true, 'old' => self::MISSING, 'expectedValue' => true], + 'value true, default true, checked' => ['value' => true, 'default' => true, 'old' => '1', 'expectedValue' => true], + 'value true, default true, unchecked' => ['value' => true, 'default' => true, 'old' => '0', 'expectedValue' => false], + + 'value true, default false, missing' => ['value' => true, 'default' => false, 'old' => self::MISSING, 'expectedValue' => true], + 'value true, default false, checked' => ['value' => true, 'default' => false, 'old' => '1', 'expectedValue' => true], + 'value true, default false, unchecked' => ['value' => true, 'default' => false, 'old' => '0', 'expectedValue' => false], + + 'value false, default true, missing' => ['value' => false, 'default' => true, 'old' => self::MISSING, 'expectedValue' => false], + 'value false, default true, checked' => ['value' => false, 'default' => true, 'old' => '1', 'expectedValue' => true], + 'value false, default true, unchecked' => ['value' => false, 'default' => true, 'old' => '0', 'expectedValue' => false], + ]; + } } class FakeTagWithRendersForms extends Tags From 923dd588ceaf9a8f62135a3d1b681b5ec7892a02 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 2 Dec 2022 17:08:24 -0500 Subject: [PATCH 2/9] extract --- tests/Tags/Concerns/RendersFormsTest.php | 35 +++++++++--------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/tests/Tags/Concerns/RendersFormsTest.php b/tests/Tags/Concerns/RendersFormsTest.php index 1bdfd692c28..3474d71c1b0 100644 --- a/tests/Tags/Concerns/RendersFormsTest.php +++ b/tests/Tags/Concerns/RendersFormsTest.php @@ -93,13 +93,9 @@ public function it_minifies_space_between_field_html_elements() $this->assertEquals($expected, $this->tag->minifyFieldHtml($fields)); } - /** - * @test - * @dataProvider renderTextProvider - */ - public function renders_text_fields($value, $default, $old, $expected) + private function createField($type, $value, $default, $old) { - $config = ['type' => 'text']; + $config = ['type' => $type]; if ($default) { $config['default'] = $default; @@ -113,7 +109,16 @@ public function renders_text_fields($value, $default, $old, $expected) $this->get('/'); // create a request so the session works. } - $rendered = $this->tag->getRenderableField($field); + return $this->tag->getRenderableField($field); + } + + /** + * @test + * @dataProvider renderTextProvider + */ + public function renders_text_fields($value, $default, $old, $expected) + { + $rendered = $this->createField('text', $value, $default, $old); $this->assertSame($expected, $rendered['value']); $this->assertStringContainsString('value="'.$rendered['value'].'"', $rendered['field']); @@ -146,21 +151,7 @@ public function renderTextProvider() */ public function renders_toggles($value, $default, $old, $expected) { - $config = ['type' => 'toggle']; - - if ($default) { - $config['default'] = $default; - } - - $field = new Field('test', $config); - $field->setValue($value); - - if ($old !== self::MISSING) { - session()->flashInput(['test' => $old]); - $this->get('/'); // create a request so the session works. - } - - $rendered = $this->tag->getRenderableField($field); + $rendered = $this->createField('toggle', $value, $default, $old); $this->assertSame($expected, (bool) $rendered['value']); From d07102f0e25d9341d4e86cc4b0aad45fff6f5f7f Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 8 Dec 2022 13:14:48 -0500 Subject: [PATCH 3/9] tests for more fieldtypes --- tests/Tags/Concerns/RendersFormsTest.php | 201 ++++++++++++++++++++++- 1 file changed, 198 insertions(+), 3 deletions(-) diff --git a/tests/Tags/Concerns/RendersFormsTest.php b/tests/Tags/Concerns/RendersFormsTest.php index 3474d71c1b0..0354ee8c9cc 100644 --- a/tests/Tags/Concerns/RendersFormsTest.php +++ b/tests/Tags/Concerns/RendersFormsTest.php @@ -4,6 +4,7 @@ use Statamic\Facades\Antlers; use Statamic\Fields\Field; +use Statamic\Support\Arr; use Statamic\Tags\Concerns; use Statamic\Tags\Tags; use Tests\TestCase; @@ -93,9 +94,9 @@ public function it_minifies_space_between_field_html_elements() $this->assertEquals($expected, $this->tag->minifyFieldHtml($fields)); } - private function createField($type, $value, $default, $old) + private function createField($type, $value, $default, $old, $config = []) { - $config = ['type' => $type]; + $config = array_merge($config, ['type' => $type]); if ($default) { $config['default'] = $default; @@ -118,12 +119,43 @@ private function createField($type, $value, $default, $old) */ public function renders_text_fields($value, $default, $old, $expected) { - $rendered = $this->createField('text', $value, $default, $old); + $this->textFieldtypeTest('text', $value, $default, $old, $expected); + } + + private function textFieldtypeTest($fieldtype, $value, $default, $old, $expected) + { + $rendered = $this->createField($fieldtype, $value, $default, $old); $this->assertSame($expected, $rendered['value']); $this->assertStringContainsString('value="'.$rendered['value'].'"', $rendered['field']); } + /** + * @test + * @dataProvider renderTextProvider + */ + public function renders_fallback_fields_as_text_fields($value, $default, $old, $expected) + { + (new class extends \Statamic\Fields\Fieldtype + { + protected static $handle = 'testing'; + })::register(); + + $this->textFieldtypeTest('testing', $value, $default, $old, $expected); + } + + /** + * @test + * @dataProvider renderTextProvider + */ + public function renders_textarea_fields($value, $default, $old, $expected) + { + $rendered = $this->createField('textarea', $value, $default, $old); + + $this->assertSame($expected, $rendered['value']); + $this->assertStringContainsString('>'.$rendered['value'].' ['value' => false, 'default' => true, 'old' => '0', 'expectedValue' => false], ]; } + + /** + * @test + * @dataProvider renderSingleSelectProvider + */ + public function renders_single_select_fields($value, $default, $old, $expected) + { + $rendered = $this->createField('select', $value, $default, $old, [ + 'options' => $options = [ + 'alfa' => 'Alfa', + 'bravo' => 'Bravo', + 'charlie' => 'Charlie', + ], + ]); + + $this->assertStringContainsString('name="test"', $rendered['field']); + $this->assertStringNotContainsString('multiple', $rendered['field']); + + if ($expected) { + $unexpected = array_keys(Arr::except($options, $expected)); + $this->assertStringContainsString('value="'.$expected.'" selected', $rendered['field']); + foreach ($unexpected as $e) { + $this->assertStringNotContainsString('value="'.$e.'" selected', $rendered['field']); + } + } else { + $this->assertStringNotContainsString('selected', $rendered['field']); + } + } + + /** + * @test + * @dataProvider renderSingleSelectProvider + */ + public function renders_radio_fields($value, $default, $old, $expected) + { + $rendered = $this->createField('radio', $value, $default, $old, [ + 'options' => $options = [ + 'alfa' => 'Alfa', + 'bravo' => 'Bravo', + 'charlie' => 'Charlie', + ], + ]); + + if ($expected) { + $unexpected = array_keys(Arr::except($options, $expected)); + $this->assertTrue( + (bool) preg_match('/value="'.$expected.'"\s+checked/', $rendered['field']), + 'The "'.$expected.'" radio button was not checked within '.$rendered['field'], + ); + foreach ($unexpected as $e) { + $this->assertFalse( + (bool) preg_match('/value="'.$e.'"\s+checked/', $rendered['field']), + 'The "'.$expected.'" radio button was checked within '.$rendered['field'], + ); + } + } else { + $this->assertStringNotContainsString('checked', $rendered['field'], 'No radio button should be checked within '.$rendered['field']); + } + } + + public function renderSingleSelectProvider() + { + return [ + 'no value, no default, missing' => ['value' => null, 'default' => null, 'old' => self::MISSING, 'expectedValue' => null], + 'no value, no default, selected' => ['value' => null, 'default' => null, 'old' => 'bravo', 'expectedValue' => 'bravo'], + + 'value, no default, missing' => ['value' => 'alfa', 'default' => null, 'old' => self::MISSING, 'expectedValue' => 'alfa'], + 'value, no default, selected' => ['value' => 'alfa', 'default' => null, 'old' => 'bravo', 'expectedValue' => 'bravo'], + + 'no value, default, missing' => ['value' => null, 'default' => 'alfa', 'old' => self::MISSING, 'expectedValue' => 'alfa'], + 'no value, default, selected' => ['value' => null, 'default' => 'alfa', 'old' => 'bravo', 'expectedValue' => 'bravo'], + + 'value, default, missing' => ['value' => 'alfa', 'default' => 'bravo', 'old' => self::MISSING, 'expectedValue' => 'alfa'], + 'value, default, selected' => ['value' => 'alfa', 'default' => 'bravo', 'old' => 'charlie', 'expectedValue' => 'charlie'], + ]; + } + + /** + * @test + * @dataProvider renderMultipleSelectProvider + */ + public function renders_multiple_select_fields($value, $default, $old, $expected) + { + $rendered = $this->createField('select', $value, $default, $old, [ + 'multiple' => true, + 'options' => $options = [ + 'alfa' => 'Alfa', + 'bravo' => 'Bravo', + 'charlie' => 'Charlie', + 'delta' => 'Delta', + ], + ]); + + $this->assertStringContainsString('name="test[]"', $rendered['field']); + $this->assertStringContainsString('multiple', $rendered['field']); + + if ($expected) { + $unexpected = array_diff(array_keys($options), $expected); + foreach ($expected as $e) { + $this->assertStringContainsString('value="'.$e.'" selected', $rendered['field']); + } + foreach ($unexpected as $e) { + $this->assertStringNotContainsString('value="'.$e.'" selected', $rendered['field']); + } + } else { + $this->assertStringNotContainsString('selected', $rendered['field']); + } + } + + /** + * @test + * @dataProvider renderMultipleSelectProvider + */ + public function renders_checkboxes_fields($value, $default, $old, $expected) + { + $rendered = $this->createField('checkboxes', $value, $default, $old, [ + 'options' => $options = [ + 'alfa' => 'Alfa', + 'bravo' => 'Bravo', + 'charlie' => 'Charlie', + 'delta' => 'Delta', + ], + ]); + + if ($expected) { + $unexpected = array_diff(array_keys($options), $expected); + foreach ($expected as $e) { + $this->assertTrue( + (bool) preg_match('/value="'.$e.'"\s+checked/', $rendered['field']), + 'The "'.$e.'" box was not checked within '.$rendered['field'], + ); + } + foreach ($unexpected as $e) { + $this->assertFalse( + (bool) preg_match('/value="'.$e.'"\s+checked/', $rendered['field']), + 'The "'.$e.'" box was checked within '.$rendered['field'], + ); + } + } else { + $this->assertStringNotContainsString('checked', $rendered['field'], 'No boxes should be checked within '.$rendered['field']); + } + } + + public function renderMultipleSelectProvider() + { + return [ + 'no value, no default, missing' => ['value' => null, 'default' => null, 'old' => self::MISSING, 'expectedValue' => null], + 'no value, no default, selected' => ['value' => null, 'default' => null, 'old' => ['alfa'], 'expectedValue' => ['alfa']], + 'no value, no default, selected multiple' => ['value' => null, 'default' => null, 'old' => ['alfa', 'bravo'], 'expectedValue' => ['alfa', 'bravo']], + + 'value, no default, missing' => ['value' => ['alfa'], 'default' => null, 'old' => self::MISSING, 'expectedValue' => ['alfa']], + 'value, no default, selected' => ['value' => ['alfa'], 'default' => null, 'old' => ['bravo'], 'expectedValue' => ['bravo']], + 'value, no default, selected multiple' => ['value' => ['alfa'], 'default' => null, 'old' => ['bravo', 'charlie'], 'expectedValue' => ['bravo', 'charlie']], + + 'no value, default, missing' => ['value' => null, 'default' => ['alfa'], 'old' => self::MISSING, 'expectedValue' => ['alfa']], + 'no value, default, selected' => ['value' => null, 'default' => ['alfa'], 'old' => ['bravo'], 'expectedValue' => ['bravo']], + 'no value, default, selected multiple' => ['value' => null, 'default' => ['alfa'], 'old' => ['bravo', 'charlie'], 'expectedValue' => ['bravo', 'charlie']], + + 'value, default, missing' => ['value' => ['alfa'], 'default' => ['bravo'], 'old' => self::MISSING, 'expectedValue' => ['alfa']], + 'value, default, selected' => ['value' => ['alfa'], 'default' => ['bravo'], 'old' => ['charlie'], 'expectedValue' => ['charlie']], + 'value, default, selected multiple' => ['value' => ['alfa'], 'default' => ['bravo'], 'old' => ['charlie', 'delta'], 'expectedValue' => ['charlie', 'delta']], + ]; + } } class FakeTagWithRendersForms extends Tags From 8efceab32faf54c227e408501f37d4b8ed60c4b2 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 8 Dec 2022 13:17:00 -0500 Subject: [PATCH 4/9] implement --- .../views/extend/forms/fields/checkboxes.antlers.html | 9 ++++----- resources/views/extend/forms/fields/default.antlers.html | 4 ++-- resources/views/extend/forms/fields/radio.antlers.html | 9 ++++----- resources/views/extend/forms/fields/select.antlers.html | 6 ++---- resources/views/extend/forms/fields/text.antlers.html | 2 +- .../views/extend/forms/fields/textarea.antlers.html | 2 +- resources/views/extend/forms/fields/toggle.antlers.html | 2 +- src/Tags/Concerns/RendersForms.php | 7 +++++++ 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/resources/views/extend/forms/fields/checkboxes.antlers.html b/resources/views/extend/forms/fields/checkboxes.antlers.html index 5864bdb2893..909a9e76ccf 100644 --- a/resources/views/extend/forms/fields/checkboxes.antlers.html +++ b/resources/views/extend/forms/fields/checkboxes.antlers.html @@ -1,15 +1,14 @@ -{{ foreach:options as="value|label" }} +{{ foreach:options as="option|label" }} {{ unless inline }}
diff --git a/resources/views/extend/forms/fields/default.antlers.html b/resources/views/extend/forms/fields/default.antlers.html index dc01262b2af..44c28b9ba00 100644 --- a/resources/views/extend/forms/fields/default.antlers.html +++ b/resources/views/extend/forms/fields/default.antlers.html @@ -1,7 +1,7 @@ - {{ label !== null ? label : value }} + {{ label !== null ? label : option }} {{ unless inline }}
diff --git a/resources/views/extend/forms/fields/select.antlers.html b/resources/views/extend/forms/fields/select.antlers.html index 4fa8cc2f022..0c4a566e248 100644 --- a/resources/views/extend/forms/fields/select.antlers.html +++ b/resources/views/extend/forms/fields/select.antlers.html @@ -13,9 +13,7 @@ {{ /if }} {{ /unless }} - {{ foreach:options as="value|label" }} - + {{ foreach:options as="option|label" }} +