author | Ryan VanderMeulen <ryanvm@gmail.com> |
Tue, 25 Aug 2015 16:54:11 -0400 | |
changeset 259328 | c47ccde36664172dff25f8b444ffd7a6b150cee3 |
parent 259327 | 3a5257ac933dce09eb38c8f3615aa14ce996f1ee (current diff) |
parent 259302 | c46370eea81a9860ae77d1f0c7776c24e816138e (diff) |
child 259329 | 7c5cc8cfca19afaeb4af08c669a78219edea72c4 |
push id | 29277 |
push user | ryanvm@gmail.com |
push date | Wed, 26 Aug 2015 18:32:23 +0000 |
treeherder | mozilla-central@fea87cbeaa6b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 43.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
browser/components/loop/test/shared/vendor/sinon-1.15.0.js | file | annotate | diff | comparison | revisions |
--- a/browser/base/content/browser-fxaccounts.js +++ b/browser/base/content/browser-fxaccounts.js @@ -442,25 +442,25 @@ let gFxAccounts = { break; case "migrate-signup": case "migrate-verify": // The migration flow calls for the menu item to open sync prefs rather // than requesting migration start immediately. this.openPreferences(); break; default: - this.openAccountsPage(null, { entrypoint: "menupanel" }); + this.openPreferences(); break; } PanelUI.hide(); }, openPreferences: function () { - openPreferences("paneSync"); + openPreferences("paneSync", { urlParams: { entrypoint: "menupanel" } }); }, openAccountsPage: function (action, urlParams={}) { // An entrypoint param is used for server-side metrics. If the current tab // is UITour, assume that it initiated the call to this method and override // the entrypoint accordingly. if (UITour.tourBrowsersByWindow.get(window) && UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
--- a/browser/base/content/browser-syncui.js +++ b/browser/base/content/browser-syncui.js @@ -266,30 +266,22 @@ let gSyncUI = { * Indicates the entrypoint from where this method was called. */ openSetup: function SUI_openSetup(wizardType, entryPoint = "syncbutton") { let xps = Components.classes["@mozilla.org/weave/service;1"] .getService(Components.interfaces.nsISupports) .wrappedJSObject; if (xps.fxAccountsEnabled) { - fxAccounts.getSignedInUser().then(userData => { - if (userData) { - this.openPrefs(); - } else { - // If the user is also in an uitour, set the entrypoint to `uitour` - if (UITour.tourBrowsersByWindow.get(window) && - UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) { - entryPoint = "uitour"; - } - switchToTabHavingURI("about:accounts?entrypoint=" + entryPoint, true, { - replaceQueryString: true - }); - } - }); + // If the user is also in an uitour, set the entrypoint to `uitour` + if (UITour.tourBrowsersByWindow.get(window) && + UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) { + entryPoint = "uitour"; + } + this.openPrefs(entryPoint); } else { let win = Services.wm.getMostRecentWindow("Weave:AccountSetup"); if (win) win.focus(); else { window.openDialog("chrome://browser/content/sync/setup.xul", "weaveSetup", "centerscreen,chrome,resizable=no", wizardType); @@ -304,18 +296,18 @@ let gSyncUI = { let win = Services.wm.getMostRecentWindow("Sync:AddDevice"); if (win) win.focus(); else window.openDialog("chrome://browser/content/sync/addDevice.xul", "syncAddDevice", "centerscreen,chrome,resizable=no"); }, - openPrefs: function SUI_openPrefs() { - openPreferences("paneSync"); + openPrefs: function (entryPoint) { + openPreferences("paneSync", { urlParams: { entrypoint: entryPoint } }); }, openSignInAgainPage: function (entryPoint = "syncbutton") { gFxAccounts.openSignInAgainPage(entryPoint); }, // Helpers _updateLastSyncTime: function SUI__updateLastSyncTime() {
--- a/browser/base/content/test/general/browser_fullscreen-window-open.js +++ b/browser/base/content/test/general/browser_fullscreen-window-open.js @@ -327,17 +327,17 @@ WindowListener.prototype = { callback_onSuccess: null, callBack_onFinalize: null, onOpenWindow: function(aXULWindow) { Services.wm.removeListener(this); let domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindow); - domwindow.addEventListener("load", function onLoad(aEvent) { + let onLoad = aEvent => { is(domwindow.document.location.href, this.test_url, "Opened Window is expected: "+ this.test_title); if (this.callback_onSuccess) { this.callback_onSuccess(); } domwindow.removeEventListener("load", onLoad, true); @@ -347,15 +347,16 @@ WindowListener.prototype = { domwindow.close(); executeSoon(this.callBack_onFinalize); }.bind(this), 3000); } else { domwindow.close(); executeSoon(this.callBack_onFinalize); } - }.bind(this), true); + }; + domwindow.addEventListener("load", onLoad, true); }, onCloseWindow: function(aXULWindow) {}, onWindowTitleChange: function(aXULWindow, aNewTitle) {}, QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediatorListener, Ci.nsISupports]), };
--- a/browser/base/content/test/general/browser_fxaccounts.js +++ b/browser/base/content/test/general/browser_fxaccounts.js @@ -79,19 +79,19 @@ add_task(function* test_nouser() { // Check the world - the FxA footer area is visible as it is offering a signin. Assert.ok(isFooterVisible()) Assert.equal(panelUILabel.getAttribute("label"), panelUIStatus.getAttribute("defaultlabel")); Assert.ok(!panelUIStatus.hasAttribute("tooltiptext"), "no tooltip when signed out"); Assert.ok(!panelUIFooter.hasAttribute("fxastatus"), "no fxsstatus when signed out"); Assert.ok(!panelUIFooter.hasAttribute("fxaprofileimage"), "no fxaprofileimage when signed out"); - let promiseOpen = promiseTabOpen("about:accounts?entrypoint=menupanel"); + let promisePreferencesOpened = promiseObserver("test:browser_fxaccounts:openPreferences"); panelUIStatus.click(); - yield promiseOpen; + yield promisePreferencesOpened; }); /* XXX - Bug 1191162 - need a better hawk mock story or this will leak in debug builds. add_task(function* test_unverifiedUser() { let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem"); yield setSignedInUser(false); // this will fire the observer that does the update.
--- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -527,17 +527,27 @@ function openPreferences(paneID, extraAr // This function is duplicated from preferences.js. function internalPrefCategoryNameToFriendlyName(aName) { return (aName || "").replace(/^pane./, function(toReplace) { return toReplace[4].toLowerCase(); }); } if (getBoolPref("browser.preferences.inContent")) { let win = Services.wm.getMostRecentWindow("navigator:browser"); let friendlyCategoryName = internalPrefCategoryNameToFriendlyName(paneID); - let preferencesURL = "about:preferences" + + let params; + if (extraArgs && extraArgs["urlParams"]) { + params = new URLSearchParams(); + let urlParams = extraArgs["urlParams"]; + for (let name in urlParams) { + if (urlParams[name] !== undefined) { + params.set(name, urlParams[name]); + } + } + } + let preferencesURL = "about:preferences" + (params ? "?" + params : "") + (friendlyCategoryName ? "#" + friendlyCategoryName : ""); let newLoad = true; let browser = null; if (!win) { const Cc = Components.classes; const Ci = Components.interfaces; let windowArguments = Cc["@mozilla.org/supports-array;1"] .createInstance(Ci.nsISupportsArray);
--- a/browser/components/customizableui/test/browser_967000_button_sync.js +++ b/browser/components/customizableui/test/browser_967000_button_sync.js @@ -40,18 +40,18 @@ function openAboutAccountsFromMenuPanel( deferred.resolve(); } gBrowser.selectedBrowser.addEventListener("load", handler, true); syncButton.click(); yield deferred.promise; newTab = gBrowser.selectedTab; - is(gBrowser.currentURI.spec, "about:accounts?entrypoint=" + entryPoint, - "Firefox Sync page opened with `menupanel` entrypoint"); + is(gBrowser.currentURI.spec, "about:preferences?entrypoint=" + entryPoint + "#sync", + "Firefox Sync preference page opened with `menupanel` entrypoint"); ok(!isPanelUIOpen(), "The panel closed"); if(isPanelUIOpen()) { let panelHidePromise = promisePanelHidden(window); PanelUI.hide(); yield panelHidePromise; } }
--- a/browser/components/loop/.eslintrc +++ b/browser/components/loop/.eslintrc @@ -31,16 +31,17 @@ }, "rules": { // turn off all kinds of stuff that we actually do want, because // right now, we're bootstrapping the linting infrastructure. We'll // want to audit these rules, and start turning them on and fixing the // problems they find, one at a time. // Eslint built-in rules are documented at <http://eslint.org/docs/rules/> + "block-spacing": [2, "always"], "callback-return": 0, // TBD "camelcase": 0, // TODO: set to 2 "comma-spacing": 2, "computed-property-spacing": [2, "never"], "consistent-return": 0, // TODO: set to 2 "curly": [2, "all"], "dot-location": [2, "property"], "eol-last": 2,
--- a/browser/components/loop/.eslintrc-gecko +++ b/browser/components/loop/.eslintrc-gecko @@ -57,12 +57,13 @@ }, "rules": { "arrow-parens": 0, // TBD "arrow-spacing": 2, "eqeqeq": 0, // TBD "generator-star-spacing": [2, "after"], // We should fix the errors and enable this (set to 2) "no-var": 0, + "prefer-arrow-callback": 0,// TODO: Set to 2. "require-yield": 0, // TODO: Set to 2. "strict": [2, "global"] } }
--- a/browser/components/loop/content/js/otconfig.js +++ b/browser/components/loop/content/js/otconfig.js @@ -2,8 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ window.OTProperties = { cdnURL: "loop/" }; window.OTProperties.assetURL = window.OTProperties.cdnURL + "sdk-content/"; window.OTProperties.configURL = window.OTProperties.assetURL + "js/dynamic_config.min.js"; + +// We don't use the SDK's CSS. This will prevent spurious 404 errors. +window.OTProperties.cssURL = "about:blank";
--- a/browser/components/loop/content/shared/css/common.css +++ b/browser/components/loop/content/shared/css/common.css @@ -581,15 +581,18 @@ html[dir="rtl"] .context-wrapper > .cont .context-wrapper > .context-info > .context-url { display: block; color: #00a9dc; font-weight: 700; clear: both; } .clicks-allowed.context-wrapper:hover { - background-color: #dbf7ff; + border: 2px solid #5cccee; + /* Due to the increased border width, reduce the padding accordingly so that + the text doesn't move. */ + padding: calc(.8em - 1px); } /* Only underline the url, not the associated text */ .clicks-allowed.context-wrapper:hover > .context-info > .context-url { text-decoration: underline; }
--- a/browser/components/loop/content/shared/css/conversation.css +++ b/browser/components/loop/content/shared/css/conversation.css @@ -878,17 +878,17 @@ body[platform="win"] .share-service-drop background-image: url("../img/icons-16x16.svg#add-active"); } .context-url-view-wrapper { /* 18px for indent of .text-chat-arrow, 1px for border of .text-chat-entry > p, 0.5rem for padding of .text-chat-entry > p */ padding: calc(18px - 1px - 0.5rem); margin-bottom: 0.5em; - background-color: #E8F6FE; + background-color: #dbf7ff; } .room-context { background: rgba(0,0,0,.8); border-top: 2px solid #444; border-bottom: 2px solid #444; padding: .5rem; position: absolute; @@ -1605,23 +1605,23 @@ html[dir="rtl"] .text-chat-entry.receive margin-right: 0; margin-left: -10px; } .text-chat-entry.special.room-name { color: black; font-weight: bold; text-align: start; - background-color: #E8F6FE; + background-color: #dbf7ff; margin-bottom: 0; margin-right: 0; } .text-chat-entry.special.room-name p { - background: #E8F6FE; + background: #dbf7ff; max-width: 100%; /* 18px for indent of .text-chat-arrow, 1px for border of .text-chat-entry > p, 0.5rem for padding of .text-chat-entry > p */ padding: calc(18px - 1px - 0.5rem); padding-bottom: 0px; } .text-chat-entry.special > p {
--- a/browser/components/loop/content/shared/js/otSdkDriver.js +++ b/browser/components/loop/content/shared/js/otSdkDriver.js @@ -267,24 +267,27 @@ loop.OTSdkDriver = (function() { disconnectSession: function() { this.endScreenShare(); this.dispatcher.dispatch(new sharedActions.DataChannelsAvailable({ available: false })); if (this.session) { - this.session.off("sessionDisconnected streamCreated streamDestroyed connectionCreated connectionDestroyed streamPropertyChanged"); + this.session.off("sessionDisconnected streamCreated streamDestroyed " + + "connectionCreated connectionDestroyed " + + "streamPropertyChanged signal:readyForDataChannel"); this.session.disconnect(); delete this.session; this._notifyMetricsEvent("Session.connectionDestroyed", "local"); } if (this.publisher) { - this.publisher.off("accessAllowed accessDenied accessDialogOpened streamCreated"); + this.publisher.off("accessAllowed accessDenied accessDialogOpened " + + "streamCreated streamDestroyed"); this.publisher.destroy(); delete this.publisher; } this._noteConnectionLengthIfNeeded(this._getTwoWayMediaStartTime(), performance.now()); // Also, tidy these variables ready for next time. delete this._sessionConnected;
--- a/browser/components/loop/content/shared/js/textChatView.js +++ b/browser/components/loop/content/shared/js/textChatView.js @@ -71,18 +71,17 @@ loop.shared.views.chat = (function(mozL1 ); } }); var TextChatRoomName = React.createClass({displayName: "TextChatRoomName", mixins: [React.addons.PureRenderMixin], propTypes: { - message: React.PropTypes.string.isRequired, - useDesktopPaths: React.PropTypes.bool.isRequired + message: React.PropTypes.string.isRequired }, render: function() { return ( React.createElement("div", {className: "text-chat-entry special room-name"}, React.createElement("p", null, mozL10n.get("rooms_welcome_title", {conversationName: this.props.message})) ) ); @@ -175,18 +174,17 @@ loop.shared.views.chat = (function(mozL1 this.props.messageList.map(function(entry, i) { if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL) { switch (entry.contentType) { case CHAT_CONTENT_TYPES.ROOM_NAME: return ( React.createElement(TextChatRoomName, { key: i, - message: entry.message, - useDesktopPaths: this.props.useDesktopPaths}) + message: entry.message}) ); case CHAT_CONTENT_TYPES.CONTEXT: return ( React.createElement("div", {className: "context-url-view-wrapper", key: i}, React.createElement(sharedViews.ContextUrlView, { allowClick: true, description: entry.message, dispatcher: this.props.dispatcher,
--- a/browser/components/loop/content/shared/js/textChatView.jsx +++ b/browser/components/loop/content/shared/js/textChatView.jsx @@ -71,18 +71,17 @@ loop.shared.views.chat = (function(mozL1 ); } }); var TextChatRoomName = React.createClass({ mixins: [React.addons.PureRenderMixin], propTypes: { - message: React.PropTypes.string.isRequired, - useDesktopPaths: React.PropTypes.bool.isRequired + message: React.PropTypes.string.isRequired }, render: function() { return ( <div className="text-chat-entry special room-name"> <p>{mozL10n.get("rooms_welcome_title", {conversationName: this.props.message})}</p> </div> ); @@ -175,18 +174,17 @@ loop.shared.views.chat = (function(mozL1 { this.props.messageList.map(function(entry, i) { if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL) { switch (entry.contentType) { case CHAT_CONTENT_TYPES.ROOM_NAME: return ( <TextChatRoomName key={i} - message={entry.message} - useDesktopPaths={this.props.useDesktopPaths} /> + message={entry.message} /> ); case CHAT_CONTENT_TYPES.CONTEXT: return ( <div className="context-url-view-wrapper" key={i}> <sharedViews.ContextUrlView allowClick={true} description={entry.message} dispatcher={this.props.dispatcher}
--- a/browser/components/loop/content/shared/js/views.js +++ b/browser/components/loop/content/shared/js/views.js @@ -1150,17 +1150,17 @@ loop.shared.views = (function(_, mozL10n isLoading: this.props.isScreenShareLoading, mediaType: "screen-share", posterUrl: this.props.screenSharePosterUrl, srcVideoObject: this.props.screenShareVideoObject}) ), React.createElement(loop.shared.views.chat.TextChatView, { dispatcher: this.props.dispatcher, showRoomName: this.props.showContextRoomName, - useDesktopPaths: false}), + useDesktopPaths: this.props.useDesktopPaths}), this.state.localMediaAboslutelyPositioned ? null : this.renderLocalVideo() ) ) ); } });
--- a/browser/components/loop/content/shared/js/views.jsx +++ b/browser/components/loop/content/shared/js/views.jsx @@ -1150,17 +1150,17 @@ loop.shared.views = (function(_, mozL10n isLoading={this.props.isScreenShareLoading} mediaType="screen-share" posterUrl={this.props.screenSharePosterUrl} srcVideoObject={this.props.screenShareVideoObject} /> </div> <loop.shared.views.chat.TextChatView dispatcher={this.props.dispatcher} showRoomName={this.props.showContextRoomName} - useDesktopPaths={false} /> + useDesktopPaths={this.props.useDesktopPaths} /> { this.state.localMediaAboslutelyPositioned ? null : this.renderLocalVideo() } </div> </div> ); } });
--- a/browser/components/loop/modules/MozLoopService.jsm +++ b/browser/components/loop/modules/MozLoopService.jsm @@ -893,17 +893,17 @@ let MozLoopServiceInternal = { // in about:blank and then get lost. // Sadly we can't use chatbox.promiseChatLoaded() as promise chaining // involves event loop spins, which means it might be too late. // Have we already done it? if (chatbox.contentWindow.navigator.mozLoop) { return; } - chatbox.addEventListener("DOMContentLoaded", function loaded(event) { + let loaded = event => { if (event.target != chatbox.contentDocument) { return; } chatbox.removeEventListener("DOMContentLoaded", loaded, true); let chatbar = chatbox.parentNode; let window = chatbox.contentWindow; @@ -982,17 +982,18 @@ let MozLoopServiceInternal = { } } }; let pc_static = new window.mozRTCPeerConnectionStatic(); pc_static.registerPeerConnectionLifecycleCallback(onPCLifecycleChange); UITour.notify("Loop:ChatWindowOpened"); - }.bind(this), true); + }; + chatbox.addEventListener("DOMContentLoaded", loaded, true); }; let chatboxInstance = Chat.open(null, origin, "", url, undefined, undefined, callback); if (!chatboxInstance) { return null; // It's common for unit tests to overload Chat.open. } else if (chatboxInstance.setAttribute) {
--- a/browser/components/loop/standalone/content/index.html +++ b/browser/components/loop/standalone/content/index.html @@ -111,16 +111,19 @@ window.MutationObserver = myMutationObserver; } window.OTProperties = { cdnURL: "shared/libs/" }; window.OTProperties.assetURL = window.OTProperties.cdnURL + "sdk-content/"; window.OTProperties.configURL = window.OTProperties.assetURL + "js/dynamic_config.min.js"; + + // We don't use the SDK's CSS. This will prevent spurious 404 errors. + window.OTProperties.cssURL = "about:blank"; </script> <script type="text/javascript" src="js/multiplexGum.js"></script> <script type="text/javascript" src="shared/libs/sdk.js"></script> <script> // multiplexGum needs evaluation before sdk.js, but TBPlugin is not // defined until after sdk.js has been evaluated. This updates the // navigator object to reference TBPlugin if it was defined by sdk.js. if (!navigator.originalGum) {
--- a/browser/components/loop/standalone/package.json +++ b/browser/components/loop/standalone/package.json @@ -7,17 +7,17 @@ "url": "git@github.com:mozilla/loop-client.git" }, "engines": { "node": "0.10.x", "npm": "1.3.x" }, "dependencies": {}, "devDependencies": { - "eslint": "1.0.x", + "eslint": "1.2.x", "eslint-plugin-react": "3.2.x", "express": "4.x" }, "scripts": { "test": "make test", "start": "make runserver" }, "license": "MPL-2.0"
--- a/browser/components/loop/test/desktop-local/index.html +++ b/browser/components/loop/test/desktop-local/index.html @@ -32,17 +32,17 @@ <script src="../../content/libs/l10n.js"></script> <script src="../../content/shared/libs/react-0.12.2.js"></script> <script src="../../content/shared/libs/lodash-3.9.3.js"></script> <script src="../../content/shared/libs/backbone-1.2.1.js"></script> <!-- test dependencies --> <script src="../shared/vendor/mocha-2.2.5.js"></script> <script src="../shared/vendor/chai-3.0.0.js"></script> - <script src="../shared/vendor/sinon-1.15.0.js"></script> + <script src="../shared/vendor/sinon-1.16.1.js"></script> <script> /*global chai,mocha */ chai.config.includeStack = true; mocha.setup({ui: 'bdd', timeout: 10000}); </script> <!-- App scripts --> <script src="../../content/shared/js/utils.js"></script>
--- a/browser/components/loop/test/shared/index.html +++ b/browser/components/loop/test/shared/index.html @@ -33,17 +33,17 @@ <script src="../../content/shared/libs/lodash-3.9.3.js"></script> <script src="../../content/shared/libs/backbone-1.2.1.js"></script> <script src="../../standalone/content/libs/l10n-gaia-02ca67948fe8.js"></script> <!-- test dependencies --> <script src="vendor/mocha-2.2.5.js"></script> <script src="vendor/chai-3.0.0.js"></script> <script src="vendor/chai-as-promised-5.1.0.js"></script> - <script src="vendor/sinon-1.15.0.js"></script> + <script src="vendor/sinon-1.16.1.js"></script> <script> /*global chai, mocha */ chai.config.includeStack = true; mocha.setup({ui: 'bdd', timeout: 10000}); </script> <!-- App scripts --> <script src="../../content/shared/js/utils.js"></script>
--- a/browser/components/loop/test/shared/otSdkDriver_test.js +++ b/browser/components/loop/test/shared/otSdkDriver_test.js @@ -408,16 +408,76 @@ describe("loop.OTSdkDriver", function () it("should disconnect the session", function() { driver.session = session; driver.disconnectSession(); sinon.assert.calledOnce(session.disconnect); }); + it("should unsubscribe to all the publisher events that were subscribed to in #setupStreamElements", function() { + var subscribedEvents = []; + + // First find out which events were subscribed to. + sandbox.stub(publisher, "on", function(eventName) { + subscribedEvents.push(eventName); + }); + + driver.setupStreamElements(new sharedActions.SetupStreamElements({ + publisherConfig: publisherConfig + })); + + // Now disconnect, checking for any unexpected unsubscribes, or any missed + // unsubscribes. + sandbox.stub(publisher, "off", function(eventNames) { + var events = eventNames.split(" "); + + events.forEach(function(eventName) { + var index = subscribedEvents.indexOf(eventName); + + expect(index).not.eql(-1); + + subscribedEvents.splice(index, 1); + }); + }); + + driver.disconnectSession(); + + expect(subscribedEvents).eql([]); + }); + + it("should unsubscribe to all the subscriber events that were subscribed to in #connectSession", function() { + var subscribedEvents = []; + + // First find out which events were subscribed to. + sandbox.stub(session, "on", function(eventName) { + subscribedEvents.push(eventName); + }); + + driver.connectSession(sessionData); + + // Now disconnect, checking for any unexpected unsubscribes, or any missed + // unsubscribes. + sandbox.stub(session, "off", function(eventNames) { + var events = eventNames.split(" "); + + events.forEach(function(eventName) { + var index = subscribedEvents.indexOf(eventName); + + expect(index).not.eql(-1); + + subscribedEvents.splice(index, 1); + }); + }); + + driver.disconnectSession(); + + expect(subscribedEvents).eql([]); + }); + it("should dispatch a DataChannelsAvailable action with available = false", function() { driver.disconnectSession(); sinon.assert.calledOnce(dispatcher.dispatch); sinon.assert.calledWithExactly(dispatcher.dispatch, new sharedActions.DataChannelsAvailable({ available: false }));
rename from browser/components/loop/test/shared/vendor/sinon-1.15.0.js rename to browser/components/loop/test/shared/vendor/sinon-1.16.1.js --- a/browser/components/loop/test/shared/vendor/sinon-1.15.0.js +++ b/browser/components/loop/test/shared/vendor/sinon-1.16.1.js @@ -1,10 +1,10 @@ /** - * Sinon.JS 1.15.0, 2015/05/30 + * Sinon.JS 1.16.1, 2015/08/20 * * @author Christian Johansen (christian@cjohansen.no) * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS * * (The BSD License) * * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no * All rights reserved. @@ -666,461 +666,521 @@ return ascii(this, object, processed, indent); } }; return Formatio.prototype; }); !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.lolex=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ (function (global){ -/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ -/*global global*/ +/*global global, window*/ /** * @author Christian Johansen (christian@cjohansen.no) and contributors * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ -// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref() -// browsers, a number. -// see https://github.com/cjohansen/Sinon.JS/pull/436 -var timeoutResult = setTimeout(function() {}, 0); -var addTimerReturnsObject = typeof timeoutResult === "object"; -clearTimeout(timeoutResult); - -var NativeDate = Date; -var id = 1; - -/** - * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into - * number of milliseconds. This is used to support human-readable strings passed - * to clock.tick() - */ -function parseTime(str) { - if (!str) { - return 0; - } - - var strings = str.split(":"); - var l = strings.length, i = l; - var ms = 0, parsed; - - if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { - throw new Error("tick only understands numbers and 'h:m:s'"); - } - - while (i--) { - parsed = parseInt(strings[i], 10); - - if (parsed >= 60) { - throw new Error("Invalid time " + str); +(function (global) { + + // Make properties writable in IE, as per + // http://www.adequatelygood.com/Replacing-setTimeout-Globally.html + // JSLint being anal + var glbl = global; + + global.setTimeout = glbl.setTimeout; + global.clearTimeout = glbl.clearTimeout; + global.setImmediate = glbl.setImmediate; + global.clearImmediate = glbl.clearImmediate; + global.setInterval = glbl.setInterval; + global.clearInterval = glbl.clearInterval; + global.Date = glbl.Date; + + // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref() + // browsers, a number. + // see https://github.com/cjohansen/Sinon.JS/pull/436 + + var NOOP = function () { return undefined; }; + var timeoutResult = setTimeout(NOOP, 0); + var addTimerReturnsObject = typeof timeoutResult === "object"; + clearTimeout(timeoutResult); + + var NativeDate = Date; + var uniqueTimerId = 1; + + /** + * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into + * number of milliseconds. This is used to support human-readable strings passed + * to clock.tick() + */ + function parseTime(str) { + if (!str) { + return 0; + } + + var strings = str.split(":"); + var l = strings.length, i = l; + var ms = 0, parsed; + + if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { + throw new Error("tick only understands numbers and 'h:m:s'"); } - ms += parsed * Math.pow(60, (l - i - 1)); - } - - return ms * 1000; -} - -/** - * Used to grok the `now` parameter to createClock. - */ -function getEpoch(epoch) { - if (!epoch) { return 0; } - if (typeof epoch.getTime === "function") { return epoch.getTime(); } - if (typeof epoch === "number") { return epoch; } - throw new TypeError("now should be milliseconds since UNIX epoch"); -} - -function inRange(from, to, timer) { - return timer && timer.callAt >= from && timer.callAt <= to; -} - -function mirrorDateProperties(target, source) { - if (source.now) { - target.now = function now() { - return target.clock.now; - }; - } else { - delete target.now; - } - - if (source.toSource) { - target.toSource = function toSource() { - return source.toSource(); - }; - } else { - delete target.toSource; - } - - target.toString = function toString() { - return source.toString(); - }; - - target.prototype = source.prototype; - target.parse = source.parse; - target.UTC = source.UTC; - target.prototype.toUTCString = source.prototype.toUTCString; - - for (var prop in source) { - if (source.hasOwnProperty(prop)) { - target[prop] = source[prop]; + while (i--) { + parsed = parseInt(strings[i], 10); + + if (parsed >= 60) { + throw new Error("Invalid time " + str); + } + + ms += parsed * Math.pow(60, (l - i - 1)); + } + + return ms * 1000; + } + + /** + * Used to grok the `now` parameter to createClock. + */ + function getEpoch(epoch) { + if (!epoch) { return 0; } + if (typeof epoch.getTime === "function") { return epoch.getTime(); } + if (typeof epoch === "number") { return epoch; } + throw new TypeError("now should be milliseconds since UNIX epoch"); + } + + function inRange(from, to, timer) { + return timer && timer.callAt >= from && timer.callAt <= to; + } + + function mirrorDateProperties(target, source) { + var prop; + for (prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + + // set special now implementation + if (source.now) { + target.now = function now() { + return target.clock.now; + }; + } else { + delete target.now; + } + + // set special toSource implementation + if (source.toSource) { + target.toSource = function toSource() { + return source.toSource(); + }; + } else { + delete target.toSource; } - } - - return target; -} - -function createDate() { - function ClockDate(year, month, date, hour, minute, second, ms) { - // Defensive and verbose to avoid potential harm in passing - // explicit undefined when user does not pass argument - switch (arguments.length) { - case 0: - return new NativeDate(ClockDate.clock.now); - case 1: - return new NativeDate(year); - case 2: - return new NativeDate(year, month); - case 3: - return new NativeDate(year, month, date); - case 4: - return new NativeDate(year, month, date, hour); - case 5: - return new NativeDate(year, month, date, hour, minute); - case 6: - return new NativeDate(year, month, date, hour, minute, second); - default: - return new NativeDate(year, month, date, hour, minute, second, ms); + + // set special toString implementation + target.toString = function toString() { + return source.toString(); + }; + + target.prototype = source.prototype; + target.parse = source.parse; + target.UTC = source.UTC; + target.prototype.toUTCString = source.prototype.toUTCString; + + return target; + } + + function createDate() { + function ClockDate(year, month, date, hour, minute, second, ms) { + // Defensive and verbose to avoid potential harm in passing + // explicit undefined when user does not pass argument + switch (arguments.length) { + case 0: + return new NativeDate(ClockDate.clock.now); + case 1: + return new NativeDate(year); + case 2: + return new NativeDate(year, month); + case 3: + return new NativeDate(year, month, date); + case 4: + return new NativeDate(year, month, date, hour); + case 5: + return new NativeDate(year, month, date, hour, minute); + case 6: + return new NativeDate(year, month, date, hour, minute, second); + default: + return new NativeDate(year, month, date, hour, minute, second, ms); + } } - } - - return mirrorDateProperties(ClockDate, NativeDate); -} - -function addTimer(clock, timer) { - if (typeof timer.func === "undefined") { - throw new Error("Callback must be provided to timer calls"); - } - - if (!clock.timers) { - clock.timers = {}; - } - - timer.id = id++; - timer.createdAt = clock.now; - timer.callAt = clock.now + (timer.delay || 0); - - clock.timers[timer.id] = timer; - - if (addTimerReturnsObject) { - return { - id: timer.id, - ref: function() {}, - unref: function() {} - }; - } - else { + + return mirrorDateProperties(ClockDate, NativeDate); + } + + function addTimer(clock, timer) { + if (timer.func === undefined) { + throw new Error("Callback must be provided to timer calls"); + } + + if (!clock.timers) { + clock.timers = {}; + } + + timer.id = uniqueTimerId++; + timer.createdAt = clock.now; + timer.callAt = clock.now + (timer.delay || (clock.duringTick ? 1 : 0)); + + clock.timers[timer.id] = timer; + + if (addTimerReturnsObject) { + return { + id: timer.id, + ref: NOOP, + unref: NOOP + }; + } + return timer.id; } -} - -function firstTimerInRange(clock, from, to) { - var timers = clock.timers, timer = null; - - for (var id in timers) { - if (!inRange(from, to, timers[id])) { - continue; + + + function compareTimers(a, b) { + // Sort first by absolute timing + if (a.callAt < b.callAt) { + return -1; + } + if (a.callAt > b.callAt) { + return 1; + } + + // Sort next by immediate, immediate timers take precedence + if (a.immediate && !b.immediate) { + return -1; } - - if (!timer || ~compareTimers(timer, timers[id])) { - timer = timers[id]; + if (!a.immediate && b.immediate) { + return 1; + } + + // Sort next by creation time, earlier-created timers take precedence + if (a.createdAt < b.createdAt) { + return -1; + } + if (a.createdAt > b.createdAt) { + return 1; + } + + // Sort next by id, lower-id timers take precedence + if (a.id < b.id) { + return -1; + } + if (a.id > b.id) { + return 1; } - } - - return timer; -} - -function compareTimers(a, b) { - // Sort first by absolute timing - if (a.callAt < b.callAt) { - return -1; - } - if (a.callAt > b.callAt) { - return 1; - } - - // Sort next by immediate, immediate timers take precedence - if (a.immediate && !b.immediate) { - return -1; - } - if (!a.immediate && b.immediate) { - return 1; - } - - // Sort next by creation time, earlier-created timers take precedence - if (a.createdAt < b.createdAt) { - return -1; - } - if (a.createdAt > b.createdAt) { - return 1; - } - - // Sort next by id, lower-id timers take precedence - if (a.id < b.id) { - return -1; - } - if (a.id > b.id) { - return 1; - } - - // As timer ids are unique, no fallback `0` is necessary -} - -function callTimer(clock, timer) { - if (typeof timer.interval == "number") { - clock.timers[timer.id].callAt += timer.interval; - } else { - delete clock.timers[timer.id]; - } - - try { - if (typeof timer.func == "function") { - timer.func.apply(null, timer.args); + + // As timer ids are unique, no fallback `0` is necessary + } + + function firstTimerInRange(clock, from, to) { + var timers = clock.timers, + timer = null, + id, + isInRange; + + for (id in timers) { + if (timers.hasOwnProperty(id)) { + isInRange = inRange(from, to, timers[id]); + + if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) { + timer = timers[id]; + } + } + } + + return timer; + } + + function callTimer(clock, timer) { + var exception; + + if (typeof timer.interval === "number") { + clock.timers[timer.id].callAt += timer.interval; } else { - eval(timer.func); + delete clock.timers[timer.id]; } - } catch (e) { - var exception = e; - } - - if (!clock.timers[timer.id]) { + + try { + if (typeof timer.func === "function") { + timer.func.apply(null, timer.args); + } else { + eval(timer.func); + } + } catch (e) { + exception = e; + } + + if (!clock.timers[timer.id]) { + if (exception) { + throw exception; + } + return; + } + if (exception) { throw exception; } - return; - } - - if (exception) { - throw exception; - } -} - -function uninstall(clock, target) { - var method; - - for (var i = 0, l = clock.methods.length; i < l; i++) { - method = clock.methods[i]; - - if (target[method].hadOwnProperty) { - target[method] = clock["_" + method]; - } else { - try { - delete target[method]; - } catch (e) {} + } + + function uninstall(clock, target) { + var method, + i, + l; + + for (i = 0, l = clock.methods.length; i < l; i++) { + method = clock.methods[i]; + + if (target[method].hadOwnProperty) { + target[method] = clock["_" + method]; + } else { + try { + delete target[method]; + } catch (ignore) {} + } } - } - - // Prevent multiple executions which will completely remove these props - clock.methods = []; -} - -function hijackMethod(target, method, clock) { - clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method); - clock["_" + method] = target[method]; - - if (method == "Date") { - var date = mirrorDateProperties(clock[method], target[method]); - target[method] = date; - } else { - target[method] = function () { - return clock[method].apply(clock, arguments); - }; - - for (var prop in clock[method]) { - if (clock[method].hasOwnProperty(prop)) { - target[method][prop] = clock[method][prop]; + + // Prevent multiple executions which will completely remove these props + clock.methods = []; + } + + function hijackMethod(target, method, clock) { + var prop; + + clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method); + clock["_" + method] = target[method]; + + if (method === "Date") { + var date = mirrorDateProperties(clock[method], target[method]); + target[method] = date; + } else { + target[method] = function () { + return clock[method].apply(clock, arguments); + }; + + for (prop in clock[method]) { + if (clock[method].hasOwnProperty(prop)) { + target[method][prop] = clock[method][prop]; + } + } + } + + target[method].clock = clock; + } + + var timers = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setImmediate: global.setImmediate, + clearImmediate: global.clearImmediate, + setInterval: setInterval, + clearInterval: clearInterval, + Date: Date + }; + + var keys = Object.keys || function (obj) { + var ks = [], + key; + + for (key in obj) { + if (obj.hasOwnProperty(key)) { + ks.push(key); } } - } - - target[method].clock = clock; -} - -var timers = { - setTimeout: setTimeout, - clearTimeout: clearTimeout, - setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), - clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined), - setInterval: setInterval, - clearInterval: clearInterval, - Date: Date -}; - -var keys = Object.keys || function (obj) { - var ks = []; - for (var key in obj) { - ks.push(key); - } - return ks; -}; - -exports.timers = timers; - -var createClock = exports.createClock = function (now) { - var clock = { - now: getEpoch(now), - timeouts: {}, - Date: createDate() - }; - - clock.Date.clock = clock; - - clock.setTimeout = function setTimeout(func, timeout) { - return addTimer(clock, { - func: func, - args: Array.prototype.slice.call(arguments, 2), - delay: timeout - }); - }; - - clock.clearTimeout = function clearTimeout(timerId) { - if (!timerId) { - // null appears to be allowed in most browsers, and appears to be - // relied upon by some libraries, like Bootstrap carousel - return; - } - if (!clock.timers) { - clock.timers = []; - } - // in Node, timerId is an object with .ref()/.unref(), and - // its .id field is the actual timer id. - if (typeof timerId === "object") { - timerId = timerId.id - } - if (timerId in clock.timers) { - delete clock.timers[timerId]; - } - }; - - clock.setInterval = function setInterval(func, timeout) { - return addTimer(clock, { - func: func, - args: Array.prototype.slice.call(arguments, 2), - delay: timeout, - interval: timeout - }); - }; - - clock.clearInterval = function clearInterval(timerId) { - clock.clearTimeout(timerId); + + return ks; }; - clock.setImmediate = function setImmediate(func) { - return addTimer(clock, { - func: func, - args: Array.prototype.slice.call(arguments, 1), - immediate: true - }); - }; - - clock.clearImmediate = function clearImmediate(timerId) { - clock.clearTimeout(timerId); - }; - - clock.tick = function tick(ms) { - ms = typeof ms == "number" ? ms : parseTime(ms); - var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now; - var timer = firstTimerInRange(clock, tickFrom, tickTo); - - var firstException; - while (timer && tickFrom <= tickTo) { - if (clock.timers[timer.id]) { - tickFrom = clock.now = timer.callAt; - try { - callTimer(clock, timer); - } catch (e) { - firstException = firstException || e; - } + exports.timers = timers; + + function createClock(now) { + var clock = { + now: getEpoch(now), + timeouts: {}, + Date: createDate() + }; + + clock.Date.clock = clock; + + clock.setTimeout = function setTimeout(func, timeout) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 2), + delay: timeout + }); + }; + + clock.clearTimeout = function clearTimeout(timerId) { + if (!timerId) { + // null appears to be allowed in most browsers, and appears to be + // relied upon by some libraries, like Bootstrap carousel + return; + } + + if (!clock.timers) { + clock.timers = []; + } + + // in Node, timerId is an object with .ref()/.unref(), and + // its .id field is the actual timer id. + if (typeof timerId === "object") { + timerId = timerId.id; + } + + if (clock.timers.hasOwnProperty(timerId)) { + delete clock.timers[timerId]; } - - timer = firstTimerInRange(clock, previous, tickTo); - previous = tickFrom; - } - - clock.now = tickTo; - - if (firstException) { - throw firstException; + }; + + clock.setInterval = function setInterval(func, timeout) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 2), + delay: timeout, + interval: timeout + }); + }; + + clock.clearInterval = function clearInterval(timerId) { + clock.clearTimeout(timerId); + }; + + clock.setImmediate = function setImmediate(func) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 1), + immediate: true + }); + }; + + clock.clearImmediate = function clearImmediate(timerId) { + clock.clearTimeout(timerId); + }; + + clock.tick = function tick(ms) { + ms = typeof ms === "number" ? ms : parseTime(ms); + var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now; + var timer = firstTimerInRange(clock, tickFrom, tickTo); + + clock.duringTick = true; + + var firstException; + while (timer && tickFrom <= tickTo) { + if (clock.timers[timer.id]) { + tickFrom = clock.now = timer.callAt; + try { + callTimer(clock, timer); + } catch (e) { + firstException = firstException || e; + } + } + + timer = firstTimerInRange(clock, previous, tickTo); + previous = tickFrom; + } + + clock.duringTick = false; + clock.now = tickTo; + + if (firstException) { + throw firstException; + } + + return clock.now; + }; + + clock.reset = function reset() { + clock.timers = {}; + }; + + return clock; + } + exports.createClock = createClock; + + function detectKnownFailSituation(methods) { + if (methods.indexOf("Date") < 0) { return; } + + if (methods.indexOf("setTimeout") < 0) { + throw new Error("Native setTimeout will not work when Date is faked"); } - return clock.now; - }; - - clock.reset = function reset() { - clock.timers = {}; + if (methods.indexOf("setImmediate") < 0) { + throw new Error("Native setImmediate will not work when Date is faked"); + } + } + + exports.install = function install(target, now, toFake) { + var i, + l; + + if (typeof target === "number") { + toFake = now; + now = target; + target = null; + } + + if (!target) { + target = global; + } + + var clock = createClock(now); + + clock.uninstall = function () { + uninstall(clock, target); + }; + + clock.methods = toFake || []; + + if (clock.methods.length === 0) { + clock.methods = keys(timers); + } + + detectKnownFailSituation(clock.methods); + + for (i = 0, l = clock.methods.length; i < l; i++) { + hijackMethod(target, clock.methods[i], clock); + } + + return clock; }; - return clock; -}; - -exports.install = function install(target, now, toFake) { - if (typeof target === "number") { - toFake = now; - now = target; - target = null; - } - - if (!target) { - target = global; - } - - var clock = createClock(now); - - clock.uninstall = function () { - uninstall(clock, target); - }; - - clock.methods = toFake || []; - - if (clock.methods.length === 0) { - clock.methods = keys(timers); - } - - for (var i = 0, l = clock.methods.length; i < l; i++) { - hijackMethod(target, clock.methods[i], clock); - } - - return clock; -}; +}(global || this)); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}]},{},[1])(1) }); })(); var define; /** * Sinon core utilities. For internal use only. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - var sinon = (function () { "use strict"; - - var sinon; + // eslint-disable-line no-unused-vars + + var sinonModule; var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { - sinon = module.exports = require("./sinon/util/core"); + sinonModule = module.exports = require("./sinon/util/core"); require("./sinon/extend"); require("./sinon/typeOf"); require("./sinon/times_in_words"); require("./sinon/spy"); require("./sinon/call"); require("./sinon/behavior"); require("./sinon/stub"); require("./sinon/mock"); @@ -1133,46 +1193,46 @@ var sinon = (function () { require("./sinon/format"); require("./sinon/log_error"); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); - sinon = module.exports; + sinonModule = module.exports; } else { - sinon = {}; - } - - return sinon; + sinonModule = {}; + } + + return sinonModule; }()); /** * @depend ../../sinon.js */ /** * Sinon core utilities. For internal use only. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { - var div = typeof document != "undefined" && document.createElement("div"); +(function (sinonGlobal) { + + var div = typeof document !== "undefined" && document.createElement("div"); var hasOwn = Object.prototype.hasOwnProperty; function isDOMNode(obj) { var success = false; try { obj.appendChild(div); - success = div.parentNode == obj; + success = div.parentNode === obj; } catch (e) { return false; } finally { try { obj.removeChild(div); } catch (e) { // Remove failed, not much we can do about that } @@ -1209,49 +1269,50 @@ var sinon = (function () { var hasES5Support = "keys" in Object; function makeApi(sinon) { sinon.wrapMethod = function wrapMethod(object, property, method) { if (!object) { throw new TypeError("Should wrap property of object"); } - if (typeof method != "function" && typeof method != "object") { + if (typeof method !== "function" && typeof method !== "object") { throw new TypeError("Method wrapper should be a function or a property descriptor"); } function checkWrappedMethod(wrappedMethod) { + var error; + if (!isFunction(wrappedMethod)) { error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + property + " as function"); } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) { error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); } else if (wrappedMethod.calledBefore) { - var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; + var verb = wrappedMethod.returns ? "stubbed" : "spied on"; error = new TypeError("Attempted to wrap " + property + " which is already " + verb); } if (error) { if (wrappedMethod && wrappedMethod.stackTrace) { error.stack += "\n--------------\n" + wrappedMethod.stackTrace; } throw error; } } - var error, wrappedMethod; + var error, wrappedMethod, i; // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem // when using hasOwn.call on objects from other frames. var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property); if (hasES5Support) { - var methodDesc = (typeof method == "function") ? {value: method} : method, - wrappedMethodDesc = sinon.getPropertyDescriptor(object, property), - i; + var methodDesc = (typeof method === "function") ? {value: method} : method; + var wrappedMethodDesc = sinon.getPropertyDescriptor(object, property); if (!wrappedMethodDesc) { error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + property + " as function"); } else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) { error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); } if (error) { @@ -1288,17 +1349,17 @@ var sinon = (function () { method.restore = function () { // For prototype properties try to reset by delete first. // If this fails (ex: localStorage on mobile safari) then force a reset // via direct assignment. if (!owned) { // In some cases `delete` may throw an error try { delete object[property]; - } catch (e) {} + } catch (e) {} // eslint-disable-line no-empty // For native code functions `delete` fails without throwing an error // on Chrome < 43, PhantomJS, etc. } else if (hasES5Support) { Object.defineProperty(object, property, wrappedMethodDesc); } // Use strict equality comparison to check failures then force a reset // via direct assignment. @@ -1322,22 +1383,18 @@ var sinon = (function () { return new F(); }; sinon.deepEqual = function deepEqual(a, b) { if (sinon.match && sinon.match.isMatcher(a)) { return a.test(b); } - if (typeof a != "object" || typeof b != "object") { - if (isReallyNaN(a) && isReallyNaN(b)) { - return true; - } else { - return a === b; - } + if (typeof a !== "object" || typeof b !== "object") { + return isReallyNaN(a) && isReallyNaN(b) || a === b; } if (isElement(a) || isElement(b)) { return a === b; } if (a === b) { return true; @@ -1348,47 +1405,53 @@ var sinon = (function () { } if (a instanceof RegExp && b instanceof RegExp) { return (a.source === b.source) && (a.global === b.global) && (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline); } var aString = Object.prototype.toString.call(a); - if (aString != Object.prototype.toString.call(b)) { + if (aString !== Object.prototype.toString.call(b)) { return false; } - if (aString == "[object Date]") { + if (aString === "[object Date]") { return a.valueOf() === b.valueOf(); } - var prop, aLength = 0, bLength = 0; - - if (aString == "[object Array]" && a.length !== b.length) { + var prop; + var aLength = 0; + var bLength = 0; + + if (aString === "[object Array]" && a.length !== b.length) { return false; } for (prop in a) { - aLength += 1; - - if (!(prop in b)) { - return false; - } - - if (!deepEqual(a[prop], b[prop])) { - return false; + if (a.hasOwnProperty(prop)) { + aLength += 1; + + if (!(prop in b)) { + return false; + } + + if (!deepEqual(a[prop], b[prop])) { + return false; + } } } for (prop in b) { - bLength += 1; + if (b.hasOwnProperty(prop)) { + bLength += 1; + } } - return aLength == bLength; + return aLength === bLength; }; sinon.functionName = function functionName(func) { var name = func.displayName || func.name; // Use function decomposition as a last resort to get function // name. Does not rely on function decomposition to work - if it // doesn't debugging will be slightly less informative @@ -1398,17 +1461,19 @@ var sinon = (function () { name = matches && matches[1]; } return name; }; sinon.functionToString = function toString() { if (this.getCall && this.callCount) { - var thisValue, prop, i = this.callCount; + var thisValue, + prop; + var i = this.callCount; while (i--) { thisValue = this.getCall(i).thisValue; for (prop in thisValue) { if (thisValue[prop] === this) { return prop; } @@ -1431,22 +1496,24 @@ var sinon = (function () { keys.push(key); } } return keys; }; sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) { - var proto = object, descriptor; + var proto = object; + var descriptor; + while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) { proto = Object.getPrototypeOf(proto); } return descriptor; - } + }; sinon.getConfig = function (custom) { var config = {}; custom = custom || {}; var defaults = sinon.defaultConfig; for (var prop in defaults) { if (defaults.hasOwnProperty(prop)) { @@ -1461,19 +1528,19 @@ var sinon = (function () { injectIntoThis: true, injectInto: null, properties: ["spy", "stub", "mock", "clock", "server", "requests"], useFakeTimers: true, useFakeServer: true }; sinon.timesInWords = function timesInWords(count) { - return count == 1 && "once" || - count == 2 && "twice" || - count == 3 && "thrice" || + return count === 1 && "once" || + count === 2 && "twice" || + count === 3 && "thrice" || (count || 0) + " times"; }; sinon.calledInOrder = function (spies) { for (var i = 1, l = spies.length; i < l; i++) { if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { return false; } @@ -1511,39 +1578,45 @@ var sinon = (function () { } else if (isRestorable(object)) { object.restore(); } }; return sinon; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports) { makeApi(exports); } if (isAMD) { define(loadDependencies); - } else if (isNode) { - loadDependencies(require, module.exports); - } else if (!sinon) { + return; + } + + if (isNode) { + loadDependencies(require, module.exports, module); return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug var hasDontEnumBug = (function () { var obj = { constructor: function () { return "0"; }, @@ -1567,38 +1640,40 @@ var sinon = (function () { }, hasOwnProperty: function () { return "7"; }, length: function () { return "8"; }, unique: function () { - return "9" + return "9"; } }; var result = []; for (var prop in obj) { - result.push(obj[prop]()); + if (obj.hasOwnProperty(prop)) { + result.push(obj[prop]()); + } } return result.join("") !== "0123456789"; })(); /* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will * override properties in previous sources. * * target - The Object to extend * sources - Objects to copy properties from. * * Returns the extended target */ function extend(target /*, sources */) { - var sources = Array.prototype.slice.call(arguments, 1), - source, i, prop; + var sources = Array.prototype.slice.call(arguments, 1); + var source, i, prop; for (i = 0; i < sources.length; i++) { source = sources[i]; for (prop in source) { if (source.hasOwnProperty(prop)) { target[prop] = source[prop]; } @@ -1607,46 +1682,52 @@ var sinon = (function () { // Make sure we copy (own) toString method even when in JScript with DontEnum bug // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) { target.toString = source.toString; } } return target; - }; + } sinon.extend = extend; return sinon.extend; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { function timesInWords(count) { switch (count) { case 1: return "once"; case 2: return "twice"; @@ -1657,100 +1738,109 @@ var sinon = (function () { } } sinon.timesInWords = timesInWords; return sinon.timesInWords; } function loadDependencies(require, exports, module) { - var sinon = require("./util/core"); - module.exports = makeApi(sinon); - } - - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var core = require("./util/core"); + module.exports = makeApi(core); + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js */ /** * Format functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ - -(function (sinon, formatio) { +(function (sinonGlobal) { + function makeApi(sinon) { function typeOf(value) { if (value === null) { return "null"; } else if (value === undefined) { return "undefined"; } var string = Object.prototype.toString.call(value); return string.substring(8, string.length - 1).toLowerCase(); - }; + } sinon.typeOf = typeOf; return sinon.typeOf; } function loadDependencies(require, exports, module) { - var sinon = require("./util/core"); - module.exports = makeApi(sinon); - } - - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var core = require("./util/core"); + module.exports = makeApi(core); + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); } }( - (typeof sinon == "object" && sinon || null), - (typeof formatio == "object" && formatio) + typeof sinon === "object" && sinon // eslint-disable-line no-undef )); /** * @depend util/core.js * @depend typeOf.js */ /*jslint eqeqeq: false, onevar: false, plusplus: false*/ /*global module, require, sinon*/ /** * Match functions * * @author Maximilian Antoni (mail@maxantoni.de) * @license BSD * * Copyright (c) 2012 Maximilian Antoni */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { function assertType(value, type, name) { var actual = sinon.typeOf(value); if (actual !== type) { throw new TypeError("Expected type of " + name + " to be " + type + ", but was " + actual); } } @@ -1768,63 +1858,33 @@ var sinon = (function () { function matchObject(expectation, actual) { if (actual === null || actual === undefined) { return false; } for (var key in expectation) { if (expectation.hasOwnProperty(key)) { var exp = expectation[key]; var act = actual[key]; - if (match.isMatcher(exp)) { + if (isMatcher(exp)) { if (!exp.test(act)) { return false; } } else if (sinon.typeOf(exp) === "object") { if (!matchObject(exp, act)) { return false; } } else if (!sinon.deepEqual(exp, act)) { return false; } } } return true; } - matcher.or = function (m2) { - if (!arguments.length) { - throw new TypeError("Matcher expected"); - } else if (!isMatcher(m2)) { - m2 = match(m2); - } - var m1 = this; - var or = sinon.create(matcher); - or.test = function (actual) { - return m1.test(actual) || m2.test(actual); - }; - or.message = m1.message + ".or(" + m2.message + ")"; - return or; - }; - - matcher.and = function (m2) { - if (!arguments.length) { - throw new TypeError("Matcher expected"); - } else if (!isMatcher(m2)) { - m2 = match(m2); - } - var m1 = this; - var and = sinon.create(matcher); - and.test = function (actual) { - return m1.test(actual) && m2.test(actual); - }; - and.message = m1.message + ".and(" + m2.message + ")"; - return and; - }; - - var match = function (expectation, message) { + function match(expectation, message) { var m = sinon.create(matcher); var type = sinon.typeOf(expectation); switch (type) { case "object": if (typeof expectation.test === "function") { m.test = function (actual) { return expectation.test(actual) === true; }; @@ -1839,17 +1899,18 @@ var sinon = (function () { } m.test = function (actual) { return matchObject(expectation, actual); }; m.message = "match(" + str.join(", ") + ")"; break; case "number": m.test = function (actual) { - return expectation == actual; + // we need type coercion here + return expectation == actual; // eslint-disable-line eqeqeq }; break; case "string": m.test = function (actual) { if (typeof actual !== "string") { return false; } return actual.indexOf(expectation) !== -1; @@ -1876,16 +1937,46 @@ var sinon = (function () { m.test = function (actual) { return sinon.deepEqual(expectation, actual); }; } if (!m.message) { m.message = "match(" + expectation + ")"; } return m; + } + + matcher.or = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var or = sinon.create(matcher); + or.test = function (actual) { + return m1.test(actual) || m2.test(actual); + }; + or.message = m1.message + ".or(" + m2.message + ")"; + return or; + }; + + matcher.and = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var and = sinon.create(matcher); + and.test = function (actual) { + return m1.test(actual) && m2.test(actual); + }; + and.message = m1.message + ".and(" + m2.message + ")"; + return and; }; match.isMatcher = isMatcher; match.any = match(function () { return true; }, "any"); @@ -1959,122 +2050,134 @@ var sinon = (function () { match.array = match.typeOf("array"); match.regexp = match.typeOf("regexp"); match.date = match.typeOf("date"); sinon.match = match; return match; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./typeOf"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js */ /** * Format functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ - -(function (sinon, formatio) { +(function (sinonGlobal, formatio) { + function makeApi(sinon) { function valueFormatter(value) { return "" + value; } function getFormatioFormatter() { var formatter = formatio.configure({ quoteStrings: false, limitChildrenCount: 250 }); function format() { return formatter.ascii.apply(formatter, arguments); - }; + } return format; } - function getNodeFormatter(value) { - function format(value) { - return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value; - }; - + function getNodeFormatter() { try { var util = require("util"); } catch (e) { /* Node, but no util module - would be very old, but better safe than sorry */ } + function format(v) { + var isObjectWithNativeToString = typeof v === "object" && v.toString === Object.prototype.toString; + return isObjectWithNativeToString ? util.inspect(v) : v; + } + return util ? format : valueFormatter; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function", - formatter; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; + var formatter; if (isNode) { try { formatio = require("formatio"); - } catch (e) {} + } + catch (e) {} // eslint-disable-line no-empty } if (formatio) { - formatter = getFormatioFormatter() + formatter = getFormatioFormatter(); } else if (isNode) { formatter = getNodeFormatter(); } else { formatter = valueFormatter; } sinon.format = formatter; return sinon.format; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); } }( - (typeof sinon == "object" && sinon || null), - (typeof formatio == "object" && formatio) + typeof sinon === "object" && sinon, // eslint-disable-line no-undef + typeof formatio === "object" && formatio // eslint-disable-line no-undef )); /** * @depend util/core.js * @depend match.js * @depend format.js */ /** @@ -2082,29 +2185,29 @@ var sinon = (function () { * * @author Christian Johansen (christian@cjohansen.no) * @author Maximilian Antoni (mail@maxantoni.de) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen * Copyright (c) 2013 Maximilian Antoni */ - -(function (sinon) { +(function (sinonGlobal) { + + var slice = Array.prototype.slice; + function makeApi(sinon) { function throwYieldError(proxy, text, args) { var msg = sinon.functionName(proxy) + text; if (args.length) { msg += " Received [" + slice.call(args).join(", ") + "]"; } throw new Error(msg); } - var slice = Array.prototype.slice; - var callProto = { calledOn: function calledOn(thisValue) { if (sinon.match && sinon.match.isMatcher(thisValue)) { return thisValue.test(this.thisValue); } return this.thisValue === thisValue; }, @@ -2133,17 +2236,17 @@ var sinon = (function () { if (!sinon.match || !sinon.match(expectation).test(actual)) { return false; } } return true; }, calledWithExactly: function calledWithExactly() { - return arguments.length == this.args.length && + return arguments.length === this.args.length && this.calledWith.apply(this, arguments); }, notCalledWith: function notCalledWith() { return !this.calledWith.apply(this, arguments); }, notCalledWithMatch: function notCalledWithMatch() { @@ -2186,17 +2289,17 @@ var sinon = (function () { this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); }, callArgOnWith: function (pos, thisValue) { var args = slice.call(arguments, 2); this.args[pos].apply(thisValue, args); }, - yield: function () { + "yield": function () { this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); }, yieldOn: function (thisValue) { var args = this.args; for (var i = 0, l = args.length; i < l; ++i) { if (typeof args[i] === "function") { args[i].apply(thisValue, slice.call(arguments, 1)); @@ -2217,163 +2320,177 @@ var sinon = (function () { args[i][prop].apply(thisValue, slice.call(arguments, 2)); return; } } throwYieldError(this.proxy, " cannot yield to '" + prop + "' since no callback was passed.", args); }, + getStackFrames: function () { + // Omit the error message and the two top stack frames in sinon itself: + return this.stack && this.stack.split("\n").slice(3); + }, + toString: function () { var callStr = this.proxy.toString() + "("; var args = []; for (var i = 0, l = this.args.length; i < l; ++i) { args.push(sinon.format(this.args[i])); } callStr = callStr + args.join(", ") + ")"; - if (typeof this.returnValue != "undefined") { + if (typeof this.returnValue !== "undefined") { callStr += " => " + sinon.format(this.returnValue); } if (this.exception) { callStr += " !" + this.exception.name; if (this.exception.message) { callStr += "(" + this.exception.message + ")"; } } + if (this.stack) { + callStr += this.getStackFrames()[0].replace(/^\s*(?:at\s+|@)?/, " at "); + + } return callStr; } }; callProto.invokeCallback = callProto.yield; - function createSpyCall(spy, thisValue, args, returnValue, exception, id) { + function createSpyCall(spy, thisValue, args, returnValue, exception, id, stack) { if (typeof id !== "number") { throw new TypeError("Call id is not a number"); } var proxyCall = sinon.create(callProto); proxyCall.proxy = spy; proxyCall.thisValue = thisValue; proxyCall.args = args; proxyCall.returnValue = returnValue; proxyCall.exception = exception; proxyCall.callId = id; + proxyCall.stack = stack; return proxyCall; } createSpyCall.toString = callProto.toString; // used by mocks sinon.spyCall = createSpyCall; return createSpyCall; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./match"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend times_in_words.js * @depend util/core.js * @depend extend.js * @depend call.js * @depend format.js */ /** * Spy functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { - +(function (sinonGlobal) { + function makeApi(sinon) { var push = Array.prototype.push; var slice = Array.prototype.slice; var callId = 0; function spy(object, property, types) { - if (!property && typeof object == "function") { + if (!property && typeof object === "function") { return spy.create(object); } if (!object && !property) { return spy.create(function () { }); } if (types) { var methodDesc = sinon.getPropertyDescriptor(object, property); for (var i = 0; i < types.length; i++) { methodDesc[types[i]] = spy.create(methodDesc[types[i]]); } return sinon.wrapMethod(object, property, methodDesc); - } else { - var method = object[property]; - return sinon.wrapMethod(object, property, spy.create(method)); } + + return sinon.wrapMethod(object, property, spy.create(object[property])); } function matchingFake(fakes, args, strict) { if (!fakes) { - return; + return undefined; } for (var i = 0, l = fakes.length; i < l; i++) { if (fakes[i].matches(args, strict)) { return fakes[i]; } } } function incrementCallCount() { this.called = true; this.callCount += 1; this.notCalled = false; - this.calledOnce = this.callCount == 1; - this.calledTwice = this.callCount == 2; - this.calledThrice = this.callCount == 3; + this.calledOnce = this.callCount === 1; + this.calledTwice = this.callCount === 2; + this.calledThrice = this.callCount === 3; } function createCallProperties() { this.firstCall = this.getCall(0); this.secondCall = this.getCall(1); this.thirdCall = this.getCall(2); this.lastCall = this.getCall(this.callCount - 1); } var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; function createProxy(func, proxyLength) { // Retain the function length: var p; if (proxyLength) { - eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + + eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + // eslint-disable-line no-eval ") { return p.invoke(func, this, slice.call(arguments)); });"); } else { p = function proxy() { return p.invoke(func, this, slice.call(arguments)); }; } p.isSinonProxy = true; return p; @@ -2401,29 +2518,30 @@ var sinon = (function () { this.secondCall = null; this.thirdCall = null; this.lastCall = null; this.args = []; this.returnValues = []; this.thisValues = []; this.exceptions = []; this.callIds = []; + this.stacks = []; if (this.fakes) { for (var i = 0; i < this.fakes.length; i++) { this.fakes[i].reset(); } } return this; }, create: function create(func, spyLength) { var name; - if (typeof func != "function") { + if (typeof func !== "function") { func = function () { }; } else { name = sinon.functionName(func); } if (!spyLength) { spyLength = func.length; } @@ -2472,16 +2590,17 @@ var sinon = (function () { } catch (e) { exception = e; } finally { delete this.invoking; } push.call(this.exceptions, exception); push.call(this.returnValues, returnValue); + push.call(this.stacks, new Error().stack); // Make return value and exception available in the calls: createCallProperties.call(this); if (exception !== undefined) { throw exception; } @@ -2495,17 +2614,17 @@ var sinon = (function () { getCall: function getCall(i) { if (i < 0 || i >= this.callCount) { return null; } return sinon.spyCall(this, this.thisValues[i], this.args[i], this.returnValues[i], this.exceptions[i], - this.callIds[i]); + this.callIds[i], this.stacks[i]); }, getCalls: function () { var calls = []; var i; for (i = 0; i < this.callCount; i++) { calls.push(this.getCall(i)); @@ -2572,30 +2691,30 @@ var sinon = (function () { return fake; }, matches: function (args, strict) { var margs = this.matchingAguments; if (margs.length <= args.length && sinon.deepEqual(margs, args.slice(0, margs.length))) { - return !strict || margs.length == args.length; + return !strict || margs.length === args.length; } }, printf: function (format) { - var spy = this; + var spyInstance = this; var args = slice.call(arguments, 1); var formatter; return (format || "").replace(/%(.)/g, function (match, specifyer) { formatter = spyApi.formatters[specifyer]; - if (typeof formatter == "function") { - return formatter.call(null, spy, args); + if (typeof formatter === "function") { + return formatter.call(null, spyInstance, args); } else if (!isNaN(parseInt(specifyer, 10))) { return sinon.format(args[specifyer - 1]); } return "%" + specifyer; }); } }; @@ -2669,49 +2788,49 @@ var sinon = (function () { "' since it was not yet invoked."); }); delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { throw new Error(this.toString() + " cannot yield to '" + property + "' since it was not yet invoked."); }); spyApi.formatters = { - c: function (spy) { - return sinon.timesInWords(spy.callCount); + c: function (spyInstance) { + return sinon.timesInWords(spyInstance.callCount); }, - n: function (spy) { - return spy.toString(); + n: function (spyInstance) { + return spyInstance.toString(); }, - C: function (spy) { + C: function (spyInstance) { var calls = []; - for (var i = 0, l = spy.callCount; i < l; ++i) { - var stringifiedCall = " " + spy.getCall(i).toString(); + for (var i = 0, l = spyInstance.callCount; i < l; ++i) { + var stringifiedCall = " " + spyInstance.getCall(i).toString(); if (/\n/.test(calls[i - 1])) { stringifiedCall = "\n" + stringifiedCall; } push.call(calls, stringifiedCall); } return calls.length > 0 ? "\n" + calls.join("\n") : ""; }, - t: function (spy) { + t: function (spyInstance) { var objects = []; - for (var i = 0, l = spy.callCount; i < l; ++i) { - push.call(objects, sinon.format(spy.thisValues[i])); + for (var i = 0, l = spyInstance.callCount; i < l; ++i) { + push.call(objects, sinon.format(spyInstance.thisValues[i])); } return objects.join(", "); }, - "*": function (spy, args) { + "*": function (spyInstance, args) { var formatted = []; for (var i = 0, l = args.length; i < l; ++i) { push.call(formatted, sinon.format(args[i])); } return formatted.join(", "); } @@ -2720,73 +2839,81 @@ var sinon = (function () { sinon.extend(spy, spyApi); spy.spyCall = sinon.spyCall; sinon.spy = spy; return spy; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { - var sinon = require("./util/core"); + var core = require("./util/core"); require("./call"); require("./extend"); require("./times_in_words"); require("./format"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js * @depend extend.js */ /** * Stub behavior * * @author Christian Johansen (christian@cjohansen.no) * @author Tim Fischbach (mail@timfischbach.de) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + var slice = Array.prototype.slice; var join = Array.prototype.join; var useLeftMostCallback = -1; var useRightMostCallback = -2; var nextTick = (function () { if (typeof process === "object" && typeof process.nextTick === "function") { return process.nextTick; - } else if (typeof setImmediate === "function") { + } + + if (typeof setImmediate === "function") { return setImmediate; - } else { - return function (callback) { - setTimeout(callback, 0); - }; } + + return function (callback) { + setTimeout(callback, 0); + }; })(); function throwsException(error, message) { - if (typeof error == "string") { + if (typeof error === "string") { this.exception = new Error(message || ""); this.exception.name = error; } else if (!error) { this.exception = new Error("Error"); } else { this.exception = error; } @@ -2808,22 +2935,22 @@ var sinon = (function () { if (callArgAt === useRightMostCallback) { argumentList = slice.call(args).reverse(); } var callArgProp = behavior.callArgProp; for (var i = 0, l = argumentList.length; i < l; ++i) { - if (!callArgProp && typeof argumentList[i] == "function") { + if (!callArgProp && typeof argumentList[i] === "function") { return argumentList[i]; } if (callArgProp && argumentList[i] && - typeof argumentList[i][callArgProp] == "function") { + typeof argumentList[i][callArgProp] === "function") { return argumentList[i][callArgProp]; } } return null; } function makeApi(sinon) { @@ -2846,20 +2973,20 @@ var sinon = (function () { return msg; } return "argument at index " + behavior.callArgAt + " is not a function: " + func; } function callCallback(behavior, args) { - if (typeof behavior.callArgAt == "number") { + if (typeof behavior.callArgAt === "number") { var func = getCallback(behavior, args); - if (typeof func != "function") { + if (typeof func !== "function") { throw new TypeError(getCallbackError(behavior, func, args)); } if (behavior.callbackAsync) { nextTick(function () { func.apply(behavior.callbackContext, behavior.callbackArguments); }); } else { @@ -2873,29 +3000,29 @@ var sinon = (function () { var behavior = sinon.extend({}, sinon.behavior); delete behavior.create; behavior.stub = stub; return behavior; }, isPresent: function isPresent() { - return (typeof this.callArgAt == "number" || + return (typeof this.callArgAt === "number" || this.exception || - typeof this.returnArgAt == "number" || + typeof this.returnArgAt === "number" || this.returnThis || this.returnValueDefined); }, invoke: function invoke(context, args) { callCallback(this, args); if (this.exception) { throw this.exception; - } else if (typeof this.returnArgAt == "number") { + } else if (typeof this.returnArgAt === "number") { return args[this.returnArgAt]; } else if (this.returnThis) { return context; } return this.returnValue; }, @@ -2911,70 +3038,73 @@ var sinon = (function () { return this.stub.onSecondCall(); }, onThirdCall: function onThirdCall() { return this.stub.onThirdCall(); }, withArgs: function withArgs(/* arguments */) { - throw new Error("Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" is not supported. " + - "Use \"stub.withArgs(...).onCall(...)\" to define sequential behavior for calls with certain arguments."); + throw new Error( + "Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" " + + "is not supported. Use \"stub.withArgs(...).onCall(...)\" " + + "to define sequential behavior for calls with certain arguments." + ); }, callsArg: function callsArg(pos) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } this.callArgAt = pos; this.callbackArguments = []; this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgOn: function callsArgOn(pos, context) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = pos; this.callbackArguments = []; this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgWith: function callsArgWith(pos) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } this.callArgAt = pos; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgOnWith: function callsArgWith(pos, context) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = pos; this.callbackArguments = slice.call(arguments, 2); this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; @@ -2998,17 +3128,17 @@ var sinon = (function () { this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yieldsOn: function (context) { - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; @@ -3022,17 +3152,17 @@ var sinon = (function () { this.callbackContext = undefined; this.callArgProp = prop; this.callbackAsync = false; return this; }, yieldsToOn: function (prop, context) { - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 2); this.callbackContext = context; this.callArgProp = prop; this.callbackAsync = false; @@ -3041,150 +3171,163 @@ var sinon = (function () { }, throws: throwsException, throwsException: throwsException, returns: function returns(value) { this.returnValue = value; this.returnValueDefined = true; + this.exception = undefined; return this; }, returnsArg: function returnsArg(pos) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } this.returnArgAt = pos; return this; }, returnsThis: function returnsThis() { this.returnThis = true; return this; } }; + function createAsyncVersion(syncFnName) { + return function () { + var result = this[syncFnName].apply(this, arguments); + this.callbackAsync = true; + return result; + }; + } + // create asynchronous versions of callsArg* and yields* methods for (var method in proto) { // need to avoid creating anotherasync versions of the newly added async methods - if (proto.hasOwnProperty(method) && - method.match(/^(callsArg|yields)/) && - !method.match(/Async/)) { - proto[method + "Async"] = (function (syncFnName) { - return function () { - var result = this[syncFnName].apply(this, arguments); - this.callbackAsync = true; - return result; - }; - })(method); + if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/) && !method.match(/Async/)) { + proto[method + "Async"] = createAsyncVersion(method); } } sinon.behavior = proto; return proto; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./extend"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js * @depend extend.js * @depend spy.js * @depend behavior.js */ /** * Stub functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { function stub(object, property, func) { - if (!!func && typeof func != "function" && typeof func != "object") { + if (!!func && typeof func !== "function" && typeof func !== "object") { throw new TypeError("Custom stub should be a function or a property descriptor"); } - var wrapper; + var wrapper, + prop; if (func) { - if (typeof func == "function") { + if (typeof func === "function") { wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; } else { wrapper = func; if (sinon.spy && sinon.spy.create) { var types = sinon.objectKeys(wrapper); for (var i = 0; i < types.length; i++) { wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]); } } } } else { var stubLength = 0; - if (typeof object == "object" && typeof object[property] == "function") { + if (typeof object === "object" && typeof object[property] === "function") { stubLength = object[property].length; } wrapper = stub.create(stubLength); } if (!object && typeof property === "undefined") { return sinon.stub.create(); } - if (typeof property === "undefined" && typeof object == "object") { - for (var prop in object) { + if (typeof property === "undefined" && typeof object === "object") { + for (prop in object) { if (typeof sinon.getPropertyDescriptor(object, prop).value === "function") { stub(object, prop); } } return object; } return sinon.wrapMethod(object, property, wrapper); } - function getDefaultBehavior(stub) { - return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub); + + /*eslint-disable no-use-before-define*/ + function getParentBehaviour(stubInstance) { + return (stubInstance.parent && getCurrentBehavior(stubInstance.parent)); } - function getParentBehaviour(stub) { - return (stub.parent && getCurrentBehavior(stub.parent)); + function getDefaultBehavior(stubInstance) { + return stubInstance.defaultBehavior || + getParentBehaviour(stubInstance) || + sinon.behavior.create(stubInstance); } - function getCurrentBehavior(stub) { - var behavior = stub.behaviors[stub.callCount - 1]; - return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub); + function getCurrentBehavior(stubInstance) { + var behavior = stubInstance.behaviors[stubInstance.callCount - 1]; + return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stubInstance); } + /*eslint-enable no-use-before-define*/ var uuid = 0; var proto = { create: function create(stubLength) { var functionStub = function () { return getCurrentBehavior(functionStub).invoke(this, arguments); }; @@ -3238,59 +3381,67 @@ var sinon = (function () { return this.onCall(1); }, onThirdCall: function onThirdCall() { return this.onCall(2); } }; + function createBehavior(behaviorMethod) { + return function () { + this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); + this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); + return this; + }; + } + for (var method in sinon.behavior) { if (sinon.behavior.hasOwnProperty(method) && !proto.hasOwnProperty(method) && - method != "create" && - method != "withArgs" && - method != "invoke") { - proto[method] = (function (behaviorMethod) { - return function () { - this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); - this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); - return this; - }; - }(method)); + method !== "create" && + method !== "withArgs" && + method !== "invoke") { + proto[method] = createBehavior(method); } } sinon.extend(stub, proto); sinon.stub = stub; return stub; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { - var sinon = require("./util/core"); + var core = require("./util/core"); require("./behavior"); require("./spy"); require("./extend"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend times_in_words.js * @depend util/core.js * @depend call.js * @depend extend.js * @depend match.js * @depend spy.js @@ -3300,26 +3451,26 @@ var sinon = (function () { /** * Mock functions. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { var push = [].push; var match = sinon.match; function mock(object) { - if (typeof console !== undefined && console.warn) { - console.warn("mock will be removed from Sinon.JS v2.0"); - } + // if (typeof console !== undefined && console.warn) { + // console.warn("mock will be removed from Sinon.JS v2.0"); + // } if (!object) { return sinon.expectation.create("Anonymous mock"); } return mock.create(object); } @@ -3328,16 +3479,29 @@ var sinon = (function () { return; } for (var i = 0, l = collection.length; i < l; i += 1) { callback(collection[i]); } } + function arrayEquals(arr1, arr2, compareLength) { + if (compareLength && (arr1.length !== arr2.length)) { + return false; + } + + for (var i = 0, l = arr1.length; i < l; i++) { + if (!sinon.deepEqual(arr1[i], arr2[i])) { + return false; + } + } + return true; + } + sinon.extend(mock, { create: function create(object) { if (!object) { throw new TypeError("object is null"); } var mockObject = sinon.extend({}, mock); mockObject.object = object; @@ -3372,25 +3536,26 @@ var sinon = (function () { return expectation; }, restore: function restore() { var object = this.object; each(this.proxies, function (proxy) { - if (typeof object[proxy].restore == "function") { + if (typeof object[proxy].restore === "function") { object[proxy].restore(); } }); }, verify: function verify() { var expectations = this.expectations || {}; - var messages = [], met = []; + var messages = []; + var met = []; each(this.proxies, function (proxy) { each(expectations[proxy], function (expectation) { if (!expectation.met()) { push.call(messages, expectation.toString()); } else { push.call(met, expectation.toString()); } @@ -3404,101 +3569,112 @@ var sinon = (function () { } else if (met.length > 0) { sinon.expectation.pass(messages.concat(met).join("\n")); } return true; }, invokeMethod: function invokeMethod(method, thisValue, args) { - var expectations = this.expectations && this.expectations[method]; - var length = expectations && expectations.length || 0, i; - - for (i = 0; i < length; i += 1) { - if (!expectations[i].met() && - expectations[i].allowsCall(thisValue, args)) { - return expectations[i].apply(thisValue, args); + var expectations = this.expectations && this.expectations[method] ? this.expectations[method] : []; + var expectationsWithMatchingArgs = []; + var currentArgs = args || []; + var i, available; + + for (i = 0; i < expectations.length; i += 1) { + var expectedArgs = expectations[i].expectedArguments || []; + if (arrayEquals(expectedArgs, currentArgs, expectations[i].expectsExactArgCount)) { + expectationsWithMatchingArgs.push(expectations[i]); } } - var messages = [], available, exhausted = 0; - - for (i = 0; i < length; i += 1) { - if (expectations[i].allowsCall(thisValue, args)) { - available = available || expectations[i]; + for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { + if (!expectationsWithMatchingArgs[i].met() && + expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { + return expectationsWithMatchingArgs[i].apply(thisValue, args); + } + } + + var messages = []; + var exhausted = 0; + + for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { + if (expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { + available = available || expectationsWithMatchingArgs[i]; } else { exhausted += 1; } + } + + if (available && exhausted === 0) { + return available.apply(thisValue, args); + } + + for (i = 0; i < expectations.length; i += 1) { push.call(messages, " " + expectations[i].toString()); } - if (exhausted === 0) { - return available.apply(thisValue, args); - } - messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ proxy: method, args: args })); sinon.expectation.fail(messages.join("\n")); } }); var times = sinon.timesInWords; var slice = Array.prototype.slice; function callCountInWords(callCount) { - if (callCount == 0) { + if (callCount === 0) { return "never called"; - } else { - return "called " + times(callCount); } + + return "called " + times(callCount); } function expectedCallCountInWords(expectation) { var min = expectation.minCalls; var max = expectation.maxCalls; - if (typeof min == "number" && typeof max == "number") { + if (typeof min === "number" && typeof max === "number") { var str = times(min); - if (min != max) { + if (min !== max) { str = "at least " + str + " and at most " + times(max); } return str; } - if (typeof min == "number") { + if (typeof min === "number") { return "at least " + times(min); } return "at most " + times(max); } function receivedMinCalls(expectation) { - var hasMinLimit = typeof expectation.minCalls == "number"; + var hasMinLimit = typeof expectation.minCalls === "number"; return !hasMinLimit || expectation.callCount >= expectation.minCalls; } function receivedMaxCalls(expectation) { - if (typeof expectation.maxCalls != "number") { + if (typeof expectation.maxCalls !== "number") { return false; } - return expectation.callCount == expectation.maxCalls; + return expectation.callCount === expectation.maxCalls; } function verifyMatcher(possibleMatcher, arg) { - if (match && match.isMatcher(possibleMatcher)) { - return possibleMatcher.test(arg); - } else { - return true; - } + var isMatcher = match && match.isMatcher(possibleMatcher); + + return isMatcher && possibleMatcher.test(arg) || true; } sinon.expectation = { minCalls: 1, maxCalls: 1, create: function create(methodName) { var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); @@ -3510,32 +3686,32 @@ var sinon = (function () { invoke: function invoke(func, thisValue, args) { this.verifyCallAllowed(thisValue, args); return sinon.spy.invoke.apply(this, arguments); }, atLeast: function atLeast(num) { - if (typeof num != "number") { + if (typeof num !== "number") { throw new TypeError("'" + num + "' is not number"); } if (!this.limitsSet) { this.maxCalls = null; this.limitsSet = true; } this.minCalls = num; return this; }, atMost: function atMost(num) { - if (typeof num != "number") { + if (typeof num !== "number") { throw new TypeError("'" + num + "' is not number"); } if (!this.limitsSet) { this.minCalls = null; this.limitsSet = true; } @@ -3556,17 +3732,17 @@ var sinon = (function () { return this.exactly(2); }, thrice: function thrice() { return this.exactly(3); }, exactly: function exactly(num) { - if (typeof num != "number") { + if (typeof num !== "number") { throw new TypeError("'" + num + "' is not a number"); } this.atLeast(num); return this.atMost(num); }, met: function met() { @@ -3594,17 +3770,17 @@ var sinon = (function () { } if (args.length < this.expectedArguments.length) { sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + "), expected " + sinon.format(this.expectedArguments)); } if (this.expectsExactArgCount && - args.length != this.expectedArguments.length) { + args.length !== this.expectedArguments.length) { sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + "), expected " + sinon.format(this.expectedArguments)); } for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { if (!verifyMatcher(this.expectedArguments[i], args[i])) { sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + @@ -3633,17 +3809,17 @@ var sinon = (function () { args = args || []; if (args.length < this.expectedArguments.length) { return false; } if (this.expectsExactArgCount && - args.length != this.expectedArguments.length) { + args.length !== this.expectedArguments.length) { return false; } for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { if (!verifyMatcher(this.expectedArguments[i], args[i])) { return false; } @@ -3715,17 +3891,17 @@ var sinon = (function () { throw exception; } }; sinon.mock = mock; return mock; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./times_in_words"); require("./call"); require("./extend"); require("./match"); @@ -3733,57 +3909,63 @@ var sinon = (function () { require("./stub"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js * @depend spy.js * @depend stub.js * @depend mock.js */ /** * Collections of stubs, spies and mocks. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + var push = [].push; var hasOwnProperty = Object.prototype.hasOwnProperty; function getFakes(fakeCollection) { if (!fakeCollection.fakes) { fakeCollection.fakes = []; } return fakeCollection.fakes; } function each(fakeCollection, method) { var fakes = getFakes(fakeCollection); for (var i = 0, l = fakes.length; i < l; i += 1) { - if (typeof fakes[i][method] == "function") { + if (typeof fakes[i][method] === "function") { fakes[i][method](); } } } function compact(fakeCollection) { var fakes = getFakes(fakeCollection); var i = 0; @@ -3831,31 +4013,31 @@ var sinon = (function () { spy: function spy() { return this.add(sinon.spy.apply(sinon, arguments)); }, stub: function stub(object, property, value) { if (property) { var original = object[property]; - if (typeof original != "function") { + if (typeof original !== "function") { if (!hasOwnProperty.call(object, property)) { throw new TypeError("Cannot stub non-existent own property " + property); } object[property] = value; return this.add({ restore: function () { object[property] = original; } }); } } - if (!property && !!object && typeof object == "object") { + if (!property && !!object && typeof object === "object") { var stubbedObj = sinon.stub.apply(sinon, arguments); for (var prop in stubbedObj) { if (typeof stubbedObj[prop] === "function") { this.add(stubbedObj[prop]); } } @@ -3887,39 +4069,43 @@ var sinon = (function () { return obj; } }; sinon.collection = collection; return collection; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./mock"); require("./spy"); require("./stub"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); - -/*global lolex */ + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * Fake timer API * setTimeout * setInterval * clearTimeout * clearInterval * tick @@ -3928,92 +4114,90 @@ var sinon = (function () { * * Inspired by jsUnitMockTimeOut from JsUnit * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -if (typeof sinon == "undefined") { - var sinon = {}; -} - -(function (global) { - function makeApi(sinon, lol) { +(function () { + + function makeApi(s, lol) { + /*global lolex */ var llx = typeof lolex !== "undefined" ? lolex : lol; - sinon.useFakeTimers = function () { - var now, methods = Array.prototype.slice.call(arguments); + s.useFakeTimers = function () { + var now; + var methods = Array.prototype.slice.call(arguments); if (typeof methods[0] === "string") { now = 0; } else { now = methods.shift(); } var clock = llx.install(now || 0, methods); clock.restore = clock.uninstall; return clock; }; - sinon.clock = { + s.clock = { create: function (now) { return llx.createClock(now); } }; - sinon.timers = { + s.timers = { setTimeout: setTimeout, clearTimeout: clearTimeout, setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined), setInterval: setInterval, clearInterval: clearInterval, Date: Date }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, epxorts, module, lolex) { - var sinon = require("./core"); - makeApi(sinon, lolex); - module.exports = sinon; + var core = require("./core"); + makeApi(core, lolex); + module.exports = core; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module, require("lolex")); } else { - makeApi(sinon); - } -}(typeof global != "undefined" && typeof global !== "function" ? global : this)); + makeApi(sinon); // eslint-disable-line no-undef + } +}()); /** * Minimal Event interface implementation * * Original implementation by Sven Fuchs: https://gist.github.com/995028 * Modifications and tests by Christian Johansen. * * @author Sven Fuchs (svenfuchs@artweb-design.de) * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2011 Sven Fuchs, Christian Johansen */ - -if (typeof sinon == "undefined") { +if (typeof sinon === "undefined") { this.sinon = {}; } (function () { + var push = [].push; function makeApi(sinon) { sinon.Event = function Event(type, bubbles, cancelable, target) { this.initEvent(type, bubbles, cancelable, target); }; sinon.Event.prototype = { @@ -4035,91 +4219,91 @@ if (typeof sinon == "undefined") { this.initEvent(type, false, false, target); this.loaded = progressEventRaw.loaded || null; this.total = progressEventRaw.total || null; this.lengthComputable = !!progressEventRaw.total; }; sinon.ProgressEvent.prototype = new sinon.Event(); - sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; + sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; sinon.CustomEvent = function CustomEvent(type, customData, target) { this.initEvent(type, false, false, target); this.detail = customData.detail || null; }; sinon.CustomEvent.prototype = new sinon.Event(); - sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; + sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; sinon.EventTarget = { addEventListener: function addEventListener(event, listener) { this.eventListeners = this.eventListeners || {}; this.eventListeners[event] = this.eventListeners[event] || []; push.call(this.eventListeners[event], listener); }, removeEventListener: function removeEventListener(event, listener) { var listeners = this.eventListeners && this.eventListeners[event] || []; for (var i = 0, l = listeners.length; i < l; ++i) { - if (listeners[i] == listener) { + if (listeners[i] === listener) { return listeners.splice(i, 1); } } }, dispatchEvent: function dispatchEvent(event) { var type = event.type; var listeners = this.eventListeners && this.eventListeners[type] || []; for (var i = 0; i < listeners.length; i++) { - if (typeof listeners[i] == "function") { + if (typeof listeners[i] === "function") { listeners[i].call(this, event); } else { listeners[i].handleEvent(event); } } return !!event.defaultPrevented; } }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { var sinon = require("./core"); makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } }()); /** * @depend util/core.js */ /** * Logs errors * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + // cache a reference to setTimeout, so that our reference won't be stubbed out // when using fake timers and errors will still get logged // https://github.com/cjohansen/Sinon.JS/issues/381 var realSetTimeout = setTimeout; function makeApi(sinon) { function log() {} @@ -4132,106 +4316,112 @@ if (typeof sinon == "undefined") { if (err.stack) { sinon.log(err.stack); } logError.setTimeout(function () { err.message = msg + err.message; throw err; }, 0); - }; + } // wrap realSetTimeout with something we can stub in tests logError.setTimeout = function (func, timeout) { realSetTimeout(func, timeout); - } + }; var exports = {}; exports.log = sinon.log = log; exports.logError = sinon.logError = logError; return exports; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend core.js * @depend ../extend.js * @depend event.js * @depend ../log_error.js */ /** * Fake XDomainRequest object */ - -if (typeof sinon == "undefined") { +if (typeof sinon === "undefined") { this.sinon = {}; } // wrapper for global (function (global) { + var xdr = { XDomainRequest: global.XDomainRequest }; xdr.GlobalXDomainRequest = global.XDomainRequest; - xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined"; - xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; + xdr.supportsXDR = typeof xdr.GlobalXDomainRequest !== "undefined"; + xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; function makeApi(sinon) { sinon.xdr = xdr; function FakeXDomainRequest() { this.readyState = FakeXDomainRequest.UNSENT; this.requestBody = null; this.requestHeaders = {}; this.status = 0; this.timeout = null; - if (typeof FakeXDomainRequest.onCreate == "function") { + if (typeof FakeXDomainRequest.onCreate === "function") { FakeXDomainRequest.onCreate(this); } } - function verifyState(xdr) { - if (xdr.readyState !== FakeXDomainRequest.OPENED) { + function verifyState(x) { + if (x.readyState !== FakeXDomainRequest.OPENED) { throw new Error("INVALID_STATE_ERR"); } - if (xdr.sendFlag) { + if (x.sendFlag) { throw new Error("INVALID_STATE_ERR"); } } - function verifyRequestSent(xdr) { - if (xdr.readyState == FakeXDomainRequest.UNSENT) { + function verifyRequestSent(x) { + if (x.readyState === FakeXDomainRequest.UNSENT) { throw new Error("Request not sent"); } - if (xdr.readyState == FakeXDomainRequest.DONE) { + if (x.readyState === FakeXDomainRequest.DONE) { throw new Error("Request done"); } } function verifyResponseBodyType(body) { - if (typeof body != "string") { + if (typeof body !== "string") { var error = new Error("Attempted to respond to fake XDomainRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; throw error; } } sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { @@ -4256,28 +4446,28 @@ if (typeof sinon == "undefined") { case FakeXDomainRequest.LOADING: if (this.sendFlag) { //raise the progress event eventName = "onprogress"; } break; case FakeXDomainRequest.DONE: if (this.isTimeout) { - eventName = "ontimeout" + eventName = "ontimeout"; } else if (this.errorFlag || (this.status < 200 || this.status > 299)) { eventName = "onerror"; } else { - eventName = "onload" + eventName = "onload"; } break; } // raising event (if defined) if (eventName) { - if (typeof this[eventName] == "function") { + if (typeof this[eventName] === "function") { try { this[eventName](); } catch (e) { sinon.logError("Fake XHR " + eventName + " handler", e); } } } }, @@ -4289,17 +4479,17 @@ if (typeof sinon == "undefined") { this.requestBody = data; } this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; this.errorFlag = false; this.sendFlag = true; this.readyStateChange(FakeXDomainRequest.OPENED); - if (typeof this.onSend == "function") { + if (typeof this.onSend === "function") { this.onSend(this); } }, abort: function abort() { this.aborted = true; this.responseText = null; this.errorFlag = true; @@ -4326,17 +4516,17 @@ if (typeof sinon == "undefined") { this.readyStateChange(FakeXDomainRequest.DONE); }, respond: function respond(status, contentType, body) { // content-type ignored, since XDomainRequest does not carry this // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease // test integration across browsers - this.status = typeof status == "number" ? status : 200; + this.status = typeof status === "number" ? status : 200; this.setResponseBody(body || ""); }, simulatetimeout: function simulatetimeout() { this.status = 0; this.isTimeout = true; // Access to this should actually throw an error this.responseText = undefined; @@ -4367,34 +4557,34 @@ if (typeof sinon == "undefined") { global.XDomainRequest = sinon.FakeXDomainRequest; } return sinon.FakeXDomainRequest; }; sinon.FakeXDomainRequest = FakeXDomainRequest; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("../extend"); require("./event"); require("../log_error"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } })(typeof global !== "undefined" ? global : self); /** * @depend core.js * @depend ../extend.js * @depend event.js * @depend ../log_error.js @@ -4402,34 +4592,45 @@ if (typeof sinon == "undefined") { /** * Fake XMLHttpRequest object * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (global) { +(function (sinonGlobal, global) { + + function getWorkingXHR(globalScope) { + var supportsXHR = typeof globalScope.XMLHttpRequest !== "undefined"; + if (supportsXHR) { + return globalScope.XMLHttpRequest; + } + + var supportsActiveX = typeof globalScope.ActiveXObject !== "undefined"; + if (supportsActiveX) { + return function () { + return new globalScope.ActiveXObject("MSXML2.XMLHTTP.3.0"); + }; + } + + return false; + } var supportsProgress = typeof ProgressEvent !== "undefined"; var supportsCustomEvent = typeof CustomEvent !== "undefined"; var supportsFormData = typeof FormData !== "undefined"; var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest }; sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest; sinonXhr.GlobalActiveXObject = global.ActiveXObject; - sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject != "undefined"; - sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest != "undefined"; - sinonXhr.workingXHR = sinonXhr.supportsXHR ? sinonXhr.GlobalXMLHttpRequest : sinonXhr.supportsActiveX - ? function () { - return new sinonXhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") - } : false; + sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject !== "undefined"; + sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest !== "undefined"; + sinonXhr.workingXHR = getWorkingXHR(global); sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest()); - /*jsl:ignore*/ var unsafeHeaders = { "Accept-Charset": true, "Accept-Encoding": true, Connection: true, "Content-Length": true, Cookie: true, Cookie2: true, "Content-Transfer-Encoding": true, @@ -4440,101 +4641,106 @@ if (typeof sinon == "undefined") { Referer: true, TE: true, Trailer: true, "Transfer-Encoding": true, Upgrade: true, "User-Agent": true, Via: true }; - /*jsl:end*/ - - function FakeXMLHttpRequest() { - this.readyState = FakeXMLHttpRequest.UNSENT; - this.requestHeaders = {}; - this.requestBody = null; - this.status = 0; - this.statusText = ""; - this.upload = new UploadProgress(); - if (sinonXhr.supportsCORS) { - this.withCredentials = false; - } - - var xhr = this; - var events = ["loadstart", "load", "abort", "loadend"]; - - function addEventListener(eventName) { - xhr.addEventListener(eventName, function (event) { - var listener = xhr["on" + eventName]; - - if (listener && typeof listener == "function") { - listener.call(this, event); - } - }); - } - - for (var i = events.length - 1; i >= 0; i--) { - addEventListener(events[i]); - } - - if (typeof FakeXMLHttpRequest.onCreate == "function") { - FakeXMLHttpRequest.onCreate(this); - } - } // An upload object is created for each // FakeXMLHttpRequest and allows upload // events to be simulated using uploadProgress // and uploadError. function UploadProgress() { this.eventListeners = { progress: [], load: [], abort: [], error: [] - } + }; } UploadProgress.prototype.addEventListener = function addEventListener(event, listener) { this.eventListeners[event].push(listener); }; UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) { var listeners = this.eventListeners[event] || []; for (var i = 0, l = listeners.length; i < l; ++i) { - if (listeners[i] == listener) { + if (listeners[i] === listener) { return listeners.splice(i, 1); } } }; UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) { var listeners = this.eventListeners[event.type] || []; for (var i = 0, listener; (listener = listeners[i]) != null; i++) { listener(event); } }; + // Note that for FakeXMLHttpRequest to work pre ES5 + // we lose some of the alignment with the spec. + // To ensure as close a match as possible, + // set responseType before calling open, send or respond; + function FakeXMLHttpRequest() { + this.readyState = FakeXMLHttpRequest.UNSENT; + this.requestHeaders = {}; + this.requestBody = null; + this.status = 0; + this.statusText = ""; + this.upload = new UploadProgress(); + this.responseType = ""; + this.response = ""; + if (sinonXhr.supportsCORS) { + this.withCredentials = false; + } + + var xhr = this; + var events = ["loadstart", "load", "abort", "loadend"]; + + function addEventListener(eventName) { + xhr.addEventListener(eventName, function (event) { + var listener = xhr["on" + eventName]; + + if (listener && typeof listener === "function") { + listener.call(this, event); + } + }); + } + + for (var i = events.length - 1; i >= 0; i--) { + addEventListener(events[i]); + } + + if (typeof FakeXMLHttpRequest.onCreate === "function") { + FakeXMLHttpRequest.onCreate(this); + } + } + function verifyState(xhr) { if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { throw new Error("INVALID_STATE_ERR"); } if (xhr.sendFlag) { throw new Error("INVALID_STATE_ERR"); } } function getHeader(headers, header) { header = header.toLowerCase(); for (var h in headers) { - if (h.toLowerCase() == header) { + if (h.toLowerCase() === header) { return h; } } return null; } // filtering to enable a white-list version of Sinon FakeXhr, @@ -4565,21 +4771,22 @@ if (typeof sinon == "undefined") { case 3: return obj[method](args[0], args[1], args[2]); case 4: return obj[method](args[0], args[1], args[2], args[3]); case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]); } }; FakeXMLHttpRequest.filters = []; FakeXMLHttpRequest.addFilter = function addFilter(fn) { - this.filters.push(fn) + this.filters.push(fn); }; var IE6Re = /MSIE 6/; FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) { - var xhr = new sinonXhr.workingXHR(); + var xhr = new sinonXhr.workingXHR(); // eslint-disable-line new-cap + each([ "open", "setRequestHeader", "send", "abort", "getResponseHeader", "getAllResponseHeaders", "addEventListener", @@ -4589,17 +4796,17 @@ if (typeof sinon == "undefined") { fakeXhr[method] = function () { return apply(xhr, method, arguments); }; }); var copyAttrs = function (args) { each(args, function (attr) { try { - fakeXhr[attr] = xhr[attr] + fakeXhr[attr] = xhr[attr]; } catch (e) { if (!IE6Re.test(navigator.userAgent)) { throw e; } } }); }; @@ -4617,64 +4824,67 @@ if (typeof sinon == "undefined") { if (fakeXhr.onreadystatechange) { fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); } }; if (xhr.addEventListener) { for (var event in fakeXhr.eventListeners) { if (fakeXhr.eventListeners.hasOwnProperty(event)) { + + /*eslint-disable no-loop-func*/ each(fakeXhr.eventListeners[event], function (handler) { xhr.addEventListener(event, handler); }); + /*eslint-enable no-loop-func*/ } } xhr.addEventListener("readystatechange", stateChange); } else { xhr.onreadystatechange = stateChange; } apply(xhr, "open", xhrArgs); }; FakeXMLHttpRequest.useFilters = false; function verifyRequestOpened(xhr) { - if (xhr.readyState != FakeXMLHttpRequest.OPENED) { + if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { throw new Error("INVALID_STATE_ERR - " + xhr.readyState); } } function verifyRequestSent(xhr) { - if (xhr.readyState == FakeXMLHttpRequest.DONE) { + if (xhr.readyState === FakeXMLHttpRequest.DONE) { throw new Error("Request done"); } } function verifyHeadersReceived(xhr) { - if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { + if (xhr.async && xhr.readyState !== FakeXMLHttpRequest.HEADERS_RECEIVED) { throw new Error("No headers received"); } } function verifyResponseBodyType(body) { - if (typeof body != "string") { + if (typeof body !== "string") { var error = new Error("Attempted to respond to fake XMLHttpRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; throw error; } } FakeXMLHttpRequest.parseXML = function parseXML(text) { var xmlDoc; - if (typeof DOMParser != "undefined") { + if (typeof DOMParser !== "undefined") { var parser = new DOMParser(); xmlDoc = parser.parseFromString(text, "text/xml"); } else { - xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = "false"; xmlDoc.loadXML(text); } return xmlDoc; }; FakeXMLHttpRequest.statusCodes = { @@ -4726,42 +4936,45 @@ if (typeof sinon == "undefined") { sinon.xhr = sinonXhr; sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { async: true, open: function open(method, url, async, username, password) { this.method = method; this.url = url; - this.async = typeof async == "boolean" ? async : true; + this.async = typeof async === "boolean" ? async : true; this.username = username; this.password = password; this.responseText = null; + this.response = this.responseType === "json" ? null : ""; this.responseXML = null; this.requestHeaders = {}; this.sendFlag = false; if (FakeXMLHttpRequest.useFilters === true) { var xhrArgs = arguments; var defake = some(FakeXMLHttpRequest.filters, function (filter) { - return filter.apply(this, xhrArgs) + return filter.apply(this, xhrArgs); }); if (defake) { return FakeXMLHttpRequest.defake(this, arguments); } } this.readyStateChange(FakeXMLHttpRequest.OPENED); }, readyStateChange: function readyStateChange(state) { this.readyState = state; - if (typeof this.onreadystatechange == "function") { + var readyStateChangeEvent = new sinon.Event("readystatechange", false, false, this); + + if (typeof this.onreadystatechange === "function") { try { - this.onreadystatechange(); + this.onreadystatechange(readyStateChangeEvent); } catch (e) { sinon.logError("Fake XHR onreadystatechange handler", e); } } switch (this.readyState) { case FakeXMLHttpRequest.DONE: if (supportsProgress) { @@ -4769,17 +4982,17 @@ if (typeof sinon == "undefined") { this.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100})); } this.upload.dispatchEvent(new sinon.Event("load", false, false, this)); this.dispatchEvent(new sinon.Event("load", false, false, this)); this.dispatchEvent(new sinon.Event("loadend", false, false, this)); break; } - this.dispatchEvent(new sinon.Event("readystatechange")); + this.dispatchEvent(readyStateChangeEvent); }, setRequestHeader: function setRequestHeader(header, value) { verifyState(this); if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { throw new Error("Refused to set unsafe header \"" + header + "\""); } @@ -4822,28 +5035,30 @@ if (typeof sinon == "undefined") { this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; } this.requestBody = data; } this.errorFlag = false; this.sendFlag = this.async; + this.response = this.responseType === "json" ? null : ""; this.readyStateChange(FakeXMLHttpRequest.OPENED); - if (typeof this.onSend == "function") { + if (typeof this.onSend === "function") { this.onSend(this); } this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); }, abort: function abort() { this.aborted = true; this.responseText = null; + this.response = this.responseType === "json" ? null : ""; this.errorFlag = true; this.requestHeaders = {}; this.responseHeaders = {}; if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) { this.readyStateChange(FakeXMLHttpRequest.DONE); this.sendFlag = false; } @@ -4914,21 +5129,22 @@ if (typeof sinon == "undefined") { (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { try { this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); } catch (e) { // Unable to parse XML - no biggie } } + this.response = this.responseType === "json" ? JSON.parse(this.responseText) : this.responseText; this.readyStateChange(FakeXMLHttpRequest.DONE); }, respond: function respond(status, headers, body) { - this.status = typeof status == "number" ? status : 200; + this.status = typeof status === "number" ? status : 200; this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; this.setResponseHeaders(headers || {}); this.setResponseBody(body || ""); }, uploadProgress: function uploadProgress(progressEventRaw) { if (supportsProgress) { this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); @@ -4973,54 +5189,60 @@ if (typeof sinon == "undefined") { } }; if (sinonXhr.supportsXHR) { global.XMLHttpRequest = FakeXMLHttpRequest; } if (sinonXhr.supportsActiveX) { global.ActiveXObject = function ActiveXObject(objId) { - if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { + if (objId === "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { return new FakeXMLHttpRequest(); } return new sinonXhr.GlobalActiveXObject(objId); }; } return FakeXMLHttpRequest; }; sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("../extend"); require("./event"); require("../log_error"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (typeof sinon === "undefined") { return; - } else { - makeApi(sinon); - } - -})(typeof global !== "undefined" ? global : self); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon, // eslint-disable-line no-undef + typeof global !== "undefined" ? global : self +)); /** * @depend fake_xdomain_request.js * @depend fake_xml_http_request.js * @depend ../format.js * @depend ../log_error.js */ /** @@ -5029,95 +5251,101 @@ if (typeof sinon == "undefined") { * both synchronously and asynchronously. To respond synchronuously, canned * answers have to be provided upfront. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -if (typeof sinon == "undefined") { - var sinon = {}; -} - (function () { + var push = [].push; - function F() {} - - function create(proto) { - F.prototype = proto; - return new F(); - } function responseArray(handler) { var response = handler; - if (Object.prototype.toString.call(handler) != "[object Array]") { + if (Object.prototype.toString.call(handler) !== "[object Array]") { response = [200, {}, handler]; } - if (typeof response[2] != "string") { + if (typeof response[2] !== "string") { throw new TypeError("Fake server response body should be string, but was " + typeof response[2]); } return response; } var wloc = typeof window !== "undefined" ? window.location : {}; var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); function matchOne(response, reqMethod, reqUrl) { var rmeth = response.method; - var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); + var matchMethod = !rmeth || rmeth.toLowerCase() === reqMethod.toLowerCase(); var url = response.url; - var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); + var matchUrl = !url || url === reqUrl || (typeof url.test === "function" && url.test(reqUrl)); return matchMethod && matchUrl; } function match(response, request) { var requestUrl = request.url; if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { requestUrl = requestUrl.replace(rCurrLoc, ""); } if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { - if (typeof response.response == "function") { + if (typeof response.response === "function") { var ru = response.url; - var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []); + var args = [request].concat(ru && typeof ru.exec === "function" ? ru.exec(requestUrl).slice(1) : []); return response.response.apply(response, args); } return true; } return false; } function makeApi(sinon) { sinon.fakeServer = { - create: function () { - var server = create(this); + create: function (config) { + var server = sinon.create(this); + server.configure(config); if (!sinon.xhr.supportsCORS) { this.xhr = sinon.useFakeXDomainRequest(); } else { this.xhr = sinon.useFakeXMLHttpRequest(); } server.requests = []; this.xhr.onCreate = function (xhrObj) { server.addRequest(xhrObj); }; return server; }, - + configure: function (config) { + var whitelist = { + "autoRespond": true, + "autoRespondAfter": true, + "respondImmediately": true, + "fakeHTTPMethods": true + }; + var setting; + + config = config || {}; + for (setting in config) { + if (whitelist.hasOwnProperty(setting) && config.hasOwnProperty(setting)) { + this[setting] = config[setting]; + } + } + }, addRequest: function addRequest(xhrObj) { var server = this; push.call(this.requests, xhrObj); xhrObj.onSend = function () { server.handleRequest(this); if (server.respondImmediately) { @@ -5131,17 +5359,17 @@ if (typeof sinon == "undefined") { server.responding = true; } }; }, getHTTPMethod: function getHTTPMethod(request) { if (this.fakeHTTPMethods && /post/i.test(request.method)) { var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); - return !!matches ? matches[1] : request.method; + return matches ? matches[1] : request.method; } return request.method; }, handleRequest: function handleRequest(xhr) { if (xhr.async) { if (!this.queue) { @@ -5152,61 +5380,60 @@ if (typeof sinon == "undefined") { } else { this.processRequest(xhr); } }, log: function log(response, request) { var str; - str = "Request:\n" + sinon.format(request) + "\n\n"; + str = "Request:\n" + sinon.format(request) + "\n\n"; str += "Response:\n" + sinon.format(response) + "\n\n"; sinon.log(str); }, respondWith: function respondWith(method, url, body) { - if (arguments.length == 1 && typeof method != "function") { + if (arguments.length === 1 && typeof method !== "function") { this.response = responseArray(method); return; } if (!this.responses) { this.responses = []; } - if (arguments.length == 1) { + if (arguments.length === 1) { body = method; url = method = null; } - if (arguments.length == 2) { + if (arguments.length === 2) { body = url; url = method; method = null; } push.call(this.responses, { method: method, url: url, - response: typeof body == "function" ? body : responseArray(body) + response: typeof body === "function" ? body : responseArray(body) }); }, respond: function respond() { if (arguments.length > 0) { this.respondWith.apply(this, arguments); } var queue = this.queue || []; var requests = queue.splice(0, queue.length); - var request; - - while (request = requests.shift()) { - this.processRequest(request); + + for (var i = 0; i < requests.length; i++) { + this.processRequest(requests[i]); } }, processRequest: function processRequest(request) { try { if (request.aborted) { return; } @@ -5217,50 +5444,50 @@ if (typeof sinon == "undefined") { for (var l = this.responses.length, i = l - 1; i >= 0; i--) { if (match.call(this, this.responses[i], request)) { response = this.responses[i].response; break; } } } - if (request.readyState != 4) { + if (request.readyState !== 4) { this.log(response, request); request.respond(response[0], response[1], response[2]); } } catch (e) { sinon.logError("Fake server request processing", e); } }, restore: function restore() { return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); } }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("./fake_xdomain_request"); require("./fake_xml_http_request"); require("../format"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } }()); /** * @depend fake_server.js * @depend fake_timers.js */ /** @@ -5272,27 +5499,27 @@ if (typeof sinon == "undefined") { * in any environment where the ajax implementation depends on setInterval or * setTimeout. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - (function () { + function makeApi(sinon) { function Server() {} Server.prototype = sinon.fakeServer; sinon.fakeServerWithClock = new Server(); sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { if (xhr.async) { - if (typeof setTimeout.clock == "object") { + if (typeof setTimeout.clock === "object") { this.clock = setTimeout.clock; } else { this.clock = sinon.useFakeTimers(); this.resetClock = true; } if (!this.longestTimeout) { var clockSetTimeout = this.clock.setTimeout; @@ -5336,32 +5563,32 @@ if (typeof sinon == "undefined") { if (this.clock) { this.clock.restore(); } return sinon.fakeServer.restore.apply(this, arguments); }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { var sinon = require("./core"); require("./fake_server"); require("./fake_timers"); makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } }()); /** * @depend util/core.js * @depend extend.js * @depend collection.js * @depend util/fake_timers.js @@ -5371,18 +5598,18 @@ if (typeof sinon == "undefined") { * Manages fake collections as well as fake utilities such as Sinon's * timers and fake XHR implementation in one convenient object. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function () { +(function (sinonGlobal) { + function makeApi(sinon) { var push = [].push; function exposeValue(sandbox, config, key, value) { if (!value) { return; } @@ -5393,25 +5620,25 @@ if (typeof sinon == "undefined") { push.call(sandbox.args, value); } } function prepareSandboxFromConfig(config) { var sandbox = sinon.create(sinon.sandbox); if (config.useFakeServer) { - if (typeof config.useFakeServer == "object") { + if (typeof config.useFakeServer === "object") { sandbox.serverPrototype = config.useFakeServer; } sandbox.useFakeServer(); } if (config.useFakeTimers) { - if (typeof config.useFakeTimers == "object") { + if (typeof config.useFakeTimers === "object") { sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); } else { sandbox.useFakeTimers(); } } return sandbox; } @@ -5471,22 +5698,24 @@ if (typeof sinon == "undefined") { if (!config) { return sinon.create(sinon.sandbox); } var sandbox = prepareSandboxFromConfig(config); sandbox.args = sandbox.args || []; sandbox.injectedKeys = []; sandbox.injectInto = config.injectInto; - var prop, value, exposed = sandbox.inject({}); + var prop, + value; + var exposed = sandbox.inject({}); if (config.properties) { for (var i = 0, l = config.properties.length; i < l; i++) { prop = config.properties[i]; - value = exposed[prop] || prop == "sandbox" && sandbox; + value = exposed[prop] || prop === "sandbox" && sandbox; exposeValue(sandbox, config, prop, value); } } else { exposeValue(sandbox, config, "sandbox", value); } return sandbox; }, @@ -5494,103 +5723,109 @@ if (typeof sinon == "undefined") { match: sinon.match }); sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; return sinon.sandbox; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./extend"); require("./util/fake_server_with_clock"); require("./util/fake_timers"); require("./collection"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}()); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js * @depend sandbox.js */ /** * Test function, sandboxes fakes * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { var slice = Array.prototype.slice; function test(callback) { var type = typeof callback; - if (type != "function") { + if (type !== "function") { throw new TypeError("sinon.test needs to wrap a test function, got " + type); } function sinonSandboxedTest() { var config = sinon.getConfig(sinon.config); config.injectInto = config.injectIntoThis && this || config.injectInto; var sandbox = sinon.sandbox.create(config); var args = slice.call(arguments); var oldDone = args.length && args[args.length - 1]; var exception, result; - if (typeof oldDone == "function") { - args[args.length - 1] = function sinonDone(result) { - if (result) { + if (typeof oldDone === "function") { + args[args.length - 1] = function sinonDone(res) { + if (res) { sandbox.restore(); throw exception; } else { sandbox.verifyAndRestore(); } - oldDone(result); + oldDone(res); }; } try { result = callback.apply(this, args.concat(sandbox.args)); } catch (e) { exception = e; } - if (typeof oldDone != "function") { + if (typeof oldDone !== "function") { if (typeof exception !== "undefined") { sandbox.restore(); throw exception; } else { sandbox.verifyAndRestore(); } } return result; } if (callback.length) { - return function sinonAsyncSandboxedTest(callback) { + return function sinonAsyncSandboxedTest(done) { // eslint-disable-line no-unused-vars return sinonSandboxedTest.apply(this, arguments); }; } return sinonSandboxedTest; } test.config = { @@ -5600,48 +5835,48 @@ if (typeof sinon == "undefined") { useFakeTimers: true, useFakeServer: true }; sinon.test = test; return test; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { - var sinon = require("./util/core"); + var core = require("./util/core"); require("./sandbox"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); - } else if (sinon) { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } else if (sinonGlobal) { + makeApi(sinonGlobal); + } +}(typeof sinon === "object" && sinon || null)); // eslint-disable-line no-undef /** * @depend util/core.js * @depend test.js */ /** * Test case, sandboxes all test functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function createTest(property, setUp, tearDown) { return function () { if (setUp) { setUp.apply(this, arguments); } var exception, result; @@ -5660,31 +5895,34 @@ if (typeof sinon == "undefined") { } return result; }; } function makeApi(sinon) { function testCase(tests, prefix) { - if (!tests || typeof tests != "object") { + if (!tests || typeof tests !== "object") { throw new TypeError("sinon.testCase needs an object with test functions"); } prefix = prefix || "test"; var rPrefix = new RegExp("^" + prefix); - var methods = {}, testName, property, method; + var methods = {}; var setUp = tests.setUp; var tearDown = tests.tearDown; + var testName, + property, + method; for (testName in tests) { if (tests.hasOwnProperty(testName) && !/^(setUp|tearDown)$/.test(testName)) { property = tests[testName]; - if (typeof property == "function" && rPrefix.test(testName)) { + if (typeof property === "function" && rPrefix.test(testName)) { method = property; if (setUp || tearDown) { method = createTest(property, setUp, tearDown); } methods[testName] = sinon.test(method); } else { @@ -5695,52 +5933,58 @@ if (typeof sinon == "undefined") { return methods; } sinon.testCase = testCase; return testCase; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { - var sinon = require("./util/core"); + var core = require("./util/core"); require("./test"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } -}(typeof sinon == "object" && sinon || null)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend times_in_words.js * @depend util/core.js * @depend match.js * @depend format.js */ /** * Assertions matching the test spy retrieval interface. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon, global) { +(function (sinonGlobal, global) { + var slice = Array.prototype.slice; function makeApi(sinon) { var assert; function verifyIsStub() { var method; @@ -5749,50 +5993,50 @@ if (typeof sinon == "undefined") { if (!method) { assert.fail("fake is not a spy"); } if (method.proxy && method.proxy.isSinonProxy) { verifyIsStub(method.proxy); } else { - if (typeof method != "function") { + if (typeof method !== "function") { assert.fail(method + " is not a function"); } - if (typeof method.getCall != "function") { + if (typeof method.getCall !== "function") { assert.fail(method + " is not stubbed"); } } } } function failAssertion(object, msg) { object = object || global; var failMethod = object.fail || assert.fail; failMethod.call(object, msg); } function mirrorPropAsAssertion(name, method, message) { - if (arguments.length == 2) { + if (arguments.length === 2) { message = method; method = name; } assert[name] = function (fake) { verifyIsStub(fake); var args = slice.call(arguments, 1); var failed = false; - if (typeof method == "function") { + if (typeof method === "function") { failed = !method(fake); } else { - failed = typeof fake[method] == "function" ? + failed = typeof fake[method] === "function" ? !fake[method].apply(fake, args) : !fake[method]; } if (failed) { failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args))); } else { assert.pass(name); } @@ -5809,21 +6053,22 @@ if (typeof sinon == "undefined") { fail: function fail(message) { var error = new Error(message); error.name = this.failException || assert.failException; throw error; }, - pass: function pass(assertion) {}, + pass: function pass() {}, callOrder: function assertCallOrder() { verifyIsStub.apply(null, arguments); - var expected = "", actual = ""; + var expected = ""; + var actual = ""; if (!sinon.calledInOrder(arguments)) { try { expected = [].join.call(arguments, ", "); var calls = slice.call(arguments); var i = calls.length; while (i) { if (!calls[--i].called) { @@ -5840,67 +6085,71 @@ if (typeof sinon == "undefined") { } else { assert.pass("callOrder"); } }, callCount: function assertCallCount(method, count) { verifyIsStub(method); - if (method.callCount != count) { + if (method.callCount !== count) { var msg = "expected %n to be called " + sinon.timesInWords(count) + " but was called %c%C"; failAssertion(this, method.printf(msg)); } else { assert.pass("callCount"); } }, expose: function expose(target, options) { if (!target) { throw new TypeError("target is null or undefined"); } var o = options || {}; - var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; - var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; + var prefix = typeof o.prefix === "undefined" && "assert" || o.prefix; + var includeFail = typeof o.includeFail === "undefined" || !!o.includeFail; for (var method in this) { - if (method != "expose" && (includeFail || !/^(fail)/.test(method))) { + if (method !== "expose" && (includeFail || !/^(fail)/.test(method))) { target[exposedName(prefix, method)] = this[method]; } } return target; }, match: function match(actual, expectation) { var matcher = sinon.match(expectation); if (matcher.test(actual)) { assert.pass("match"); } else { var formatted = [ "expected value to match", " expected = " + sinon.format(expectation), " actual = " + sinon.format(actual) - ] + ]; + failAssertion(this, formatted.join("\n")); } } }; mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, "expected %n to not have been called but was called %c%C"); mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); - mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); + mirrorPropAsAssertion( + "alwaysCalledOn", + "expected %n to always be called with %1 as this but was called with %t" + ); mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); @@ -5908,32 +6157,38 @@ if (typeof sinon == "undefined") { mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); mirrorPropAsAssertion("threw", "%n did not throw exception%C"); mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); sinon.assert = assert; return assert; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./match"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); - } - -}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global)); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon, // eslint-disable-line no-undef + typeof global !== "undefined" ? global : self +)); return sinon; }));
--- a/browser/components/loop/test/standalone/index.html +++ b/browser/components/loop/test/standalone/index.html @@ -33,17 +33,17 @@ <script src="../../content/shared/libs/react-0.12.2.js"></script> <script src="../../content/shared/libs/jquery-2.1.4.js"></script> <script src="../../content/shared/libs/lodash-3.9.3.js"></script> <script src="../../content/shared/libs/backbone-1.2.1.js"></script> <script src="../../standalone/content/libs/l10n-gaia-02ca67948fe8.js"></script> <!-- test dependencies --> <script src="../shared/vendor/mocha-2.2.5.js"></script> <script src="../shared/vendor/chai-3.0.0.js"></script> - <script src="../shared/vendor/sinon-1.15.0.js"></script> + <script src="../shared/vendor/sinon-1.16.1.js"></script> <script src="../shared/sdk_mock.js"></script> <script> chai.config.includeStack = true; mocha.setup({ui: 'bdd', timeout: 10000}); </script> <!-- App scripts --> <script src="../../content/shared/js/utils.js"></script> <script src="../../content/shared/js/models.js"></script>
--- a/browser/components/loop/test/xpcshell/head.js +++ b/browser/components/loop/test/xpcshell/head.js @@ -66,17 +66,17 @@ function setupFakeFxAUserProfile() { MozLoopServiceInternal.fxAOAuthProfile = { email: "fake@invalid.com" }; do_register_cleanup(function() { MozLoopServiceInternal.fxAOAuthTokenData = null; MozLoopServiceInternal.fxAOAuthProfile = null; }); } -function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) { +function waitForCondition(aConditionFn, aMaxTries = 50, aCheckInterval = 100) { function tryAgain() { function tryNow() { tries++; if (aConditionFn()) { deferred.resolve(); } else if (tries < aMaxTries) { tryAgain(); } else {
--- a/browser/components/loop/test/xpcshell/test_looppush_initialize.js +++ b/browser/components/loop/test/xpcshell/test_looppush_initialize.js @@ -156,38 +156,37 @@ add_test(function test_ping_websocket() ); }); add_test(function test_retry_pushurl() { MozLoopPushHandler.shutdown(); loopServer.registerPathHandler("/push-server-config", (request, response) => { // The PushHandler should retry the request for the push-server-config for // each of these cases without throwing an error. - let n = 0; switch (++pushServerRequestCount) { - case ++n: + case 1: // Non-200 response response.setStatusLine(null, 500, "Retry"); response.processAsync(); response.finish(); break; - case ++n: + case 2: // missing parameter response.setStatusLine(null, 200, "OK"); response.write(JSON.stringify({pushServerURI: null})); response.processAsync(); response.finish(); break; - case ++n: + case 3: // json parse error response.setStatusLine(null, 200, "OK"); response.processAsync(); response.finish(); break; - case ++n: + case 4: response.setStatusLine(null, 200, "OK"); response.write(JSON.stringify({pushServerURI: kServerPushUrl})); response.processAsync(); response.finish(); run_next_test(); break; }
--- a/browser/components/migration/IEProfileMigrator.js +++ b/browser/components/migration/IEProfileMigrator.js @@ -287,17 +287,17 @@ Cookies.prototype = { aCallback(success); }).apply(this); cookiesGenerator.next(); }, _readCookieFile: function C__readCookieFile(aFile, aCallback) { let fileReader = Cc["@mozilla.org/files/filereader;1"]. createInstance(Ci.nsIDOMFileReader); - fileReader.addEventListener("loadend", (function onLoadEnd() { + let onLoadEnd = () => { fileReader.removeEventListener("loadend", onLoadEnd, false); if (fileReader.readyState != fileReader.DONE) { Cu.reportError("Could not read cookie contents: " + fileReader.error); aCallback(false); return; } @@ -305,17 +305,18 @@ Cookies.prototype = { try { this._parseCookieBuffer(fileReader.result); } catch (ex) { Components.utils.reportError("Unable to migrate cookie: " + ex); success = false; } finally { aCallback(success); } - }).bind(this), false); + }; + fileReader.addEventListener("loadend", onLoadEnd, false); fileReader.readAsText(new File(aFile)); }, /** * Parses a cookie file buffer and returns an array of the contained cookies. * * The cookie file format is a newline-separated-values with a "*" used as * delimeter between multiple records.
--- a/browser/components/places/tests/browser/browser.ini +++ b/browser/components/places/tests/browser/browser.ini @@ -15,17 +15,19 @@ support-files = [browser_0_library_left_pane_migration.js] [browser_410196_paste_into_tags.js] [browser_416459_cut.js] [browser_423515.js] [browser_425884.js] [browser_435851_copy_query.js] [browser_475045.js] [browser_555547.js] +[browser_bookmarkProperties_addFolderDefaultButton.js] [browser_bookmarkProperties_addKeywordForThisSearch.js] +[browser_bookmarkProperties_readOnlyRoot.js] [browser_bookmarklet_windowOpen.js] support-files = pageopeningwindow.html [browser_bookmarksProperties.js] [browser_drag_bookmarks_on_toolbar.js] skip-if = e10s # Bug ?????? - test fails - "Number of dragged items should be the same. - Got 0, expected 1" [browser_forgetthissite_single.js] [browser_history_sidebar_search.js]
new file mode 100644 --- /dev/null +++ b/browser/components/places/tests/browser/browser_bookmarkProperties_addFolderDefaultButton.js @@ -0,0 +1,37 @@ +"use strict" + +add_task(function* () { + info("Bug 475529 - Add is the default button for the new folder dialog."); + + yield withSidebarTree("bookmarks", function* (tree) { + let itemId = PlacesUIUtils.leftPaneQueries["UnfiledBookmarks"]; + tree.selectItems([itemId]); + ok(tree.controller.isCommandEnabled("placesCmd_new:folder"), + "'placesCmd_new:folder' on current selected node is enabled"); + + yield withBookmarksDialog( + false, + function openDialog() { + tree.controller.doCommand("placesCmd_new:folder"); + }, + function* test(dialogWin) { + let promiseTitleChangeNotification = promiseBookmarksNotification( + "onItemChanged", (itemId, prop, isAnno, val) => prop == "title" && val =="n"); + + fillBookmarkTextField("editBMPanel_namePicker", "n", dialogWin, false); + + // Confirm and close the dialog. + EventUtils.synthesizeKey("VK_RETURN", {}, dialogWin); + yield promiseTitleChangeNotification; + + let bookmark = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX + }); + + is(bookmark.title, "n", "folder name has been edited"); + yield PlacesUtils.bookmarks.remove(bookmark); + } + ); + }); +});
--- a/browser/components/places/tests/browser/browser_bookmarkProperties_addKeywordForThisSearch.js +++ b/browser/components/places/tests/browser/browser_bookmarkProperties_addKeywordForThisSearch.js @@ -5,17 +5,17 @@ const TEST_URL = "http://mochi.test:8888 add_task(function* () { yield BrowserTestUtils.withNewTab({ gBrowser, url: TEST_URL, }, function* (browser) { // We must wait for the context menu code to build metadata. yield openContextMenuForContentSelector(browser, 'form > input[name="search"]'); - yield withBookmarksDialog(AddKeywordForSearchField, function* (dialogWin) { + yield withBookmarksDialog(true, AddKeywordForSearchField, function* (dialogWin) { let acceptBtn = dialogWin.document.documentElement.getButton("accept"); ok(acceptBtn.disabled, "Accept button is disabled"); let promiseKeywordNotification = promiseBookmarksNotification( "onItemChanged", (itemId, prop, isAnno, val) => prop == "keyword" && val =="kw"); fillBookmarkTextField("editBMPanel_keywordField", "kw", dialogWin);
new file mode 100644 --- /dev/null +++ b/browser/components/places/tests/browser/browser_bookmarkProperties_readOnlyRoot.js @@ -0,0 +1,42 @@ +"use strict" + +add_task(function* () { + info("Bug 479348 - Properties on a root should be read-only."); + + yield withSidebarTree("bookmarks", function* (tree) { + let itemId = PlacesUIUtils.leftPaneQueries["UnfiledBookmarks"]; + tree.selectItems([itemId]); + ok(tree.controller.isCommandEnabled("placesCmd_show:info"), + "'placesCmd_show:info' on current selected node is enabled"); + + yield withBookmarksDialog( + true, + function openDialog() { + tree.controller.doCommand("placesCmd_show:info"); + }, + function* test(dialogWin) { + // Check that the dialog is read-only. + ok(dialogWin.gEditItemOverlay.readOnly, "Dialog is read-only"); + // Check that accept button is disabled + let acceptButton = dialogWin.document.documentElement.getButton("accept"); + ok(acceptButton.disabled, "Accept button is disabled"); + + // Check that name picker is read only + let namepicker = dialogWin.document.getElementById("editBMPanel_namePicker"); + ok(namepicker.readOnly, "Name field is read-only"); + is(namepicker.value, + PlacesUtils.bookmarks.getItemTitle(PlacesUtils.unfiledBookmarksFolderId), + "Node title is correct"); + // Blur the field and ensure root's name has not been changed. + namepicker.blur(); + is(namepicker.value, + PlacesUtils.bookmarks.getItemTitle(PlacesUtils.unfiledBookmarksFolderId), + "Root title is correct"); + // Check the shortcut's title. + let bookmark = yield PlacesUtils.bookmarks.fetch(tree.selectedNode.bookmarkGuid); + is(bookmark.title, null, + "Shortcut title is null"); + } + ); + }); +});
--- a/browser/components/places/tests/browser/browser_bookmarksProperties.js +++ b/browser/components/places/tests/browser/browser_bookmarksProperties.js @@ -48,110 +48,16 @@ function add_bookmark(aURI) { return bId; } // Each test is an obj w/ a desc property and run method. var gTests = []; var gCurrentTest = null; //------------------------------------------------------------------------------ -// TEST SKELETON: use this template to add new tests. -/* -gTests.push({ - desc: "Bug Description", - sidebar: SIDEBAR_BOOKMARKS_ID, // See SIDEBAR_ constants above. - action: ACTION_EDIT, // See ACTION_ constants above. - itemType: null, // See TYPE_ constants above, required for ACTION_ADD, only for Bookmarks sidebar. - historyView: SIDEBAR_HISTORY_BYLASTVISITED_VIEW, // See constants above, only for History sidebar. - window: null, // Will contain handle of dialog window - - setup: function(aCallback) { - // Setup everything needed for this test, runs before everything else. - aCallback(); - }, - - selectNode: function(tree) { - // Select the node to edit or to add to, runs when sidebar tree is visible. - }, - - run: function() { - // Actual test, runs when dialog is open. - }, - - finish: function() { - // Close window, toggle sidebar and goto next test. - this.window.document.documentElement.cancelDialog(); - SidebarUI.hide(); - runNextTest(); - }, - - cleanup: function() { - // Undo everything added during setup, runs after dialog has been closed. - } -}); -*/ - -//------------------------------------------------------------------------------ -// Bug 479348 - Properties on a root should be read-only - -gTests.push({ - desc: "Bug 479348 - Properties on a root should be read-only", - sidebar: SIDEBAR_BOOKMARKS_ID, - action: ACTION_EDIT, - itemType: null, - window: null, - - setup: function(aCallback) { - // Nothing to do. - aCallback(); - }, - - selectNode: function(tree) { - // Select Unfiled Bookmarks root. - var itemId = PlacesUIUtils.leftPaneQueries["UnfiledBookmarks"]; - tree.selectItems([itemId]); - this.selectedNode = tree.selectedNode; - }, - - run: function() { - // Check that the dialog is read-only. - ok(this.window.gEditItemOverlay.readOnly, "Dialog is read-only"); - // Check that accept button is disabled - var acceptButton = this.window.document.documentElement.getButton("accept"); - ok(acceptButton.disabled, "Accept button is disabled"); - - // Check that name picker is read only - var namepicker = this.window.document.getElementById("editBMPanel_namePicker"); - ok(namepicker.readOnly, "Name field is disabled"); - is(namepicker.value, - PlacesUtils.bookmarks.getItemTitle(PlacesUtils.unfiledBookmarksFolderId), - "Node title is correct"); - // Blur the field and ensure root's name has not been changed. - this.window.gEditItemOverlay._namePicker.blur(); - is(namepicker.value, - PlacesUtils.bookmarks.getItemTitle(PlacesUtils.unfiledBookmarksFolderId), - "Root title is correct"); - // Check the shortcut's title. - is(PlacesUtils.bookmarks.getItemTitle(this.selectedNode.itemId), null, - "Shortcut title is null"); - this.finish(); - }, - - finish: function() { - this.window.document.documentElement.cancelDialog(); - SidebarUI.hide(); - runNextTest(); - }, - - cleanup: function() { - // Nothing to do. - } -}); - -//------------------------------------------------------------------------------ // Bug 462662 - Pressing Enter to select tag from autocomplete closes bookmarks properties dialog gTests.push({ desc: "Bug 462662 - Pressing Enter to select tag from autocomplete closes bookmarks properties dialog", sidebar: SIDEBAR_BOOKMARKS_ID, action: ACTION_EDIT, itemType: null, window: null, _itemId: null, @@ -242,75 +148,16 @@ gTests.push({ is(tags[0], "testTag", "Tag on node has not changed"); // Cleanup. PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["testTag"]); PlacesUtils.bookmarks.removeItem(this._itemId); } }); - -//------------------------------------------------------------------------------ -// Bug 475529 - Add button in new folder dialog not default anymore -gTests.push({ - desc: "Bug 475529 - Add button in new folder dialog not default anymore", - sidebar: SIDEBAR_BOOKMARKS_ID, - action: ACTION_ADD, - itemType: TYPE_FOLDER, - window: null, - _itemId: null, - - setup: function(aCallback) { - // Nothing to do. - aCallback(); - }, - - selectNode: function(tree) { - // Select Unfiled Bookmarks root. - var itemId = PlacesUIUtils.leftPaneQueries["UnfiledBookmarks"]; - tree.selectItems([itemId]); - this.selectedNode = tree.selectedNode; - }, - - run: function() { - this._itemId = this.window.gEditItemOverlay._paneInfo.itemId; - // Change folder name - var namePicker = this.window.document.getElementById("editBMPanel_namePicker"); - var self = this; - - this.window.addEventListener("unload", function(event) { - self.window.removeEventListener("unload", arguments.callee, false); - executeSoon(function () { - self.finish(); - }); - }, false); - - info("About to focus the namePicker field"); - namePicker.focus(); - namePicker.select(); - EventUtils.synthesizeKey("n", {}, this.window); - EventUtils.synthesizeKey("VK_RETURN", {}, this.window); - }, - - finish: function() { - // Window is already closed. - SidebarUI.hide(); - runNextTest(); - }, - - cleanup: function() { - // Check that folder name has been changed. - is(PlacesUtils.bookmarks.getItemTitle(this._itemId), "n", - "Folder name has been edited"); - - // Cleanup. - PlacesUtils.bookmarks.removeItem(this._itemId); - } -}); - //------------------------------------------------------------------------------ // Bug 476020 - Pressing Esc while having the tag autocomplete open closes the bookmarks panel gTests.push({ desc: "Bug 476020 - Pressing Esc while having the tag autocomplete open closes the bookmarks panel", sidebar: SIDEBAR_BOOKMARKS_ID, action: ACTION_EDIT, itemType: null,
--- a/browser/components/places/tests/browser/head.js +++ b/browser/components/places/tests/browser/head.js @@ -1,12 +1,8 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - - XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", "resource://testing-common/PlacesTestUtils.jsm"); // We need to cache this before test runs... @@ -280,37 +276,42 @@ function isToolbarVisible(aToolbar) { let hidingValue = aToolbar.getAttribute(hidingAttribute).toLowerCase(); // Check for both collapsed="true" and collapsed="collapsed" return hidingValue !== "true" && hidingValue !== hidingAttribute; } /** * Executes a task after opening the bookmarks dialog, then cancels the dialog. * + * @param autoCancel + * whether to automatically cancel the dialog at the end of the task * @param openFn * generator function causing the dialog to open * @param task * the task to execute once the dialog is open */ -let withBookmarksDialog = Task.async(function* (openFn, taskFn) { +let withBookmarksDialog = Task.async(function* (autoCancel, openFn, taskFn) { + let closed = false; let dialogPromise = new Promise(resolve => { Services.ww.registerNotification(function winObserver(subject, topic, data) { - if (topic != "domwindowopened") - return; - let win = subject.QueryInterface(Ci.nsIDOMWindow); - win.addEventListener("load", function load() { - win.removeEventListener("load", load); - ok(win.location.href.startsWith("chrome://browser/content/places/bookmarkProperties"), - "The bookmark properties dialog is ready"); + if (topic == "domwindowopened") { + let win = subject.QueryInterface(Ci.nsIDOMWindow); + win.addEventListener("load", function load() { + win.removeEventListener("load", load); + ok(win.location.href.startsWith("chrome://browser/content/places/bookmarkProperties"), + "The bookmark properties dialog is ready"); + // This is needed for the overlay. + waitForFocus(() => { + resolve(win); + }, win); + }); + } else if (topic == "domwindowclosed") { Services.ww.unregisterNotification(winObserver); - // This is needed for the overlay. - waitForFocus(() => { - resolve(win); - }, win); - }); + closed = true; + } }); }); info("withBookmarksDialog: opening the dialog"); // The dialog might be modal and could block our events loop, so executeSoon. executeSoon(openFn); info("withBookmarksDialog: waiting for the dialog"); @@ -318,18 +319,23 @@ let withBookmarksDialog = Task.async(fun // Ensure overlay is loaded ok(dialogWin.gEditItemOverlay.initialized, "EditItemOverlay is initialized"); info("withBookmarksDialog: executing the task"); try { yield taskFn(dialogWin); } finally { - info("withBookmarksDialog: canceling the dialog"); - dialogWin.document.documentElement.cancelDialog(); + if (!closed) { + if (!autoCancel) { + ok(false, "The test should have closed the dialog!"); + } + info("withBookmarksDialog: canceling the dialog"); + dialogWin.document.documentElement.cancelDialog(); + } } }); /** * Opens the contextual menu on the element pointed by the given selector. * * @param selector * Valid selector syntax @@ -396,18 +402,58 @@ let waitForCondition = Task.async(functi * Fills a bookmarks dialog text field ensuring to cause expected edit events. * * @param id * id of the text field * @param text * text to fill in * @param win * dialog window + * @param [optional] blur + * whether to blur at the end. */ -function fillBookmarkTextField(id, text, win) { +function fillBookmarkTextField(id, text, win, blur = true) { let elt = win.document.getElementById(id); elt.focus(); elt.select(); for (let c of text.split("")) { EventUtils.synthesizeKey(c, {}, win); } - elt.blur(); + if (blur) + elt.blur(); } + +/** + * Executes a task after opening the bookmarks or history sidebar. Takes care + * of closing the sidebar once done. + * + * @param type + * either "bookmarks" or "history". + * @param taskFn + * The task to execute once the sidebar is ready. Will get the Places + * tree view as input. + */ +let withSidebarTree = Task.async(function* (type, taskFn) { + let sidebar = document.getElementById("sidebar"); + info("withSidebarTree: waiting sidebar load"); + let sidebarLoadedPromise = new Promise(resolve => { + sidebar.addEventListener("load", function load() { + sidebar.removeEventListener("load", load, true); + resolve(); + }, true); + }); + let sidebarId = type == "bookmarks" ? "viewBookmarksSidebar" + : "viewHistorySidebar"; + SidebarUI.show(sidebarId); + yield sidebarLoadedPromise; + + let treeId = type == "bookmarks" ? "bookmarks-view" + : "historyTree"; + let tree = sidebar.contentDocument.getElementById(treeId); + + // Need to executeSoon since the tree is initialized on sidebar load. + info("withSidebarTree: executing the task"); + try { + yield taskFn(tree); + } finally { + SidebarUI.hide(); + } +});
--- a/browser/components/preferences/in-content/sync.js +++ b/browser/components/preferences/in-content/sync.js @@ -560,34 +560,51 @@ let gSyncPane = { resetPass: function () { if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) gSyncUtils.resetPassword(); else gSyncUtils.resetPassphrase(); }, + _getEntryPoint: function () { + let params = new URLSearchParams(document.URL.split("#")[0].split("?")[1] || ""); + return params.get("entrypoint") || "preferences"; + }, + + _openAboutAccounts: function(action) { + let entryPoint = this._getEntryPoint(); + let params = new URLSearchParams(); + if (action) { + params.set("action", action); + } + params.set("entrypoint", entryPoint); + + this.openContentInBrowser("about:accounts?" + params, { + replaceQueryString: true + }); + + }, + /** * Invoke the Sync setup wizard. * * @param wizardType * Indicates type of wizard to launch: * null -- regular set up wizard * "pair" -- pair a device first * "reset" -- reset sync */ openSetup: function (wizardType) { let service = Components.classes["@mozilla.org/weave/service;1"] .getService(Components.interfaces.nsISupports) .wrappedJSObject; if (service.fxAccountsEnabled) { - this.openContentInBrowser("about:accounts?entrypoint=preferences", { - replaceQueryString: true - }); + this._openAboutAccounts(); } else { let win = Services.wm.getMostRecentWindow("Weave:AccountSetup"); if (win) win.focus(); else { window.openDialog("chrome://browser/content/sync/setup.xul", "weaveSetup", "centerscreen,chrome,resizable=no", wizardType); @@ -613,44 +630,38 @@ let gSyncPane = { }, openToS: function(aEvent) { aEvent.stopPropagation(); gSyncUtils.openToS(); }, signUp: function() { - this.openContentInBrowser("about:accounts?action=signup&entrypoint=preferences", { - replaceQueryString: true - }); + this._openAboutAccounts("signup"); }, signIn: function() { - this.openContentInBrowser("about:accounts?action=signin&entrypoint=preferences", { - replaceQueryString: true - }); + this._openAboutAccounts("signin"); }, reSignIn: function() { - this.openContentInBrowser("about:accounts?action=reauth&entrypoint=preferences", { - replaceQueryString: true - }); + this._openAboutAccounts("reauth"); }, openChangeProfileImage: function() { - fxAccounts.promiseAccountsChangeProfileURI("preferences", "avatar") + fxAccounts.promiseAccountsChangeProfileURI(this._getEntryPoint(), "avatar") .then(url => { this.openContentInBrowser(url, { replaceQueryString: true }); }); }, manageFirefoxAccount: function() { - fxAccounts.promiseAccountsManageURI("preferences") + fxAccounts.promiseAccountsManageURI(this._getEntryPoint()) .then(url => { this.openContentInBrowser(url, { replaceQueryString: true }); }); }, verifyFirefoxAccount: function() {
--- a/browser/components/search/content/search.xml +++ b/browser/components/search/content/search.xml @@ -1,13 +1,12 @@ <?xml version="1.0"?> -# -*- Mode: HTML -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <!DOCTYPE bindings [ <!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd" > %searchBarDTD; <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd"> %browserDTD; ]> @@ -487,23 +486,20 @@ if (aEvent.button == 2) return; where = whereToOpenLink(aEvent, false, true); } else { var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab"); if (((aEvent instanceof KeyboardEvent) && aEvent.altKey) ^ newTabPref) where = "tab"; - if ((aEvent instanceof MouseEvent) && (aEvent.button == 1 || -#ifdef XP_MACOSX - aEvent.metaKey)) -#else - aEvent.ctrlKey)) -#endif + if ((aEvent instanceof MouseEvent) && + (aEvent.button == 1 || aEvent.getModifierState("Accel"))) { where = "tab-background"; + } } let selection = this.telemetrySearchDetails; this.doSearch(textValue, where, aEngine); if (!selection || (selection.index == -1)) { let source = "unknown"; let type = "unknown"; @@ -866,16 +862,21 @@ element.setAttribute("accesskey", akey); element.setAttribute("cmd", "cmd_togglesuggest"); element.setAttribute("type", "checkbox"); element.setAttribute("checked", this._suggestEnabled); element.setAttribute("autocheck", "false"); this._suggestMenuItem = element; cxmenu.appendChild(element); + this.addEventListener("keypress", aEvent => { + if (navigator.platform.startsWith("Mac") && aEvent.keyCode == KeyEvent.VK_F4) + this.openSearch() + }, true); + this.controllers.appendController(this.searchbarController); document.getBindingParent(this)._textboxInitialized = true; // Add observer for suggest preference var prefs = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); prefs.addObserver("browser.search.suggest.enabled", this, false); ]]></constructor> @@ -1158,21 +1159,17 @@ let list = document.getAnonymousElementByAttribute(popup, "anonid", "search-panel-one-offs"); if (!list) // remove this check when removing the old search UI. return; // accel + up/down changes the default engine and shouldn't affect // the selection on the one-off buttons. -#ifdef XP_MACOSX - if (aEvent.metaKey) -#else - if (aEvent.ctrlKey) -#endif + if (aEvent.getModifierState("Accel")) return; let stopEvent = false; // Alt + up/down is very similar to (shift +) tab but differs in that // it loops through the list, whereas tab will move the focus out. if (aEvent.altKey && (aEvent.keyCode == KeyEvent.DOM_VK_DOWN || @@ -1246,22 +1243,16 @@ <handler event="keypress" keycode="VK_DOWN" modifiers="alt" phase="capturing" action="return this.openSearch();"/> <handler event="keypress" keycode="VK_UP" modifiers="alt" phase="capturing" action="return this.openSearch();"/> -#ifndef XP_MACOSX - <handler event="keypress" keycode="VK_F4" - phase="capturing" - action="return this.openSearch();"/> -#endif - <handler event="dragover"> <![CDATA[ var types = event.dataTransfer.types; if (types.contains("text/plain") || types.contains("text/x-moz-text-internal")) event.preventDefault(); ]]> </handler>
--- a/browser/components/search/jar.mn +++ b/browser/components/search/jar.mn @@ -1,9 +1,9 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. browser.jar: -* content/browser/search/search.xml (content/search.xml) + content/browser/search/search.xml (content/search.xml) content/browser/search/searchbarBindings.css (content/searchbarBindings.css) content/browser/search/engineManager.xul (content/engineManager.xul) content/browser/search/engineManager.js (content/engineManager.js)
--- a/browser/themes/shared/tabs.inc.css +++ b/browser/themes/shared/tabs.inc.css @@ -433,18 +433,19 @@ /* Background tab separators. Also show separators beside the selected tab when dragging it. */ #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after, .tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before, #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after { width: 1px; -moz-margin-start: -1px; - margin-top: calc(var(--tab-separator-margin) + 1px); - margin-bottom: var(--tab-separator-margin); + padding-top: calc(var(--tab-separator-margin) + 1px); + padding-bottom: var(--tab-separator-margin); + background-clip: content-box; background-color: currentColor; opacity: var(--tab-separator-opacity); content: ""; display: -moz-box; } /* New tab button */
--- a/dom/bluetooth/BluetoothHfpManagerBase.h +++ b/dom/bluetooth/BluetoothHfpManagerBase.h @@ -19,13 +19,14 @@ public: */ virtual bool IsScoConnected() = 0; virtual bool IsNrecEnabled() = 0; }; #define BT_DECL_HFP_MGR_BASE \ BT_DECL_PROFILE_MGR_BASE \ - virtual bool IsScoConnected() override; + virtual bool IsScoConnected() override; \ + virtual bool IsNrecEnabled() override; END_BLUETOOTH_NAMESPACE #endif //#ifndef mozilla_dom_bluetooth_bluetoothhfpmanagerbase_h__
--- a/dom/bluetooth/bluedroid/hfp-fallback/BluetoothHfpManager.cpp +++ b/dom/bluetooth/bluedroid/hfp-fallback/BluetoothHfpManager.cpp @@ -100,16 +100,22 @@ BluetoothHfpManager::OnUpdateSdpRecords( * BluetoothHfpManagerBase function */ bool BluetoothHfpManager::IsScoConnected() { return false; } +bool +BluetoothHfpManager::IsNrecEnabled() +{ + return false; +} + /** * Non-inherited functions */ // static BluetoothHfpManager* BluetoothHfpManager::Get() { MOZ_ASSERT(NS_IsMainThread()); @@ -200,17 +206,17 @@ BluetoothHfpManager::ConnectSco() */ return false; } void BluetoothHfpManager::HandleBackendError() { /** - * TODO: + * TODO: * Reset connection state and audio state to DISCONNECTED to handle backend * error. The state change triggers UI status bar update as ordinary * bluetooth turn-off sequence. */ } bool BluetoothHfpManager::DisconnectSco()
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.h +++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.h @@ -87,17 +87,16 @@ public: } static BluetoothHfpManager* Get(); static void InitHfpInterface(BluetoothProfileResultHandler* aRes); static void DeinitHfpInterface(BluetoothProfileResultHandler* aRes); bool ConnectSco(); bool DisconnectSco(); - bool IsNrecEnabled(); /** * @param aSend A boolean indicates whether we need to notify headset or not */ void HandleCallStateChanged(uint32_t aCallIndex, uint16_t aCallState, const nsAString& aError, const nsAString& aNumber, const bool aIsOutgoing, const bool aIsConference, bool aSend);
--- a/dom/bluetooth/bluez/BluetoothHfpManager.h +++ b/dom/bluetooth/bluez/BluetoothHfpManager.h @@ -98,17 +98,16 @@ public: * connecting HSP socket rather than HFP socket. * * @param aRunnable Indicate a BluetoothReplyRunnable to execute this * function. The default value is nullpter * @return <code>true</code> if SCO established successfully */ bool ConnectSco(BluetoothReplyRunnable* aRunnable = nullptr); bool DisconnectSco(); - bool IsNrecEnabled(); bool ListenSco(); #ifdef MOZ_B2G_RIL /** * @param aSend A boolean indicates whether we need to notify headset or not */ void HandleCallStateChanged(uint32_t aCallIndex, uint16_t aCallState, const nsAString& aError, const nsAString& aNumber,
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp +++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp @@ -452,17 +452,17 @@ nsPerformanceStatsService::nsPerformance #else : mProcessId(getpid()) #endif , mProcessStayed(0) , mProcessMoved(0) { nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { - mozilla::unused << obs->AddObserver(this, "profile-before-shutdown", false); + mozilla::unused << obs->AddObserver(this, "profile-before-change", false); } } nsPerformanceStatsService::~nsPerformanceStatsService() { } //[implicit_jscontext] attribute bool isMonitoringCPOW; @@ -525,17 +525,17 @@ NS_IMETHODIMP nsPerformanceStatsService: /* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */ NS_IMETHODIMP nsPerformanceStatsService::Observe(nsISupports *, const char *, const char16_t *) { // Upload telemetry nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { - mozilla::unused << obs->RemoveObserver(this, "profile-before-shutdown"); + mozilla::unused << obs->RemoveObserver(this, "profile-before-change"); } if (mProcessStayed + mProcessMoved == 0) { // Nothing to report. return NS_OK; } const uint32_t proportion = ( 100 * mProcessStayed ) / ( mProcessStayed + mProcessMoved ); mozilla::Telemetry::Accumulate("PERF_MONITORING_TEST_CPU_RESCHEDULING_PROPORTION_MOVED", proportion);