<commit_before>/**
 * liveSearcher - jQuery Plugin
 * version: 1.0
 * requires jQuery v1.6 or later
 *
 * Documentation: https://github.com/readdle/jquery-livesearcher
 *
 * Copyright (c) 2013 Rodik Alexandr - rodik@readdle.com
 */
(function($) {

    $.fn.liveSearch = function(options) {
        options = $.extend({
            dataSource: "",             // Data source URL
            method: "GET",              // GET/POST
            cache: false,               // (true/false) prevent request caching by adding timestamp to the URL
            search_item: 'search-item', // id of the search result list item
            fadeSpeed: 150,             // result list fadeIn and fadeOut speed
            clearOnSelect: false        // if true - input field is cleared after the user select the result list element
        }, options);

        var obj = this;

        this.search = function() {
            var query_value = $.trim($(obj).val());
            if(query_value !== '') {
                $.ajax({
                    type: options.method,
                    url: options.dataSource,
                    data: { query: query_value },
                    cache: options.cache,
                    success: function(response) {
                        var results = $(obj).parent().find(".results");
                        try {
                            results.html("");
                            var parsed = $.parseJSON(response);
                            $.each(parsed, function(i, val) {
                                $('<div/>')
                                    .addClass(options.search_item)
                                    .addClass('element')
                                    .text(val.data.split('%%')[0])
                                    .attr('data-name', val.data)
                                    .attr('data-id', val.id)
                                    .appendTo(results);
                            });
                            $(obj).trigger('liveSearch.dataLoaded', response);
                        }
                        catch (err) {}
                    }
                });
            } return false;
        };

        // Calculate position of the ".results" block
        this.calcResultsPosition = function() {
            var results = this.parent().find('.results');
            var offset = this.offset();
            var height = this.outerHeight();
            var width = this.innerWidth();
            results.offset({
                top: offset.top+height,
                left: offset.left
            });
            results.width(width);
        };

        var init = function() {
            var id = $(this).attr('id');

            $(this).live("keyup", function(e) {
                // Set Timeout
                clearTimeout($.data(this, 'timer'));

                // Set Search String
                var search_string = $(obj).val();

                // Do Search
                if (search_string == '') {
                    $(this).parent().find(".results").fadeOut({duration: options.fadeSpeed, queue: false});
                } else {
                    $(this).parent().find(".results").fadeIn({duration: options.fadeSpeed, queue: false});
                    obj.calcResultsPosition();
                    $(this).data('timer', setTimeout(obj.search, 150));
                }
                $(this).parent().find(".results").scrollTop(0);
            });

            $(this).focusin(function() {
                // calculation of the number of items found
                var elements = $(this).parent().find('.results').children().size();
                if(elements && $(this).val().length) {
                    $(this).parent().find('.results').fadeIn({duration: options.fadeSpeed, queue: false});
                }
            });

            $(this).focusout(function() {
                $(this).parent().find('.results').fadeOut(150);
            });

            // Prevent multiple event listener bind
            var addEventListener = true;
            if (typeof window.liveSearchBind === 'undefined') {
                window.liveSearchBind = []
            } else {
                var len = window.liveSearchBind.length;
                for (var i=0; i<len; i++) {
                    if(window.liveSearchBind[i] === options.search_item) {
                        addEventListener = false;
                        break;
                    }
                }
            }

            if(addEventListener) {

                $('.'+options.search_item).live("click", function(e) {
                    var id = $(this).attr('data-id');
                    var name = $(this).attr('data-name')

                    if(options.clearOnSelect) {
                        obj.val('');
                    } else {
                        obj.val($(this).text());
                    }

                    obj.attr('data-name', name);
                    obj.attr('data-id', id);

                    $(this).parent('.results').fadeOut(150)

                    $(this).trigger('liveSearch.select', {
                        'id': id,
                        'data': name
                    });

                    e.preventDefault();
                });

                window.liveSearchBind.push(options.search_item);

            }

        };

        return this.each(init);
    };
})(jQuery);<commit_msg>New version 1.1<commit_after>/**
 * liveSearcher - jQuery Plugin
 * version: 1.1
 * requires jQuery v1.6 or later
 *
 * Documentation: https://github.com/readdle/jquery-livesearcher
 *
 * Copyright (c) 2013 Rodik Alexandr - rodik@readdle.com
 */
(function($) {

    $.fn.liveSearch = function(options) {
        options = $.extend({
            dataSource: "",             // Data source URL
            method: "GET",              // GET/POST
            cache: false,               // (true/false) prevent request caching by adding timestamp to the URL
            search_item: 'search-item', // id of the search result list item
            fadeSpeed: 150,             // result list fadeIn and fadeOut speed
            clearOnSelect: false,       // if true - input field is cleared after the user select the result list element
            notFoundText: "No records found" // Show this text, if the server has not found records
        }, options);

        var obj = this;

        this.search = function() {
            var query_value = $.trim($(obj).val());
            if(query_value !== '') {
                $.ajax({
                    type: options.method,
                    url: options.dataSource,
                    data: { query: query_value },
                    cache: options.cache,
                    success: function(response) {
                        var results = $(obj).parent().find(".results");
                        try {
                            results.html("");
                            var parsed = $.parseJSON(response);
                            var count = 0;
                            $.each(parsed, function(i, val) {
                                $('<div/>')
                                    .addClass(options.search_item)
                                    .addClass('element')
                                    .text(val.data.split('%%')[0])
                                    .attr('data-name', val.data)
                                    .attr('data-id', val.id)
                                    .appendTo(results);
                                count++;
                            });

                            if (!count) {
                                $('<div/>').addClass('element-notfound').text(options.notFoundText).appendTo(results);
                            }

                            $(obj).trigger('liveSearch.dataLoaded', response);
                        }
                        catch (err) {}
                    }
                });
            } return false;
        };

        // Calculate position of the ".results" block
        this.calcResultsPosition = function() {
            var results = this.parent().find('.results');
            var offset = this.offset();
            var height = this.outerHeight();
            var width = this.innerWidth();
            results.offset({
                top: offset.top+height,
                left: offset.left
            });
            results.width(width);
        };

        var init = function() {
            var id = $(this).attr('id');

            $(this).live("keyup", function(e) {
                // Set Timeout
                clearTimeout($.data(this, 'timer'));

                // Set Search String
                var search_string = $(obj).val();

                // Do Search
                if (search_string == '') {
                    $(this).parent().find('.results').stop().fadeTo(options.fadeSpeed, 0);
                } else {
                    $(this).parent().find('.results').stop().fadeTo(options.fadeSpeed, 1);
                    obj.calcResultsPosition();
                    $(this).data('timer', setTimeout(obj.search, 150));
                }
                $(this).parent().find(".results").scrollTop(0);
            });

            $(this).focusin(function() {
                // calculation of the number of items found
                var elements = $(this).parent().find('.results').children().size();
                if(elements && $(this).val().length) {
                    $(this).parent().find('.results').stop().fadeTo(options.fadeSpeed, 1);
                }
            });

            $(this).focusout(function() {
                $(this).parent().find('.results').stop().fadeTo(options.fadeSpeed, 0);
            });

            // Prevent multiple event listener bind
            var addEventListener = true;
            if (typeof window.liveSearchBind === 'undefined') {
                window.liveSearchBind = []
            } else {
                var len = window.liveSearchBind.length;
                for (var i=0; i<len; i++) {
                    if(window.liveSearchBind[i] === options.search_item) {
                        addEventListener = false;
                        break;
                    }
                }
            }

            if(addEventListener) {

                $('.'+options.search_item).live("click", function(e) {
                    var id = $(this).attr('data-id');
                    var name = $(this).attr('data-name')

                    if(options.clearOnSelect) {
                        obj.val('');
                    } else {
                        obj.val($(this).text());
                    }

                    obj.attr('data-name', name);
                    obj.attr('data-id', id);

                    $(this).parent('.results').fadeOut(150)

                    $(this).trigger('liveSearch.select', {
                        'id': id,
                        'data': name
                    });

                    e.preventDefault();
                });

                window.liveSearchBind.push(options.search_item);

            }

        };

        return this.each(init);
    };
})(jQuery);<|endoftext|>


