<commit_before>var Checker = require('../../../lib/checker');
var expect = require('chai').expect;

describe('rules/maximum-line-length', function() {
    var checker;

    beforeEach(function() {
        checker = new Checker();
        checker.registerDefaultRules();
    });

    describe('number option', function() {
        beforeEach(function() {
            checker.configure({ maximumLineLength: 7 });
        });

        it('should report lines longer than the maximum', function() {
            expect(checker.checkString('var xyz;')).to.have.one.validation.error.from('maximumLineLength');
        });

        it('should not report lines equal to the maximum', function() {
            expect(checker.checkString('var xy;')).to.have.no.errors();
        });

        it('should not report lines shorter than the maximum', function() {
            expect(checker.checkString('var x;')).to.have.no.errors();
        });
    });

    describe('tabSize option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 8,
                    tabSize: 2
                }
            });
        });

        it('should not report lines shorter than the maximum', function() {
            expect(checker.checkString('\t\t\t\t')).to.have.no.errors();
        });

        it('should report lines longer than the maximum', function() {
            expect(checker.checkString('\t\t\t\t1')).to.have.one.validation.error.from('maximumLineLength');
        });
    });

    describe('allExcept["comments"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allExcept: ['comments']
                }
            });
        });

        it('should not report comments', function() {
            expect(checker.checkString('// a comment\n/* a multiline\n long comment*/')).to.have.no.errors();
        });

        it('should not report comments but still report long code', function() {
            expect(checker.checkString('// a comment\nvar a = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should still allow the old setting', function() {
            // we need a clean checker or we'll end up validating the file twice
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allowComments: true
                }
            });
            expect(checker.checkString('// a comment\nvar a = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });
    });

    describe('allExcept["urlComments"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 15,
                    allExcept: ['urlComments']
                }
            });
        });

        it('should report comments', function() {
            expect(checker.checkString('// 16 characters' +
                '\n/* 16 characters\n 16 characters*/')).to.have.error.count.equal(3);
        });

        it('should not report url comments if line is long because of it', function() {
            expect(checker.checkString('// <16 chars https://example.com' +
                '\n/* <16 chars http://example.com\n <16 chars http://example.com*/')).to.have.no.errors();
        });

        it('should report url comments if line is long even without it', function() {
            expect(checker.checkString('// 16 characters https://example.com'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should not report comments but still report long code', function() {
            expect(checker.checkString('// a comment\nvar a = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should recognize http', function() {
            expect(checker.checkString('// http://example.com/is/a/url')).to.have.no.errors();
            expect(checker.checkString('// http://example.com/is/a/url <16 chars')).to.have.no.errors();
        });

        it('should recognize https', function() {
            expect(checker.checkString('// https://example.com/is/a/url')).to.have.no.errors();
            expect(checker.checkString('// https://example.com/is/a/url <16 chars')).to.have.no.errors();
        });

        it('should recognize ftp', function() {
            expect(checker.checkString('// ftp://example.com/is/a/url')).to.have.no.errors();
            expect(checker.checkString('// ftp://example.com/is/a/url <16 chars')).to.have.no.errors();
        });

        it('should ignore things that arent quite urls', function() {
            expect(checker.checkString('// www.example.com/is/not/a/url'))
              .to.have.one.validation.error.from('maximumLineLength');
            expect(checker.checkString('// example.com/is/not/a/url'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should should still support the old setting', function() {
            // we need a clean checker or we'll end up validating the file twice
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: {
                    value: 15,
                    allowUrlComments: true
                }
            });
            expect(checker.checkString('// <16 chars https://example.com' +
                '\n/* <16 chars http://example.com\n <16 chars http://example.com*/')).to.have.no.errors();
        });
    });

    describe('allExcept["regex"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allExcept: ['regex']
                }
            });
        });

        it('should not report regex literals', function() {
            expect(checker.checkString('var a = /longregex/')).to.have.no.errors();
        });

        it('should not report regex literals but still report long code', function() {
            expect(checker.checkString('var a = /longregex/;\nvar b = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should not report regexes literals but still report regex constructors', function() {
            expect(checker.checkString('var a = /l/;\nvar b = l;\nvar a = new Regex("/l/");'))
              .to.have.error.count.equal(2);
        });

        it('should not be destructive to original data', function() {
            expect(checker.checkString('var a = /regex/;')._file._lines[0].length).to.be.above(1);
        });

        it('should still should support the old setting', function() {
            // we need a clean checker or we'll end up validating the file twice
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allowRegex: true
                }
            });
            expect(checker.checkString('var a = /longregex/;\nvar b = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });
    });

    describe('allExcept["functionSignature"] option', function() {
        beforeEach(function() {
            checker.configure({
                esnext: true,
                maximumLineLength: {
                    value: 20,
                    allExcept: ['functionSignature']
                }
            });
        });

        it('should not report named functions', function() {
            var code = 'function myCoolFunction(argument) { }';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report class methods', function() {
            var code = 'class MyClass {\n' +
                    '  myMethodName(withArgs) {\n' +
                    '  }\n' +
                    '}';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report functions stored in variables', function() {
            var code = 'var fn = function() {};';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report functions within IIFE blocks', function() {
            var code = '(function() {\n' +
                    '   function myCoolFunction(argument) { }\n' +
                    '})();';
            expect(checker.checkString(code)).to.have.no.errors();
        });
    });

    describe('allExcept["require"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 15,
                    allExcept: ['require']
                }
            });
        });

        it('should not report require invocation', function() {
            var code = 'var foo = require("foo");' +
                       'var bar = require("bar");';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report single-var require invocation', function() {
            var code = 'var foo = require("foo")\n' +
                       '  , bar = require("bar");';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report require line shorter than minimum', function() {
            var code = 'require("a");';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should report require used as a variable', function() {
            var code = 'var require = "foobar"';
            expect(checker.checkString(code)).to.have.one.validation.error.from('maximumLineLength');
        });

        it('should report require if the exception is disabled', function() {
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: 15
            });

            var code = 'var foo = require("foo");';
            expect(checker.checkString(code)).to.have.one.validation.error.from('maximumLineLength');
        });
    });
});
<commit_msg>maximumLineLength spec: add `should report functions within comments`<commit_after>var Checker = require('../../../lib/checker');
var expect = require('chai').expect;

describe('rules/maximum-line-length', function() {
    var checker;

    beforeEach(function() {
        checker = new Checker();
        checker.registerDefaultRules();
    });

    describe('number option', function() {
        beforeEach(function() {
            checker.configure({ maximumLineLength: 7 });
        });

        it('should report lines longer than the maximum', function() {
            expect(checker.checkString('var xyz;')).to.have.one.validation.error.from('maximumLineLength');
        });

        it('should not report lines equal to the maximum', function() {
            expect(checker.checkString('var xy;')).to.have.no.errors();
        });

        it('should not report lines shorter than the maximum', function() {
            expect(checker.checkString('var x;')).to.have.no.errors();
        });
    });

    describe('tabSize option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 8,
                    tabSize: 2
                }
            });
        });

        it('should not report lines shorter than the maximum', function() {
            expect(checker.checkString('\t\t\t\t')).to.have.no.errors();
        });

        it('should report lines longer than the maximum', function() {
            expect(checker.checkString('\t\t\t\t1')).to.have.one.validation.error.from('maximumLineLength');
        });
    });

    describe('allExcept["comments"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allExcept: ['comments']
                }
            });
        });

        it('should not report comments', function() {
            expect(checker.checkString('// a comment\n/* a multiline\n long comment*/')).to.have.no.errors();
        });

        it('should not report comments but still report long code', function() {
            expect(checker.checkString('// a comment\nvar a = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should still allow the old setting', function() {
            // we need a clean checker or we'll end up validating the file twice
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allowComments: true
                }
            });
            expect(checker.checkString('// a comment\nvar a = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });
    });

    describe('allExcept["urlComments"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 15,
                    allExcept: ['urlComments']
                }
            });
        });

        it('should report comments', function() {
            expect(checker.checkString('// 16 characters' +
                '\n/* 16 characters\n 16 characters*/')).to.have.error.count.equal(3);
        });

        it('should not report url comments if line is long because of it', function() {
            expect(checker.checkString('// <16 chars https://example.com' +
                '\n/* <16 chars http://example.com\n <16 chars http://example.com*/')).to.have.no.errors();
        });

        it('should report url comments if line is long even without it', function() {
            expect(checker.checkString('// 16 characters https://example.com'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should not report comments but still report long code', function() {
            expect(checker.checkString('// a comment\nvar a = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should recognize http', function() {
            expect(checker.checkString('// http://example.com/is/a/url')).to.have.no.errors();
            expect(checker.checkString('// http://example.com/is/a/url <16 chars')).to.have.no.errors();
        });

        it('should recognize https', function() {
            expect(checker.checkString('// https://example.com/is/a/url')).to.have.no.errors();
            expect(checker.checkString('// https://example.com/is/a/url <16 chars')).to.have.no.errors();
        });

        it('should recognize ftp', function() {
            expect(checker.checkString('// ftp://example.com/is/a/url')).to.have.no.errors();
            expect(checker.checkString('// ftp://example.com/is/a/url <16 chars')).to.have.no.errors();
        });

        it('should ignore things that arent quite urls', function() {
            expect(checker.checkString('// www.example.com/is/not/a/url'))
              .to.have.one.validation.error.from('maximumLineLength');
            expect(checker.checkString('// example.com/is/not/a/url'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should should still support the old setting', function() {
            // we need a clean checker or we'll end up validating the file twice
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: {
                    value: 15,
                    allowUrlComments: true
                }
            });
            expect(checker.checkString('// <16 chars https://example.com' +
                '\n/* <16 chars http://example.com\n <16 chars http://example.com*/')).to.have.no.errors();
        });
    });

    describe('allExcept["regex"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allExcept: ['regex']
                }
            });
        });

        it('should not report regex literals', function() {
            expect(checker.checkString('var a = /longregex/')).to.have.no.errors();
        });

        it('should not report regex literals but still report long code', function() {
            expect(checker.checkString('var a = /longregex/;\nvar b = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });

        it('should not report regexes literals but still report regex constructors', function() {
            expect(checker.checkString('var a = /l/;\nvar b = l;\nvar a = new Regex("/l/");'))
              .to.have.error.count.equal(2);
        });

        it('should not be destructive to original data', function() {
            expect(checker.checkString('var a = /regex/;')._file._lines[0].length).to.be.above(1);
        });

        it('should still should support the old setting', function() {
            // we need a clean checker or we'll end up validating the file twice
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: {
                    value: 4,
                    allowRegex: true
                }
            });
            expect(checker.checkString('var a = /longregex/;\nvar b = tooLong;'))
              .to.have.one.validation.error.from('maximumLineLength');
        });
    });

    describe('allExcept["functionSignature"] option', function() {
        beforeEach(function() {
            checker.configure({
                esnext: true,
                maximumLineLength: {
                    value: 20,
                    allExcept: ['functionSignature']
                }
            });
        });

        it('should not report named functions', function() {
            var code = 'function myCoolFunction(argument) { }';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report class methods', function() {
            var code = 'class MyClass {\n' +
                    '  myMethodName(withArgs) {\n' +
                    '  }\n' +
                    '}';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report functions stored in variables', function() {
            var code = 'var fn = function() {};';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report functions within IIFE blocks', function() {
            var code = '(function() {\n' +
                    '   function myCoolFunction(argument) { }\n' +
                    '})();';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should report functions within comments', function() {
            var code = '// function myCoolFunction(argument) { }';
            expect(checker.checkString(code)).to.have.one.validation.error.from('maximumLineLength');
        });
    });

    describe('allExcept["require"] option', function() {
        beforeEach(function() {
            checker.configure({
                maximumLineLength: {
                    value: 15,
                    allExcept: ['require']
                }
            });
        });

        it('should not report require invocation', function() {
            var code = 'var foo = require("foo");' +
                       'var bar = require("bar");';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report single-var require invocation', function() {
            var code = 'var foo = require("foo")\n' +
                       '  , bar = require("bar");';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should not report require line shorter than minimum', function() {
            var code = 'require("a");';
            expect(checker.checkString(code)).to.have.no.errors();
        });

        it('should report require used as a variable', function() {
            var code = 'var require = "foobar"';
            expect(checker.checkString(code)).to.have.one.validation.error.from('maximumLineLength');
        });

        it('should report require if the exception is disabled', function() {
            checker = new Checker();
            checker.registerDefaultRules();
            checker.configure({
                maximumLineLength: 15
            });

            var code = 'var foo = require("foo");';
            expect(checker.checkString(code)).to.have.one.validation.error.from('maximumLineLength');
        });
    });
});
<|endoftext|>


