четверг, 23 ноября 2017 г.

Собственный тестовый фреймворк, для тестирования верстки сайта на JS.

В продолжении моих изысканий в создании тестовых фреймворков я сделал расшерение для jQuery в котором можно регистрировать тесты на проверку верстки вашего сайта и в случае нарушения теста результаты проверок будут либо выведены в консоль браузера, либо будут сохранены в переданный php обработчик.
Код получился достаточно крупным, но зато он обрабатывает достаточно много случаев. Со временем код может измениться, поэтому за последними изменениями обращаться на GitHub в мой репозиторий.
(function($) {
    "use strict";

    function clone(o) {
        var obj = [];
        for(var i in o){
            obj[i] = o[i];
        }
        return obj;
    }

    /**
     * Помощник для выполнения тестирования
     * стилей сайта
     */
    var th = {
        testsCount        : 0,
        testsFailed       : 0,
        testsSuccess      : 0,
        testsSkipped      : 0,
        canTest           : false,
        currentElement    : null,
        currentSelector   : null,
        allowConsolePrint : false,
        waitTime          : 1000,
        limits            : 10,
        phpErrorHandler   : false,
        elements          : [],

        resolveParameter: function(real_parameter) {
            if (!this.canTest) return false;
            var parameter = real_parameter;
            switch(real_parameter) {
            case "top"         : parameter = this.currentElement.offset().top; break;
            case "bottom"      : parameter = this.currentElement.offset().bottom; break;
            case "parent-top"  : parameter = this.currentElement.position().top; break;
            case "parent-left" : parameter = this.currentElement.position().left; break;
            case "font-size"   : parameter = this.currentElement.css('font-size'); break;
            default            : parameter = this.currentElement[parameter]();
            }
            return parameter;
        },

        /**
         * Утверждение, выполняющее проверку равенства
         * свойства элемента ожидаемому значению
         */
        assertEqual : function(parameter, expected) {
            var real = this.resolveParameter(parameter),
                i,
                max_limit = 0,
                min_limit = 0,
                expected_values = (expected+"").split('|'),
                cur_expect,
                checkResult = false;
            if (!this.canTest) return false;
            for (i = 0; i < expected_values.length; i++) {
                cur_expect = expected_values[i].trim() * 1;
                min_limit = cur_expect - this.limits;
                max_limit = cur_expect + this.limits;
                // Если совпало хотя бы одно значение - тест пройден
                if ((min_limit <= real && real <= max_limit)) {
                    checkResult = true;
                    break;
                }
            }
            this.countTestLike(checkResult, parameter, expected, real);
            this.elements = [];
        },

        /**
         * Считаем тест либо пройденым либо
         * Нет в зависимости от входного
         * Параметра
         */
        countTestLike: function(status, parameter, expected, real) {
            if (!status) {
                var message = "Test Failed wrong "
                    + this.currentSelector + '->'
                    + parameter + " ("
                    + "expected: " + expected + " / real:" + real
                    + " / limits: " + this.limits
                    + ")";
                this.consolePrint(message);
                if (this.phpErrorHandler) {
                    $.ajax({
                        type: "POST",
                        url: this.phpErrorHandler,
                        data: {
                            "message": message,
                            "agent"  : navigator.userAgent
                        },
                        dataType: "text"
                    });
                }
                this.testsFailed++;
            } else {
                this.testsSuccess++;
            }
        },

        /**
         * Выполнение сравнения всех элементов
         * По переданому параметру
         */
        assertAllEqualsBy: function(by_parameter) {
            var i,param,etalon = 'no';
            for (i = 0; i < this.elements.length; i++) {
                this.currentElement = this.elements[i]["element"];
                if (this.currentElement.length !== 0) {
                    param = this.resolveParameter(by_parameter);
                    if (etalon === 'no')
                        etalon = param


                    this.countTestLike(etalon === param, by_parameter, etalon, param);
                }
            }
            this.elements = [];
        },

        /**
         * Конфигурирование помошника
         */
        configure: function(conf_object) {
            if (this.notEmpty(conf_object['limits']))
                this.limits = conf_object['limits'];
            if (this.notEmpty(conf_object['waitTime']))
                this.waitTime = conf_object['waitTime'];
            if (this.notEmpty(conf_object['allowConsolePrint']))
                this.allowConsolePrint = conf_object['allowConsolePrint'];
            if (this.notEmpty(conf_object['phpErrorHandler']))
                this.phpErrorHandler = conf_object['phpErrorHandler'];
        },

        /**
         * Проверка того, что элемент не пустой
         */
        notEmpty: function(value) {
            return typeof value !== 'undefined';
        },

        /**
         * Получение текущего элемента и возвращение
         * хелпера, чтобы можно было выполнять цепь
         * вызывов.
         * @selector Селектор объекта с которым работаем
         * @position Необяз параметр определющий позицию элемента
         */
        element: function(selector, position) {
            this.testsCount++;
            this.currentSelector = selector;
            if (this.notEmpty(position))
                this.currentElement = $(selector).eq(position);
            else
                this.currentElement = $(selector);
            this.elements.push({
                "selector": clone(this.currentSelector),
                "element" : clone(this.currentElement)
            });
            this.canTest = this.currentElement.length !== 0;
            if (!this.canTest) this.testsSkipped++;
            return this;
        },

        /**
         * Результат тестирования суммарно.
         */
        summorize: function() {
            this.consolePrint('ALL     tests: ' + this.testsCount);
            this.consolePrint('SKIPPED tests: ' + this.testsSkipped);
            this.consolePrint('FAILED  tests: ' + this.testsFailed);
            this.consolePrint('SUCCESS tests: ' + this.testsSuccess);
        },

        /**
         * Тестовая подборка для отложеного выполнения
         * тестирования проекта
         */
        testBundle: function(_callback) {
            this.consolePrint('Tests is runing, please wait ' + (this.waitTime/1000) + 's .' );
            setTimeout(_callback, this.waitTime, th);
        },

        /**
         * Вывод сообщений в консоль с проверкой
         * возможности вывода этих сообщений
         */
        consolePrint: function(message) {
            if (this.allowConsolePrint)
                console.log(message);
        }
    };

    /**
     * Обезъянья правка jQuery для добавления
     * Возможности тестирования.
     */
    $.tst = function(_configure) {
        var callback = _configure['bundle'];
        th.configure(_configure);
        th.testBundle(function() {
            callback(th);
            th.summorize();
        });
    };

})(jQuery)
Подключив этот плагин к своему проекту вы будете вправе выполнить вот такой код для регистрации тестов:
$( function() {
        $.tst({
            allowConsolePrint: true,
            waitTime         : 2000,
            phpErrorHandler  : '/css-error-saver.php',
            bundle: function(th) {
                // Можно проверить конкретное свойство
                th.element('.parameters-section').assertEqual('outerWidth', 495);
                // Можно проверить соответствие набору значений            
                th.element('.parameters-section').assertEqual('height', "583|781|352|676|867");
                // Можно проверить набор элементов на равенство по свойству    
                th.element('.footer-list').element('.footer-right')<p>                    .assertAllEqualsBy('parent-top');
        });</p>    } );
После выполнения этого кода, если были сделаны настройки на вывод результатов в консоль, то Вы должны увидеть общие данные от метода summarize() в которых будет описано сколько тестов прошло, сколько провалилось, и сколько их было вообще.
PHP обработчик для тестовых пакетов может быть написан Вами самостоятельно, я лично на скорую руку написал вот такой обработчик:
<?php

$message = filter_input(INPUT_POST, 'message', FILTER_SANITIZE_SPECIAL_CHARS);
$agent = filter_input(INPUT_POST, 'agent', FILTER_SANITIZE_SPECIAL_CHARS);

if ($message && $agent) {
    $was = file_get_contents('css_errors.txt');
    file_put_contents('css_errors.txt', $was . "\n"
    . "Date: " . date('Y-m-d H:i:s')
    . " Agent:" . $agent
    . " Message: " . $message);
}
echo 'ok';

Комментариев нет:

Отправить комментарий

Linux командная строка узнаем оставшееся место

Чтобы посмотреть общую картину того, сколько места осталось в системе можно выполнить команду: df -h Чтобы вывести на экран сколько мес...