<commit_before>/*
 Copyrights for code authored by Yahoo! Inc. is licensed under the following
 terms:

 MIT License

 Copyright (c) 2011-2012 Yahoo! Inc. All Rights Reserved.

 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.
*/

/*
 * Run with nodeunit:
 *   nodeunit --reporter nested mockery.functional.js
 */

/*jslint nomen: true */

"use strict";

var testCase = require('nodeunit').testCase,
    mockery = require('../mockery'),
    sinon = require('sinon'),
    m = require('module');

var mock_fake_module = {
    foo: function () {
        return 'mocked foo';
    }
};

function isCached(name) {
    var id;

    // Super-simplistic, but good enough for the tests
    for (id in m._cache) {
        if (m._cache.hasOwnProperty(id) && id.indexOf(name) !== -1) {
            return true;
        }
    }

    return false;
}

module.exports = testCase({
    setUp: function (callback) {
        callback();
    },

    tearDown: function (callback) {
        mockery.disable();
        mockery.deregisterAll();
        callback();
    },

    "when nothing is registered": testCase({
        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring a module causes a warning to be logged": function (test) {
                var mock_console, fake_module;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').once();

                fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'real foo');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and warnings are disabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnUnregistered(false);
                    callback();
                },

                "requiring a module causes no warning to be logged": function (test) {
                    var mock_console, fake_module;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').never();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            }),

            "and warnings are reenabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnUnregistered(true);
                    callback();
                },

                "requiring a module causes a warning to be logged": function (test) {
                    var mock_console, fake_module;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').once();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            })
        })
    }),

    "when an allowable is registered": testCase({
        setUp: function (callback) {
            mockery.registerAllowable('./fixtures/fake_module');
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the module causes no warning to be logged": function (test) {
                var mock_console, fake_module;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').never();

                fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'real foo');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and the allowable is deregistered": testCase({
                setUp: function (callback) {
                    mockery.deregisterAllowable('./fixtures/fake_module');
                    callback();
                },

                "requiring the module causes a warning to be logged": function (test) {
                    var mock_console, fake_module;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').once();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            })
        })
    }),

    "when an array of allowables is registered": testCase({
        setUp: function (callback) {
            mockery.registerAllowables(
                ['./fixtures/fake_module', './fixtures/fake_module_2']
            );
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the modules causes no warning to be logged": function (test) {
                var mock_console, fake_module, fake_module_2;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').never();

                fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'real foo');

                fake_module_2 = require('./fixtures/fake_module_2');
                test.equal(fake_module_2.bar(), 'real bar');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and the allowables are deregistered": testCase({
                setUp: function (callback) {
                    mockery.deregisterAllowables(
                        ['./fixtures/fake_module', './fixtures/fake_module_2']
                    );
                    callback();
                },

                "requiring the modules causes warnings to be logged": function (test) {
                    var mock_console, fake_module, fake_module_2;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').twice();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    fake_module_2 = require('./fixtures/fake_module_2');
                    test.equal(fake_module_2.bar(), 'real bar');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            })
        })
    }),

    "when an allowable is registered for unhooking": testCase({
        setUp: function (callback) {
            mockery.registerAllowable('./fixtures/fake_module', true);
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                if (!this.originalCache) {
                    // Initialise a clean cache
                    this.originalCache = m._cache;
                    m._cache = {};
                }
                mockery.enable();
                callback();
            },

            tearDown: function (callback) {
                if (this.originalCache) {
                    // Restore the original cache
                    m._cache = this.originalCache;
                    this.originalCache = null;
                }
                callback();
            },

            "the module is not cached": function (test) {
                test.ok(!isCached('fixtures/fake_module'));
                test.done();
            },

            "and the module is required": testCase({
                setUp: function (callback) {
                    require('./fixtures/fake_module');
                    callback();
                },

                "the module is cached": function (test) {
                    test.ok(isCached('fixtures/fake_module'));
                    test.done();
                },

                "and the module is deregistered": testCase({
                    setUp: function (callback) {
                        mockery.deregisterAllowable('./fixtures/fake_module');
                        callback();
                    },

                    "the module is not cached": function (test) {
                        test.ok(!isCached('fixtures/fake_module'));
                        test.done();
                    }
                })
            })
        })
    }),

    "when a mock is registered": testCase({
        setUp: function (callback) {
            mockery.registerMock('./fixtures/fake_module', mock_fake_module);
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the module returns the mock instead": function (test) {
                var fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'mocked foo');
                test.done();
            },

            "and the mock is deregistered": testCase({
                "requiring the module returns the original module": function (test) {
                    mockery.deregisterMock('./fixtures/fake_module', mock_fake_module);
                    mockery.registerAllowable('./fixtures/fake_module');
                    var fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');
                    test.done();
                }
            }),

            "and mockery is then disabled": testCase({
                "requiring the module returns the original module": function (test) {
                    mockery.disable();
                    var fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');
                    test.done();
                }
            }),

            "registering a replacement causes a warning to be logged": function (test) {
                var mock_console;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').once();

                mockery.registerMock('./fixtures/fake_module', mock_fake_module);

                mock_console.verify();
                mock_console.restore();
                test.done();
            },
            "and warnings are disabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnReplace(false);
                    callback();
                },

                "registering a replacement causes no warning to be logged": function (test) {
                    var mock_console;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').never();

                    mockery.registerMock('./fixtures/fake_module', mock_fake_module);

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                },

                "and warnings are reenabled": testCase({
                    setUp: function (callback) {
                        mockery.warnOnReplace(true);
                        callback();
                    },

                    "registering a replacement causes a warning to be logged": function (test) {
                        var mock_console;

                        mock_console = sinon.mock(console);
                        mock_console.expects('warn').once();

                        mockery.registerMock('./fixtures/fake_module', mock_fake_module);

                        mock_console.verify();
                        mock_console.restore();
                        test.done();
                    }
                })
            })
        })
    }),

    "when a substitute is registered": testCase({
        setUp: function (callback) {
            mockery.registerSubstitute('./fixtures/fake_module',
                './fixtures/substitute_fake_module');
            callback();
        },

        tearDown: function (callback) {
            mockery.deregisterSubstitute('./fixtures/fake_module');
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the module returns the substitute instead": function (test) {
                var fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'substitute foo');
                test.done();
            },

            "registering a replacement causes a warning to be logged": function (test) {
                var mock_console;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').once();

                mockery.registerSubstitute('./fixtures/fake_module',
                    './fixtures/substitute_fake_module');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },
            "and warnings are disabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnReplace(false);
                    callback();
                },

                "registering a replacement causes no warning to be logged": function (test) {
                    var mock_console;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').never();

                    mockery.registerSubstitute('./fixtures/fake_module',
                        './fixtures/substitute_fake_module');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                },

                "and warnings are reenabled": testCase({
                    setUp: function (callback) {
                        mockery.warnOnReplace(true);
                        callback();
                    },

                    "registering a replacement causes a warning to be logged": function (test) {
                        var mock_console;

                        mock_console = sinon.mock(console);
                        mock_console.expects('warn').once();

                        mockery.registerSubstitute('./fixtures/fake_module',
                            './fixtures/substitute_fake_module');

                        mock_console.verify();
                        mock_console.restore();
                        test.done();
                    }
                })
            })
        })
    }),

    "when an intermediary module is involved": testCase({
        "and mockery is not enabled": testCase({
            "requiring the intermediary causes the original to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'real foo');
                test.done();
            }
        }),
        "and mockery is enabled without the clean cache option": testCase({
            setUp: function (callback) {
                mockery.registerMock('./fake_module', mock_fake_module);
                mockery.registerAllowable('./fixtures/intermediary');
                mockery.enable({ useCleanCache: false });
                callback();
            },

            "requiring the intermediary causes the original to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'real foo');
                test.done();
            }
        }),
        "and mockery is enabled with the clean cache option": testCase({
            setUp: function (callback) {
                mockery.registerMock('./fake_module', mock_fake_module);
                mockery.registerAllowable('./fixtures/intermediary');
                mockery.enable({ useCleanCache: true });
                callback();
            },

            "requiring the intermediary causes the mock to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'mocked foo');
                test.done();
            }
        }),
        "and mockery is disabled": testCase({
            "requiring the intermediary causes the original to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'real foo');
                test.done();
            }
        })
    })

});
<commit_msg>Spacing adjustments.<commit_after>/*
 Copyrights for code authored by Yahoo! Inc. is licensed under the following
 terms:

 MIT License

 Copyright (c) 2011-2012 Yahoo! Inc. All Rights Reserved.

 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.
*/

