Не в состоянии протестировать предоставленный вывод после перенаправления от маршрута УДАЛИТЬ - Mojolicious

В настоящее время я расширяю свой набор тестов, чтобы увеличить охват тестами. Я хочу проверить мой контроллер и вывод html, который он отображает, но я обнаружил проблему в использовании методов удаления. Позвольте мне объяснить это на примере.

У меня есть маршрут:

$r->delete('/backups/:id')
  ->to('backup#delete_backup')
  ->name('backup_delete');

что указывает на следующую функцию в backup контроллер:

sub delete_backup {
    my $self       = shift;
    my $id         = $self->param('id');


    if ( something ) {
        $self->flash( msg => "Backup id $id deleted!" );
    }
    else{
        $self->flash( msg => "Cannot delete, backup id $id not found!" );   
    }
    $self->redirect_to($self->url_for('backup_index'));
}

где метод, который обрабатывает маршрут backup_index просто отображает $msg и показывает несколько других не относящихся к делу данных.

Далее я хочу протестировать этот метод, поэтому я пишу тест:

$t_logged_in->ua->max_redirects(3);
my $page = $t_logged_in->app->url_for( 'backup_delete', id => $backup_id );
$t_logged_in->delete_ok($page)
            ->status_isnt( 404, "Checking: 404 $page" )
            ->status_isnt( 500, "Checking: 500 $page" );

Тест пройден. Но теперь я хочу проверить правильность текста на веб-странице, которая отображается после перенаправления. Поэтому я делаю следующее:

$t_logged_in->ua->max_redirects(3);
my $page = $t_logged_in->app->url_for( 'backup_delete', id => $backup_id );
$t_logged_in->delete_ok($page)
            ->status_isnt( 404, "Checking: 404 $page" )
            ->status_isnt( 500, "Checking: 500 $page" )
            ->content_unlike(qr/Cannot delete,/i)
            ->content_like(qr/deleted/i);

Тест не пройден. Это терпит неудачу, потому что содержание пусто, таким образом, сопоставление сделано, как было:

'' =~ /deleted/i;
'' !~ /Cannot delete,/i;

и это, конечно, неверно в обоих случаях. Конечно, в браузере перенаправления работают отлично, и я вижу все, как задумано в тесте. Я могу изменить метод на POST или же GET но я хотел сделать маршрутизацию должным образом так, как будет разработан API.

Вопрос: как спроектировать тест таким образом, чтобы контент мог соответствовать после перенаправления?

Для тех, кто хочет копать глубже, я даю ссылки на Github.

1 ответ

Извините, никто еще не ответил на это. Раньше я старался внимательно следить за переполнением стека, но мне стало лень:-P. Это очень интересный вопрос.

Стандартные перенаправления (301/302) используют тот же глагол, что и исходный запрос, ЕСЛИ исходный запрос не был POST Интересно, что это поведение не было предназначено. Перенаправление должно использовать тот же метод запроса, что и оригинал, но POST->GET Перенаправление так часто предназначено, что большинство браузеров добавили такое поведение, даже если оно противоречило исходному определению. Однако некоторые люди действительно хотели POST оставаться POST и теперь это зависит от реализации. На самом деле это стало настолько плохо, что HTTP добавил статусы ответов 307/308, которые всегда перенаправляют как один и тот же HTTP-глагол (т.е. POST -> POST), даже думал, что это уже официальное поведение старых, но этот корабль уже отплыл. Это означает, что POST->GET, но DELETE->DELETE является дефактным поведением 301/302.

Это можно продемонстрировать на следующем вкладыше ($_ в этих однострочниках есть контроллер)

perl -Mojo -E 'del "/delete" => sub { $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete

DELETE /delete HTTP/1.1
Host: 127.0.0.1:62690
Accept-Encoding: gzip
User-Agent: Mojolicious (Perl)
Content-Length: 0

