gemini-testing / gemini

💀💀💀[DEPRECATED] Use hermione
https://github.com/gemini-testing/hermione
MIT License
1.5k stars 149 forks source link

Pass in matrix of possibilities instead of multiple calls of gemini.suite #507

Open qfox opened 8 years ago

qfox commented 8 years ago

So I suggest to implement something like this:

    gemini.suite('states', function() {
        gemini.matrix({
          background: ['transparent', 'colored'],
          size: ['xs', 's', 'm']
        }, function(values: {background: String, size: String}, suite) {
            // This one will be called ${background.length * size.length} times
            // It's like the usual callback for gemini.suite just with values
            // `name` of each suite will be generated somehow automatically using values
            // (e.g. `background-${background} size-${size}`)
            …
            // We should be free to put suite-calls into matrix-calls and vice versa
            gemini.suite('disabled', …);
            gemini.suite('enabled', …);
        });

instead of this:

    gemini.suite('states', function() {
        ['transparent', 'colored'].forEach(function(background) {
            gemini.suite('bg-' + background, function() {
                ['xs', 's', 'm'].forEach(function(size) {
                    gemini.suite('size-' + size, function() {
                        gemini.suite('disabled', …);
                        gemini.suite('enabled', …);

API could be:

gemini.matrix(
    namePattern: ?String,
    matrix: Object<String, Array>,
    callback: function(values: Object, suite: SuiteBuilder): void
): void;

UPD: Possible realization:

gemini.matrix = function(namePattern, matrix, fn) {
    var generateName;
    if (arguments.length < 3) {
        fn = matrix;
        matrix = namePattern;
        generateName = _defaultNameGenerator;
    } else {
        generateName = typeof namePattern === 'function'
            ? namePattern
            : _buildNameGenerator(namePattern);
    }

    _calcCombinations(matrix).forEach(values => {
        gemini.suite(generateName(values), function(suite) {
            fn(values, suite);
        });
    });
};

function _defaultNameGenerator(obj) {
    return Object.keys(obj).map(k => `${k}:${obj[k]}`).join(' ');
}

function _buildNameGenerator(pattern) {
    return function(obj) {
        return pattern.replace(/\${([^}]+?)}/g, (_, key) => values);
    };
}

function _calcCombinations(matrix) {
    return Object.keys(matrix).reduce((combs, k) => _multiply(combs, k, matrix[k]), [{}]);

    /**
     * Adds all combinations of existing array and incoming variants
     * @param {Array<Object>} combs - existing combinations
     * @param {String} key - new key for items in combinations
     * @param {Array} values - values for new key
     * @returns {Array<Object>} - modified
     */
    function _multiply(combs, key, values) {
        var res = [];
        combs.forEach(obj => {
            values.forEach(value => {
                var _new = _clone(obj);
                if (v !== undefined) _new[key] = value;
                res.push(_new);
            });
        });
        return res;
    }

    function _clone(old) {
        var _new = {};
        for (var k in old)
            if (old.hasOwnProperty(k))
                _new[k] = old[k];
        return _new;
    }
}
qfox commented 8 years ago

Mogu prislat' PR if ok

sipayRT commented 8 years ago

prisilay - posmotrim ;)

SevInf commented 8 years ago

Не вижу необходимости это в ядре делать. Код из описания вполне себе в сторонней либе может жить.