/*
 * Run with nodeunit:
 *   nodeunit --reporter nested mockery.functional.js
 */

/*jslint nomen: true */

"use strict";

var testCase = require('nodeunit').testCase,
    mockery = require('../mockery'),
    sinon = require('sinon'),
    m = require('module');

var mock_fake_module = {
    foo: function () {
        return 'mocked foo';
    }
};

function isCached(name) {
    var id;

    // Super-simplistic, but good enough for the tests
    for (id in m._cache) {
        if (m._cache.hasOwnProperty(id) && id.indexOf(name) !== -1) {
            return true;
        }
    }

    return false;
}

module.exports = testCase({
    setUp: function (callback) {
        callback();
    },

    tearDown: function (callback) {
        mockery.disable();
        mockery.deregisterAll();
        callback();
    },

    "when nothing is registered": testCase({
        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring a module causes a warning to be logged": function (test) {
                var mock_console, fake_module;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').once();

                fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'real foo');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and warnings are disabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnUnregistered(false);
                    callback();
                },

                "requiring a module causes no warning to be logged": function (test) {
                    var mock_console, fake_module;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').never();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            }),

            "and warnings are reenabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnUnregistered(true);
                    callback();
                },

                "requiring a module causes a warning to be logged": function (test) {
                    var mock_console, fake_module;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').once();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            })
        })
    }),

    "when an allowable is registered": testCase({
        setUp: function (callback) {
            mockery.registerAllowable('./fixtures/fake_module');
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the module causes no warning to be logged": function (test) {
                var mock_console, fake_module;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').never();

                fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'real foo');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and the allowable is deregistered": testCase({
                setUp: function (callback) {
                    mockery.deregisterAllowable('./fixtures/fake_module');
                    callback();
                },

                "requiring the module causes a warning to be logged": function (test) {
                    var mock_console, fake_module;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').once();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            })
        })
    }),

    "when an array of allowables is registered": testCase({
        setUp: function (callback) {
            mockery.registerAllowables(
                ['./fixtures/fake_module', './fixtures/fake_module_2']
            );
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the modules causes no warning to be logged": function (test) {
                var mock_console, fake_module, fake_module_2;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').never();

                fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'real foo');

                fake_module_2 = require('./fixtures/fake_module_2');
                test.equal(fake_module_2.bar(), 'real bar');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and the allowables are deregistered": testCase({
                setUp: function (callback) {
                    mockery.deregisterAllowables(
                        ['./fixtures/fake_module', './fixtures/fake_module_2']
                    );
                    callback();
                },

                "requiring the modules causes warnings to be logged": function (test) {
                    var mock_console, fake_module, fake_module_2;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').twice();

                    fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');

                    fake_module_2 = require('./fixtures/fake_module_2');
                    test.equal(fake_module_2.bar(), 'real bar');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                }
            })
        })
    }),

    "when an allowable is registered for unhooking": testCase({
        setUp: function (callback) {
            mockery.registerAllowable('./fixtures/fake_module', true);
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                if (!this.originalCache) {
                    // Initialise a clean cache
                    this.originalCache = m._cache;
                    m._cache = {};
                }
                mockery.enable();
                callback();
            },

            tearDown: function (callback) {
                if (this.originalCache) {
                    // Restore the original cache
                    m._cache = this.originalCache;
                    this.originalCache = null;
                }
                callback();
            },

            "the module is not cached": function (test) {
                test.ok(!isCached('fixtures/fake_module'));
                test.done();
            },

            "and the module is required": testCase({
                setUp: function (callback) {
                    require('./fixtures/fake_module');
                    callback();
                },

                "the module is cached": function (test) {
                    test.ok(isCached('fixtures/fake_module'));
                    test.done();
                },

                "and the module is deregistered": testCase({
                    setUp: function (callback) {
                        mockery.deregisterAllowable('./fixtures/fake_module');
                        callback();
                    },

                    "the module is not cached": function (test) {
                        test.ok(!isCached('fixtures/fake_module'));
                        test.done();
                    }
                })
            })
        })
    }),

    "when a mock is registered": testCase({
        setUp: function (callback) {
            mockery.registerMock('./fixtures/fake_module', mock_fake_module);
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the module returns the mock instead": function (test) {
                var fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'mocked foo');
                test.done();
            },

            "and the mock is deregistered": testCase({
                "requiring the module returns the original module": function (test) {
                    mockery.deregisterMock('./fixtures/fake_module', mock_fake_module);
                    mockery.registerAllowable('./fixtures/fake_module');
                    var fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');
                    test.done();
                }
            }),

            "and mockery is then disabled": testCase({
                "requiring the module returns the original module": function (test) {
                    mockery.disable();
                    var fake_module = require('./fixtures/fake_module');
                    test.equal(fake_module.foo(), 'real foo');
                    test.done();
                }
            }),

            "registering a replacement causes a warning to be logged": function (test) {
                var mock_console;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').once();

                mockery.registerMock('./fixtures/fake_module', mock_fake_module);

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and warnings are disabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnReplace(false);
                    callback();
                },

                "registering a replacement causes no warning to be logged": function (test) {
                    var mock_console;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').never();

                    mockery.registerMock('./fixtures/fake_module', mock_fake_module);

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                },

                "and warnings are reenabled": testCase({
                    setUp: function (callback) {
                        mockery.warnOnReplace(true);
                        callback();
                    },

                    "registering a replacement causes a warning to be logged": function (test) {
                        var mock_console;

                        mock_console = sinon.mock(console);
                        mock_console.expects('warn').once();

                        mockery.registerMock('./fixtures/fake_module', mock_fake_module);

                        mock_console.verify();
                        mock_console.restore();
                        test.done();
                    }
                })
            })
        })
    }),

    "when a substitute is registered": testCase({
        setUp: function (callback) {
            mockery.registerSubstitute('./fixtures/fake_module',
                './fixtures/substitute_fake_module');
            callback();
        },

        tearDown: function (callback) {
            mockery.deregisterSubstitute('./fixtures/fake_module');
            callback();
        },

        "and mockery is enabled": testCase({
            setUp: function (callback) {
                mockery.enable();
                callback();
            },

            "requiring the module returns the substitute instead": function (test) {
                var fake_module = require('./fixtures/fake_module');
                test.equal(fake_module.foo(), 'substitute foo');
                test.done();
            },

            "registering a replacement causes a warning to be logged": function (test) {
                var mock_console;

                mock_console = sinon.mock(console);
                mock_console.expects('warn').once();

                mockery.registerSubstitute('./fixtures/fake_module',
                    './fixtures/substitute_fake_module');

                mock_console.verify();
                mock_console.restore();
                test.done();
            },

            "and warnings are disabled": testCase({
                setUp: function (callback) {
                    mockery.warnOnReplace(false);
                    callback();
                },

                "registering a replacement causes no warning to be logged": function (test) {
                    var mock_console;

                    mock_console = sinon.mock(console);
                    mock_console.expects('warn').never();

                    mockery.registerSubstitute('./fixtures/fake_module',
                        './fixtures/substitute_fake_module');

                    mock_console.verify();
                    mock_console.restore();
                    test.done();
                },

                "and warnings are reenabled": testCase({
                    setUp: function (callback) {
                        mockery.warnOnReplace(true);
                        callback();
                    },

                    "registering a replacement causes a warning to be logged": function (test) {
                        var mock_console;

                        mock_console = sinon.mock(console);
                        mock_console.expects('warn').once();

                        mockery.registerSubstitute('./fixtures/fake_module',
                            './fixtures/substitute_fake_module');

                        mock_console.verify();
                        mock_console.restore();
                        test.done();
                    }
                })
            })
        })
    }),

    "when an intermediary module is involved": testCase({
        "and mockery is not enabled": testCase({
            "requiring the intermediary causes the original to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'real foo');
                test.done();
            }
        }),

        "and mockery is enabled without the clean cache option": testCase({
            setUp: function (callback) {
                mockery.registerMock('./fake_module', mock_fake_module);
                mockery.registerAllowable('./fixtures/intermediary');
                mockery.enable({ useCleanCache: false });
                callback();
            },

            "requiring the intermediary causes the original to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'real foo');
                test.done();
            }
        }),

        "and mockery is enabled with the clean cache option": testCase({
            setUp: function (callback) {
                mockery.registerMock('./fake_module', mock_fake_module);
                mockery.registerAllowable('./fixtures/intermediary');
                mockery.enable({ useCleanCache: true });
                callback();
            },

            "requiring the intermediary causes the mock to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'mocked foo');
                test.done();
            }
        }),

        "and mockery is disabled": testCase({
            "requiring the intermediary causes the original to be used": function (test) {
                var intermediary = require('./fixtures/intermediary');
                test.equal(intermediary.bar(), 'real foo');
                test.done();
            }
        })
    })

});
<|endoftext|>


