packages feed

wai-cors-0.2.3: test/index.html

<!DOCTYPE html>
<!-- Copyright (c) 2015 Lars Kuhtz <lakuhtz@gmail.coml> -->
<html>
    <head> 
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript">

    var url = 'http://localhost:8080'
    var wsurl = 'ws://localhost:8080'

/* ************************************************************************** */
/* Utils */

    /* asynchronous array map function
     *
     * The function f is called on each element in the value and
     * is expected to return a promise object.
     *
     * asyncMap itself returns a promise object that is completed
     * when the promises for all elements completed. When all element
     * promises resolve the array promises is resolved. If at least
     * one element promise is reject the array promises is rejected.
     *
     * The done and fail callbacks are called with an object of the form
     *
     * { 'successes':successes, 'failures': failures, 'results': results }
     *
     * The results that array has one value for each element of the original
     * array. The values in the result array are objects of the form
     *
     * { success: trueOrFalse, result: elementPromiseResult }
     *
     * The progress callback is given an object of the form
     *
     * { successes: sumS, failures: numF, missing: numberOfMissingElementPromises }
     */
    var asyncMap = function (a,f) {
        var def = $.Deferred();
        var successes = 0;
        var failures = 0;
        var results = new Array(a.length);
        var c = a.length;

        a.map(function (val, idx, arr) {
            t = f(val);
            t.done(function(arg) {
                successes++;
                results[idx] = { 'success':true, 'result':arg };
            });
            t.fail(function(arg) {
                failures++;
                results[idx] = { 'success':false, 'result':arg };
            });
            t.always(function() {
                c--;
                if (c > 0) {
                    def.notify({ 'successes':successes, 'failures': failures, 'missing': c });
                } else {
                    var result = { 'successes':successes, 'failures': failures, 'results': results };
                    if (failures === 0) {
                        def.resolve(result);
                    } else {
                        def.reject(result);
                    };
                };
            });
        });
        return def.promise();
    };

    // monoid concatenation for asyncMap results
    var concatResults = function (r1, r2) {
        return {
            'successes': r1.successes + r2.successes,
            'failures': r1.failures + r2.failures,
            'results': r1.results.concat(r2.results)
        };
    }

    // monoid identity for asyncMap results
    var emptyResult = { 'successes': 0, 'failures': 0, 'results':[] };

    // monad join for asyncMap results
    var flattenResults = function (r) {
        return r.results.reduce(function (p,c,i,a) { return concatResults(p,c.result); }, emptyResult);
    };

/* ************************************************************************** */
/* PhantomJS Integration */

    // Integration with PhantomJS
    //
    // call with: phantomjs --ignore-ssl-errors=true phantomjs.js $PWD/index.html
    //
    if (typeof window.callPhantom === 'function') {
        window.setTimeout(function () { window.callPhantom("timeout"); },3000);
    };

    var phantomJsCb = function (result) { 
        if (typeof window.callPhantom === 'function') {
            window.callPhantom(result);
        };
    };

/* ************************************************************************** */
/* Run Tests */

    var runTest = function (params) {

        var test = $.Deferred();
        var req = $.ajax(
            { 'method': params.method
            , 'url': url
            , 'contentType': params.contentType
            , 'crossDomain': true
            , 'headers': params.headers
            });

        var succ = function () { test.resolve(params); }
        var fail = function () { test.reject(params); }
        req.done(params.expectedResult ? succ : fail);
        req.fail(params.expectedResult ? fail : succ);

        return test.promise();
    }

    var pageTest = function (params) {
        test = runTest(params);

        test.done(function() {
            $('#results').append('<p style="color:green">' + params.label + ': success</p>');
        });

        test.fail(function() {
            $('#results').append('<p style="color:red">' + params.label + ': failure</p>');
        });
        return test;
    }

    var runAllPageTests = function (tests) {
        return asyncMap(tests, pageTest);
    }

