Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recommended way to unittest javascript in Laravel 5

Is there a recommended way to unittest javascript in Laravel 5? I'm using the jQuery framework to do the search autocomplete task (code below). There's a lot of if blocks that I want to test but I'm not sure how to best test everything in Laravel 5. Any help is appreciated.

<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>
like image 968
bonbon.langes Avatar asked Jul 13 '15 11:07

bonbon.langes


1 Answers

The choice of Laravel (or any other back-end framework/language/platform) is entirely irrelevant. This is purely front-end code. As such, you need to be using front-end testing tools for it.

However, even before you start thinking about unit testing this code, you need to do some re-coding so that it is actually testable in units. As things stand, you have a large monolithic blob of code there which cannot really be unit tested at all. You need to extract the functionality into discrete functions; the shorter the better.

Once you've done that, I'd suggest that the best starting point for your testing would be QUnit. This is a unit test framework developed by the jQuery foundation, and used for testing jQuery itself. Since your code has jQuery as a dependency, I'd suggest that this would probably be the best place to start. However there are numerous other testing frameworks for JavaScript, and you may want to investigate some of those as well.

Bear in mind that UI code (which most front-end JavaScript is) is notoriously difficult to write good quality unit tests for. You may find that functional testing -- ie automated end-user testing via a browser -- will serve you better. (indeed, you should be considering doing this kind of testing, even if you do also write unit tests for the JS code). For this, you will need an automation tool for the browser. The most well known one is Selenium, but you may also want to look into Sahi and also PhantomJS.

like image 195
Simba Avatar answered Oct 07 '22 17:10

Simba