<commit_before>// Copyright 2017, University of Colorado Boulder

/**
 * Semi-transparent black barrier used to block input events when a dialog
 * (or other popup) is present, and fade out the background.
 *
 * @author - Michael Kauzmann (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  var inherit = require( 'PHET_CORE/inherit' );
  var joist = require( 'JOIST/joist' );

  var Emitter = require( 'AXON/Emitter' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var ButtonListener = require( 'SCENERY/input/ButtonListener' );

  // phet-io modules
  var TBarrierRectangle = require( 'ifphetio!PHET_IO/types/scenery/nodes/TBarrierRectangle' );

  /**
   * @param x
   * @param y
   * @param width
   * @param height
   * @param cornerXRadius
   * @param cornerYRadius
   * @param {ObservableArray} modalNodeStack - see usage in Sim.js
   * @param {Object} [options]
   * @constructor
   */
  function BarrierRectangle( x, y, width, height, cornerXRadius, cornerYRadius, modalNodeStack, options ) {

    var self = this;

    var tandem = options.tandem;

    // This will be passed up to parents
    options.tandem = tandem.createSupertypeTandem();

    Rectangle.call( this, x, y, width, height, cornerXRadius, cornerYRadius, options );

    this.startedCallbacksForFiredEmitter = new Emitter();
    this.endedCallbacksForFiredEmitter = new Emitter();

    modalNodeStack.lengthProperty.link( function( numBarriers ) {
      self.visible = numBarriers > 0;
    } );

    this.addInputListener( new ButtonListener( {
      fire: function( event ) {
        self.startedCallbacksForFiredEmitter.emit();
        assert && assert( modalNodeStack.length > 0 );
        modalNodeStack.get( modalNodeStack.length - 1 ).hide();
        self.endedCallbacksForFiredEmitter.emit();
      }
    } ) );

    this.mutate( {
      tandem: tandem,
      phetioType: TBarrierRectangle
    } );
  }

  joist.register( 'BarrierRectangle', BarrierRectangle );

  return inherit( Rectangle, BarrierRectangle );
} );<commit_msg>fix failure when constructor is called without options, #394<commit_after>// Copyright 2017, University of Colorado Boulder

