From 7b7b8cabc56684057e7c9ec7e5c19bcaef1c9a25 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Wed, 9 Jan 2019 10:51:59 -0800 Subject: [PATCH] Release 1.0.0-beta.11 (#746) * reenable Request-Context header in fetch requests * rename ikey to iKey from ITelemetryItem * rename timestamp to time from ITelemetryItem * add updateSnippetDefinitions * Bump dependency versions to latest for 1.0.0-beta.11 --- AISKU/package.json | 12 +- AISKU/src/ApplicationInsightsContainer.ts | 7 +- AISKU/src/ApplicationInsightsDeprecated.ts | 42 +- AISKU/src/Init.ts | 10 +- AISKU/src/Initialization.ts | 16 + AISKULight/package.json | 8 +- API-reference.md | 2 +- AppInsightsCommon/package.json | 4 +- AppInsightsCommon/src/TelemetryItemCreator.ts | 18 +- .../Tests/ApplicationInsights.tests.ts | 2 +- ApplicationInsights/package.json | 6 +- .../src/JavaScriptSDK/ApplicationInsights.ts | 6 +- .../Tests/Selenium/ajax.tests.ts | 477 +++++++++--------- .../package.json | 6 +- .../src/ajax.ts | 8 +- .../package.json | 6 +- 16 files changed, 326 insertions(+), 304 deletions(-) diff --git a/AISKU/package.json b/AISKU/package.json index 4ce786abf..88a054d46 100644 --- a/AISKU/package.json +++ b/AISKU/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/applicationinsights-web", - "version": "1.0.0-beta.10", + "version": "1.0.0-beta.11", "description": "Microsoft Application Insights Javascript SDK API 1.0 beta", "main": "dist/applicationinsights-web.js", "module": "dist-esm/applicationinsights-web.js", @@ -22,10 +22,10 @@ }, "dependencies": { "@microsoft/applicationinsights-analytics-js": "^1.0.0-beta.12", - "@microsoft/applicationinsights-channel-js": "^1.0.0-beta.11", - "@microsoft/applicationinsights-common": "^1.0.0-beta.13", - "@microsoft/applicationinsights-core-js": "^1.0.0-beta.3", - "@microsoft/applicationinsights-dependencies-js": "^1.0.0-beta.11", - "@microsoft/applicationinsights-properties-js": "^1.0.0-beta.8" + "@microsoft/applicationinsights-channel-js": "^1.0.0-beta.12", + "@microsoft/applicationinsights-common": "^1.0.0-beta.14", + "@microsoft/applicationinsights-core-js": "^1.0.0-beta.5", + "@microsoft/applicationinsights-dependencies-js": "^1.0.0-beta.12", + "@microsoft/applicationinsights-properties-js": "^1.0.0-beta.9" } } diff --git a/AISKU/src/ApplicationInsightsContainer.ts b/AISKU/src/ApplicationInsightsContainer.ts index 8ba4cb437..e19332a12 100644 --- a/AISKU/src/ApplicationInsightsContainer.ts +++ b/AISKU/src/ApplicationInsightsContainer.ts @@ -3,14 +3,15 @@ import { Initialization as ApplicationInsights, Snippet, IApplicationInsights } export class ApplicationInsightsContainer { - public static getAppInsights(snippet: Snippet, version: number) : IApplicationInsights | IAppInsightsDeprecated { + public static getAppInsights(snippet: Snippet, version: number = 2.0) : IApplicationInsights | IAppInsightsDeprecated { let initialization = new ApplicationInsights(snippet); let legacyMode = version === 2.0 ? false : true; + initialization.updateSnippetDefinitions(snippet); initialization.loadAppInsights(legacyMode); // Two target scenarios: // 1. Customer runs v1 snippet + runtime. If customer updates just cdn location to new SDK, it will run in compat mode so old apis work - // 2. Customer updates to new snippet (that uses cdn location to new SDK. This is same as a new customer onboarding + // 2. Customer updates to new snippet (that uses cdn location to new SDK. This is same as a new customer onboarding // and all api signatures are expected to map to new SDK. Note new snippet specifies version if (version === 2.0) { @@ -19,4 +20,4 @@ export class ApplicationInsightsContainer { return new AppInsightsDeprecated(snippet, initialization); // target scenario old snippet + updated endpoint } } -} \ No newline at end of file +} diff --git a/AISKU/src/ApplicationInsightsDeprecated.ts b/AISKU/src/ApplicationInsightsDeprecated.ts index ccd74ef94..5553c640a 100644 --- a/AISKU/src/ApplicationInsightsDeprecated.ts +++ b/AISKU/src/ApplicationInsightsDeprecated.ts @@ -1,6 +1,6 @@ -import { IConfig, PageViewPerformance, SeverityLevel, Util, - IPageViewTelemetry, ITraceTelemetry, IMetricTelemetry, - IAutoExceptionTelemetry, IDependencyTelemetry, IExceptionTelemetry, +import { IConfig, PageViewPerformance, SeverityLevel, Util, + IPageViewTelemetry, ITraceTelemetry, IMetricTelemetry, + IAutoExceptionTelemetry, IDependencyTelemetry, IExceptionTelemetry, IEventTelemetry, IEnvelope, ProcessLegacy, HttpMethod } from "@microsoft/applicationinsights-common"; import { Snippet, IApplicationInsights } from "./Initialization"; import { ITelemetryItem, IDiagnosticLogger, IConfiguration } from "@microsoft/applicationinsights-core-js"; @@ -24,11 +24,11 @@ export class AppInsightsDeprecated implements IAppInsightsDeprecated { // Add initializer to current processing only if there is any old telemetry initializer if (!this._hasLegacyInitializers) { - + this.appInsightsNew.addTelemetryInitializer(item => { this._processLegacyInitializers(item); // setup call back for each legacy processor }) - + this._hasLegacyInitializers = true; } @@ -36,7 +36,7 @@ export class AppInsightsDeprecated implements IAppInsightsDeprecated { } private _processLegacyInitializers(item: ITelemetryItem): ITelemetryItem { - + // instead of mapping new to legacy and then back again and repeating in channel, attach callback for channel to call item.tags[ProcessLegacy] = this._queue; return item; @@ -74,13 +74,13 @@ export class AppInsightsDeprecated implements IAppInsightsDeprecated { trackDependency(id: string, method: string, absoluteUrl: string, pathName: string, totalTime: number, success: boolean, resultCode: number) { this.appInsightsNew.trackDependencyData( - { - id: id, - absoluteUrl: absoluteUrl, - type: pathName, + { + id: id, + absoluteUrl: absoluteUrl, + type: pathName, duration: totalTime, properties: { HttpMethod: method }, - success: success, + success: success, responseCode: resultCode }); } @@ -110,12 +110,12 @@ export class AppInsightsDeprecated implements IAppInsightsDeprecated { clearAuthenticatedUserContext() { this.appInsightsNew.clearAuthenticatedUserContext(); } - + _onerror(message: string, url: string, lineNumber: number, columnNumber: number, error: Error) { this.appInsightsNew._onerror({ message: message, url: url, lineNumber: lineNumber, columnNumber: columnNumber, error: error }); } - - + + startTrackEvent(name: string) { this.appInsightsNew.startTrackEvent(name); } @@ -186,11 +186,11 @@ export class AppInsightsDeprecated implements IAppInsightsDeprecated { config.disableAjaxTracking = Util.stringToBoolOrDefault(config.disableAjaxTracking); config.maxAjaxCallsPerView = !isNaN(config.maxAjaxCallsPerView) ? config.maxAjaxCallsPerView : 500; - + config.isBeaconApiDisabled = Util.stringToBoolOrDefault(config.isBeaconApiDisabled, true); config.disableCorrelationHeaders = Util.stringToBoolOrDefault(config.disableCorrelationHeaders); config.correlationHeaderExcludedDomains = config.correlationHeaderExcludedDomains || [ - "*.blob.core.windows.net", + "*.blob.core.windows.net", "*.blob.core.chinacloudapi.cn", "*.blob.core.cloudapi.de", "*.blob.core.usgovcloudapi.net"]; @@ -352,11 +352,11 @@ export interface IAppInsightsDeprecated { } export interface ITelemetryContext { - + /** - * Adds a telemetry initializer to the collection. Telemetry initializers will be called one by one, - * in the order they were added, before the telemetry item is pushed for sending. + * Adds a telemetry initializer to the collection. Telemetry initializers will be called one by one, + * in the order they were added, before the telemetry item is pushed for sending. * If one of the telemetry initializers returns false or throws an error then the telemetry item will not be sent. */ - addTelemetryInitializer(telemetryInitializer: (IEnvelope) => boolean | void); -} \ No newline at end of file + addTelemetryInitializer(telemetryInitializer: (envelope: IEnvelope) => boolean | void); +} diff --git a/AISKU/src/Init.ts b/AISKU/src/Init.ts index 0355737bb..5543ef0d6 100644 --- a/AISKU/src/Init.ts +++ b/AISKU/src/Init.ts @@ -20,17 +20,11 @@ try { if (window[aiName] !== undefined) { // this is the typical case for browser+snippet var snippet: Snippet = window[aiName] || { version: 2.0 }; - + // overwrite snippet with full appInsights // for 2.0 initialize only if required if ((snippet.version === 2.0 && window[aiName].initialize) || snippet.version === undefined ) { - - var initialization = ApplicationInsightsContainer.getAppInsights(snippet, snippet.version); - - // apply full appInsights to the global instance that was initialized in the snippet - for (var field in initialization) { - snippet[field] = initialization[field]; - } + ApplicationInsightsContainer.getAppInsights(snippet, snippet.version); } } } diff --git a/AISKU/src/Initialization.ts b/AISKU/src/Initialization.ts index e3bbabab0..260035f0f 100644 --- a/AISKU/src/Initialization.ts +++ b/AISKU/src/Initialization.ts @@ -267,6 +267,22 @@ export class Initialization implements IApplicationInsights { return this; } + /** + * Overwrite the lazy loaded fields of global window snippet to contain the + * actual initialized API methods + * @param {Snippet} snippet + * @memberof Initialization + */ + public updateSnippetDefinitions(snippet: Snippet) { + // apply full appInsights to the global instance + // Note: This must be called before loadAppInsights is called + for (var field in this) { + if (typeof field === 'string') { + snippet[field as string] = this[field]; + } + } + + } /** * Call any functions that were queued before the main script was loaded diff --git a/AISKULight/package.json b/AISKULight/package.json index 9d8e105a4..6ecda13c6 100644 --- a/AISKULight/package.json +++ b/AISKULight/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/applicationinsights-web-basic", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "Microsoft Application Insights Javascript SDK core and channel", "main": "dist/applicationinsights-web-basic.js", "module": "dist-esm/index.js", @@ -22,8 +22,8 @@ "typescript": "2.5.3" }, "dependencies": { - "@microsoft/applicationinsights-common": "^1.0.0-beta.13", - "@microsoft/applicationinsights-channel-js": "^1.0.0-beta.11", - "@microsoft/applicationinsights-core-js": "^1.0.0-beta.3" + "@microsoft/applicationinsights-common": "^1.0.0-beta.14", + "@microsoft/applicationinsights-channel-js": "^1.0.0-beta.12", + "@microsoft/applicationinsights-core-js": "^1.0.0-beta.5" } } diff --git a/API-reference.md b/API-reference.md index cfe9787d7..ed3cd9738 100644 --- a/API-reference.md +++ b/API-reference.md @@ -157,7 +157,7 @@ Log an exception you have caught. (Exceptions caught by the browser are also log Parameter | Description ---|--- `exception` | An Error from a catch clause. -`handledAt` | Defaults to "unhandled". +`handledAt` | Deprecated. This argument is ignored. Please pass `null`. `properties` | Map of string to string: Additional data used to [filter exceptions](https://azure.microsoft.com/documentation/articles/app-insights-api-custom-events-metrics/#properties) in the portal. Defaults to empty. `measurements` | Map of string to number: Metrics associated with this page, displayed in Metrics Explorer on the portal. Defaults to empty. `severityLevel` | Supported values: [SeverityLevel.ts](https://github.com/Microsoft/ApplicationInsights-JS/blob/master/JavaScript/JavaScriptSDK.Interfaces/Contracts/Generated/SeverityLevel.ts) diff --git a/AppInsightsCommon/package.json b/AppInsightsCommon/package.json index 9553ad8da..989fb8d41 100644 --- a/AppInsightsCommon/package.json +++ b/AppInsightsCommon/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/applicationinsights-common", - "version": "1.0.0-beta.13", + "version": "1.0.0-beta.14", "description": "Microsoft Application Insights Common JavaScript Library", "main": "./dist/applicationinsights-common.js", "module": "./dist-esm/applicationinsights-common.js", @@ -28,7 +28,7 @@ "typescript": "2.5.3" }, "dependencies": { - "@microsoft/applicationinsights-core-js": "^1.0.0-beta.3" + "@microsoft/applicationinsights-core-js": "^1.0.0-beta.5" }, "license": "MIT" } diff --git a/AppInsightsCommon/src/TelemetryItemCreator.ts b/AppInsightsCommon/src/TelemetryItemCreator.ts index 73542f3ca..fe2e59b45 100644 --- a/AppInsightsCommon/src/TelemetryItemCreator.ts +++ b/AppInsightsCommon/src/TelemetryItemCreator.ts @@ -39,8 +39,8 @@ export class TelemetryItemCreator { let telemetryItem: ITelemetryItem = { name: envelopeName, - timestamp: new Date(), - instrumentationKey: "", // this will be set in TelemetryContext + time: new Date().toISOString(), + iKey: "", // this will be set in TelemetryContext ctx: systemProperties ? systemProperties : {}, // part A tags: [], data: { @@ -79,10 +79,10 @@ export class TelemetryItemCreator { let dependencyTelemetry = (env.data.baseType); telemetryItem = TelemetryItemCreator.create( - dependencyTelemetry, - RemoteDependencyData.dataType, + dependencyTelemetry, + RemoteDependencyData.dataType, RemoteDependencyData.envelopeType, - logger, + logger, customProperties); } @@ -216,18 +216,18 @@ export class TelemetryItemCreator { } - + if (env.tags[CtxTagKeys.operationRootId]) { item.tags[CtxTagKeys.operationRootId] = env.tags[CtxTagKeys.operationRootId]; keysFound.push(CtxTagKeys.operationRootId); } - + if (env.tags[CtxTagKeys.operationSyntheticSource]) { item.tags[CtxTagKeys.operationSyntheticSource] = env.tags[CtxTagKeys.operationSyntheticSource]; keysFound.push(CtxTagKeys.operationSyntheticSource); } - + if (env.tags[CtxTagKeys.operationParentId]) { item.tags[CtxTagKeys.operationParentId] = env.tags[CtxTagKeys.operationParentId]; keysFound.push(CtxTagKeys.operationParentId); @@ -249,4 +249,4 @@ export class TelemetryItemCreator { } }) } -} \ No newline at end of file +} diff --git a/ApplicationInsights/Tests/ApplicationInsights.tests.ts b/ApplicationInsights/Tests/ApplicationInsights.tests.ts index d81f40d31..86d90efd8 100644 --- a/ApplicationInsights/Tests/ApplicationInsights.tests.ts +++ b/ApplicationInsights/Tests/ApplicationInsights.tests.ts @@ -114,7 +114,7 @@ export class ApplicationInsightsTests extends TestClass { var test = (action, expectedEnvelopeType, expectedDataType, test?: () => void) => { action(); envelope = this.getFirstResult(action, trackStub); - Assert.equal(iKey, envelope.instrumentationKey, "envelope iKey"); + Assert.equal(iKey, envelope.iKey, "envelope iKey"); Assert.equal(expectedEnvelopeType.replace("{0}", iKeyNoDash), envelope.name, "envelope name"); Assert.equal(expectedDataType, envelope.baseType, "data type name"); if (typeof test === 'function') {test();} diff --git a/ApplicationInsights/package.json b/ApplicationInsights/package.json index cae46e241..27f8915f4 100644 --- a/ApplicationInsights/package.json +++ b/ApplicationInsights/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/applicationinsights-analytics-js", - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12", "description": "Microsoft Application Insights Javascript SDK apis", "main": "dist/applicationinsights-analytics-js.js", "module": "dist-esm/applicationinsights-analytics-js.js", @@ -23,8 +23,8 @@ "rollup-plugin-uglify": "^6.0.0" }, "dependencies": { - "@microsoft/applicationinsights-core-js": "^1.0.0-beta.3", - "@microsoft/applicationinsights-common": "^1.0.0-beta.13" + "@microsoft/applicationinsights-core-js": "^1.0.0-beta.5", + "@microsoft/applicationinsights-common": "^1.0.0-beta.14" }, "license": "MIT" } diff --git a/ApplicationInsights/src/JavaScriptSDK/ApplicationInsights.ts b/ApplicationInsights/src/JavaScriptSDK/ApplicationInsights.ts index 23263a3d9..d35ff3d32 100644 --- a/ApplicationInsights/src/JavaScriptSDK/ApplicationInsights.ts +++ b/ApplicationInsights/src/JavaScriptSDK/ApplicationInsights.ts @@ -482,13 +482,13 @@ export class ApplicationInsights implements IAppInsights, ITelemetryPlugin, IApp this._eventTracking = new Timing(this._logger, "trackEvent"); - this._eventTracking.action = + this._eventTracking.action = (name?: string, url?: string, duration?: number, properties?: Object, measurements?: Object) => { if (!measurements) { measurements = {}; } - measurements["duration"] = duration ; // ToDo: fix once IEventTelemetry is updated + measurements["duration"] = duration ; // ToDo: fix once IEventTelemetry is updated this.trackEvent({ name: name }); } @@ -581,7 +581,7 @@ export class ApplicationInsights implements IAppInsights, ITelemetryPlugin, IApp // Mutate telemetryItem inplace to add boilerplate iKey & name info private _setTelemetryNameAndIKey(telemetryItem: ITelemetryItem): void { - telemetryItem.instrumentationKey = this._globalconfig.instrumentationKey; + telemetryItem.iKey = this._globalconfig.instrumentationKey; var iKeyNoDashes = this._globalconfig.instrumentationKey.replace(/-/g, ""); telemetryItem.name = telemetryItem.name.replace("{0}", iKeyNoDashes); diff --git a/extensions/applicationinsights-dependencies-js/Tests/Selenium/ajax.tests.ts b/extensions/applicationinsights-dependencies-js/Tests/Selenium/ajax.tests.ts index ee738a23d..d9dd3fc0c 100644 --- a/extensions/applicationinsights-dependencies-js/Tests/Selenium/ajax.tests.ts +++ b/extensions/applicationinsights-dependencies-js/Tests/Selenium/ajax.tests.ts @@ -4,26 +4,7 @@ import { RemoteDependencyData, DisabledPropertyName, IConfig } from "@microsoft/ import { AppInsightsCore, IConfiguration, ITelemetryItem, ITelemetryPlugin, IChannelControls } from "@microsoft/applicationinsights-core-js"; export class AjaxTests extends TestClass { - - private appInsightsMock = { - trackDependency: (id: string, method: string, absoluteUrl: string, isAsync: boolean, totalTime: number, success: boolean) => { }, - trackDependencyData: (dependency: RemoteDependencyData) => { }, - context: { - operation: { - id: "asdf" - }, - appId: () => "someid" - }, - config: { - disableCorrelationHeaders: false, - enableCorsCorrelation: false - } - } - private trackDependencySpy; - public testInitialize() { - this.trackDependencySpy = this.sandbox.spy(this.appInsightsMock, "trackDependencyData"); - this.trackDependencySpy.reset(); var xhr = sinon.useFakeXMLHttpRequest(); } @@ -123,7 +104,6 @@ export class AjaxTests extends TestClass { Assert.ok(fetchSpy.notCalled, "No fetch called yet"); fetch("https://httpbin.org/status/200", {method: "post", [DisabledPropertyName]: false}); - // Assert Assert.ok(fetchSpy.calledOnce, "createFetchRecord called once after using fetch"); } @@ -146,7 +126,7 @@ export class AjaxTests extends TestClass { appInsightsCore.initialize(coreConfig, [ajaxMonitor, new TestChannelPlugin()]); let fetchSpy = this.sandbox.spy(window, "fetch"); - // Setup + // Setup let headers = new Headers(); headers.append('My-Header', 'Header field'); let init = { @@ -163,7 +143,8 @@ export class AjaxTests extends TestClass { // Assert Assert.ok(fetchSpy.calledOnce); - Assert.deepEqual(headerSpy.returnValue, init); + Assert.ok(headerSpy.calledOnce); + Assert.deepEqual(init, headerSpy.returnValue || headerSpy.returnValues[0]); } }); @@ -197,220 +178,250 @@ export class AjaxTests extends TestClass { } }); - // Todo: uncomment tests - // this.testCase({ - // name: "Ajax: custom onreadystatechange gets called", - // test: () => { - // var onreadystatechangeSpy = this.sandbox.spy(); - // var ajax = new AjaxMonitor(); - - // // Act - // var xhr = new XMLHttpRequest(); - // xhr.onreadystatechange = onreadystatechangeSpy; - // xhr.open("GET", "/bla"); - // xhr.send(); - - // Assert.ok(!this.trackDependencySpy.called, "TrackAjax should not be called yet"); - - // // Emulate response - // (xhr).respond(); - - // // Assert - // Assert.ok(this.trackDependencySpy.called, "TrackAjax is called"); - // Assert.ok(onreadystatechangeSpy.called, "custom onreadystatechange should be called"); - - // } - // }); - - // this.testCase({ - // name: "Ajax: 200 means success", - // test: () => { - // var ajax = new AjaxMonitor(); - // // Act - // var xhr = new XMLHttpRequest(); - // xhr.open("GET", "/bla"); - // xhr.send(); - - // // Emulate response - // (xhr).respond(200, {}, ""); - - // // Assert - // Assert.equal(true, this.trackDependencySpy.args[0][0].success, "TrackAjax should receive true as a 'success' argument"); - - // } - // }); - - // this.testCase({ - // name: "Ajax: non 200 means failure", - // test: () => { - // var ajax = new AjaxMonitor(); - - // // Act - // var xhr = new XMLHttpRequest(); - // xhr.open("GET", "/bla"); - // xhr.send(); - - // // Emulate response - // (xhr).respond(404, {}, ""); - - // // Assert - // Assert.equal(false, this.trackDependencySpy.args[0][0].success, "TrackAjax should receive false as a 'success' argument"); - - // } - // }); - - // [200, 201, 202, 203, 204, 301, 302, 303, 304].forEach((responseCode) => { - // this.testCase({ - // name: "Ajax: test success http response code: " + responseCode, - // test: () => { - // this.testAjaxSuccess(responseCode, true); - // } - // }) - // }); - - // [400, 401, 402, 403, 404, 500, 501].forEach((responseCode) => { - // this.testCase({ - // name: "Ajax: test failure http response code: " + responseCode, - // test: () => { - // this.testAjaxSuccess(responseCode, false); - // } - // }) - // }); - - // this.testCase({ - // name: "Ajax: overriding ready state change handlers in all possible ways", - // test: () => { - // var ajax = new AjaxMonitor(); - // var cb1 = this.sandbox.spy(); - // var cb2 = this.sandbox.spy(); - // var cb3 = this.sandbox.spy(); - // var cb4 = this.sandbox.spy(); - // var cb5 = this.sandbox.spy(); - // var cb6 = this.sandbox.spy(); - // var cb7 = this.sandbox.spy(); - - // // Act - // var xhr = new XMLHttpRequest(); - // xhr.addEventListener("readystatechange", cb1); - // xhr.addEventListener("readystatechange", cb2); - // xhr.open("GET", "/bla"); - // xhr.onreadystatechange = cb3; - // xhr.addEventListener("readystatechange", cb4); - // xhr.addEventListener("readystatechange", cb5); - // xhr.send(); - // xhr.addEventListener("readystatechange", cb6); - // xhr.addEventListener("readystatechange", cb7); - - // Assert.ok(!this.trackDependencySpy.called, "TrackAjax should not be called yet"); - - // // Emulate response - // (xhr).respond(404, {}, ""); - - // // Assert - // Assert.ok(this.trackDependencySpy.calledOnce, "TrackAjax should be called"); - // Assert.ok(cb1.called, "callback 1 should be called"); - // Assert.ok(cb2.called, "callback 2 should be called"); - // Assert.ok(cb3.called, "callback 3 should be called"); - // Assert.ok(cb4.called, "callback 4 should be called"); - // Assert.ok(cb5.called, "callback 5 should be called"); - // Assert.ok(cb6.called, "callback 6 should be called"); - // Assert.ok(cb7.called, "callback 7 should be called"); - - // } - // }); - - // this.testCase({ - // name: "Ajax: test ajax duration is calculated correctly", - // test: () => { - // var initialPerformance = window.performance; - // try { - // // Mocking window performance (sinon doesn't have it). - // // tick() is similar to sinon's clock.tick() - // (window).performance = { - // current: 0, - - // now: function () { - // return this.current; - // }, - - // tick: function (ms: number) { - // this.current += ms; - // }, - - // timing: initialPerformance.timing - // }; - - // var ajax = new AjaxMonitor(); - // // tick to set the initial time be non zero - // (window.performance).tick(23); - - // // Act - // var xhr = new XMLHttpRequest(); - // var clock = this.clock; - // var expectedResponseDuration = 50; - // xhr.onreadystatechange = () => { - // if (xhr.readyState == 3) { - // (window.performance).tick(expectedResponseDuration); - // } - // } - // xhr.open("GET", "/bla"); - // xhr.send(); - // // Emulate response - // (xhr).respond(404, {}, ""); - - // // Assert - // Assert.ok(this.trackDependencySpy.calledOnce, "TrackAjax should be called"); - // Assert.equal("00:00:00.050", this.trackDependencySpy.args[0][0].duration, "Ajax duration should match expected duration"); - // } finally { - // (window.performance).performance = initialPerformance; - // } - // } - // }); - - // this.testCase({ - // name: "Ajax: 2nd invokation of xhr.send doesn't cause send wrapper to execute 2nd time", - // test: () => { - // var ajax = new AjaxMonitor(); - // var spy = this.sandbox.spy(ajax, "sendHandler"); - - // // Act - // var xhr = new XMLHttpRequest(); - // xhr.open("GET", "/bla"); - // xhr.send(); - - // try { - // xhr.send(); - // } catch (e) { } - - - // // Assert - // Assert.ok(spy.calledOnce, "sendPrefixInstrumentor should be called only once"); - // } - // }); - - // this.testCase({ - // name: "Ajax: 2 invokation of xhr.open() doesn't cause send wrapper to execute 2nd time", - // test: () => { - // var ajax = new AjaxMonitor(); - // var spy = this.sandbox.spy(ajax, "openHandler"); - - // // Act - // var xhr = new XMLHttpRequest(); - // xhr.open("GET", "/bla"); - - // try { - // xhr.open("GET", "/bla"); - // } catch (e) { } - - - // // Assert - // Assert.ok(spy.calledOnce, "sendPrefixInstrumentor should be called only once"); - // } - // }); + this.testCase({ + name: "Ajax: custom onreadystatechange gets called", + test: () => { + var onreadystatechangeSpy = this.sandbox.spy(); + var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var trackStub = this.sandbox.stub(ajax, "trackDependencyDataInternal"); + + // Act + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = onreadystatechangeSpy; + xhr.open("GET", "/bla"); + xhr.send(); + + Assert.ok(trackStub.notCalled, "TrackAjax should not be called yet"); + + // Emulate response + (xhr).respond(200, {}, ""); + + // Assert + Assert.ok(trackStub.called, "TrackAjax is called"); + Assert.equal(5, onreadystatechangeSpy.callCount, "custom onreadystatechange should be called"); + + } + }); + + this.testCase({ + name: "Ajax: 200 means success", + test: () => { + var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var trackStub = this.sandbox.stub(ajax, "trackDependencyDataInternal"); + + // Act + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/bla"); + xhr.send(); + + // Emulate response + (xhr).respond(200, {}, ""); + + // Assert + Assert.equal(true, trackStub.args[0][0].success, "TrackAjax should receive true as a 'success' argument"); + + } + }); + + this.testCase({ + name: "Ajax: non 200 means failure", + test: () => { + var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var trackStub = this.sandbox.stub(ajax, "trackDependencyDataInternal"); + + // Act + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/bla"); + xhr.send(); + + // Emulate response + (xhr).respond(404, {}, ""); + + // Assert + Assert.equal(false, trackStub.args[0][0].success, "TrackAjax should receive false as a 'success' argument"); + + } + }); + + [200, 201, 202, 203, 204, 301, 302, 303, 304].forEach((responseCode) => { + this.testCase({ + name: "Ajax: test success http response code: " + responseCode, + test: () => { + this.testAjaxSuccess(responseCode, true); + } + }) + }); + + [400, 401, 402, 403, 404, 500, 501].forEach((responseCode) => { + this.testCase({ + name: "Ajax: test failure http response code: " + responseCode, + test: () => { + this.testAjaxSuccess(responseCode, false); + } + }) + }); + + this.testCase({ + name: "Ajax: overriding ready state change handlers in all possible ways", + test: () => { + var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var trackStub = this.sandbox.stub(ajax, "trackDependencyDataInternal"); + var cb1 = this.sandbox.spy(); + var cb2 = this.sandbox.spy(); + var cb3 = this.sandbox.spy(); + var cb4 = this.sandbox.spy(); + var cb5 = this.sandbox.spy(); + var cb6 = this.sandbox.spy(); + var cb7 = this.sandbox.spy(); + + // Act + var xhr = new XMLHttpRequest(); + xhr.addEventListener("readystatechange", cb1); + xhr.addEventListener("readystatechange", cb2); + xhr.open("GET", "/bla"); + xhr.onreadystatechange = cb3; + xhr.addEventListener("readystatechange", cb4); + xhr.addEventListener("readystatechange", cb5); + xhr.send(); + xhr.addEventListener("readystatechange", cb6); + xhr.addEventListener("readystatechange", cb7); + + Assert.ok(!trackStub.called, "TrackAjax should not be called yet"); + + // Emulate response + (xhr).respond(404, {}, ""); + + // Assert + Assert.ok(trackStub.calledOnce, "TrackAjax should be called"); + Assert.ok(cb1.called, "callback 1 should be called"); + Assert.ok(cb2.called, "callback 2 should be called"); + Assert.ok(cb3.called, "callback 3 should be called"); + Assert.ok(cb4.called, "callback 4 should be called"); + Assert.ok(cb5.called, "callback 5 should be called"); + Assert.ok(cb6.called, "callback 6 should be called"); + Assert.ok(cb7.called, "callback 7 should be called"); + + } + }); + + this.testCase({ + name: "Ajax: test ajax duration is calculated correctly", + test: () => { + var initialPerformance = window.performance; + try { + // Mocking window performance (sinon doesn't have it). + // tick() is similar to sinon's clock.tick() + (window).performance = { + current: 0, + + now: function () { + return this.current; + }, + + tick: function (ms: number) { + this.current += ms; + }, + + timing: initialPerformance.timing + }; + + var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var trackStub = this.sandbox.stub(ajax, "trackDependencyDataInternal"); + // tick to set the initial time be non zero + (window.performance).tick(23); + + // Act + var xhr = new XMLHttpRequest(); + var clock = this.clock; + var expectedResponseDuration = 50; + xhr.onreadystatechange = () => { + if (xhr.readyState == 3) { + (window.performance).tick(expectedResponseDuration); + } + } + xhr.open("GET", "/bla"); + xhr.send(); + // Emulate response + (xhr).respond(404, {}, ""); + + // Assert + Assert.ok(trackStub.calledOnce, "TrackAjax should be called"); + Assert.equal(expectedResponseDuration, trackStub.args[0][0].duration, "Ajax duration should match expected duration"); + } finally { + (window.performance).performance = initialPerformance; + } + } + }); + + this.testCase({ + name: "Ajax: 2nd invokation of xhr.send doesn't cause send wrapper to execute 2nd time", + test: () => { + var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var spy = this.sandbox.spy(ajax, "sendHandler"); + + // Act + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/bla"); + xhr.send(); + + try { + xhr.send(); + } catch (e) { } + + + // Assert + Assert.ok(spy.calledOnce, "sendPrefixInstrumentor should be called only once"); + } + }); + + this.testCase({ + name: "Ajax: 2 invokation of xhr.open() doesn't cause send wrapper to execute 2nd time", + test: () => { + var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var spy = this.sandbox.spy(ajax, "openHandler"); + + // Act + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/bla"); + + try { + xhr.open("GET", "/bla"); + } catch (e) { } + + + // Assert + Assert.ok(spy.calledOnce, "sendPrefixInstrumentor should be called only once"); + } + }); } private testAjaxSuccess(responseCode: number, success: boolean) { var ajax = new AjaxMonitor(); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { instrumentationKey: "instrumentationKey", extensionConfig: {"AjaxPlugin": {}}}; + appInsightsCore.initialize(coreConfig, [ajax, new TestChannelPlugin()]); + var trackStub = this.sandbox.stub(ajax, "trackDependencyDataInternal"); // Act var xhr = new XMLHttpRequest(); @@ -421,7 +432,7 @@ export class AjaxTests extends TestClass { (xhr).respond(responseCode, {}, ""); // Assert - Assert.equal(success, this.trackDependencySpy.args[0][0].success, "TrackAjax should receive " + success + " as a 'success' argument"); + Assert.equal(success, trackStub.args[0][0].success, "TrackAjax should receive " + success + " as a 'success' argument"); } } diff --git a/extensions/applicationinsights-dependencies-js/package.json b/extensions/applicationinsights-dependencies-js/package.json index b0828902d..b86a6107a 100644 --- a/extensions/applicationinsights-dependencies-js/package.json +++ b/extensions/applicationinsights-dependencies-js/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/applicationinsights-dependencies-js", - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12", "description": "Microsoft Application Insights XHR dependencies plugin", "main": "dist/applicationinsights-dependencies-js.js", "module": "dist-esm/applicationinsights-dependencies-js.js", @@ -27,8 +27,8 @@ "rollup-plugin-uglify": "^6.0.0" }, "dependencies": { - "@microsoft/applicationinsights-core-js": "^1.0.0-beta.3", - "@microsoft/applicationinsights-common": "^1.0.0-beta.13" + "@microsoft/applicationinsights-core-js": "^1.0.0-beta.5", + "@microsoft/applicationinsights-common": "^1.0.0-beta.14" }, "license": "MIT" } diff --git a/extensions/applicationinsights-dependencies-js/src/ajax.ts b/extensions/applicationinsights-dependencies-js/src/ajax.ts index aed8d67db..50d95ff55 100644 --- a/extensions/applicationinsights-dependencies-js/src/ajax.ts +++ b/extensions/applicationinsights-dependencies-js/src/ajax.ts @@ -424,10 +424,10 @@ export class AjaxMonitor implements ITelemetryPlugin, IDependenciesPlugin, IInst // not using original request headers will result in them being lost init.headers = new Headers(init.headers || (input instanceof Request ? (input.headers || {}) : {})); init.headers.set(RequestHeaders.requestIdHeader, ajaxData.id); - // let appId: string = this.appInsights.context ? this.appInsights.context.appId() : null; - // if (appId) { - // init.headers.set(RequestHeaders.requestContextHeader, RequestHeaders.requestContextAppIdFormat + appId); - // } + let appId: string = this._config.appId; + if (appId) { + init.headers.set(RequestHeaders.requestContextHeader, RequestHeaders.requestContextAppIdFormat + appId); + } return init; } diff --git a/extensions/applicationinsights-properties-js/package.json b/extensions/applicationinsights-properties-js/package.json index 51f325c9c..5e09387f3 100644 --- a/extensions/applicationinsights-properties-js/package.json +++ b/extensions/applicationinsights-properties-js/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/applicationinsights-properties-js", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "Microsoft Application Insights properties (Part A) plugin", "main": "dist/applicationinsights-properties-js.js", "module": "dist-esm/applicationinsights-properties-js.js", @@ -27,8 +27,8 @@ "rollup-plugin-uglify": "^6.0.0" }, "dependencies": { - "@microsoft/applicationinsights-core-js": "^1.0.0-beta.3", - "@microsoft/applicationinsights-common": "^1.0.0-beta.13" + "@microsoft/applicationinsights-core-js": "^1.0.0-beta.5", + "@microsoft/applicationinsights-common": "^1.0.0-beta.14" }, "license": "MIT" }