Sinnbeck's avatar
Level 102

Working on new package. Needs feedback

I am working on a new package for asserting the structure in a response (in testing).

The API currently looks something like this (Might change heavily in the future!)

    $this->get('form')
        ->assertForm(function (FormAssert $form) {
            $form->hasAction('/form')
                ->hasMethod('post')
                ->hasInput([
                    'name'  => 'first_name',
                    'type'  => 'text',
                    'value' => 'Foo',
                ])
                ->hasInput([
                    'name'  => 'tags[]',
                    'type'  => 'text',
                    'value' => 'Happy',
                ])
                ->hasInput([
                    'name'  => 'tags[]',
                    'type'  => 'text',
                    'value' => 'Buys cheese',
                ]);
        }, 1)
        ->assertOk();

Now imaging you have multiple forms on the same page. How would you prefer to define which one? Currently it is the second argument of ->assertForm() and is the 0 based index of the form on the page (So the second form on the page).

Would a css selector be better? Or should I find some way to just check every single form on page for a match (that might make it hard to say exactly what wasn't found)

Any ideas or suggestions?

0 likes
13 replies
kokoshneta's avatar

A zero-based index requires that the forms always appear on the page in exactly the order you’re asserting for. If you move the forms around on the page, you’ll have to rewrite your assertion code as well. For that reason alone, I would not personally go for that. An ID attribute is unique and would be more flexible. It’s also more telling – it’s more obvious what you’re asserting if you pass hasNameTypeValueInputs than 23 as a parameter.

You could also use class attributes – that would give you the advantage that you could assert multiple forms by the same set of rules simply by adding appropriate classes to the form elements.

If you wanted to get really fancy, you could add a third (optional) argument detailing what type the second argument is: ID attribute (default, I would suggest), zero-based index or class attribute.

1 like
Sinnbeck's avatar
Level 102

@kokoshneta Thanks for the feedback!

I have concidered a bit of laravel magic.

Something like

return function (Closure $callback, $selector = null): TestResponse {
    if (is_null($selector)) {
        $selector = 0;
    }
    if (is_int($selector)) {
        //get by type and index
    } elseif (is_string($selector)) {
        //get by css selector
    } else {
        throw new \Exception('NO!');
    }
kokoshneta's avatar
Level 27

@Sinnbeck I considered that too – that would work if you just had a choice between zero-based and one specific type of CSS selector, but CSS selectors could be so many things.

Unless of course you meant for the selector to be a full CSS selector string? So you might pass something like .main-content .left-column > #updateForm:first-of-type and it would then resolve the element based on that whole selector? That would be even more flexible, of course.

1 like
Sinnbeck's avatar
Level 102

@kokoshneta laravel actually ships with symfonys css to XPath tool for some reason, so I have already written a prototype that takes any css selector and gets it from the dom

So yes that would be entirely possible

Tray2's avatar

Looks good, as I said before I prefer giving an id to the form, but a class would work as well. The nth would like @kokoshneta mentioned prevent moving the forms around the page.

1 like
MohamedTammam's avatar

I would rather to have a query select like syntax

For example

#my-form
.my-form-class
form[data-tested-form]
...etc

And for every select you get the first matched one. and for forms it should be only one.

1 like
Sinnbeck's avatar
Level 102

@MohamedTammam yeah so a css selector right? I have a prototype of that working. Think I might go forward with that. Thanks!

2 likes

Please or to participate in this conversation.