在Laravel 5中单元测试JavaScript的推荐方式是什么?

6

是否有推荐的方法在Laravel 5中对JavaScript进行单元测试?我正在使用jQuery框架来完成搜索自动完成任务(以下是代码)。有很多if块,我想要测试它们,但是我不确定如何最好地在Laravel 5中测试所有内容。任何帮助都将不胜感激。

<script type="text/javascript">
    (function($) {
        var autocomplete_timer;
        var ajax_request;
        var autocomplete_delay = 50;
        var search_keyword = "";
        var max_result_count = 5;
        var autocomplete_results = $('#autocomplete-results');
        var autocomplete_results_list;
        var default_report_url = '{{ route('report_summary_date_range_filter') }}';
        var selected_autocomplete_item_index = 0;
        var active_li = false;
        var autocomplete_error = $('#autocomplete-error');
        var redirect_state = false; //

        $(document).ready(function () {
            autocomplete_results_list = autocomplete_results.children('ul');

            // Search Autocomplete
            $("#search").keyup(function (e) {
                search_keyword = $(this).val();

                // If there is an existing XHR, abort it.
                if (ajax_request) {
                    ajax_request.abort()
                }

                // Enable list iteration via keyboard
                if (e.keyCode == 40 || e.keyCode == 38) {
                    ajax_request.abort();
                    var results_count = autocomplete_results_list.children('li').length;
                    if (e.keyCode == 40 && selected_autocomplete_item_index < results_count && active_li != false) {
                        selected_autocomplete_item_index++;
                    } else if (e.keyCode == 38 && selected_autocomplete_item_index > 0 && active_li != false) {
                        selected_autocomplete_item_index--;
                    }

                    active_li = autocomplete_results_list.children('li:eq(' + selected_autocomplete_item_index + ')');
                    if (active_li.length > 0) {
                        active_li.addClass('active');
                        autocomplete_results_list.children('li').not(active_li).removeClass('active');
                        $('#search').val(active_li.children('.autocomplete-ticker').text());
                    }

                    e.preventDefault();
                    return false;
                }

                // Clear the timer so we don't end up with dupes.
                clearTimeout(autocomplete_timer);

                // don't trigger ajax if user pressed enter/return key
                // while a redirect is triggered
                if (e.keyCode == 13 && redirect_state == true) {
                    return false;
                }

                if (search_keyword != '') {
                    // reset the index
                    selected_autocomplete_item_index = 0;
                    active_li = false;

                    // assign timer a new timeout
                    autocomplete_timer = setTimeout(function() {
                        ajax_request = $.ajax({
                            type: 'POST',
                            url: '/ajax/company/search/' + search_keyword,
                            data: {'_token': '{{ csrf_token() }}'},
                            success: function(response) {
                                if (response.count != 0) {
                                    autocomplete_results.show();
                                    autocomplete_results_list.empty();
                                    autocomplete_error.hide();

                                    var current_results = ((response.count > max_result_count) ? max_result_count : response.count);
                                    for (var index = 0; index < current_results; index++) {
                                        autocomplete_results_list.append(
                                                '<li>' +
                                                '<span class="autocomplete-ticker">' + response.results[index].ticker + '</span>' +
                                                '<span class="autocomplete-company">' + response.results[index].name + '</span>' +
                                                '</li>'
                                        );
                                    }
                                } else {
                                    autocomplete_results_list.empty();
                                    autocomplete_results.show();
                                    autocomplete_error.show();
                                }
                            }
                        });
                    }, autocomplete_delay);
                } else {
                    autocomplete_results.hide();
                    autocomplete_results_list.empty();
                }
            }).keydown(function (e) {
                // prevent moving cursor to start of input field
                // if the user presses the up arrow key
                if (e.keyCode == 38) {
                    e.preventDefault();
                }
            });

            // handle user clicking of an autocomplete item
            autocomplete_results_list.on('click', 'li', function () {
                var ticker = $(this).children('.autocomplete-ticker').text();
                $('#search').val(ticker);
                default_report_url = default_report_url.replace('%7Bticker%7D', ticker);

                // redirect
                $(location).attr('href', default_report_url);
                redirect_state = true;
            });

            // if the user presses the return key while an autocomplete list
            // is present, select the first item on the list and trigger a redirect
            $('#searchbar form').submit(function (e) {
                if ($('#search').val() != '') {
                    if (autocomplete_results_list.has('li').length > 0) {
                        autocomplete_results_list.children('li').first().addClass('active');
                        var ticker = autocomplete_results_list.children('li').first()
                                .children('.autocomplete-ticker').text().toUpperCase();

                        if (ticker != '') {
                            default_report_url = default_report_url.replace('%7Bticker%7D', ticker);
                            // redirect
                            $(location).attr('href', default_report_url);
                            redirect_state = true;
                        }
                    }
                }

                e.preventDefault();
            });
        });

        $(document).click(function (e) {

            // Hide autocomplete results if user clicked outside the search input field
            // or the autocomplete listing
            var container = $('#searchbar');
            if (!container.is(e.target) // if the target of the click isn't the container...
                    && container.has(e.target).length === 0) // ... nor a descendant of the container
            {
                $('#autocomplete-results').hide();
                $('#autocomplete-results ul').empty();
            }
        });

    })(jQuery);
</script>

2
你使用哪个服务器端框架对于这个问题完全无关紧要... - lukasgeiter
1个回答

5
选择 Laravel(或其他后端框架/语言/平台)是完全无关紧要的。这是纯粹的前端代码。因此,您需要使用前端测试工具进行测试。
但是,在开始考虑对该代码进行单元测试之前,您需要进行一些重新编码,以使其可以实际上进行单元测试。目前的情况下,您有一个大型的单块代码,它根本无法进行单元测试。您需要将功能提取到离散函数中;越短越好。
完成这些之后,建议您最好从QUnit作为起点进行测试。这是jQuery基金会开发的一个单元测试框架,用于测试 jQuery 本身。由于您的代码依赖于 jQuery,因此建议这可能是最好的起点。但是,JavaScript 还有许多其他测试框架,您可能还想调查其中的一些。
请记住,UI 代码(大多数前端 JavaScript)往往难以编写高质量的单元测试。您可能会发现功能测试 - 即通过浏览器自动化测试终端用户 - 更适合您。 (事实上,即使您也编写 JS 代码的单元测试,您也应该考虑进行此类测试)。为此,您需要浏览器的自动化工具。最著名的是Selenium,但您还可以查看SahiPhantomJS

谢谢!我已经使用Laravel的测试框架创建了功能测试,但我还没有尝试过创建JavaScript单元测试。通过您的评论,我倾向于认为我所做的已经足够了,只要有东西来测试我的代码。 - bonbon.langes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接