HTTP/1.1 302 Found
Date: Sun, 18 Sep 2016 03:25:58 GMT
Server: Mojolicious (Perl)
Location: /
Content-Length: 0

DELETE / HTTP/1.1
Content-Length: 0
User-Agent: Mojolicious (Perl)
Host: 127.0.0.1:62690
Accept-Encoding: gzip

HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 5
Date: Sun, 18 Sep 2016 03:25:58 GMT
Server: Mojolicious (Perl)

I got a DELETE

Вы можете видеть это, так как мой / Маршрут обрабатывает все методы, которые мы получаем ответ, однако запрос был DELETE, Я вижу, что в вашем приложении вы перенаправляете на другой именованный маршрут, URL которого также обрабатывает DELETE, Это источник вашего замешательства, так как вы на самом деле попадаете в свои тесты. Ваш редирект эффективно DELETE /backups/<<id>> -> DELETE /backups, если я правильно читаю ваш код.

Теперь в отличие от людей, которые хотели сохранить POST как POST, то, что вы хотите здесь, наоборот, вы хотите перенаправить с DELETE в GET потому что вы пытаетесь показать ответ, который не является исходным ресурсом. Это определенное поведение малоизвестного ответа 303, в котором любой метод запроса перенаправляется на GET, Действительно, именно на этом должны были настаивать ранние браузеры, а не ломать 302.

В следующем примере я явно изменяю код ответа на 303.

$ perl -Mojo -E 'del "/delete" => sub { $_->res->code(303); $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete
DELETE /delete HTTP/1.1
User-Agent: Mojolicious (Perl)
Host: 127.0.0.1:62716
Accept-Encoding: gzip
Content-Length: 0

HTTP/1.1 303 See Other
Location: /
Content-Length: 0
Server: Mojolicious (Perl)
Date: Sun, 18 Sep 2016 03:27:19 GMT

DELETE / HTTP/1.1
User-Agent: Mojolicious (Perl)
Accept-Encoding: gzip
Content-Length: 0
Host: 127.0.0.1:62716

HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Server: Mojolicious (Perl)
Content-Length: 5
Date: Sun, 18 Sep 2016 03:27:19 GMT

I got a DELETE

Но упс, это все еще DELETE! Это связано с тем, что в Mojo::UserAgent была ошибка, из- за которой он неправильно обрабатывал 303. Я бы посоветовал вам по-прежнему вносить изменения в свой код, поскольку браузеры, похоже, правильно обрабатывают 303-е. Однако, так как Mojo::UserAgent поддерживает Test::Mojo, ваши тесты еще не могут проверить это поведение. После исправления вы увидите, что он работает правильно, как мой пример в моей локальной ветке:

$ perl -Ilib -Mojo -E 'del "/delete" => sub { $_->res->code(303); $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete
DELETE /delete HTTP/1.1                                                                  
Content-Length: 0                                                                        
User-Agent: Mojolicious (Perl)                                                           
Host: 127.0.0.1:64924                                                                    
Accept-Encoding: gzip                                                                    

HTTP/1.1 303 See Other                                                                   
Date: Sun, 18 Sep 2016 04:59:37 GMT                                                      
Location: /                                                                              
Server: Mojolicious (Perl)                                                               
Content-Length: 0                                                                        

GET / HTTP/1.1                                                                           
Content-Length: 0                                                                        
User-Agent: Mojolicious (Perl)                                                           
Host: 127.0.0.1:64924                                                                    
Accept-Encoding: gzip                                                                    

HTTP/1.1 200 OK                                                                          
Date: Sun, 18 Sep 2016 04:59:37 GMT                                                      
Content-Type: text/html;charset=UTF-8                                                    
Server: Mojolicious (Perl)                                                               
Content-Length: 12                                                                       

I got a GET

Чтобы узнать больше о типах ответов перенаправления, см. https://en.wikipedia.org/wiki/List_of_HTTP_status_codes.

Другие вопросы по тегам