Skip to content

[LiveComponent] Add a new helper to interact with forms in functional tests #1992

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/LiveComponent/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# CHANGELOG

- Add `submitForm()` to `TestLiveComponent`.

## 2.18.0

- Add parameter to `TestLiveComponent::call()` to add files to the request
Expand Down
6 changes: 5 additions & 1 deletion src/LiveComponent/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3659,7 +3659,7 @@ uses Symfony's test client to render and make requests to your components::

// call live action with file uploads
$testComponent
->save('processUpload', files: ['file' => new UploadedFile(...)]);
->call('processUpload', files: ['file' => new UploadedFile(...)]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted!


// emit live events
$testComponent
Expand All @@ -3672,6 +3672,10 @@ uses Symfony's test client to render and make requests to your components::
->set('count', 99)
;

// Submit form data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should create an entire block "Test LiveComponent with Forms" (or something like that), wdyt ?

If "no", i think some comment to precise what is "form" and "save" here could avoid some missunderstandings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As Test helper is only one block, I didn't want to change that. But I understand that my array is a bit confusing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep as it is..

Who knows, mabe if you add other nice helpers... we will be forced to add a dedicated block ? :))

$testComponent
->submitForm(['form' => ['input' => 'value']], 'save');

$this->assertStringContainsString('Count: 99', $testComponent->render());

// refresh the component
Expand Down
22 changes: 22 additions & 0 deletions src/LiveComponent/src/Test/TestLiveComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ public function response(): Response
return $this->client()->getResponse();
}

public function submitForm(array $formValues, ?string $action = null): self
{
$flattenValues = $this->flattenFormValues($formValues);

return $this->request(['updated' => $flattenValues, 'validatedFields' => array_keys($flattenValues)], $action);
}

private function request(array $content = [], ?string $action = null, array $files = []): self
{
$csrfToken = $this->csrfToken();
Expand Down Expand Up @@ -205,4 +212,19 @@ private function client(): KernelBrowser

return $this->client;
}

private function flattenFormValues(array $values, string $prefix = ''): array
{
$result = [];

foreach ($values as $key => $value) {
if (\is_array($value)) {
$result += $this->flattenFormValues($value, $prefix.$key.'.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No difference array_is_list / map ? (geniune question)

Does this work with fields accepting multiple values ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know how to use array_is_list here. With array_map I can't handle keys.

Yes, I was a little undecided to not add a test for that method. At first I've thinked to add a public static method in Symfony\UX\LiveComponent\Util\LiveFormUtility which could be easily tested. But I don't know if it make sence as it will be created only for test purpose.

But this will work.

    public function testFlatten(): void
    {
        $data = [
            'foo' => ['bar' => 'baz'],
            'collection' => ['one', 'two', 'three'],
            'collection_with_sub' => [
                'sub_one' => ['child_one', 'child_two'],
                'sub_two' => ['child_three', 'key' => 'child_four'],
            ],
        ];

        $this->assertSame([
            'foo.bar' => 'baz',
            'collection.0' => 'one',
            'collection.1' => 'two',
            'collection.2' => 'three',
            'collection_with_sub.sub_one.0' => 'child_one',
            'collection_with_sub.sub_one.1' => 'child_two',
            'collection_with_sub.sub_two.0' => 'child_three',
            'collection_with_sub.sub_two.key' => 'child_four',
        ], TestLiveComponent::flattenFormValues($data));
    }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good for me then, thank you for taking time to answer :)

} else {
$result[$prefix.$key] = $value;
}
}

return $result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,14 @@ public function testActingAs(): void

$this->assertStringContainsString('Username: kevin', $testComponent->render());
}

public function testCanSubmitForm(): void
{
$testComponent = $this->createLiveComponent('form_with_many_different_fields_type');

$response = $testComponent->submitForm(['form' => ['text' => 'foobar']])->response();

$this->assertSame(200, $response->getStatusCode());
$this->assertStringContainsString('foobar', $testComponent->render());
}
}