| /** |
| * Copyright 2013, Twitter Inc. and other contributors |
| * Licensed under the MIT License |
| */ |
| |
| (function (root) { |
| 'use strict'; |
| |
| jasmine.flight = {}; |
| |
| /** |
| * Wrapper for describe. Load component before each test. |
| * |
| * @param componentPath |
| * @param specDefinitions |
| */ |
| |
| root.describeComponent = function (componentPath, specDefinitions) { |
| jasmine.getEnv().describeComponent(componentPath, specDefinitions); |
| }; |
| |
| jasmine.Env.prototype.describeComponent = function (componentPath, specDefinitions) { |
| describe(componentPath, function () { |
| beforeEach(function () { |
| this.Component = this.component = this.$node = null; |
| |
| var requireCallback = function (registry, Component) { |
| registry.reset(); |
| this.Component = Component; |
| }.bind(this); |
| |
| require(['flight/lib/registry', componentPath], requireCallback); |
| |
| waitsFor(function () { |
| return this.Component !== null; |
| }.bind(this)); |
| }); |
| |
| afterEach(function () { |
| if (this.$node) { |
| this.$node.remove(); |
| this.$node = null; |
| } |
| |
| var requireCallback = function (defineComponent) { |
| if (this.component) { |
| this.component = null; |
| } |
| |
| this.Component = null; |
| defineComponent.teardownAll(); |
| }.bind(this); |
| |
| require(['flight/lib/component'], requireCallback); |
| |
| waitsFor(function () { |
| return this.Component === null; |
| }.bind(this)); |
| }); |
| |
| specDefinitions.apply(this); |
| }); |
| }; |
| |
| /** |
| * Wrapper for describe. Load mixin before each test. |
| * |
| * @param mixinPath |
| * @param specDefinitions |
| */ |
| |
| root.describeMixin = function (mixinPath, specDefinitions) { |
| jasmine.getEnv().describeMixin(mixinPath, specDefinitions); |
| }; |
| |
| jasmine.Env.prototype.describeMixin = function (mixinPath, specDefinitions) { |
| describe(mixinPath, function () { |
| beforeEach(function () { |
| this.Component = this.component = this.$node = null; |
| |
| var requireCallback = function (registry, defineComponent, Mixin) { |
| registry.reset(); |
| this.Component = defineComponent(function () {}, Mixin); |
| }.bind(this); |
| |
| require(['flight/lib/registry', 'flight/lib/component', mixinPath], requireCallback); |
| |
| waitsFor(function () { |
| return this.Component !== null; |
| }); |
| }); |
| |
| afterEach(function () { |
| if (this.$node) { |
| this.$node.remove(); |
| this.$node = null; |
| } |
| |
| var requireCallback = function (defineComponent) { |
| if (this.component) { |
| this.component = null; |
| } |
| |
| this.Component = null; |
| defineComponent.teardownAll(); |
| }.bind(this); |
| |
| require(['flight/lib/component'], requireCallback); |
| |
| waitsFor(function () { |
| return this.Component === null; |
| }.bind(this)); |
| }); |
| |
| specDefinitions.apply(this); |
| }); |
| }; |
| |
| /** |
| * Wrapper for describe. Load module before each test. |
| * |
| * @param modulePath |
| * @param specDefinitions |
| */ |
| |
| root.describeModule = function (modulePath, specDefinitions) { |
| return jasmine.getEnv().describeModule(modulePath, specDefinitions); |
| }; |
| |
| jasmine.Env.prototype.describeModule = function (modulePath, specDefinitions) { |
| describe(modulePath, function () { |
| beforeEach(function () { |
| this.module = null; |
| |
| var requireCallback = function (module) { |
| this.module = module; |
| }.bind(this); |
| |
| require([modulePath], requireCallback); |
| |
| waitsFor(function () { |
| return this.module !== null; |
| }); |
| }); |
| |
| specDefinitions.apply(this); |
| }); |
| }; |
| |
| /** |
| * Create root node and initialize component. Fixture should be html string |
| * or jQuery object. |
| * |
| * @param fixture {String} (Optional) |
| * @param options {Options} (Optional) |
| */ |
| |
| root.setupComponent = function (fixture, options) { |
| jasmine.getEnv().currentSpec.setupComponent(fixture, options); |
| }; |
| |
| jasmine.Spec.prototype.setupComponent = function (fixture, options) { |
| if (this.component) { |
| this.component.teardown(); |
| this.$node.remove(); |
| } |
| |
| this.$node = $('<div class="component-root" />'); |
| $('body').append(this.$node); |
| |
| if (fixture instanceof jQuery || typeof fixture === 'string') { |
| this.$node.append(fixture); |
| } else { |
| options = fixture; |
| fixture = null; |
| } |
| |
| options = options === undefined ? {} : options; |
| |
| this.component = new this.Component(this.$node, options); |
| }; |
| |
| |
| (function (namespace) { |
| var eventsData = { |
| spiedEvents: {}, |
| handlers: [] |
| }; |
| |
| namespace.formatElement = function ($element) { |
| var limit = 200; |
| var output = ''; |
| |
| if ($element instanceof jQuery) { |
| output = jasmine.JQuery.elementToString($element); |
| if (output.length > limit) { |
| output = output.slice(0, 200) + '...'; |
| } |
| } else { |
| //$element should always be a jQuery object |
| output = 'element is not a jQuery object'; |
| } |
| |
| return output; |
| }; |
| |
| namespace.compareColors = function (color1, color2) { |
| if (color1.charAt(0) === color2.charAt(0)) { |
| return color1 === color2; |
| } else { |
| return namespace.hex2rgb(color1) === namespace.hex2rgb(color2); |
| } |
| }; |
| |
| namespace.hex2rgb = function (colorString) { |
| if (colorString.charAt(0) !== '#') return colorString; |
| // note: hexStr should be #rrggbb |
| var hex = parseInt(colorString.substring(1), 16); |
| var r = (hex & 0xff0000) >> 16; |
| var g = (hex & 0x00ff00) >> 8; |
| var b = hex & 0x0000ff; |
| return 'rgb(' + r + ', ' + g + ', ' + b + ')'; |
| }; |
| |
| namespace.events = { |
| spyOn: function (selector, eventName) { |
| eventsData.spiedEvents[[selector, eventName]] = { |
| callCount: 0, |
| calls: [], |
| mostRecentCall: {}, |
| name: eventName |
| }; |
| |
| var handler = function (e, data) { |
| var call = { |
| event: e, |
| args: jasmine.util.argsToArray(arguments), |
| data: data |
| }; |
| eventsData.spiedEvents[[selector, eventName]].callCount++; |
| eventsData.spiedEvents[[selector, eventName]].calls.push(call); |
| eventsData.spiedEvents[[selector, eventName]].mostRecentCall = call; |
| }; |
| |
| jQuery(selector).on(eventName, handler); |
| eventsData.handlers.push(handler); |
| return eventsData.spiedEvents[[selector, eventName]]; |
| }, |
| |
| eventArgs: function (selector, eventName, expectedArg) { |
| var actualArgs = eventsData.spiedEvents[[selector, eventName]].mostRecentCall.args; |
| |
| if (!actualArgs) { |
| throw 'No event spy found on ' + eventName + '. Try adding a call to spyOnEvent or make sure that the selector the event is triggered on and the selector being spied on are correct.'; |
| } |
| |
| // remove extra event metadata if it is not tested for |
| if ((actualArgs.length === 2) && typeof actualArgs[1] === 'object' && |
| expectedArg && !expectedArg.scribeContext && !expectedArg.sourceEventData && !expectedArg.scribeData) { |
| actualArgs[1] = $.extend({}, actualArgs[1]); |
| delete actualArgs[1].sourceEventData; |
| delete actualArgs[1].scribeContext; |
| delete actualArgs[1].scribeData; |
| } |
| |
| return actualArgs; |
| }, |
| |
| wasTriggered: function (selector, event) { |
| var spiedEvent = eventsData.spiedEvents[[selector, event]]; |
| return spiedEvent && spiedEvent.callCount > 0; |
| }, |
| |
| wasTriggeredWith: function (selector, eventName, expectedArg, env) { |
| var actualArgs = jasmine.flight.events.eventArgs(selector, eventName, expectedArg); |
| return actualArgs && env.contains_(actualArgs, expectedArg); |
| }, |
| |
| wasTriggeredWithData: function (selector, eventName, expectedArg, env) { |
| var actualArgs = jasmine.flight.events.eventArgs(selector, eventName, expectedArg); |
| var valid; |
| |
| if (actualArgs) { |
| valid = false; |
| for (var i = 0; i < actualArgs.length; i++) { |
| if (jasmine.flight.validateHash(expectedArg, actualArgs[i])) { |
| return true; |
| } |
| } |
| return valid; |
| } |
| |
| return false; |
| }, |
| |
| cleanUp: function () { |
| eventsData.spiedEvents = {}; |
| eventsData.handlers = []; |
| } |
| }; |
| |
| namespace.validateHash = function (a, b, intersection) { |
| var validHash; |
| for (var field in a) { |
| if ((typeof a[field] === 'object') && (typeof b[field] === 'object')) { |
| validHash = jasmine.flight.validateHash(a[field], b[field]); |
| } else if (intersection && (typeof a[field] === 'undefined' || typeof b[field] === 'undefined')) { |
| validHash = true; |
| } else { |
| validHash = (a[field] === b[field]); |
| } |
| if (!validHash) { |
| break; |
| } |
| } |
| return validHash; |
| }; |
| })(jasmine.flight); |
| |
| beforeEach(function () { |
| this.addMatchers({ |
| toHaveBeenTriggeredOn: function () { |
| var selector = arguments[0]; |
| var eventName = typeof this.actual === 'string' ? this.actual : this.actual.name; |
| var wasTriggered = jasmine.flight.events.wasTriggered(selector, eventName); |
| |
| this.message = function () { |
| var $pp = function (obj) { |
| var description; |
| var attr; |
| |
| if (!(obj instanceof jQuery)) { |
| obj = $(obj); |
| } |
| |
| description = [ |
| obj.get(0).nodeName |
| ]; |
| |
| attr = obj.get(0).attributes || []; |
| |
| for (var x = 0; x < attr.length; x++) { |
| description.push(attr[x].name + '="' + attr[x].value + '"'); |
| } |
| |
| return '<' + description.join(' ') + '>'; |
| }; |
| |
| if (wasTriggered) { |
| return [ |
| '<div class="value-mismatch">Expected event ' + eventName + ' to have been triggered on' + selector, |
| '<div class="value-mismatch">Expected event ' + eventName + ' not to have been triggered on' + selector |
| ]; |
| } else { |
| return [ |
| 'Expected event ' + eventName + ' to have been triggered on ' + $pp(selector), |
| 'Expected event ' + eventName + ' not to have been triggered on ' + $pp(selector) |
| ]; |
| } |
| }; |
| |
| return wasTriggered; |
| }, |
| |
| toHaveBeenTriggeredOnAndWith: function () { |
| var selector = arguments[0]; |
| var expectedArg = arguments[1]; |
| var exactMatch = !arguments[2]; |
| var wasTriggered = jasmine.flight.events.wasTriggered(selector, this.actual); |
| |
| this.message = function () { |
| var $pp = function (obj) { |
| var description; |
| var attr; |
| |
| if (!(obj instanceof jQuery)) { |
| obj = $(obj); |
| } |
| |
| description = [ |
| obj.get(0).nodeName |
| ]; |
| |
| attr = obj.get(0).attributes || []; |
| |
| for (var x = 0; x < attr.length; x++) { |
| description.push(attr[x].name + '="' + attr[x].value + '"'); |
| } |
| |
| return '<' + description.join(' ') + '>'; |
| }; |
| |
| if (wasTriggered) { |
| var actualArg = jasmine.flight.events.eventArgs(selector, this.actual, expectedArg)[1]; |
| return [ |
| '<div class="value-mismatch">Expected event ' + this.actual.name + ' to have been triggered on' + selector, |
| '<div class="value-mismatch">Expected event ' + this.actual.name + ' not to have been triggered on' + selector |
| ]; |
| } else { |
| return [ |
| 'Expected event ' + this.actual.name + ' to have been triggered on ' + $pp(selector), |
| 'Expected event ' + this.actual.name + ' not to have been triggered on ' + $pp(selector) |
| ]; |
| } |
| }; |
| |
| if (!wasTriggered) { |
| return false; |
| } |
| |
| if (exactMatch) { |
| return jasmine.flight.events.wasTriggeredWith(selector, this.actual, expectedArg, this.env); |
| } else { |
| return jasmine.flight.events.wasTriggeredWithData(selector, this.actual, expectedArg, this.env); |
| } |
| }, |
| |
| toHaveCss: function (prop, val) { |
| var result; |
| if (val instanceof RegExp) { |
| result = val.test(this.actual.css(prop)); |
| } else if (prop.match(/color/)) { |
| //IE returns colors as hex strings; other browsers return rgb(r, g, b) strings |
| result = jasmine.flight.compareColors(this.actual.css(prop), val); |
| } else { |
| result = this.actual.css(prop) === val; |
| //sometimes .css() returns strings when it should return numbers |
| if (!result && typeof val === 'number') { |
| result = parseFloat(this.actual.css(prop), 10) === val; |
| } |
| } |
| |
| this.actual = jasmine.flight.formatElement(this.actual); |
| return result; |
| } |
| }); |
| }); |
| |
| root.spyOnEvent = function (selector, eventName) { |
| jasmine.JQuery.events.spyOn(selector, eventName); |
| return jasmine.flight.events.spyOn(selector, eventName); |
| }; |
| |
| }(this)); |