<commit_before>/***********************************************************
** TJHSST Proxy Auto-Configuration Script                 **
** For use with TJHSST school databases                   **
** Use is restricted to TJHSST students and faculty ONLY. **
** All other use is prohibited.                           **
** Originally contributed by William Yang.                **
** Autogenerated version by Brandon Vargo.                **
************************************************************/

function FindProxyForURL(url, host)
{
	if (
		dnsDomainIs(host, ".abc-clio.com") ||
		dnsDomainIs(host, "accessscience.com") ||
		dnsDomainIs(host, ".accessscience.com") ||
		dnsDomainIs(host, "mcgraw-hill.com") ||
		dnsDomainIs(host, ".mcgraw-hill.com") ||
		dnsDomainIs(host, ".eb.com") ||
		dnsDomainIs(host, "library.cqpress.com") ||
		dnsDomainIs(host, ".earthscape.org") ||
		dnsDomainIs(host, ".ebscohost.com") ||
		dnsDomainIs(host, ".ebsco-content.com") ||
		dnsDomainIs(host, "search.serialssolutions.com") ||
		dnsDomainIs(host, "ehrafworldcultures.yale.edu") ||
		dnsDomainIs(host, ".galegroup.com") ||
		dnsDomainIs(host, "nelnetsolutions.com") ||
		dnsDomainIs(host, ".grolier.com") ||
		dnsDomainIs(host, "jchemed.chem.wisc.edu") ||
		dnsDomainIs(host, "www.jstor.org") ||
		dnsDomainIs(host, "web.lexis-nexis.com") ||
		dnsDomainIs(host, ".oed.com") ||
		dnsDomainIs(host, "poll.orspub.com") ||
		dnsDomainIs(host, "proquestk12.com") ||
		dnsDomainIs(host, "proquest.com") ||
		dnsDomainIs(host, ".umi.com") ||
		dnsDomainIs(host, "www.sciencedirect.com") ||
		dnsDomainIs(host, "hwwilsonweb.com") ||
		dnsDomainIs(host, ".nature.com") ||
		dnsDomainIs(host, "portal.bigchalk.com") ||
		dnsDomainIs(host, ".culturegrams.com") ||
		dnsDomainIs(host, ".acs.org") ||
		dnsDomainIs(host, ".opticsinfobase.org") ||
		dnsDomainIs(host, "www.worldbookonline.com") ||
		dnsDomainIs(host, ".tumblebooks.com") ||
		dnsDomainIs(host, "hsus.cambridge.org") ||
		dnsDomainIs(host, ".aps.org") ||
		dnsDomainIs(host, "rm124camera1.tjhsst.edu") ||
		dnsDomainIs(host, "rm124camera2.tjhsst.edu") ||
		dnsDomainIs(host, "rm124camera3.tjhsst.edu") ||
		dnsDomainIs(host, "rm124ipvideo.tjhsst.edu") ||
		dnsDomainIs(host, ".humanitiesebook.org") ||
		dnsDomainIs(host, ".lib.umich.edu") ||
		dnsDomainIs(host, ".hdl.handle.net") ||
		dnsDomainIs(host, ".jove.com") ||
		dnsDomainIs(host, ".marshallcavendishdigital.com") ||
		dnsDomainIs(host, ".cavendishsquaredigital.com") ||
		dnsDomainIs(host, ".salempress.com") ||
		dnsDomainIs(host, "booksinprint.com") ||
		dnsDomainIs(host, ".booksinprint.com") ||
		dnsDomainIs(host, "booksinprint2.com") ||
		dnsDomainIs(host, "ion.tjhsst.edu") ||
		dnsDomainIs(host, ".booksinprint2.com") ||
		dnsDomainIs(host, "whiv.alexanderstreet.com") ||
		dnsDomainIs(host, ".ebrary.com") ||
		dnsDomainIs(host, ".oxfordartonline.com") ||
		dnsDomainIs(host, ".apimages.com") ||
		dnsDomainIs(host, ".sciencemag.org") ||
		dnsDomainIs(host, "whatsmyip.org") ||
		dnsDomainIs(host, ".currenthistory.com") ||
		dnsDomainIs(host, "cms.math.ca") ||
		dnsDomainIs(host, "charon.tjhsst.edu")

	)
			return "PROXY local.border.tjhsst.edu:8080";
		else
			return "DIRECT";
}
<commit_msg>debugging<commit_after>/***********************************************************
** TJHSST Proxy Auto-Configuration Script                 **
** For use with TJHSST school databases                   **
** Use is restricted to TJHSST students and faculty ONLY. **
** All other use is prohibited.                           **
** Originally contributed by William Yang.                **
** Autogenerated version by Brandon Vargo.                **
************************************************************/

function FindProxyForURL(url, host)
{
	if (
		dnsDomainIs(host, ".abc-clio.com") ||
		dnsDomainIs(host, "accessscience.com") ||
		dnsDomainIs(host, ".accessscience.com") ||
		dnsDomainIs(host, "mcgraw-hill.com") ||
		dnsDomainIs(host, ".mcgraw-hill.com") ||
		dnsDomainIs(host, ".eb.com") ||
		dnsDomainIs(host, "library.cqpress.com") ||
		dnsDomainIs(host, ".earthscape.org") ||
		dnsDomainIs(host, ".ebscohost.com") ||
		dnsDomainIs(host, ".ebsco-content.com") ||
		dnsDomainIs(host, "search.serialssolutions.com") ||
		dnsDomainIs(host, "ehrafworldcultures.yale.edu") ||
		dnsDomainIs(host, ".galegroup.com") ||
		dnsDomainIs(host, "nelnetsolutions.com") ||
		dnsDomainIs(host, ".grolier.com") ||
		dnsDomainIs(host, "jchemed.chem.wisc.edu") ||
		dnsDomainIs(host, "www.jstor.org") ||
		dnsDomainIs(host, "web.lexis-nexis.com") ||
		dnsDomainIs(host, ".oed.com") ||
		dnsDomainIs(host, "poll.orspub.com") ||
		dnsDomainIs(host, "proquestk12.com") ||
		dnsDomainIs(host, "proquest.com") ||
		dnsDomainIs(host, ".umi.com") ||
		dnsDomainIs(host, "www.sciencedirect.com") ||
		dnsDomainIs(host, "hwwilsonweb.com") ||
		dnsDomainIs(host, ".nature.com") ||
		dnsDomainIs(host, "portal.bigchalk.com") ||
		dnsDomainIs(host, ".culturegrams.com") ||
		dnsDomainIs(host, ".acs.org") ||
		dnsDomainIs(host, ".opticsinfobase.org") ||
		dnsDomainIs(host, "www.worldbookonline.com") ||
		dnsDomainIs(host, ".tumblebooks.com") ||
		dnsDomainIs(host, "hsus.cambridge.org") ||
		dnsDomainIs(host, ".aps.org") ||
		dnsDomainIs(host, "rm124camera1.tjhsst.edu") ||
		dnsDomainIs(host, "rm124camera2.tjhsst.edu") ||
		dnsDomainIs(host, "rm124camera3.tjhsst.edu") ||
		dnsDomainIs(host, "rm124ipvideo.tjhsst.edu") ||
		dnsDomainIs(host, ".humanitiesebook.org") ||
		dnsDomainIs(host, ".lib.umich.edu") ||
		dnsDomainIs(host, ".hdl.handle.net") ||
		dnsDomainIs(host, ".jove.com") ||
		dnsDomainIs(host, ".marshallcavendishdigital.com") ||
		dnsDomainIs(host, ".cavendishsquaredigital.com") ||
		dnsDomainIs(host, ".salempress.com") ||
		dnsDomainIs(host, "booksinprint.com") ||
		dnsDomainIs(host, ".booksinprint.com") ||
		dnsDomainIs(host, "booksinprint2.com") ||
		dnsDomainIs(host, "ion.tjhsst.edu") ||
		dnsDomainIs(host, ".booksinprint2.com") ||
		dnsDomainIs(host, "whiv.alexanderstreet.com") ||
		dnsDomainIs(host, ".ebrary.com") ||
		dnsDomainIs(host, ".oxfordartonline.com") ||
		dnsDomainIs(host, ".apimages.com") ||
		dnsDomainIs(host, ".sciencemag.org") ||
		dnsDomainIs(host, ".whatsmyip.org") ||
		dnsDomainIs(host, ".currenthistory.com") ||
		dnsDomainIs(host, "cms.math.ca") ||
		dnsDomainIs(host, "charon.tjhsst.edu")

	)
			return "PROXY local.border.tjhsst.edu:8080";
		else
			return "DIRECT";
}
<|endoftext|>