/* ************************************************************************** */
/* WebSockets */

    /* a super simple ws service client
     *
     * TODO add proper callbacks (e.g. close, error);
     * TODO in case we use this for anything more complex we should add proper
     *      streaming by supporting chunking.
     *
     */
    var WsService = function (url, timeout) {
        var timeout = timeout ? timeout : 1000;
        var curMsgId = 0;
        var ready = $.Deferred();
        var websocket = new WebSocket(url);
        var newMsgId = function () { return ++curMsgId; };

        // maps message ids data to promise objects
        var msgMap = {}

        var ws = function (msg) {
            var p = $.Deferred();
            var req = { id: newMsgId(), msg: msg};
            ready.then(function () { websocket.send(JSON.stringify(req)); });
            msgMap[req.id] = p;
            setTimeout(function () { p.reject("timeout: no response from websocket after " + timeout + " milliseconds"); }, timeout);
            return p.promise();
        };

        websocket.onmessage = function (evt) {
            var resp = JSON.parse(evt.data);
            var prom = msgMap[resp.id];
            if (prom) {
                prom.resolve(resp.msg);
            } else {
                console.log("unexpected message from websocket: " + JSON.stringify(resp));
            };
        };

        var wserror = function (evt) {
            for (i in msgMap) {
                if (msgMap.hasOwnProperty(i)) {
                    msgMap[i].fail();
                };
            };
            msgMap = {};
        };

        websocket.onopen = function(evt) {
            ready.resolve();
        };

        websocket.onerror = function(evt) {
            console.log("websocket error: " + evt.data);
            wserror(evt);
        };

        websocket.onclose = function(evt) {
            console.log("websocket closed unexpectedly: " + evt.data);
            wserror(evt);
        };

        return ws;
    };

    var websocketTest = function () {

        var ws = WsService(wsurl);

        var wstest = function (msg) {
            var p = ws(msg);

            p.done(function() {
                $('#wsresults').append('<p style="color:green">' + msg + ': success</p>');
            });

            p.fail(function() {
                $('#wsresults').append('<p style="color:red">' + msg + ': failure</p>');
            });
            return p;
        }

        return asyncMap(["msg 0", "msg 1", "msg 2"], wstest);
    };

/* ************************************************************************** */
/* Test Vectors */

    var mkTest = function (label, expectedResult, method, credentials, contentType, headers) {
        return {
            label: label,
            expectedResult: expectedResult,
            method: method,
            credentials: credentials,
            contentType: contentType,
            headers: headers
        };
    }

    var tests = [
        mkTest("simple GET 1", true, "GET", false, 'text/plain', []),
        mkTest("simple GET 2", true, "GET", false, 'application/x-www-form-urlencoded', []),
        mkTest("simple GET 3", true, "GET", false, 'multipart/form-data', []),
        mkTest("simple GET 4", false, "GET", false, 'application/json', []),
        mkTest("simple GET 5", false, "GET", false, 'text/plain', {'abc': 'abc'}),

        mkTest("simple HEAD 1", true, "HEAD", false, 'text/plain', []),
        mkTest("simple HEAD 2", true, "HEAD", false, 'application/x-www-form-urlencoded', []),
        mkTest("simple HEAD 3", true, "HEAD", false, 'multipart/form-data', []),
        mkTest("simple HEAD 4", false, "HEAD", false, 'application/json', []),
        mkTest("simple HEAD 5", false, "HEAD", false, 'text/plain', {'abc': 'abc'}),

        mkTest("simple POST 1", true, "POST", false, 'text/plain', []),
        mkTest("simple POST 2", true, "POST", false, 'application/x-www-form-urlencoded', []),
        mkTest("simple POST 3", true, "POST", false, 'multipart/form-data', []),
        mkTest("simple POST 4", false, "POST", false, 'application/json', []),
        mkTest("simple POST 5", false, "POST", false, 'test/plain', {'abc':'abc'}),

        mkTest("simple PUT 1", false, "PUT", false, 'text/plain', []),
        mkTest("simple DELETE 1", false, "DELETE", false, 'text/plain', []),
        mkTest("simple PATCH 1", false, "PATCH", false, 'text/plain', []),
    ];

    $(document).ready(function() {
        var p = runAllPageTests(tests);
        var q = websocketTest();
        var r = asyncMap([p,q], function (x) { return x; });
        r.always(function (x) { phantomJsCb(flattenResults(x)); });
    });

    </script>
    </head>
    <body>
        <h1>Results</h1>
        <div id="results"></div>
        <h1>Websocket Test Results</h1>
        <div id="wsresults"></div>
    </body>
</html>