/**
 * Semi-transparent black barrier used to block input events when a dialog
 * (or other popup) is present, and fade out the background.
 *
 * @author - Michael Kauzmann (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  var inherit = require( 'PHET_CORE/inherit' );
  var joist = require( 'JOIST/joist' );

  var Emitter = require( 'AXON/Emitter' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var ButtonListener = require( 'SCENERY/input/ButtonListener' );

  // phet-io modules
  var TBarrierRectangle = require( 'ifphetio!PHET_IO/types/scenery/nodes/TBarrierRectangle' );

  /**
   * @param x
   * @param y
   * @param width
   * @param height
   * @param cornerXRadius
   * @param cornerYRadius
   * @param {ObservableArray} modalNodeStack - see usage in Sim.js
   * @param {Object} [options]
   * @constructor
   */
  function BarrierRectangle( x, y, width, height, cornerXRadius, cornerYRadius, modalNodeStack, options ) {

    options = options || {};

    var self = this;

    var tandem = options.tandem;

    // This will be passed up to parents
    options.tandem = tandem.createSupertypeTandem();

    Rectangle.call( this, x, y, width, height, cornerXRadius, cornerYRadius, options );

    this.startedCallbacksForFiredEmitter = new Emitter();
    this.endedCallbacksForFiredEmitter = new Emitter();

    modalNodeStack.lengthProperty.link( function( numBarriers ) {
      self.visible = numBarriers > 0;
    } );

    this.addInputListener( new ButtonListener( {
      fire: function( event ) {
        self.startedCallbacksForFiredEmitter.emit();
        assert && assert( modalNodeStack.length > 0 );
        modalNodeStack.get( modalNodeStack.length - 1 ).hide();
        self.endedCallbacksForFiredEmitter.emit();
      }
    } ) );

    this.mutate( {
      tandem: tandem,
      phetioType: TBarrierRectangle
    } );
  }

  joist.register( 'BarrierRectangle', BarrierRectangle );

  return inherit( Rectangle, BarrierRectangle );
} );<|endoftext|>


<commit_before>import { ADD_CHILD, MOVE_CHILD, DELETE_COMPONENT, UPDATE_STYLE } from '../../app/actions/workspace';
import { ADD_STATE, ADD_PROPS, ADD_STYLES, ADD_EVENTS, DELETE_STATE, DELETE_PROPS, DELETE_STYLES, DELETE_EVENTS } from '../../app/actions/config';
import { SET_ACTIVE_COMPONENT } from '../../app/actions/FileSystemActions';
import { WORKSPACE_ID } from '../../app/constants';
import addComponent from '../../app/reducers/workspace/addComponent';
import moveChild from '../../app/reducers/workspace/moveChild';
import addStateValue from '../../app/reducers/workspace/addStateValue';
import addPropsValue from '../../app/reducers/workspace/addPropsValue';
import addStyleValue from '../../app/reducers/workspace/addStyleValue';
import addEvent from '../../app/reducers/workspace/addEvent';
import deleteStateValue from '../../app/reducers/workspace/deleteStateValue';
import deletePropsValue from '../../app/reducers/workspace/deletePropsValue';
import deleteStylesValue from '../../app/reducers/workspace/deleteStylesValue';
import deleteEvent from '../../app/reducers/workspace/deleteEvent';
import setActiveComponent from '../../app/reducers/workspace/setActiveComponent';
import updateStyle from '../../app/reducers/workspace/updateStyle';

import workspace from '../../app/reducers/workspace/index';

const defaultWorkspace = {
  componentCounter: 2,
  activeComponent: '0',
  components: {
    workspace: {
      id: WORKSPACE_ID,
      children: [0, 1],
    },
  },
  state: { default: 'default' },
};

defaultWorkspace.components[0] = {
  id: 0,
  name: 'BlackBox',
  children: [],
  parentID: WORKSPACE_ID,
  props: {
    style: {
      position: 'relative',
      height: '100px',
      width: '100px',
      display: 'inline-block',
      backgroundColor: 'black',
      overflow: 'auto',
    },
    testProp: null,
  },
  events: { test: 'test' }
};

defaultWorkspace.components[1] = {
  id: 1,
  name: 'BlueBox',
  children: [],
  parentID: WORKSPACE_ID,
  props: {
    style: {
      position: 'relative',
      height: '100px',
      width: '100px',
      display: 'inline-block',
      backgroundColor: 'blue',
      overflow: 'auto',
    },
  },
  events: { test: 'event test =]' }
};