<commit_before>// Use this hook to manipulate incoming or outgoing data.
// For more information on hooks see: http://docs.feathersjs.com/api/hooks.html

// We need this to create the MD5 hash
const crypto = require('crypto');

// The Gravatar image service
const gravatarUrl = 'https://s.gravatar.com/avatar';
// The size query. Our chat needs 60px images
const query = 's=60';

module.exports = function (options = {}) { // eslint-disable-line no-unused-vars
  return async context => {
    // The user email
    const { email } = context.data;
    // Gravatar uses MD5 hashes from an email address to get the image
    const hash = crypto.createHash('md5').update(email).digest('hex');

    context.data.avatar = `${gravatarUrl}/${hash}?${query}`;

    // Best practise, hooks should always return the context
    return context;
  };
};
<commit_msg>Gravatar emails are always lowercase (#95)<commit_after>// Use this hook to manipulate incoming or outgoing data.
// For more information on hooks see: http://docs.feathersjs.com/api/hooks.html

// We need this to create the MD5 hash
const crypto = require('crypto');

// The Gravatar image service
const gravatarUrl = 'https://s.gravatar.com/avatar';
// The size query. Our chat needs 60px images
const query = 's=60';

module.exports = function (options = {}) { // eslint-disable-line no-unused-vars
  return async context => {
    // The user email
    const { email } = context.data;
    // Gravatar uses MD5 hashes from an email address (all lowercase) to get the image
    const hash = crypto.createHash('md5').update(email.toLowerCase()).digest('hex');

    context.data.avatar = `${gravatarUrl}/${hash}?${query}`;

    // Best practise, hooks should always return the context
    return context;
  };
};
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var DebugLogtron = require('debug-logtron');
var setTimeout = require('timers').setTimeout;

var HyperbahnClient = require('tchannel/hyperbahn/index.js');
var TChannelJSON = require('tchannel/as/json');
// var timers = TimeMock(Date.now());

module.exports = runTests;

if (require.main === module) {
    runTests(require('../lib/test-cluster.js'));
}

function runTests(HyperbahnCluster) {
    HyperbahnCluster.test('advertise and forward', {
        size: 5,
        servicePurgePeriod: 50
    }, function t(cluster, assert) {
        var steve = cluster.remotes.steve;
        var bob = cluster.remotes.bob;

        var tchannelJSON = TChannelJSON({
            logger: cluster.logger
        });

        var steveHyperbahnClient = new HyperbahnClient({
            serviceName: steve.serviceName,
            callerName: 'forward-test',
            hostPortList: cluster.hostPortList,
            tchannel: steve.channel,
            advertiseInterval: 2,
            logger: DebugLogtron('hyperbahnClient')
        });

        steveHyperbahnClient.once('advertised', onAdvertised);
        steveHyperbahnClient.advertise();

        function onAdvertised() {
            setTimeout(function onSend() {
                tchannelJSON.send(bob.clientChannel.request({
                    timeout: 5000,
                    serviceName: steve.serviceName
                }), 'echo', null, 'oh hi lol', onForwarded);
            }, 55);
        }

        function onForwarded(err, resp) {
            assert.ifError(err);
            assert.equal(String(resp.body), 'oh hi lol');

            steveHyperbahnClient.destroy();
            assert.end();
        }
    });

    HyperbahnCluster.test('advertise, unadvertise and forward', {
        size: 5,
        servicePurgePeriod: 50
    }, function t(cluster, assert) {
        var steve = cluster.remotes.steve;
        var bob = cluster.remotes.bob;

        var tchannelJSON = TChannelJSON({
            logger: cluster.logger
        });

        var steveHyperbahnClient = new HyperbahnClient({
            serviceName: steve.serviceName,
            callerName: 'forward-test',
            hostPortList: cluster.hostPortList,
            tchannel: steve.channel,
            advertiseInterval: 2,
            logger: DebugLogtron('hyperbahnClient')
        });
        steveHyperbahnClient.once('advertised', onAdvertised);
        steveHyperbahnClient.advertise();

        function onAdvertised() {
            steveHyperbahnClient.once('unadvertised', onUnadvertised);
            steveHyperbahnClient.unadvertise();
        }

        var fwdreq;
        function onUnadvertised() {
            assert.equal(steveHyperbahnClient.latestAdvertisementResult, null, 'latestAdvertisementResult is null');
            assert.equal(steveHyperbahnClient.state, 'UNADVERTISED', 'state should be UNADVERTISED');

            setTimeout(function onSend() {
                fwdreq = bob.clientChannel.request({
                    timeout: 5000,
                    serviceName: steve.serviceName
                });
                tchannelJSON.send(fwdreq, 'echo', null, 'oh hi lol', onForwarded);
            }, 100);
        }

        function onForwarded(err, resp) {
            assert.ok(err && err.type === 'tchannel.declined' && err.message === 'no peer available for request');
            steveHyperbahnClient.destroy();
            assert.end();
        }
    });

    HyperbahnCluster.test('advertise, unadvertise and re-advertise', {
        size: 5
    }, function t(cluster, assert) {
        var steve = cluster.remotes.steve;
        var steveHyperbahnClient = new HyperbahnClient({
            serviceName: steve.serviceName,
            callerName: 'forward-test',
            hostPortList: cluster.hostPortList,
            tchannel: steve.channel,
            advertiseInterval: 2,
            logger: DebugLogtron('hyperbahnClient')
        });
        steveHyperbahnClient.once('advertised', onAdvertised);
        steveHyperbahnClient.advertise();

        function onAdvertised() {
            assert.equal(steveHyperbahnClient.state, 'ADVERTISED', 'state should be ADVERTISED');
            steveHyperbahnClient.once('unadvertised', onUnadvertised);
            steveHyperbahnClient.unadvertise();
        }

        function onUnadvertised() {
            assert.equal(steveHyperbahnClient.latestAdvertisementResult, null, 'latestAdvertisementResult is null');
            assert.equal(steveHyperbahnClient.state, 'UNADVERTISED', 'state should be UNADVERTISED');
            setTimeout(function readvertise() {
                steveHyperbahnClient.once('advertised', onReadvertised);
                steveHyperbahnClient.advertise();
            }, 100);
        }

        function onReadvertised() {
            assert.equal(steveHyperbahnClient.state, 'ADVERTISED', 'state should be ADVERTISED');
            steveHyperbahnClient.destroy();
            assert.end();
        }
    });

}
<commit_msg>Wait for all in connections to be removed to confirm unadvertise<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var DebugLogtron = require('debug-logtron');
var setTimeout = require('timers').setTimeout;

var HyperbahnClient = require('tchannel/hyperbahn/index.js');
var TChannelJSON = require('tchannel/as/json');
// var timers = TimeMock(Date.now());

module.exports = runTests;

if (require.main === module) {
    runTests(require('../lib/test-cluster.js'));
}

function runTests(HyperbahnCluster) {
    HyperbahnCluster.test('advertise and forward', {
        size: 5,
        servicePurgePeriod: 50
    }, function t(cluster, assert) {
        var steve = cluster.remotes.steve;
        var bob = cluster.remotes.bob;

        var tchannelJSON = TChannelJSON({
            logger: cluster.logger
        });

        var steveHyperbahnClient = new HyperbahnClient({
            serviceName: steve.serviceName,
            callerName: 'forward-test',
            hostPortList: cluster.hostPortList,
            tchannel: steve.channel,
            advertiseInterval: 2,
            logger: DebugLogtron('hyperbahnClient')
        });

        steveHyperbahnClient.once('advertised', onAdvertised);
        steveHyperbahnClient.advertise();

        function onAdvertised() {
            assert.equal(steveHyperbahnClient.state, 'ADVERTISED', 'state should be ADVERTISED');
            setTimeout(function onSend() {
                tchannelJSON.send(bob.clientChannel.request({
                    timeout: 5000,
                    serviceName: steve.serviceName
                }), 'echo', null, 'oh hi lol', onForwarded);
            }, 55);
        }

        function onForwarded(err, resp) {
            assert.ifError(err);
            assert.equal(String(resp.body), 'oh hi lol');

            steveHyperbahnClient.destroy();
            assert.end();
        }
    });

    HyperbahnCluster.test('advertise, unadvertise and forward', {
        size: 5,
        servicePurgePeriod: 50
    }, function t(cluster, assert) {
        var steve = cluster.remotes.steve;
        var bob = cluster.remotes.bob;

        var tchannelJSON = TChannelJSON({
            logger: cluster.logger
        });

        var steveHyperbahnClient = new HyperbahnClient({
            serviceName: steve.serviceName,
            callerName: 'forward-test',
            hostPortList: cluster.hostPortList,
            tchannel: steve.channel,
            advertiseInterval: 2,
            logger: DebugLogtron('hyperbahnClient')
        });
        steveHyperbahnClient.once('advertised', onAdvertised);
        steveHyperbahnClient.advertise();

        function onAdvertised() {
            assert.equal(steveHyperbahnClient.state, 'ADVERTISED', 'state should be ADVERTISED');
            untilAllInConnsRemoved(steve, function onSend() {
                fwdreq = bob.clientChannel.request({
                    timeout: 5000,
                    serviceName: steve.serviceName
                });
                tchannelJSON.send(fwdreq, 'echo', null, 'oh hi lol', onForwarded);
            });
            steveHyperbahnClient.once('unadvertised', onUnadvertised);
            steveHyperbahnClient.unadvertise();
        }

        var fwdreq;
        function onUnadvertised() {
            assert.equal(steveHyperbahnClient.latestAdvertisementResult, null, 'latestAdvertisementResult is null');
            assert.equal(steveHyperbahnClient.state, 'UNADVERTISED', 'state should be UNADVERTISED');
        }

        function onForwarded(err, resp) {
            assert.ok(err && err.type === 'tchannel.declined' && err.message === 'no peer available for request');
            steveHyperbahnClient.destroy();
            assert.end();
        }
    });

    HyperbahnCluster.test('advertise, unadvertise and re-advertise', {
        size: 5
    }, function t(cluster, assert) {
        var steve = cluster.remotes.steve;
        var steveHyperbahnClient = new HyperbahnClient({
            serviceName: steve.serviceName,
            callerName: 'forward-test',
            hostPortList: cluster.hostPortList,
            tchannel: steve.channel,
            advertiseInterval: 2,
            logger: DebugLogtron('hyperbahnClient')
        });
        steveHyperbahnClient.once('advertised', onAdvertised);
        steveHyperbahnClient.advertise();

        function onAdvertised() {
            assert.equal(steveHyperbahnClient.state, 'ADVERTISED', 'state should be ADVERTISED');
            untilAllInConnsRemoved(steve, function readvertise() {
                steveHyperbahnClient.once('advertised', onReadvertised);
                steveHyperbahnClient.advertise();
            });
            steveHyperbahnClient.once('unadvertised', onUnadvertised);
            steveHyperbahnClient.unadvertise();
        }

        function onUnadvertised() {
            assert.equal(steveHyperbahnClient.latestAdvertisementResult, null, 'latestAdvertisementResult is null');
            assert.equal(steveHyperbahnClient.state, 'UNADVERTISED', 'state should be UNADVERTISED');
        }

        function onReadvertised() {
            assert.equal(steveHyperbahnClient.state, 'ADVERTISED', 'state should be ADVERTISED');
            steveHyperbahnClient.destroy();
            assert.end();
        }
    });

    function untilAllInConnsRemoved(remote, callback) {
        var peers = remote.channel.peers.values();
        var count = 0;
        peers.forEach(function eachPeer(peer) {
            peer.connections.forEach(function eachConn(conn) {
                if (conn.direction === 'in') {
                    count++;
                }
            });
            peer.removeConnectionEvent.on(onRemove);
        });
        function onRemove(conn) {
            if (conn.direction === 'in') {
                if (--count <= 0) {
                    callback(null);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
//
import {
  applyHooks,
  applyPropHooks,
  mergeProps,
  flexRender,
  decorateColumnTree,
  makeHeaderGroups,
  findMaxDepth,
  flattenBy,
} from '../utils'

import { useTableState } from './useTableState'

const propTypes = {
  // General
  data: PropTypes.array.isRequired,
  columns: PropTypes.arrayOf(
    PropTypes.shape({
      Cell: PropTypes.any,
      Header: PropTypes.any,
    })
  ).isRequired,
  defaultColumn: PropTypes.object,
  subRowsKey: PropTypes.string,
  debug: PropTypes.bool,
}

const renderErr =
  'You must specify a valid render component. This could be "column.Cell", "column.Header", "column.Filter", "column.Aggregated" or any other custom renderer component.'

const defaultColumnInstance = {}

export const useTable = (props, ...plugins) => {
  // Validate props
  PropTypes.checkPropTypes(propTypes, props, 'property', 'useTable')

  // Destructure props
  let {
    data,
    state: userState,
    columns: userColumns,
    defaultColumn = defaultColumnInstance,
    subRowsKey = 'subRows',
    debug,
  } = props

  debug = process.env.NODE_ENV === 'production' ? false : debug

  // Always provide a default state
  const defaultState = useTableState()

  // But use the users state if provided
  const state = userState || defaultState

  // The initial api
  let instanceRef = React.useRef({})

  Object.assign(instanceRef.current, {
    ...props,
    data,
    state,
    plugins,
    hooks: {
      columnsBeforeHeaderGroups: [],
      columnsBeforeHeaderGroupsDeps: [],
      useMain: [],
      useColumns: [],
      useHeaders: [],
      useHeaderGroups: [],
      useRows: [],
      prepareRow: [],
      getTableProps: [],
      getRowProps: [],
      getHeaderGroupProps: [],
      getHeaderProps: [],
      getCellProps: [],
    },
  })

  // Allow plugins to register hooks
  if (process.env.NODE_ENV === 'development' && debug) console.time('plugins')
  plugins.filter(Boolean).forEach(plugin => {
    plugin(instanceRef.current.hooks)
  })
  if (process.env.NODE_ENV === 'development' && debug)
    console.timeEnd('plugins')

  if (process.env.NODE_ENV === 'development' && debug)
    console.info('buildColumns/headerGroup/headers')
  // Decorate All the columns
  let columnTree = React.useMemo(
    () => decorateColumnTree(userColumns, defaultColumn),
    [defaultColumn, userColumns]
  )

  // Get the flat list of all columns
  let columns = React.useMemo(() => flattenBy(columnTree, 'columns'), [
    columnTree,
  ])

  // Allow hooks to decorate columns (and trigger this memoization via deps)
  columns = React.useMemo(() => {
    if (process.env.NODE_ENV === 'development' && debug)
      console.time('hooks.columnsBeforeHeaderGroups')
    const newColumns = applyHooks(
      instanceRef.current.hooks.columnsBeforeHeaderGroups,
      columns,
      instanceRef.current
    )
    if (process.env.NODE_ENV === 'development' && debug)
      console.timeEnd('hooks.columnsBeforeHeaderGroups')
    return newColumns
  }, [
    columns,
    debug,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    ...applyHooks(
      instanceRef.current.hooks.columnsBeforeHeaderGroupsDeps,
      [],
      instanceRef.current
    ),
  ])

  // Make the headerGroups
  const headerGroups = React.useMemo(
    () => makeHeaderGroups(columns, findMaxDepth(columnTree), defaultColumn),
    [columnTree, columns, defaultColumn]
  )

  const headers = React.useMemo(() => flattenBy(headerGroups, 'headers'), [
    headerGroups,
  ])

  Object.assign(instanceRef.current, {
    columns,
    headerGroups,
    headers,
  })

  // Access the row model
  const [rows, rowPaths, flatRows] = React.useMemo(() => {
    if (process.env.NODE_ENV === 'development' && debug)
      console.time('getAccessedRows')

    let flatRows = 0
    const rowPaths = []

    // Access the row's data
    const accessRow = (originalRow, i, depth = 0, parentPath = []) => {
      // Keep the original reference around
      const original = originalRow

      // Make the new path for the row
      const path = [...parentPath, i]

      flatRows++
      rowPaths.push(path.join('.'))

      // Process any subRows
      const subRows = originalRow[subRowsKey]
        ? originalRow[subRowsKey].map((d, i) =>
            accessRow(d, i, depth + 1, path)
          )
        : []

      const row = {
        original,
        index: i,
        path, // used to create a key for each row even if not nested
        subRows,
        depth,
        cells: [{}], // This is a dummy cell
      }

      // Override common array functions (and the dummy cell's getCellProps function)
      // to show an error if it is accessed without calling prepareRow
      const unpreparedAccessWarning = () => {
        throw new Error(
          'React-Table: You have not called prepareRow(row) one or more rows you are attempting to render.'
        )
      }
      row.cells.map = unpreparedAccessWarning
      row.cells.filter = unpreparedAccessWarning
      row.cells.forEach = unpreparedAccessWarning
      row.cells[0].getCellProps = unpreparedAccessWarning

      // Create the cells and values
      row.values = {}
      instanceRef.current.columns.forEach(column => {
        row.values[column.id] = column.accessor
          ? column.accessor(originalRow, i, { subRows, depth, data })
          : undefined
      })

      return row
    }

    // Use the resolved data
    const accessedData = data.map((d, i) => accessRow(d, i))
    if (process.env.NODE_ENV === 'development' && debug)
      console.timeEnd('getAccessedRows')
    return [accessedData, rowPaths, flatRows]
  }, [debug, data, subRowsKey])

  instanceRef.current.rows = rows
  instanceRef.current.rowPaths = rowPaths
  instanceRef.current.flatRows = flatRows

  // Determine column visibility
  instanceRef.current.columns.forEach(column => {
    column.visible =
      typeof column.show === 'function'
        ? column.show(instanceRef.current)
        : !!column.show
  })

  if (process.env.NODE_ENV === 'development' && debug)
    console.time('hooks.useMain')
  instanceRef.current = applyHooks(
    instanceRef.current.hooks.useMain,
    instanceRef.current
  )
  if (process.env.NODE_ENV === 'development' && debug)
    console.timeEnd('hooks.useMain')
  ;[...instanceRef.current.columns, ...instanceRef.current.headers].forEach(
    column => {
      // Give columns/headers rendering power
      column.render = (type, userProps = {}) => {
        const Comp = typeof type === 'string' ? column[type] : type

        if (typeof Comp === 'undefined') {
          throw new Error(renderErr)
        }

        return flexRender(Comp, {
          ...instanceRef.current,
          column,
          ...userProps,
        })
      }

      // Give columns/headers a default getHeaderProps
      column.getHeaderProps = props =>
        mergeProps(
          {
            key: ['header', column.id].join('_'),
            colSpan: column.columns
              ? column.columns.filter(column => column.visible).length
              : 1,
          },
          applyPropHooks(
            instanceRef.current.hooks.getHeaderProps,
            column,
            instanceRef.current
          ),
          props
        )
    }
  )

  instanceRef.current.headerGroups.filter((headerGroup, i) => {
    // Filter out any headers and headerGroups that don't have visible columns
    headerGroup.headers = headerGroup.headers.filter(header => {
      const recurse = columns =>
        columns.filter(column => {
          if (column.columns) {
            return recurse(column.columns)
          }
          return column.visible
        }).length
      if (header.columns) {
        return recurse(header.columns)
      }
      return header.visible
    })

    // Give headerGroups getRowProps
    if (headerGroup.headers.length) {
      headerGroup.getHeaderGroupProps = (props = {}) =>
        mergeProps(
          {
            key: [`header${i}`].join('_'),
          },
          applyPropHooks(
            instanceRef.current.hooks.getHeaderGroupProps,
            headerGroup,
            instanceRef.current
          ),
          props
        )
      return true
    }

    return false
  })

  // Run the rows (this could be a dangerous hook with a ton of data)
  if (process.env.NODE_ENV === 'development' && debug)
    console.time('hooks.useRows')
  instanceRef.current.rows = applyHooks(
    instanceRef.current.hooks.useRows,
    instanceRef.current.rows,
    instanceRef.current
  )
  if (process.env.NODE_ENV === 'development' && debug)
    console.timeEnd('hooks.useRows')

  // The prepareRow function is absolutely necessary and MUST be called on
  // any rows the user wishes to be displayed.

  instanceRef.current.prepareRow = row => {
    row.getRowProps = props =>
      mergeProps(
        { key: ['row', ...row.path].join('_') },
        applyPropHooks(
          instanceRef.current.hooks.getRowProps,
          row,
          instanceRef.current
        ),
        props
      )

    const visibleColumns = instanceRef.current.columns.filter(
      column => column.visible
    )

    // Build the cells for each row
    row.cells = visibleColumns.map(column => {
      const cell = {
        column,
        row,
        value: row.values[column.id],
      }

      // Give each cell a getCellProps base
      cell.getCellProps = props => {
        const columnPathStr = [...row.path, column.id].join('_')
        return mergeProps(
          {
            key: ['cell', columnPathStr].join('_'),
          },
          applyPropHooks(
            instanceRef.current.hooks.getCellProps,
            cell,
            instanceRef.current
          ),
          props
        )
      }

      // Give each cell a renderer function (supports multiple renderers)
      cell.render = (type, userProps = {}) => {
        const Comp = typeof type === 'string' ? column[type] : type

        if (typeof Comp === 'undefined') {
          throw new Error(renderErr)
        }

        return flexRender(Comp, {
          ...instanceRef.current,
          column,
          row,
          cell,
          ...userProps,
        })
      }

      return cell
    })

    // need to apply any row specific hooks (useExpanded requires this)
    applyHooks(instanceRef.current.hooks.prepareRow, row, instanceRef.current)
  }

  instanceRef.current.getTableProps = userProps =>
    mergeProps(
      applyPropHooks(
        instanceRef.current.hooks.getTableProps,
        instanceRef.current
      ),
      userProps
    )

  return instanceRef.current
}
<commit_msg>Allow row generator to listen for column changes (#1442)<commit_after>import React from 'react'
import PropTypes from 'prop-types'
//
import {
  applyHooks,
  applyPropHooks,
  mergeProps,
  flexRender,
  decorateColumnTree,
  makeHeaderGroups,
  findMaxDepth,
  flattenBy,
} from '../utils'

import { useTableState } from './useTableState'

const propTypes = {
  // General
  data: PropTypes.array.isRequired,
  columns: PropTypes.arrayOf(
    PropTypes.shape({
      Cell: PropTypes.any,
      Header: PropTypes.any,
    })
  ).isRequired,
  defaultColumn: PropTypes.object,
  subRowsKey: PropTypes.string,
  debug: PropTypes.bool,
}

const renderErr =
  'You must specify a valid render component. This could be "column.Cell", "column.Header", "column.Filter", "column.Aggregated" or any other custom renderer component.'

const defaultColumnInstance = {}

export const useTable = (props, ...plugins) => {
  // Validate props
  PropTypes.checkPropTypes(propTypes, props, 'property', 'useTable')

  // Destructure props
  let {
    data,
    state: userState,
    columns: userColumns,
    defaultColumn = defaultColumnInstance,
    subRowsKey = 'subRows',
    debug,
  } = props

  debug = process.env.NODE_ENV === 'production' ? false : debug

  // Always provide a default state
  const defaultState = useTableState()

  // But use the users state if provided
  const state = userState || defaultState

  // The initial api
  let instanceRef = React.useRef({})

  Object.assign(instanceRef.current, {
    ...props,
    data,
    state,
    plugins,
    hooks: {
      columnsBeforeHeaderGroups: [],
      columnsBeforeHeaderGroupsDeps: [],
      useMain: [],
      useColumns: [],
      useHeaders: [],
      useHeaderGroups: [],
      useRows: [],
      prepareRow: [],
      getTableProps: [],
      getRowProps: [],
      getHeaderGroupProps: [],
      getHeaderProps: [],
      getCellProps: [],
    },
  })

  // Allow plugins to register hooks
  if (process.env.NODE_ENV === 'development' && debug) console.time('plugins')
  plugins.filter(Boolean).forEach(plugin => {
    plugin(instanceRef.current.hooks)
  })
  if (process.env.NODE_ENV === 'development' && debug)
    console.timeEnd('plugins')

  if (process.env.NODE_ENV === 'development' && debug)
    console.info('buildColumns/headerGroup/headers')
  // Decorate All the columns
  let columnTree = React.useMemo(
    () => decorateColumnTree(userColumns, defaultColumn),
    [defaultColumn, userColumns]
  )

  // Get the flat list of all columns
  let columns = React.useMemo(() => flattenBy(columnTree, 'columns'), [
    columnTree,
  ])

  // Allow hooks to decorate columns (and trigger this memoization via deps)
  columns = React.useMemo(() => {
    if (process.env.NODE_ENV === 'development' && debug)
      console.time('hooks.columnsBeforeHeaderGroups')
    const newColumns = applyHooks(
      instanceRef.current.hooks.columnsBeforeHeaderGroups,
      columns,
      instanceRef.current
    )
    if (process.env.NODE_ENV === 'development' && debug)
      console.timeEnd('hooks.columnsBeforeHeaderGroups')
    return newColumns
  }, [
    columns,
    debug,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    ...applyHooks(
      instanceRef.current.hooks.columnsBeforeHeaderGroupsDeps,
      [],
      instanceRef.current
    ),
  ])

  // Make the headerGroups
  const headerGroups = React.useMemo(
    () => makeHeaderGroups(columns, findMaxDepth(columnTree), defaultColumn),
    [columnTree, columns, defaultColumn]
  )

  const headers = React.useMemo(() => flattenBy(headerGroups, 'headers'), [
    headerGroups,
  ])

  Object.assign(instanceRef.current, {
    columns,
    headerGroups,
    headers,
  })

  // Access the row model
  const [rows, rowPaths, flatRows] = React.useMemo(() => {
    if (process.env.NODE_ENV === 'development' && debug)
      console.time('getAccessedRows')

    let flatRows = 0
    const rowPaths = []

    // Access the row's data
    const accessRow = (originalRow, i, depth = 0, parentPath = []) => {
      // Keep the original reference around
      const original = originalRow

      // Make the new path for the row
      const path = [...parentPath, i]

      flatRows++
      rowPaths.push(path.join('.'))

      // Process any subRows
      const subRows = originalRow[subRowsKey]
        ? originalRow[subRowsKey].map((d, i) =>
            accessRow(d, i, depth + 1, path)
          )
        : []

      const row = {
        original,
        index: i,
        path, // used to create a key for each row even if not nested
        subRows,
        depth,
        cells: [{}], // This is a dummy cell
      }

      // Override common array functions (and the dummy cell's getCellProps function)
      // to show an error if it is accessed without calling prepareRow
      const unpreparedAccessWarning = () => {
        throw new Error(
          'React-Table: You have not called prepareRow(row) one or more rows you are attempting to render.'
        )
      }
      row.cells.map = unpreparedAccessWarning
      row.cells.filter = unpreparedAccessWarning
      row.cells.forEach = unpreparedAccessWarning
      row.cells[0].getCellProps = unpreparedAccessWarning

      // Create the cells and values
      row.values = {}
      columns.forEach(column => {
        row.values[column.id] = column.accessor
          ? column.accessor(originalRow, i, { subRows, depth, data })
          : undefined
      })

      return row
    }

    // Use the resolved data
    const accessedData = data.map((d, i) => accessRow(d, i))
    if (process.env.NODE_ENV === 'development' && debug)
      console.timeEnd('getAccessedRows')
    return [accessedData, rowPaths, flatRows]
  }, [debug, data, columns, subRowsKey])

  instanceRef.current.rows = rows
  instanceRef.current.rowPaths = rowPaths
  instanceRef.current.flatRows = flatRows

  // Determine column visibility
  instanceRef.current.columns.forEach(column => {
    column.visible =
      typeof column.show === 'function'
        ? column.show(instanceRef.current)
        : !!column.show
  })

  if (process.env.NODE_ENV === 'development' && debug)
    console.time('hooks.useMain')
  instanceRef.current = applyHooks(
    instanceRef.current.hooks.useMain,
    instanceRef.current
  )
  if (process.env.NODE_ENV === 'development' && debug)
    console.timeEnd('hooks.useMain')
  ;[...instanceRef.current.columns, ...instanceRef.current.headers].forEach(
    column => {
      // Give columns/headers rendering power
      column.render = (type, userProps = {}) => {
        const Comp = typeof type === 'string' ? column[type] : type

        if (typeof Comp === 'undefined') {
          throw new Error(renderErr)
        }

        return flexRender(Comp, {
          ...instanceRef.current,
          column,
          ...userProps,
        })
      }

      // Give columns/headers a default getHeaderProps
      column.getHeaderProps = props =>
        mergeProps(
          {
            key: ['header', column.id].join('_'),
            colSpan: column.columns
              ? column.columns.filter(column => column.visible).length
              : 1,
          },
          applyPropHooks(
            instanceRef.current.hooks.getHeaderProps,
            column,
            instanceRef.current
          ),
          props
        )
    }
  )

  instanceRef.current.headerGroups.filter((headerGroup, i) => {
    // Filter out any headers and headerGroups that don't have visible columns
    headerGroup.headers = headerGroup.headers.filter(header => {
      const recurse = columns =>
        columns.filter(column => {
          if (column.columns) {
            return recurse(column.columns)
          }
          return column.visible
        }).length
      if (header.columns) {
        return recurse(header.columns)
      }
      return header.visible
    })

    // Give headerGroups getRowProps
    if (headerGroup.headers.length) {
      headerGroup.getHeaderGroupProps = (props = {}) =>
        mergeProps(
          {
            key: [`header${i}`].join('_'),
          },
          applyPropHooks(
            instanceRef.current.hooks.getHeaderGroupProps,
            headerGroup,
            instanceRef.current
          ),
          props
        )
      return true
    }

    return false
  })

  // Run the rows (this could be a dangerous hook with a ton of data)
  if (process.env.NODE_ENV === 'development' && debug)
    console.time('hooks.useRows')
  instanceRef.current.rows = applyHooks(
    instanceRef.current.hooks.useRows,
    instanceRef.current.rows,
    instanceRef.current
  )
  if (process.env.NODE_ENV === 'development' && debug)
    console.timeEnd('hooks.useRows')

  // The prepareRow function is absolutely necessary and MUST be called on
  // any rows the user wishes to be displayed.

  instanceRef.current.prepareRow = row => {
    row.getRowProps = props =>
      mergeProps(
        { key: ['row', ...row.path].join('_') },
        applyPropHooks(
          instanceRef.current.hooks.getRowProps,
          row,
          instanceRef.current
        ),
        props
      )

    const visibleColumns = instanceRef.current.columns.filter(
      column => column.visible
    )

    // Build the cells for each row
    row.cells = visibleColumns.map(column => {
      const cell = {
        column,
        row,
        value: row.values[column.id],
      }

      // Give each cell a getCellProps base
      cell.getCellProps = props => {
        const columnPathStr = [...row.path, column.id].join('_')
        return mergeProps(
          {
            key: ['cell', columnPathStr].join('_'),
          },
          applyPropHooks(
            instanceRef.current.hooks.getCellProps,
            cell,
            instanceRef.current
          ),
          props
        )
      }

      // Give each cell a renderer function (supports multiple renderers)
      cell.render = (type, userProps = {}) => {
        const Comp = typeof type === 'string' ? column[type] : type

        if (typeof Comp === 'undefined') {
          throw new Error(renderErr)
        }

        return flexRender(Comp, {
          ...instanceRef.current,
          column,
          row,
          cell,
          ...userProps,
        })
      }

      return cell
    })

    // need to apply any row specific hooks (useExpanded requires this)
    applyHooks(instanceRef.current.hooks.prepareRow, row, instanceRef.current)
  }

  instanceRef.current.getTableProps = userProps =>
    mergeProps(
      applyPropHooks(
        instanceRef.current.hooks.getTableProps,
        instanceRef.current
      ),
      userProps
    )

  return instanceRef.current
}
<|endoftext|>


<commit_before>import { CloudContext } from './utils';

describe('OpenGraph story', () => {
  const ctx = new CloudContext();

  describe('When alice requests opengraph info for our blog', () => {
    ctx.requestShouldNotError(async () => {
      ctx.response = await ctx.alice.og('https://getstream.io/blog/try-out-the-stream-api-with-postman');
    });

    ctx.responseShould('have the expected content', () => {
      ctx.shouldHaveNonEmptyKeys(ctx.response, 'type', 'title', 'description', 'url', 'favicon', 'images');
      ctx.shouldHaveNonEmptyKeys(ctx.response.images[0], 'height', 'width', 'image');
    });
  });

  describe('When alice requests opengraph info for a binary blob', () => {
    ctx.requestShouldError(400, async () => {
      ctx.response = await ctx.alice.og('https://github.com/buger/goreplay/releases/download/v0.14.0/gor.exe');
    });

    ctx.responseShould('have the expected content', () => {
      ctx.shouldEqualBesideDuration(ctx.response, {
        detail: 'url content too big',
        status_code: 400,
        code: 4,
        exception: 'InputException',
        more_info: 'https://getstream.io/docs/api_error_responses',
      });
    });
  });
});
<commit_msg>Do not expect width/height in og test (#394)<commit_after>import { CloudContext } from './utils';

describe('OpenGraph story', () => {
  const ctx = new CloudContext();

  describe('When alice requests opengraph info for our blog', () => {
    ctx.requestShouldNotError(async () => {
      ctx.response = await ctx.alice.og('https://getstream.io/blog/try-out-the-stream-api-with-postman');
    });

    ctx.responseShould('have the expected content', () => {
      ctx.shouldHaveNonEmptyKeys(ctx.response, 'type', 'title', 'description', 'url', 'favicon', 'images');
      ctx.shouldHaveNonEmptyKeys(ctx.response.images[0], 'image');
    });
  });

  describe('When alice requests opengraph info for a binary blob', () => {
    ctx.requestShouldError(400, async () => {
      ctx.response = await ctx.alice.og('https://github.com/buger/goreplay/releases/download/v0.14.0/gor.exe');
    });

    ctx.responseShould('have the expected content', () => {
      ctx.shouldEqualBesideDuration(ctx.response, {
        detail: 'url content too big',
        status_code: 400,
        code: 4,
        exception: 'InputException',
        more_info: 'https://getstream.io/docs/api_error_responses',
      });
    });
  });
});
<|endoftext|>


<commit_before>import {expect} from 'chai'
import {spawn} from 'child_process'
import exec from '../../util/exec'
import kill from '../../util/kill'
import stdouted from '../../util/stdouted'
import spawnAsync from '../../util/spawnAsync'
import execAsync from '../../util/execAsync'
import path from 'path'
import fs from 'fs'
import rimraf from 'rimraf'
import promisify from 'es6-promisify'
import webpackConfig from '../../webpack/webpack.config.dev'

const root = path.resolve(__dirname, '..', '..')
const src = path.join(root, 'src')
const build = path.join(root, 'build')
const webpack = path.join(root, 'webpack')

async function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

function sharedTests() {
  it('serves page with correct title', async function () {
    expect(await browser.getTitle()).to.equal('Crater')
  })
  it('serves page with correct header', async function () {
    expect(await browser.getText('h1')).to.equal('Welcome to Crater!')
  })
  it('serves up client css', async function () {
    const color = await browser.getCssProperty('h1', 'color')
    expect(color.parsed.hex).to.equal('#333333')
  })
  it('updates the counter', async function () {
    const getCounter = async () => {
      const text = await browser.getText('.counter')
      const match = /(\d+)/.exec(text)
      return match && parseInt(match[1])
    }

    const initCounter = await getCounter()
    await delay(2000)
    expect(await getCounter()).to.be.above(initCounter)
  })
  it('sends Meteor.settings.public to the client', async function () {
    expect(await browser.getText('.settings-test')).to.equal('success')
  })
}

function unlinkIfExists(path, callback) {
  return fs.unlink(path, (err, result) => {
    if (err && /ENOENT/.test(err.message)) err = null
    return callback(err, result)
  })
}

describe('build scripts', function () {
  describe('build:meteor', async function () {
    it('only rebuilds when necessary', async function () {
      this.timeout(120000)

      await promisify(rimraf)(path.join(build, 'meteor'))
      expect(/building meteor packages/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true

      expect(/build\/meteor is up to date/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(root, 'meteor', '.meteor', 'packages'),
        NaN,
        NaN,
      )
      expect(/building meteor packages/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true

      expect(/build\/meteor is up to date/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true
    })
  })
  describe('build:client', function () {
    it('only rebuilds when necessary', async function () {
      this.timeout(120000)

      await spawnAsync('npm', ['run', 'build:meteor'], {stdio: 'inherit'})

      await promisify(unlinkIfExists)(path.join(build, 'assets.json'))
      expect(/building client bundle/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      expect(/client assets are up to date/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(webpack, 'webpack.config.prod.js'),
        NaN,
        NaN
      )
      expect(/building client bundle/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(src, 'client', 'index.js'),
        NaN,
        NaN
      )
      expect(/building client bundle/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      expect(/client assets are up to date/.test((await execAsync('npm run build:client')).stdout)).to.be.true
    })
  })
  describe('build:server', function () {
    it('only rebuilds when necessary', async function () {
      this.timeout(120000)

      await spawnAsync('npm', ['run', 'build:meteor'], {stdio: 'inherit'})

      await promisify(unlinkIfExists)(path.join(build, 'prerender.js'))
      expect(/building server bundle/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      expect(/server assets are up to date/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(webpack, 'webpack.config.server.js'),
        NaN,
        NaN
      )
      expect(/building server bundle/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(src, 'server', 'index.js'),
        NaN,
        NaN
      )
      expect(/building server bundle/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      expect(/server assets are up to date/.test((await execAsync('npm run build:server')).stdout)).to.be.true
    })
  })
})

describe('prod mode', function () {
  let server

  before(async function () {
    this.timeout(240000)
    server = exec('npm run prod')
    await stdouted(server, /App is listening on http/i)
    await browser.reload()
    await browser.url(process.env.ROOT_URL)
  })

  after(async function () {
    this.timeout(30000)
    if (server) await kill(server)
  })

  sharedTests()
})

describe('docker build', function () {
  let server
  let env

  before(async function () {
    this.timeout(480000)
    env = {
      ...process.env,
      TAG: (await execAsync('git rev-parse HEAD')).stdout.trim(),
    }
    await spawnAsync('npm', ['run', 'build:docker'])
    server = exec('npm run docker', {
      env: {
        ...process.env,
        METEOR_SETTINGS: JSON.stringify({
          public: {
            test: 'success'
          }
        })
      }
    })
    await stdouted(server, /App is listening on http/i)
    let host
    if (process.env.CI) host = (await execAsync('docker-compose port crater 80', {env})).stdout.trim()
    else {
      await execAsync('which docker-machine')
        .then(() => host = `192.168.99.100:${process.env.PORT}`)
        .catch(() => host = `localhost:${process.env.PORT}`)
    }
    await browser.reload()
    await browser.url(`http://${host}`)
  })

  after(async function () {
    this.timeout(20000)
    await spawnAsync('docker-compose', ['down'], {env})
  })

  sharedTests()
})

describe('dev mode', function () {
  let server

  const appFile = path.join(src, 'universal', 'components', 'App.js')
  const serverFile = path.join(src, 'server', 'index.js')
  let appCode, serverCode

  before(async function () {
    this.timeout(60000)
    appCode = await promisify(fs.readFile)(appFile, 'utf8')
    serverCode = await promisify(fs.readFile)(serverFile, 'utf8')
    server = exec('npm start')
    await stdouted(server, /webpack built [a-z0-9]+ in \d+ms/i)
    await browser.url(`http://localhost:${webpackConfig.devServer.port}`)
  })

  after(async function () {
    this.timeout(30000)
    // restore code in App.js, which (may) have been changed by hot reloading test
    if (appCode) await promisify(fs.writeFile)(appFile, appCode, 'utf8')
    if (serverCode) await promisify(fs.writeFile)(serverFile, serverCode, 'utf8')
    if (server) await kill(server)
  })

  sharedTests()

  it('supports hot reloading', async function () {
    this.timeout(40000)
    const newHeader = 'Welcome to Crater! with hot reloading'
    const modified = appCode.replace(/Welcome to Crater!/, newHeader)
    await promisify(fs.writeFile)(appFile, modified, 'utf8')
    await browser.waitUntil(
      () => browser.getText('h1') === newHeader,
      20000,
      'expected header text to hot update within 10s'
    )
  })

  it('restarts the server when code is changed', async function () {
    this.timeout(60000)
    const modified = serverCode.replace(/express\(\)/, 'express()\napp.get("/test", (req, res) => res.send("hello world"))')
    await promisify(fs.writeFile)(serverFile, modified, 'utf8')
    await stdouted(server, /App is listening on http/i)
  })
})<commit_msg>increase test timeouts<commit_after>import {expect} from 'chai'
import {spawn} from 'child_process'
import exec from '../../util/exec'
import kill from '../../util/kill'
import stdouted from '../../util/stdouted'
import spawnAsync from '../../util/spawnAsync'
import execAsync from '../../util/execAsync'
import path from 'path'
import fs from 'fs'
import rimraf from 'rimraf'
import promisify from 'es6-promisify'
import webpackConfig from '../../webpack/webpack.config.dev'

const root = path.resolve(__dirname, '..', '..')
const src = path.join(root, 'src')
const build = path.join(root, 'build')
const webpack = path.join(root, 'webpack')

async function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

function sharedTests() {
  it('serves page with correct title', async function () {
    expect(await browser.getTitle()).to.equal('Crater')
  })
  it('serves page with correct header', async function () {
    expect(await browser.getText('h1')).to.equal('Welcome to Crater!')
  })
  it('serves up client css', async function () {
    const color = await browser.getCssProperty('h1', 'color')
    expect(color.parsed.hex).to.equal('#333333')
  })
  it('updates the counter', async function () {
    const getCounter = async () => {
      const text = await browser.getText('.counter')
      const match = /(\d+)/.exec(text)
      return match && parseInt(match[1])
    }

    const initCounter = await getCounter()
    await delay(2000)
    expect(await getCounter()).to.be.above(initCounter)
  })
  it('sends Meteor.settings.public to the client', async function () {
    expect(await browser.getText('.settings-test')).to.equal('success')
  })
}

function unlinkIfExists(path, callback) {
  return fs.unlink(path, (err, result) => {
    if (err && /ENOENT/.test(err.message)) err = null
    return callback(err, result)
  })
}

describe('build scripts', function () {
  describe('build:meteor', async function () {
    it('only rebuilds when necessary', async function () {
      this.timeout(480000)

      await promisify(rimraf)(path.join(build, 'meteor'))
      expect(/building meteor packages/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true

      expect(/build\/meteor is up to date/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(root, 'meteor', '.meteor', 'packages'),
        NaN,
        NaN,
      )
      expect(/building meteor packages/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true

      expect(/build\/meteor is up to date/i.test((await execAsync('npm run build:meteor')).stdout)).to.be.true
    })
  })
  describe('build:client', function () {
    it('only rebuilds when necessary', async function () {
      this.timeout(480000)

      await spawnAsync('npm', ['run', 'build:meteor'], {stdio: 'inherit'})

      await promisify(unlinkIfExists)(path.join(build, 'assets.json'))
      expect(/building client bundle/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      expect(/client assets are up to date/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(webpack, 'webpack.config.prod.js'),
        NaN,
        NaN
      )
      expect(/building client bundle/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(src, 'client', 'index.js'),
        NaN,
        NaN
      )
      expect(/building client bundle/.test((await execAsync('npm run build:client')).stdout)).to.be.true

      expect(/client assets are up to date/.test((await execAsync('npm run build:client')).stdout)).to.be.true
    })
  })
  describe('build:server', function () {
    it('only rebuilds when necessary', async function () {
      this.timeout(480000)

      await spawnAsync('npm', ['run', 'build:meteor'], {stdio: 'inherit'})

      await promisify(unlinkIfExists)(path.join(build, 'prerender.js'))
      expect(/building server bundle/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      expect(/server assets are up to date/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(webpack, 'webpack.config.server.js'),
        NaN,
        NaN
      )
      expect(/building server bundle/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      await delay(1000)
      await promisify(fs.utimes)(
        path.resolve(src, 'server', 'index.js'),
        NaN,
        NaN
      )
      expect(/building server bundle/.test((await execAsync('npm run build:server')).stdout)).to.be.true

      expect(/server assets are up to date/.test((await execAsync('npm run build:server')).stdout)).to.be.true
    })
  })
})

describe('prod mode', function () {
  let server

  before(async function () {
    this.timeout(240000)
    server = exec('npm run prod')
    await stdouted(server, /App is listening on http/i)
    await browser.reload()
    await browser.url(process.env.ROOT_URL)
  })

  after(async function () {
    this.timeout(30000)
    if (server) await kill(server)
  })

  sharedTests()
})

describe('docker build', function () {
  let server
  let env

  before(async function () {
    this.timeout(480000)
    env = {
      ...process.env,
      TAG: (await execAsync('git rev-parse HEAD')).stdout.trim(),
    }
    await spawnAsync('npm', ['run', 'build:docker'])
    server = exec('npm run docker', {
      env: {
        ...process.env,
        METEOR_SETTINGS: JSON.stringify({
          public: {
            test: 'success'
          }
        })
      }
    })
    await stdouted(server, /App is listening on http/i)
    let host
    if (process.env.CI) host = (await execAsync('docker-compose port crater 80', {env})).stdout.trim()
    else {
      await execAsync('which docker-machine')
        .then(() => host = `192.168.99.100:${process.env.PORT}`)
        .catch(() => host = `localhost:${process.env.PORT}`)
    }
    await browser.reload()
    await browser.url(`http://${host}`)
  })

  after(async function () {
    this.timeout(20000)
    await spawnAsync('docker-compose', ['down'], {env})
  })

  sharedTests()
})

describe('dev mode', function () {
  let server

  const appFile = path.join(src, 'universal', 'components', 'App.js')
  const serverFile = path.join(src, 'server', 'index.js')
  let appCode, serverCode

  before(async function () {
    this.timeout(60000)
    appCode = await promisify(fs.readFile)(appFile, 'utf8')
    serverCode = await promisify(fs.readFile)(serverFile, 'utf8')
    server = exec('npm start')
    await stdouted(server, /webpack built [a-z0-9]+ in \d+ms/i)
    await browser.url(`http://localhost:${webpackConfig.devServer.port}`)
  })

  after(async function () {
    this.timeout(30000)
    // restore code in App.js, which (may) have been changed by hot reloading test
    if (appCode) await promisify(fs.writeFile)(appFile, appCode, 'utf8')
    if (serverCode) await promisify(fs.writeFile)(serverFile, serverCode, 'utf8')
    if (server) await kill(server)
  })

  sharedTests()

  it('supports hot reloading', async function () {
    this.timeout(40000)
    const newHeader = 'Welcome to Crater! with hot reloading'
    const modified = appCode.replace(/Welcome to Crater!/, newHeader)
    await promisify(fs.writeFile)(appFile, modified, 'utf8')
    await browser.waitUntil(
      () => browser.getText('h1') === newHeader,
      20000,
      'expected header text to hot update within 10s'
    )
  })

  it('restarts the server when code is changed', async function () {
    this.timeout(60000)
    const modified = serverCode.replace(/express\(\)/, 'express()\napp.get("/test", (req, res) => res.send("hello world"))')
    await promisify(fs.writeFile)(serverFile, modified, 'utf8')
    await stdouted(server, /App is listening on http/i)
  })
})<|endoftext|>


<commit_before>var Ambit = require('./ambitSchema.js');
var q = require('q');

var findAmbit = q.nbind(Ambit.findOne, Ambit);
var findAllAmbits = q.nbind(Ambit.find, Ambit);
var createAmbit = q.nbind(Ambit.create, Ambit);

module.exports.addAmbit = function (req, res, next) {
  //records a new ambit from the user
  var ambit = req.body.ambit;
  ambit.checkIns = [];
  ambit.refId = Math.round(Math.random()*10000);

  findAmbit({refId: ambit.refId}) //should check per user as well
    .then(function(found){
      if (found) {
        return next(new Error('Ambit refId already exists'));
      } else{
        return createAmbit(ambit);
      }
    })
    .then(function (createdAmbit) {
      if (createdAmbit) {
        res.json(createdAmbit);
      }
    })
    .fail(function (error) {
      next(error);
    });
};

module.exports.saveCheckIn = function(req, res, next) {
  //add the current date to the ambits checkIn property
  //TODO: check for a preexisting check-in for this date first

  var refId = req.params.id;

  findAmbit({refId: refId})
  .then(function(ambit) {
    var now = new Date;
    var today = now.toDateString();
    if (ambit.checkIns.length < 1) {
      ambit.checkIns.push( now );
      return ambit.save();
    } else {
      var lastCheck = ambit.checkIns[ambit.checkIns.length -1].toDateString();
      if (today !== lastCheck){
        ambit.checkIns.push( now );
        return ambit.save();
      } else {
        res.json('already checked in');
      }
    }
  })
  .then(function(savedAmbit) {
  console.log(savedAmbit);
    res.send(savedAmbit);
  });
};

module.exports.getAmbits = function(req, res, next) {
  //send an array containing all the ambits back to the user.

  findAllAmbits()
    .then(function(ambits){
      res.send(ambits);
    })
    .fail(function (error) {
      next(error);
    });
};
<commit_msg>(fix) Remove console log<commit_after>var Ambit = require('./ambitSchema.js');
var q = require('q');

var findAmbit = q.nbind(Ambit.findOne, Ambit);
var findAllAmbits = q.nbind(Ambit.find, Ambit);
var createAmbit = q.nbind(Ambit.create, Ambit);

module.exports.addAmbit = function (req, res, next) {
  //records a new ambit from the user
  var ambit = req.body.ambit;
  ambit.checkIns = [];
  ambit.refId = Math.round(Math.random()*10000);

  findAmbit({refId: ambit.refId}) //should check per user as well
    .then(function(found){
      if (found) {
        return next(new Error('Ambit refId already exists'));
      } else{
        return createAmbit(ambit);
      }
    })
    .then(function (createdAmbit) {
      if (createdAmbit) {
        res.json(createdAmbit);
      }
    })
    .fail(function (error) {
      next(error);
    });
};

module.exports.saveCheckIn = function(req, res, next) {
  //add the current date to the ambits checkIn property
  //TODO: check for a preexisting check-in for this date first

  var refId = req.params.id;

  findAmbit({refId: refId})
  .then(function(ambit) {
    var now = new Date;
    var today = now.toDateString();
    if (ambit.checkIns.length < 1) {
      ambit.checkIns.push( now );
      return ambit.save();
    } else {
      var lastCheck = ambit.checkIns[ambit.checkIns.length -1].toDateString();
      if (today !== lastCheck){
        ambit.checkIns.push( now );
        return ambit.save();
      } else {
        res.json('already checked in');
      }
    }
  })
  .then(function(savedAmbit) {
    res.send(savedAmbit);
  });
};

module.exports.getAmbits = function(req, res, next) {
  //send an array containing all the ambits back to the user.

  findAllAmbits()
    .then(function(ambits){
      res.send(ambits);
    })
    .fail(function (error) {
      next(error);
    });
};
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2019  The Software Heritage developers
 * See the AUTHORS file at the top-level directory of this distribution
 * License: GNU Affero General Public License version 3, or any later version
 * See top-level LICENSE file for more information
 */

import axios from 'axios';

export async function httpGetJson(url) {
  const response = await axios.get(url);
  return response.data;
}

/**
 * Converts string with Time information
 * to an object with Time information
 */
export function getTime(text) {
  const date = new Date(text);

  function pad(n) {
    return n < 10 ? '0' + n : n;
  }

  const time = {
    date: date.getUTCDate(),
    month: date.getUTCMonth(),
    monthName: date.toLocaleString('en', { month: 'long' }),
    year: date.getUTCFullYear(),
    hours: pad(date.getUTCHours()),
    minutes: pad(date.getUTCMinutes())
  };

  return time;
}

export function checkLanguageHighlighting(language) {
  cy.get('code')
    .should('be.visible')
    .and('have.class', 'hljs')
    .and('have.class', language)
    .and('not.be.empty')
    .find('table.hljs-ln')
    .should('be.visible')
    .and('not.be.empty');
}

export function random(start, end) {
  const range = end - start;
  return Math.floor(Math.random() * range) + start;
}

export const describeSlowTests = Cypress.env('SKIP_SLOW_TESTS') === 1 ? describe.skip : describe;
<commit_msg>cypress/utils: Fix eslint warning<commit_after>/**
 * Copyright (C) 2019  The Software Heritage developers
 * See the AUTHORS file at the top-level directory of this distribution
 * License: GNU Affero General Public License version 3, or any later version
 * See top-level LICENSE file for more information
 */

import axios from 'axios';

export async function httpGetJson(url) {
  const response = await axios.get(url);
  return response.data;
}

/**
 * Converts string with Time information
 * to an object with Time information
 */
export function getTime(text) {
  const date = new Date(text);

  function pad(n) {
    return n < 10 ? '0' + n : n;
  }

  const time = {
    date: date.getUTCDate(),
    month: date.getUTCMonth(),
    monthName: date.toLocaleString('en', {month: 'long'}),
    year: date.getUTCFullYear(),
    hours: pad(date.getUTCHours()),
    minutes: pad(date.getUTCMinutes())
  };

  return time;
}

export function checkLanguageHighlighting(language) {
  cy.get('code')
    .should('be.visible')
    .and('have.class', 'hljs')
    .and('have.class', language)
    .and('not.be.empty')
    .find('table.hljs-ln')
    .should('be.visible')
    .and('not.be.empty');
}

export function random(start, end) {
  const range = end - start;
  return Math.floor(Math.random() * range) + start;
}

export const describeSlowTests = Cypress.env('SKIP_SLOW_TESTS') === 1 ? describe.skip : describe;
<|endoftext|>


<commit_before>describe('UsageByMonthController tests', function() {
	'use strict';

	var $scope = null,
		years = [10, 5, 6],
		year = years[0],
		data = {
			usage: 5,
			total: 10
		},
		chartData = [],
		mockBWMonService = {
			getYears: function() {
				return years;
			},
			getUsageByMonth: function(year) {
				return {
					data: data,
					chartData: chartData
				};
			}
		};

	beforeEach(module('BWMonApp.controllers'));
	beforeEach(inject(function($rootScope, $controller){
		$scope = $rootScope.$new();

		$scope.chartSeries = [];

		$controller('UsageByMonthController', {
			$scope: $scope,
			BWMonService: mockBWMonService
		});

		spyOn($scope, '$watch');
	}));

	it('should update years with getYears', inject(function() {
		var expected = years,
			actual = $scope.years;

		expect(expected).toEqual(actual);

	}));

	it('should update year with getYears first element', inject(function() {
		var expected = year,
			actual = $scope.year;

		expect(expected).toEqual(actual);
	}));

	it('should update data with getUsageByMonth', inject(function() {
		var expected = data.usage,
			actual = $scope.data;

		expect(expected).toEqual(actual);
	}));

	it('should update total with getUsageByMonth', inject(function() {
		var expected = data.total,
			actual = $scope.total;

		expect(expected).toEqual(actual);
	}));

	it('should update chart data with getUsageByMonth', inject(function() {
		var expected = [],
			actual = $scope.chartData;

		expect(expected).toEqual(actual);
	}));

	it('should update graph options - series with getUsageByMonth', inject(function() {
		var expected = {series: $scope.chartSeries},
			actual = $scope.chartOptions;

		expect(expected.series).toEqual(actual.series);
	}));

	it('should update graph options with non empty label - x axes', inject(function() {
		var expected = 'February',
			actual = $scope.chartOptions.axes.x.labelFunction(1);

		expect(expected).toEqual(actual);
	}));

	it('should update graph options with empty label - x axes', inject(function() {
		var expected = '',
			actual = $scope.chartOptions.axes.x.labelFunction(1.1);

		expect(expected).toEqual(actual);
	}));

	it('should update graph options with non empty tootltip - x axes', inject(function() {
		var expected = 'February',
			actual = $scope.chartOptions.axes.x.tooltipFormatter(1);

		expect(expected).toEqual(actual);
	}));

	it('should update graph options with empty tootltip - x axes', inject(function() {
		var expected = '',
			actual = $scope.chartOptions.axes.x.tooltipFormatter(1.1);

		expect(expected).toEqual(actual);
	}));

});
<commit_msg>JB For the spec UsageByMonthController, we are now mocking the real service. If the BWMonService interface changes the tests will break.<commit_after>describe('UsageByMonthController tests', function() {
	'use strict';

	var $scope = null,
		years = [10, 5, 6],
		year = years[0],
		data = {
			usage: 5,
			total: 10
		},
		chartData = [],
		mockBWMonService;

    beforeEach(module('BWMonApp.services'));
	beforeEach(module('BWMonApp.controllers'));

	beforeEach(inject(function($rootScope, $controller, _BWMonService_){

        $scope = $rootScope.$new();
		$scope.chartSeries = [];
        spyOn($scope, '$watch');

        mockBWMonService = _BWMonService_;
        spyOn(mockBWMonService, 'getYears').andReturn(years);
        spyOn(mockBWMonService, 'getUsageByMonth').andReturn({data: data, chartData: chartData});

		$controller('UsageByMonthController', {
			$scope: $scope,
			BWMonService: mockBWMonService
		});

	}));

	it('should update years with getYears', inject(function() {
		var expected = years,
			actual = $scope.years;

		expect(expected).toEqual(actual);

	}));

	it('should update year with getYears first element', inject(function() {
		var expected = year,
			actual = $scope.year;

		expect(expected).toEqual(actual);
	}));

	it('should update data with getUsageByMonth', inject(function() {
		var expected = data.usage,
			actual = $scope.data;

		expect(expected).toEqual(actual);
	}));

	it('should update total with getUsageByMonth', inject(function() {
		var expected = data.total,
			actual = $scope.total;

		expect(expected).toEqual(actual);
	}));

	it('should update chart data with getUsageByMonth', inject(function() {
		var expected = [],
			actual = $scope.chartData;

		expect(expected).toEqual(actual);
	}));

	it('should update graph options - series with getUsageByMonth', inject(function() {
		var expected = {series: $scope.chartSeries},
			actual = $scope.chartOptions;

		expect(expected.series).toEqual(actual.series);
	}));

	it('should update graph options with non empty label - x axes', inject(function() {
		var expected = 'February',
			actual = $scope.chartOptions.axes.x.labelFunction(1);

		expect(expected).toEqual(actual);
	}));

	it('should update graph options with empty label - x axes', inject(function() {
		var expected = '',
			actual = $scope.chartOptions.axes.x.labelFunction(1.1);

		expect(expected).toEqual(actual);
	}));

	it('should update graph options with non empty tootltip - x axes', inject(function() {
		var expected = 'February',
			actual = $scope.chartOptions.axes.x.tooltipFormatter(1);

		expect(expected).toEqual(actual);
	}));

	it('should update graph options with empty tootltip - x axes', inject(function() {
		var expected = '',
			actual = $scope.chartOptions.axes.x.tooltipFormatter(1.1);

		expect(expected).toEqual(actual);
	}));

});
<|endoftext|>