describe('workspace Reducer', () => {
  describe('CASE: ADD CHILD', () => {
    it('should add a child to the workspace state', () => {
      const actionMock = {
        type: ADD_CHILD,
        newComponent: {
          id: 2,
          name: 'test',
          props: {
            style: {
              position: 'relative',
            },
          },
          events: {test: 'test'}
        },
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result).toHaveProperty('componentCounter', 3);
      expect(result).toHaveProperty('components.workspace.children', [0,1,2]);
        //write some more here later, this is a big object and needs to be controlled.
    });
  });

  describe('CASE: MOVE_CHILD', () => {
    it('should nest a component in another component', () => {
      const actionMock = {
        type: MOVE_CHILD,
        targetID: 1,
        sourceID: 0,
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result).toHaveProperty('componentCounter', 2);
      expect(result.components[1]).toHaveProperty('children', [0]);
    });

    it('should not move a component into itself', () => {
      const actionMock = {
        type: MOVE_CHILD,
        targetID: 1,
        sourceID: 1,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    });

    it('should not move a component into its own parent', () => {
      const actionMock = {
        type: MOVE_CHILD,
        targetID: WORKSPACE_ID,
        sourceID: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    })
  });

  describe('CASE: ADD STATE', () => {
    it('should add a value to the workspace state object', () => {
      const actionMock = {
        type: ADD_STATE,
        aState: {
          'test': null,
        },
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result).toHaveProperty('state.test', null);
      expect(result).toHaveProperty('state.default', 'default');
    });
  });

  describe('CASE: ADD_PROPS', () => {
    it('should add a prop to a component', () => {
      const actionMock = {
        type: ADD_PROPS,
        prop: {
          test: null,
        },
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result.components[0]).toHaveProperty('props.test', null);
    });

    it('should not add a style prop', () => {
      const actionMock = {
        type: ADD_PROPS,
        prop: {
          style: null,
        },
        component: 0,
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    })
  });

  describe('CASE: ADD_STYLES', () => {
    it('should add a new style to props.style', () => {
      const actionMock = {
        type: ADD_STYLES,
        style: { border: null },
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);

      expect(result).toMatchSnapshot();
      expect(result.components[0].props.style).toHaveProperty('border', null);
    });
  });

  describe('CASE: ADD_EVENTS', () => {
    it('should add a new event to a component', () => {
      const actionMock = {
        type: ADD_EVENTS,
        event: { onClick: null },
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);

      expect(result).toMatchSnapshot();
      expect(result.components[0].events).toHaveProperty('onClick', null);
    });
  });

  describe('CASE: DELETE_STATE', () => {
    it('should remove a value from the app state', () => {
      const actionMock = {
        type: DELETE_STATE,
        propKey: 'default'
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result.state).not.toHaveProperty('default');
    });
  });

  describe('CASE: DELETE_PROPS', () => {
    it('should remove a value from a component\'s props', () => {
      const actionMock = {
        type: DELETE_PROPS,
        prop: 'testProp',
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result.components[0].props).not.toHaveProperty('testProp');
    });

    it('should not remove the style prop from a component', () => {
      const actionMock = {
        type: DELETE_PROPS,
        prop: 'style',
        component: 0,
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].props).toHaveProperty('style');
      expect(result).toMatchObject(defaultWorkspace);
    });
  });

  describe('CASE: DELETE STYLE', () => {
    it('should remove a key from the style object', () => {
      const actionMock = {
        type: DELETE_STYLES,
        style: 'backgroundColor',
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].props.style).not.toHaveProperty('backgroundColor');
      expect(result).toMatchSnapshot();
    });
  });

  describe('CASE: DELETE EVENTS', () => {
    it('should remove an event from a component', () => {
      const actionMock = {
        type: DELETE_EVENTS,
        event: 'test',
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].events).toBeDefined();
      expect(result.components[0].events).not.toHaveProperty('test');
      expect(result).toMatchSnapshot();
    });
  });

  describe('CASE: SET ACTIVE COMPONENT', () => {
    it('should update the activeComponent', () => {
      const actionMock = {
        type: SET_ACTIVE_COMPONENT,
        component: "1",
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toHaveProperty('activeComponent', "1");
    });

    it('should do nothing if component is already active', () => {
      const actionMock = {
        type: SET_ACTIVE_COMPONENT,
        component: "0",
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toHaveProperty('activeComponent', "0");
    });
  });

  describe('CASE: UPDATE_STYLE', () => {
    it('should update style for a component', () => {
      const actionMock = {
        type: UPDATE_STYLE,
        sourceID: 0,
        newStyle: { 'newStyle': null },
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].props.style).toHaveProperty('newStyle', null);
    });
  });

  describe('CASE: GIBBERISH', () => {
    it('should do nothing when presented with a bad action type', () => {
      const actionMock = {
        type: 'GIBBERISH',
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    });
  });
});
<commit_msg>Fix bad import in test/reducers/workspace<commit_after>import { ADD_CHILD, MOVE_CHILD, DELETE_COMPONENT, UPDATE_STYLE } from '../../app/actions/workspace';
import { ADD_STATE, ADD_PROPS, ADD_STYLES, ADD_EVENTS, DELETE_STATE, DELETE_PROPS, DELETE_STYLES, DELETE_EVENTS } from '../../app/actions/config';
import { SET_ACTIVE_COMPONENT } from '../../app/actions/FileSystemActions';
import { WORKSPACE_ID } from '../../app/constants';
import addComponent from '../../app/reducers/workspace/addComponent';
import moveComponent from '../../app/reducers/workspace/moveComponent';
import addStateValue from '../../app/reducers/workspace/addStateValue';
import addPropsValue from '../../app/reducers/workspace/addPropsValue';
import addStyleValue from '../../app/reducers/workspace/addStyleValue';
import addEvent from '../../app/reducers/workspace/addEvent';
import deleteStateValue from '../../app/reducers/workspace/deleteStateValue';
import deletePropsValue from '../../app/reducers/workspace/deletePropsValue';
import deleteStylesValue from '../../app/reducers/workspace/deleteStylesValue';
import deleteEvent from '../../app/reducers/workspace/deleteEvent';
import setActiveComponent from '../../app/reducers/workspace/setActiveComponent';
import updateStyle from '../../app/reducers/workspace/updateStyle';

import workspace from '../../app/reducers/workspace/index';

const defaultWorkspace = {
  componentCounter: 2,
  activeComponent: '0',
  components: {
    workspace: {
      id: WORKSPACE_ID,
      children: [0, 1],
    },
  },
  state: { default: 'default' },
};

defaultWorkspace.components[0] = {
  id: 0,
  name: 'BlackBox',
  children: [],
  parentID: WORKSPACE_ID,
  props: {
    style: {
      position: 'relative',
      height: '100px',
      width: '100px',
      display: 'inline-block',
      backgroundColor: 'black',
      overflow: 'auto',
    },
    testProp: null,
  },
  events: { test: 'test' }
};

defaultWorkspace.components[1] = {
  id: 1,
  name: 'BlueBox',
  children: [],
  parentID: WORKSPACE_ID,
  props: {
    style: {
      position: 'relative',
      height: '100px',
      width: '100px',
      display: 'inline-block',
      backgroundColor: 'blue',
      overflow: 'auto',
    },
  },
  events: { test: 'event test =]' }
};

describe('workspace Reducer', () => {
  describe('CASE: ADD CHILD', () => {
    it('should add a child to the workspace state', () => {
      const actionMock = {
        type: ADD_CHILD,
        newComponent: {
          id: 2,
          name: 'test',
          props: {
            style: {
              position: 'relative',
            },
          },
          events: {test: 'test'}
        },
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result).toHaveProperty('componentCounter', 3);
      expect(result).toHaveProperty('components.workspace.children', [0,1,2]);
        //write some more here later, this is a big object and needs to be controlled.
    });
  });

  describe('CASE: MOVE_CHILD', () => {
    it('should nest a component in another component', () => {
      const actionMock = {
        type: MOVE_CHILD,
        targetID: 1,
        sourceID: 0,
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result).toHaveProperty('componentCounter', 2);
      expect(result.components[1]).toHaveProperty('children', [0]);
    });

    it('should not move a component into itself', () => {
      const actionMock = {
        type: MOVE_CHILD,
        targetID: 1,
        sourceID: 1,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    });

    it('should not move a component into its own parent', () => {
      const actionMock = {
        type: MOVE_CHILD,
        targetID: WORKSPACE_ID,
        sourceID: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    })
  });

  describe('CASE: ADD STATE', () => {
    it('should add a value to the workspace state object', () => {
      const actionMock = {
        type: ADD_STATE,
        aState: {
          'test': null,
        },
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result).toHaveProperty('state.test', null);
      expect(result).toHaveProperty('state.default', 'default');
    });
  });

  describe('CASE: ADD_PROPS', () => {
    it('should add a prop to a component', () => {
      const actionMock = {
        type: ADD_PROPS,
        prop: {
          test: null,
        },
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result.components[0]).toHaveProperty('props.test', null);
    });

    it('should not add a style prop', () => {
      const actionMock = {
        type: ADD_PROPS,
        prop: {
          style: null,
        },
        component: 0,
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    })
  });

  describe('CASE: ADD_STYLES', () => {
    it('should add a new style to props.style', () => {
      const actionMock = {
        type: ADD_STYLES,
        style: { border: null },
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);

      expect(result).toMatchSnapshot();
      expect(result.components[0].props.style).toHaveProperty('border', null);
    });
  });

  describe('CASE: ADD_EVENTS', () => {
    it('should add a new event to a component', () => {
      const actionMock = {
        type: ADD_EVENTS,
        event: { onClick: null },
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);

      expect(result).toMatchSnapshot();
      expect(result.components[0].events).toHaveProperty('onClick', null);
    });
  });

  describe('CASE: DELETE_STATE', () => {
    it('should remove a value from the app state', () => {
      const actionMock = {
        type: DELETE_STATE,
        propKey: 'default'
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result.state).not.toHaveProperty('default');
    });
  });

  describe('CASE: DELETE_PROPS', () => {
    it('should remove a value from a component\'s props', () => {
      const actionMock = {
        type: DELETE_PROPS,
        prop: 'testProp',
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchSnapshot();
      expect(result.components[0].props).not.toHaveProperty('testProp');
    });

    it('should not remove the style prop from a component', () => {
      const actionMock = {
        type: DELETE_PROPS,
        prop: 'style',
        component: 0,
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].props).toHaveProperty('style');
      expect(result).toMatchObject(defaultWorkspace);
    });
  });

  describe('CASE: DELETE STYLE', () => {
    it('should remove a key from the style object', () => {
      const actionMock = {
        type: DELETE_STYLES,
        style: 'backgroundColor',
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].props.style).not.toHaveProperty('backgroundColor');
      expect(result).toMatchSnapshot();
    });
  });

  describe('CASE: DELETE EVENTS', () => {
    it('should remove an event from a component', () => {
      const actionMock = {
        type: DELETE_EVENTS,
        event: 'test',
        component: 0,
      };

      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].events).toBeDefined();
      expect(result.components[0].events).not.toHaveProperty('test');
      expect(result).toMatchSnapshot();
    });
  });

  describe('CASE: SET ACTIVE COMPONENT', () => {
    it('should update the activeComponent', () => {
      const actionMock = {
        type: SET_ACTIVE_COMPONENT,
        component: "1",
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toHaveProperty('activeComponent', "1");
    });

    it('should do nothing if component is already active', () => {
      const actionMock = {
        type: SET_ACTIVE_COMPONENT,
        component: "0",
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toHaveProperty('activeComponent', "0");
    });
  });

  describe('CASE: UPDATE_STYLE', () => {
    it('should update style for a component', () => {
      const actionMock = {
        type: UPDATE_STYLE,
        sourceID: 0,
        newStyle: { 'newStyle': null },
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result.components[0].props.style).toHaveProperty('newStyle', null);
    });
  });

  describe('CASE: GIBBERISH', () => {
    it('should do nothing when presented with a bad action type', () => {
      const actionMock = {
        type: 'GIBBERISH',
      };
      const result = workspace(defaultWorkspace, actionMock);
      expect(result).toMatchObject(defaultWorkspace);
    });
  });
});
<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Button for initiating game levels and for depicting the progress made on each level.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var ButtonListener = require( 'SCENERY/input/ButtonListener' );
  var inherit = require( 'PHET_CORE/inherit' );
  var ProgressIndicator = require( 'VEGAS/ProgressIndicator' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );

  /**
   * @param {Image} icon Scenery node that appears on the button, scaled to fit
   * @param {number} numStars Number of stars to show in the progress indicator at the bottom of the button
   * @param {function} fireFunction Called when the button fires
   * @param {Property<number>} scoreProperty
   * @param {number} perfectScore
   * @param {*} options
   * @constructor
   */
  function LevelStartButton( icon, numStars, fireFunction, scoreProperty, perfectScore, options ) {

    options = _.extend( {
      buttonWidth: 150,
      buttonHeight: 150,
      backgroundColor: 'rgb( 242, 255, 204 )',
      highlightedBackgroundColor: 'rgb( 250, 255, 230 )',
      shadowColor: 'black',
      cornerRadius: 10,
      // options for progress indicator (stars)
      progressIndicatorXMargin: 10,
      progressIndicatorYMargin: 5
    }, options );
    var shadowOffset = 0.026 * options.buttonWidth;

    Node.call( this ); // Call super constructor.

    // Add the drop shadow.
    this.addChild( new Rectangle( 0, 0, options.buttonWidth, options.buttonHeight, options.cornerRadius, options.cornerRadius, {
        fill: options.shadowColor,
        top: shadowOffset,
        left: shadowOffset
      }
    ) );

    //TODO this is a non-intuitive decision that made changing this button difficult
    // Add the button outline, which is also the parent node for everything else that is on the button.
    var buttonOutline = new Rectangle( 0, 0, options.buttonWidth, options.buttonHeight, options.cornerRadius, options.cornerRadius, {
      stroke: 'black',
      lineWidth: 1,
      fill: options.backgroundColor,
      cursor: 'pointer'
    } );
    this.addChild( buttonOutline );

    //TODO add ability to specify the margins around the icon instead of hard-coding it here
    // Icon, scaled to fit.
    var iconScaleFactor = Math.min( options.buttonHeight * 0.65 / icon.height, options.buttonWidth * 0.85 / icon.width );
    icon.scale( iconScaleFactor );
    icon.centerX = options.buttonWidth / 2;
    icon.centerY = options.buttonHeight * 0.4;
    icon.pickable = false;
    buttonOutline.addChild( icon );

    // Progress indicator (stars), scaled to fit
    var progressIndicatorBackground = new Rectangle( 0, 0, options.buttonWidth, options.buttonHeight * 0.2, options.cornerRadius, options.cornerRadius, {
      fill: 'white',
      stroke: 'black',
      lineWidth: 1,
      pickable: false,
      bottom: options.buttonHeight
    } );
    var progressIndicator = new ProgressIndicator( numStars, scoreProperty, perfectScore, {
      pickable: false,
      starDiameter: options.buttonWidth / ( numStars + 1 )
    } );
    progressIndicator.setScaleMagnitude( Math.min(
      ( progressIndicatorBackground.width - 2 * options.progressIndicatorXMargin ) / progressIndicator.width,
      ( progressIndicatorBackground.height - 2 * options.progressIndicatorYMargin ) / progressIndicator.height  ) );
    progressIndicator.center = progressIndicatorBackground.center;
    buttonOutline.addChild( progressIndicatorBackground );
    buttonOutline.addChild( progressIndicator );

    //TODO This behavior was borrowed from sun.PushButton, because sun.RectanglePushButton doesn't support the look/behavior of this button.
    // Add the listener to update the appearance and handle a click.
    var update = function( state ) {
      if ( state === 'up' ) {
        buttonOutline.fill = options.backgroundColor;
        buttonOutline.top = 0;
        buttonOutline.left = 0;
      }
      else if ( state === 'over' ) {
        buttonOutline.fill = options.highlightedBackgroundColor;
      }
      else if ( state === 'down' ) {
        buttonOutline.fill = options.highlightedBackgroundColor;
        buttonOutline.top = shadowOffset;
        buttonOutline.left = shadowOffset;
      }
    };
    buttonOutline.addInputListener( new ButtonListener( {
      up: function() { update( 'up' ); },
      over: function() { update( 'over' ); },
      down: function() { update( 'down' ); },
      out: function() { update( 'up' ); }, // 'out' state looks the same as 'up'
      fire: fireFunction
    } ) );

    // Update for initial state
    update( 'up' );

    // Pass options to parent class
    this.mutate( options );
  }

  return inherit( Node, LevelStartButton );
} );<commit_msg>#13 rename buttonOutline to buttonForegroundNode, so it's more obvious that this node is everything but the shadow.<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Button for initiating game levels and for depicting the progress made on each level.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var ButtonListener = require( 'SCENERY/input/ButtonListener' );
  var inherit = require( 'PHET_CORE/inherit' );
  var ProgressIndicator = require( 'VEGAS/ProgressIndicator' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );

  /**
   * @param {Image} icon Scenery node that appears on the button, scaled to fit
   * @param {number} numStars Number of stars to show in the progress indicator at the bottom of the button
   * @param {function} fireFunction Called when the button fires
   * @param {Property<number>} scoreProperty
   * @param {number} perfectScore
   * @param {*} options
   * @constructor
   */
  function LevelStartButton( icon, numStars, fireFunction, scoreProperty, perfectScore, options ) {

    options = _.extend( {
      buttonWidth: 150,
      buttonHeight: 150,
      backgroundColor: 'rgb( 242, 255, 204 )',
      highlightedBackgroundColor: 'rgb( 250, 255, 230 )',
      shadowColor: 'black',
      cornerRadius: 10,
      // options for progress indicator (stars)
      progressIndicatorXMargin: 10,
      progressIndicatorYMargin: 5
    }, options );
    var shadowOffset = 0.026 * options.buttonWidth;

    Node.call( this ); // Call super constructor.

    // Add the drop shadow.
    this.addChild( new Rectangle( 0, 0, options.buttonWidth, options.buttonHeight, options.cornerRadius, options.cornerRadius, {
        fill: options.shadowColor,
        top: shadowOffset,
        left: shadowOffset
      }
    ) );

    // Add the button foreground, which is the parent node for everything else that is on the button.
    var buttonForegroundNode = new Rectangle( 0, 0, options.buttonWidth, options.buttonHeight, options.cornerRadius, options.cornerRadius, {
      stroke: 'black',
      lineWidth: 1,
      fill: options.backgroundColor,
      cursor: 'pointer'
    } );
    this.addChild( buttonForegroundNode );

    //TODO add ability to specify the margins around the icon instead of hard-coding it here
    // Icon, scaled to fit.
    var iconScaleFactor = Math.min( options.buttonHeight * 0.65 / icon.height, options.buttonWidth * 0.85 / icon.width );
    icon.scale( iconScaleFactor );
    icon.centerX = options.buttonWidth / 2;
    icon.centerY = options.buttonHeight * 0.4;
    icon.pickable = false;
    buttonForegroundNode.addChild( icon );

    // Progress indicator (stars), scaled to fit
    var progressIndicatorBackground = new Rectangle( 0, 0, options.buttonWidth, options.buttonHeight * 0.2, options.cornerRadius, options.cornerRadius, {
      fill: 'white',
      stroke: 'black',
      lineWidth: 1,
      pickable: false,
      bottom: options.buttonHeight
    } );
    var progressIndicator = new ProgressIndicator( numStars, scoreProperty, perfectScore, {
      pickable: false,
      starDiameter: options.buttonWidth / ( numStars + 1 )
    } );
    progressIndicator.setScaleMagnitude( Math.min(
      ( progressIndicatorBackground.width - 2 * options.progressIndicatorXMargin ) / progressIndicator.width,
      ( progressIndicatorBackground.height - 2 * options.progressIndicatorYMargin ) / progressIndicator.height  ) );
    progressIndicator.center = progressIndicatorBackground.center;
    buttonForegroundNode.addChild( progressIndicatorBackground );
    buttonForegroundNode.addChild( progressIndicator );

    //TODO This behavior was borrowed from sun.PushButton, because sun.RectanglePushButton doesn't support the look/behavior of this button.
    // Add the listener to update the appearance and handle a click.
    var update = function( state ) {
      if ( state === 'up' ) {
        buttonForegroundNode.fill = options.backgroundColor;
        buttonForegroundNode.top = 0;
        buttonForegroundNode.left = 0;
      }
      else if ( state === 'over' ) {
        buttonForegroundNode.fill = options.highlightedBackgroundColor;
      }
      else if ( state === 'down' ) {
        buttonForegroundNode.fill = options.highlightedBackgroundColor;
        buttonForegroundNode.top = shadowOffset;
        buttonForegroundNode.left = shadowOffset;
      }
    };
    buttonForegroundNode.addInputListener( new ButtonListener( {
      up: function() { update( 'up' ); },
      over: function() { update( 'over' ); },
      down: function() { update( 'down' ); },
      out: function() { update( 'up' ); }, // 'out' state looks the same as 'up'
      fire: fireFunction
    } ) );

    // Update for initial state
    update( 'up' );

    // Pass options to parent class
    this.mutate( options );
  }

  return inherit( Node, LevelStartButton );
} );<|endoftext|>