- Remove SimpleSyncPromise as it's no longer needed
This commit is contained in:
Родитель
9141ebf151
Коммит
c920fb782a
|
@ -13,8 +13,6 @@
|
|||
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
baseUrl: '../',
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<!-- <script src="../../../common/Tests/External/sinon-7.3.1.js"></script> -->
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
baseUrl: '../',
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"grunt": "^1.5.3",
|
||||
"grunt-contrib-qunit": "^6.2.1",
|
||||
"@nevware21/grunt-ts-plugin": "^0.4.3",
|
||||
"@nevware21/ts-async": "^0.1.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@rollup/plugin-replace": "^2.3.3",
|
||||
|
|
|
@ -15,7 +15,6 @@ function loadFetchModule(moduleLoader, name) {
|
|||
window.Headers = window.Headers || polyFetch.Headers;
|
||||
window.Response = window.Response || polyFetch.Response;
|
||||
window.Request = window.Request || polyFetch.Request;
|
||||
window.Promise = window.Promise || SimpleSyncPromise;
|
||||
|
||||
var usePolyFetch = getParameterByName("polyFetch");
|
||||
if (usePolyFetch) {
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
/**
|
||||
* Implementing a simple synchronous promise interface as PhantomJS doesn't support / implement the es6 Promise as used by fetch
|
||||
*/
|
||||
function SimpleSyncPromise(executor) {
|
||||
var _self = this;
|
||||
var _state = "pending";
|
||||
var _settledValue = null;
|
||||
var _queue = [];
|
||||
_self.then = function (onResolved, onRejected) {
|
||||
return new SimpleSyncPromise(function (resolve, reject) {
|
||||
// Queue the new promise returned to be resolved or rejected
|
||||
// when this promise settles.
|
||||
_enqueue(onResolved, onRejected, resolve, reject);
|
||||
});
|
||||
};
|
||||
_self["catch"] = function (onRejected) {
|
||||
// Just return an empty promise as this doesn't support rejection
|
||||
return _self.then(null, onRejected);
|
||||
}
|
||||
function _enqueue(onResolved, onRejected, resolve, reject) {
|
||||
_queue.push(function () {
|
||||
var value;
|
||||
try {
|
||||
if (_state === "resolved") {
|
||||
value = typeof onResolved === "function" ? onResolved(_settledValue) : _settledValue;
|
||||
} else {
|
||||
value = typeof onRejected === "function" ? onRejected(_settledValue) : _settledValue;
|
||||
}
|
||||
|
||||
if (value instanceof SimpleSyncPromise) {
|
||||
// The called handlers returned a new promise, so the chained promise
|
||||
// will follow the state of this promise.
|
||||
value.then(resolve, reject);
|
||||
} else if (_state === "rejected" && typeof onRejected !== "function") {
|
||||
// If there wasn't an onRejected handler and this promise is rejected, then
|
||||
// the chained promise also rejects with the same reason.
|
||||
reject(value);
|
||||
} else {
|
||||
// If this promise is fulfilled, then the chained promise is also fulfilled
|
||||
// with either the settled value of this promise (if no onFulfilled handler
|
||||
// was available) or the return value of the handler. If this promise is
|
||||
// rejected and there was an onRejected handler, then the chained promise is
|
||||
// fulfilled with the return value of the handler.
|
||||
resolve(value);
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
if (_state !== "pending") {
|
||||
_processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
function _processQueue() {
|
||||
if (_queue.length > 0) {
|
||||
var pending = _queue.slice();
|
||||
_queue = [];
|
||||
for (var i = 0, len = pending.length; i < len; ++i) {
|
||||
pending[i]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _resolve(value) {
|
||||
if (_state === "pending") {
|
||||
_settledValue = value;
|
||||
_state = "resolved";
|
||||
_processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
function _reject(reason) {
|
||||
if (_state === "pending") {
|
||||
_settledValue = reason;
|
||||
_state = "rejected";
|
||||
_processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
(function _initialize() {
|
||||
try {
|
||||
executor(_resolve, _reject);
|
||||
} catch (e) {
|
||||
_reject(e);
|
||||
}
|
||||
})();
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
"@microsoft/dynamicproto-js": "^1.1.7",
|
||||
"@nevware21/grunt-eslint-ts": "^0.2.2",
|
||||
"@nevware21/grunt-ts-plugin": "^0.4.3",
|
||||
"@nevware21/ts-async": "^0.1.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@rollup/plugin-replace": "^2.3.3",
|
||||
|
@ -413,6 +414,24 @@
|
|||
"typescript": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@nevware21/ts-async": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.1.0.tgz",
|
||||
"integrity": "sha512-O8tHb7bl7+QBaPNPQFaFONAxAdPhuAmE4rvjWKxb2VKikAl6h/WlNuXd0F/4jwZx57LdWflUokh8G2cWTRf24Q==",
|
||||
"peerDependencies": {
|
||||
"@nevware21/ts-utils": ">= 0.7 < 2.x",
|
||||
"typescript": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@nevware21/ts-utils": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.7.0.tgz",
|
||||
"integrity": "sha512-IUAjuaIekPVnLlzprfOnppE8vPTtstI4ESHz6JEzboX+BlI8WLc76PhNtxAzhkBs1glGQ5zot4L8sA8tMNgmTQ==",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"typescript": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
@ -520,10 +539,11 @@
|
|||
"node_modules/@rush-temp/ai-test-framework": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "file:projects/ai-test-framework.tgz",
|
||||
"integrity": "sha512-dkn8ZUzeaneGbu8n+QIShhtR5nB+YQaDdOPOIrHNEEtwqfV7zHHwNQ7SvBaVCd+dbqS6gwn4/uViVj+gIZzyrA==",
|
||||
"integrity": "sha512-/46+N6gn1YXvalhor8Js+EEHD3ufhqYVwwHIEJVeSRAHMtWZZC36yHWPC4ihKXsJsGo4T6UuU2lgi5AK+SjalQ==",
|
||||
"dependencies": {
|
||||
"@microsoft/dynamicproto-js": "^1.1.7",
|
||||
"@nevware21/grunt-ts-plugin": "^0.4.3",
|
||||
"@nevware21/ts-async": "^0.1.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@rollup/plugin-replace": "^2.3.3",
|
||||
|
@ -722,12 +742,13 @@
|
|||
"node_modules/@rush-temp/applicationinsights-dependencies-js": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "file:projects/applicationinsights-dependencies-js.tgz",
|
||||
"integrity": "sha512-UlxsHu42JM4o2VgtqN4zQjn2UP9o21oCRQUnOx4biuaeBt6mXmm5XTFjacEEBAUzOGWAZ97daSRzxtalIL3zIw==",
|
||||
"integrity": "sha512-GqQkRS6fd2dkwogUPMVrv8MzUzhnR+VyUuJCmujommkykbmlF65Z5v+VJfuOjS5SwMRyg+CShqpOvvHIaQXxBg==",
|
||||
"dependencies": {
|
||||
"@microsoft/api-extractor": "^7.18.1",
|
||||
"@microsoft/dynamicproto-js": "^1.1.7",
|
||||
"@nevware21/grunt-eslint-ts": "^0.2.2",
|
||||
"@nevware21/grunt-ts-plugin": "^0.4.3",
|
||||
"@nevware21/ts-async": "^0.1.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@rollup/plugin-replace": "^2.3.3",
|
||||
|
@ -2726,19 +2747,6 @@
|
|||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
|
@ -5721,6 +5729,19 @@
|
|||
"integrity": "sha512-4ALgho4uvEBMFu5jiN+bVzGMbpCGPrKjb47jus8T3zlBpi+k/swe6lKb5j6HGQ7EBSN7C41mLU02GMo9ZSgX3Q==",
|
||||
"requires": {}
|
||||
},
|
||||
"@nevware21/ts-async": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.1.0.tgz",
|
||||
"integrity": "sha512-O8tHb7bl7+QBaPNPQFaFONAxAdPhuAmE4rvjWKxb2VKikAl6h/WlNuXd0F/4jwZx57LdWflUokh8G2cWTRf24Q==",
|
||||
"requires": {}
|
||||
},
|
||||
"@nevware21/ts-utils": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.7.0.tgz",
|
||||
"integrity": "sha512-IUAjuaIekPVnLlzprfOnppE8vPTtstI4ESHz6JEzboX+BlI8WLc76PhNtxAzhkBs1glGQ5zot4L8sA8tMNgmTQ==",
|
||||
"peer": true,
|
||||
"requires": {}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
@ -5799,10 +5820,11 @@
|
|||
},
|
||||
"@rush-temp/ai-test-framework": {
|
||||
"version": "file:projects\\ai-test-framework.tgz",
|
||||
"integrity": "sha512-dkn8ZUzeaneGbu8n+QIShhtR5nB+YQaDdOPOIrHNEEtwqfV7zHHwNQ7SvBaVCd+dbqS6gwn4/uViVj+gIZzyrA==",
|
||||
"integrity": "sha512-/46+N6gn1YXvalhor8Js+EEHD3ufhqYVwwHIEJVeSRAHMtWZZC36yHWPC4ihKXsJsGo4T6UuU2lgi5AK+SjalQ==",
|
||||
"requires": {
|
||||
"@microsoft/dynamicproto-js": "^1.1.7",
|
||||
"@nevware21/grunt-ts-plugin": "^0.4.3",
|
||||
"@nevware21/ts-async": "^0.1.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@rollup/plugin-replace": "^2.3.3",
|
||||
|
@ -5993,12 +6015,13 @@
|
|||
},
|
||||
"@rush-temp/applicationinsights-dependencies-js": {
|
||||
"version": "file:projects\\applicationinsights-dependencies-js.tgz",
|
||||
"integrity": "sha512-UlxsHu42JM4o2VgtqN4zQjn2UP9o21oCRQUnOx4biuaeBt6mXmm5XTFjacEEBAUzOGWAZ97daSRzxtalIL3zIw==",
|
||||
"integrity": "sha512-GqQkRS6fd2dkwogUPMVrv8MzUzhnR+VyUuJCmujommkykbmlF65Z5v+VJfuOjS5SwMRyg+CShqpOvvHIaQXxBg==",
|
||||
"requires": {
|
||||
"@microsoft/api-extractor": "^7.18.1",
|
||||
"@microsoft/dynamicproto-js": "^1.1.7",
|
||||
"@nevware21/grunt-eslint-ts": "^0.2.2",
|
||||
"@nevware21/grunt-ts-plugin": "^0.4.3",
|
||||
"@nevware21/ts-async": "^0.1.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@rollup/plugin-replace": "^2.3.3",
|
||||
|
@ -7552,12 +7575,6 @@
|
|||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
<!-- <script src="../../../common/Tests/External/require-2.3.6.js" crossorigin="anonymous"></script> -->
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { SinonStub } from "sinon";
|
||||
import { Assert, AITestClass, PollingAssert } from "@microsoft/ai-test-framework";
|
||||
import { createSyncPromise } from "@nevware21/ts-async";
|
||||
import { AjaxMonitor } from "../../../src/ajax";
|
||||
import { DisabledPropertyName, IConfig, DistributedTracingModes, RequestHeaders, IDependencyTelemetry, IRequestContext, formatTraceParent, createTraceParent } from "@microsoft/applicationinsights-common";
|
||||
import {
|
||||
|
@ -22,7 +23,7 @@ function hookFetch<T>(executor: (resolve: (value?: T | PromiseLike<T>) => void,
|
|||
input,
|
||||
init
|
||||
});
|
||||
return new window["SimpleSyncPromise"](executor);
|
||||
return createSyncPromise(executor);
|
||||
}
|
||||
|
||||
return calls;
|
||||
|
@ -641,6 +642,7 @@ export class AjaxTests extends AITestClass {
|
|||
data = trackStub.args[1][0].baseData;
|
||||
Assert.equal("Ajax", data.type, "request is Ajax type");
|
||||
Assert.equal(undefined, data.properties.responseText, "xhr request's reponse error is not stored in part C");
|
||||
Assert.equal(undefined, data.properties.aborted, "The aborted flag should not be set");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -686,6 +688,116 @@ export class AjaxTests extends AITestClass {
|
|||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: "Ajax: xhr abort is tracked as part C data when enableAjaxErrorStatusText flag is true",
|
||||
test: () => {
|
||||
this._ajax = new AjaxMonitor();
|
||||
let appInsightsCore = new AppInsightsCore();
|
||||
let coreConfig: IConfiguration & IConfig = { instrumentationKey: "abc", disableAjaxTracking: false, enableAjaxErrorStatusText: true };
|
||||
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
|
||||
|
||||
var trackStub = this.sandbox.stub(appInsightsCore, "track");
|
||||
|
||||
// act
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://microsoft.com");
|
||||
xhr.send();
|
||||
|
||||
xhr.abort();
|
||||
|
||||
// assert
|
||||
Assert.ok(trackStub.calledOnce, "track is called");
|
||||
let data = trackStub.args[0][0].baseData;
|
||||
Assert.equal("Ajax", data.type, "request is Ajax type");
|
||||
Assert.equal(0, data.responseCode, "Check the response code");
|
||||
Assert.equal(true, data.properties.aborted, "The aborted flag should be set");
|
||||
Assert.notEqual(undefined, data.properties.responseText, "xhr request's reponse error is stored in part C");
|
||||
Assert.strictEqual("", data.properties.responseText, "Check the status Text");
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: "Ajax: xhr abort is tracked as part C data when enableAjaxErrorStatusText flag is false",
|
||||
test: () => {
|
||||
this._ajax = new AjaxMonitor();
|
||||
let appInsightsCore = new AppInsightsCore();
|
||||
let coreConfig: IConfiguration & IConfig = { instrumentationKey: "abc", disableAjaxTracking: false, enableAjaxErrorStatusText: false };
|
||||
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
|
||||
|
||||
var trackStub = this.sandbox.stub(appInsightsCore, "track");
|
||||
|
||||
// act
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://microsoft.com");
|
||||
xhr.send();
|
||||
|
||||
xhr.abort();
|
||||
|
||||
// assert
|
||||
Assert.ok(trackStub.calledOnce, "track is called");
|
||||
let data = trackStub.args[0][0].baseData;
|
||||
Assert.equal("Ajax", data.type, "request is Ajax type");
|
||||
Assert.equal(0, data.responseCode, "Check the response code");
|
||||
Assert.equal(true, data.properties.aborted, "The aborted flag should be set");
|
||||
Assert.equal(undefined, data.properties.responseText, "xhr request's reponse error is stored in part C");
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: "Ajax: xhr respond with status code zero is tracked as part C data when enableAjaxErrorStatusText flag is true",
|
||||
test: () => {
|
||||
this._ajax = new AjaxMonitor();
|
||||
let appInsightsCore = new AppInsightsCore();
|
||||
let coreConfig: IConfiguration & IConfig = { instrumentationKey: "abc", disableAjaxTracking: false, enableAjaxErrorStatusText: true };
|
||||
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
|
||||
|
||||
var trackStub = this.sandbox.stub(appInsightsCore, "track");
|
||||
|
||||
// act
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://microsoft.com");
|
||||
xhr.send();
|
||||
|
||||
(<any>xhr).respond(0);
|
||||
|
||||
// assert
|
||||
Assert.ok(trackStub.calledOnce, "track is called");
|
||||
let data = trackStub.args[0][0].baseData;
|
||||
Assert.equal("Ajax", data.type, "request is Ajax type");
|
||||
Assert.equal(0, data.responseCode, "Check the response code");
|
||||
Assert.equal(undefined, data.properties.aborted, "The aborted flag should be set");
|
||||
Assert.notEqual(undefined, data.properties.responseText, "xhr request's reponse error is stored in part C");
|
||||
Assert.strictEqual("", data.properties.responseText, "Check the status Text");
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: "Ajax: xhr respond with status code zero is tracked as part C data when enableAjaxErrorStatusText flag is false",
|
||||
test: () => {
|
||||
this._ajax = new AjaxMonitor();
|
||||
let appInsightsCore = new AppInsightsCore();
|
||||
let coreConfig: IConfiguration & IConfig = { instrumentationKey: "abc", disableAjaxTracking: false, enableAjaxErrorStatusText: false };
|
||||
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
|
||||
|
||||
var trackStub = this.sandbox.stub(appInsightsCore, "track");
|
||||
|
||||
// act
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://microsoft.com");
|
||||
xhr.send();
|
||||
|
||||
(<any>xhr).respond(0);
|
||||
|
||||
// assert
|
||||
Assert.ok(trackStub.calledOnce, "track is called");
|
||||
let data = trackStub.args[0][0].baseData;
|
||||
Assert.equal("Ajax", data.type, "request is Ajax type");
|
||||
Assert.equal(0, data.responseCode, "Check the response code");
|
||||
Assert.equal(undefined, data.properties.aborted, "The aborted flag should be set");
|
||||
Assert.equal(undefined, data.properties.responseText, "xhr request's reponse error is stored in part C");
|
||||
}
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Fetch: fetch with disabled flag isn't tracked",
|
||||
stepDelay: 10,
|
||||
|
@ -1042,6 +1154,108 @@ export class AjaxTests extends AITestClass {
|
|||
}]
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Fetch: Respond with status 0 and no status text",
|
||||
stepDelay: 10,
|
||||
autoComplete: false,
|
||||
timeOut: 10000,
|
||||
steps: [ (testContext) => {
|
||||
hookFetch((resolve) => {
|
||||
AITestClass.orgSetTimeout(function() {
|
||||
resolve({
|
||||
headers: new Headers(),
|
||||
ok: true,
|
||||
body: null,
|
||||
bodyUsed: false,
|
||||
redirected: false,
|
||||
status: 0,
|
||||
statusText: "Blocked",
|
||||
trailer: null,
|
||||
type: "basic",
|
||||
url: "https://httpbin.org/status/200"
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
|
||||
this._ajax = new AjaxMonitor();
|
||||
let dependencyFields = hookTrackDependencyInternal(this._ajax);
|
||||
let appInsightsCore = new AppInsightsCore();
|
||||
let coreConfig = { instrumentationKey: "", disableFetchTracking: false };
|
||||
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
|
||||
let fetchSpy = this.sandbox.spy(appInsightsCore, "track")
|
||||
let throwSpy = this.sandbox.spy(appInsightsCore.logger, "throwInternal");
|
||||
|
||||
// Act
|
||||
Assert.ok(fetchSpy.notCalled, "No fetch called yet");
|
||||
fetch("https://httpbin.org/status/200", {method: "post", [DisabledPropertyName]: false}).then(() => {
|
||||
// Assert
|
||||
Assert.ok(fetchSpy.calledOnce, "createFetchRecord called once after using fetch");
|
||||
let data = fetchSpy.args[0][0].baseData;
|
||||
Assert.equal("Fetch", data.type, "request is Fetch type");
|
||||
Assert.ok(throwSpy.notCalled, "Make sure we didn't fail internally");
|
||||
Assert.equal(1, dependencyFields.length, "trackDependencyDataInternal was called");
|
||||
Assert.ok(dependencyFields[0].dependency.startTime, "startTime was specified before trackDependencyDataInternal was called");
|
||||
Assert.equal(0, dependencyFields[0].dependency.responseCode, "Check the response code");
|
||||
Assert.equal(undefined, dependencyFields[0].dependency.properties.responseText);
|
||||
testContext.testDone();
|
||||
}, () => {
|
||||
Assert.ok(false, "fetch failed!");
|
||||
testContext.testDone();
|
||||
});
|
||||
}]
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Fetch: Respond with status 0 and no status text",
|
||||
stepDelay: 10,
|
||||
autoComplete: false,
|
||||
timeOut: 10000,
|
||||
steps: [ (testContext) => {
|
||||
hookFetch((resolve) => {
|
||||
AITestClass.orgSetTimeout(function() {
|
||||
resolve({
|
||||
headers: new Headers(),
|
||||
ok: true,
|
||||
body: null,
|
||||
bodyUsed: false,
|
||||
redirected: false,
|
||||
status: 0,
|
||||
statusText: "Blocked",
|
||||
trailer: null,
|
||||
type: "basic",
|
||||
url: "https://httpbin.org/status/200"
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
|
||||
this._ajax = new AjaxMonitor();
|
||||
let dependencyFields = hookTrackDependencyInternal(this._ajax);
|
||||
let appInsightsCore = new AppInsightsCore();
|
||||
let coreConfig = { instrumentationKey: "", disableFetchTracking: false, enableAjaxErrorStatusText: true };
|
||||
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
|
||||
let fetchSpy = this.sandbox.spy(appInsightsCore, "track")
|
||||
let throwSpy = this.sandbox.spy(appInsightsCore.logger, "throwInternal");
|
||||
|
||||
// Act
|
||||
Assert.ok(fetchSpy.notCalled, "No fetch called yet");
|
||||
fetch("https://httpbin.org/status/200", {method: "post", [DisabledPropertyName]: false}).then(() => {
|
||||
// Assert
|
||||
Assert.ok(fetchSpy.calledOnce, "createFetchRecord called once after using fetch");
|
||||
let data = fetchSpy.args[0][0].baseData;
|
||||
Assert.equal("Fetch", data.type, "request is Fetch type");
|
||||
Assert.ok(throwSpy.notCalled, "Make sure we didn't fail internally");
|
||||
Assert.equal(1, dependencyFields.length, "trackDependencyDataInternal was called");
|
||||
Assert.ok(dependencyFields[0].dependency.startTime, "startTime was specified before trackDependencyDataInternal was called");
|
||||
Assert.equal(0, dependencyFields[0].dependency.responseCode, "Check the response code");
|
||||
Assert.equal("Blocked", dependencyFields[0].dependency!.properties.responseText);
|
||||
testContext.testDone();
|
||||
}, () => {
|
||||
Assert.ok(false, "fetch failed!");
|
||||
testContext.testDone();
|
||||
});
|
||||
}]
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Fetch: fetch addDependencyInitializer adding context",
|
||||
stepDelay: 10,
|
||||
|
@ -2864,7 +3078,12 @@ export class AjaxPerfTrackTests extends AITestClass {
|
|||
.concat(PollingAssert.createPollingAssert(() => {
|
||||
let trackStub = this._context["trackStub"] as SinonStub;
|
||||
if (this._context["fetchComplete"]) {
|
||||
Assert.ok(trackStub.notCalled, "No fetch called yet");
|
||||
Assert.ok(trackStub.calledOnce, "track is called");
|
||||
let data = trackStub.args[0][0].baseData;
|
||||
Assert.equal("Fetch", data.type, "request is Fetch type");
|
||||
let props = data.properties;
|
||||
Assert.notEqual(undefined, props, "Should contain properties");
|
||||
Assert.equal(undefined, props.ajaxPerf, "No performance data should exist");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3200,7 +3419,7 @@ export class AjaxFrozenTests extends AITestClass {
|
|||
return false;
|
||||
}, 'response received', 60, 1000) as any)
|
||||
});
|
||||
|
||||
|
||||
// This is currently a manual test as we don't have hooks / mocks defined to automated this today
|
||||
// this.testCaseAsync({
|
||||
// name: "AjaxFrozenTests: check frozen prototype",
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
@ -32,6 +31,9 @@
|
|||
// Load Common
|
||||
modules.add("@microsoft/applicationinsights-common", "./node_modules/@microsoft/applicationinsights-common/browser/applicationinsights-common");
|
||||
|
||||
// Load Common
|
||||
modules.add("@nevware21/ts-async", "./node_modules/@nevware21/ts-async/dist/es5/umd/ts-async");
|
||||
|
||||
var testModule = modules.add("Tests/Unit/src/dependencies.tests", "./Unit/dist/dependencies.tests.js")
|
||||
testModule.run = function (tests) {
|
||||
console && console.log("Starting tests");
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"ai-restore": "grunt deps-restore"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nevware21/ts-async": "^0.1.0",
|
||||
"@microsoft/ai-test-framework": "0.0.1",
|
||||
"@microsoft/applicationinsights-rollup-plugin-uglify3-js": "1.0.0",
|
||||
"@microsoft/applicationinsights-rollup-es3": "1.1.3",
|
||||
|
|
|
@ -23,6 +23,11 @@ export interface IDependencyInitializerDetails {
|
|||
* The context that the application can assigned via the dependency listener(s)
|
||||
*/
|
||||
context?: { [key: string]: any };
|
||||
|
||||
/**
|
||||
* [Optional] A flag that indicates whether the client request was manually aborted by the `abort()`
|
||||
*/
|
||||
aborted?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,6 +51,13 @@ export interface IDependencyListenerDetails {
|
|||
* [Optional] Context that the application can assign that will also be passed to any dependency initializer
|
||||
*/
|
||||
context?: { [key: string]: any };
|
||||
|
||||
/**
|
||||
* [Optional] A flag that indicates whether the client request was manually aborted by the `abort()`,
|
||||
* as listeners are called just before the request is sent it is unlikely that an application would have
|
||||
* called `abort` before `send` this is also available in the dependency initializer.
|
||||
*/
|
||||
aborted?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,7 +23,7 @@ import { IAjaxRecordResponse, ajaxRecord } from "./ajaxRecord";
|
|||
const AJAX_MONITOR_PREFIX = "ai.ajxmn.";
|
||||
const strDiagLog = "diagLog";
|
||||
const strAjaxData = "ajaxData";
|
||||
const strFetch = "fetch";
|
||||
const STR_FETCH = "fetch";
|
||||
|
||||
const ERROR_HEADER = "Failed to monitor XMLHttpRequest";
|
||||
const ERROR_PREFIX = ", monitoring data for this ajax call ";
|
||||
|
@ -47,11 +47,11 @@ function _supportsFetch(): (input: RequestInfo, init?: RequestInit) => Promise<R
|
|||
if (!_global ||
|
||||
isNullOrUndefined((_global as any).Request) ||
|
||||
isNullOrUndefined((_global as any).Request[strPrototype]) ||
|
||||
isNullOrUndefined(_global[strFetch])) {
|
||||
isNullOrUndefined(_global[STR_FETCH])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _global[strFetch];
|
||||
return _global[STR_FETCH];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +196,8 @@ function _processDependencyListeners(listeners: _IInternalDependencyHandler<Depe
|
|||
traceId: ajaxData.traceID,
|
||||
spanId: ajaxData.spanID,
|
||||
traceFlags: ajaxData.traceFlags,
|
||||
context: ajaxData.context || {}
|
||||
context: ajaxData.context || {},
|
||||
aborted: !!ajaxData.aborted
|
||||
};
|
||||
|
||||
_processDependencyContainer(core, listeners, details, "listener");
|
||||
|
@ -559,7 +560,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
let global = getGlobal();
|
||||
let isPolyfill = (fetch as any).polyfill;
|
||||
if (!_disableFetchTracking && !_fetchInitialized) {
|
||||
_addHook(InstrumentFunc(global, strFetch, {
|
||||
_addHook(InstrumentFunc(global, STR_FETCH, {
|
||||
ns: _evtNamespace,
|
||||
// Add request hook
|
||||
req: (callDetails: IInstrumentCallDetails, input, init) => {
|
||||
|
@ -585,12 +586,12 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
callDetails.rslt = callDetails.rslt.then((response: any) => {
|
||||
_reportFetchMetrics(callDetails, (response||{}).status, input, response, fetchData, () => {
|
||||
let ajaxResponse:IAjaxRecordResponse = {
|
||||
statusText: response.statusText,
|
||||
statusText: (response||{}).statusText,
|
||||
headerMap: null,
|
||||
correlationContext: _getFetchCorrelationContext(response)
|
||||
};
|
||||
|
||||
if (_enableResponseHeaderTracking) {
|
||||
if (_enableResponseHeaderTracking && response) {
|
||||
const responseHeaderMap = {};
|
||||
response.headers.forEach((value: string, name: string) => { // @skip-minify
|
||||
if (_canIncludeHeaders(name)) {
|
||||
|
@ -607,7 +608,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
return response;
|
||||
})
|
||||
.catch((reason: any) => {
|
||||
_reportFetchMetrics(callDetails, 0, input, null, fetchData, null, { error: reason.message });
|
||||
_reportFetchMetrics(callDetails, 0, input, null, fetchData, null, { error: reason.message || dumpObj(reason) });
|
||||
throw reason;
|
||||
});
|
||||
}
|
||||
|
@ -626,7 +627,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
// Note: Polyfill implementations that don't support the "poyyfill" tag are not supported
|
||||
// the workaround is to add a polyfill property to your fetch implementation before initializing
|
||||
// App Insights
|
||||
_addHook(InstrumentFunc(global, strFetch, {
|
||||
_addHook(InstrumentFunc(global, STR_FETCH, {
|
||||
ns: _evtNamespace,
|
||||
req: (callDetails: IInstrumentCallDetails, input, init) => {
|
||||
// Just call so that we record any disabled URL
|
||||
|
@ -638,7 +639,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
if (isPolyfill) {
|
||||
// retag the instrumented fetch with the same polyfill settings this is mostly for testing
|
||||
// But also supports multiple App Insights usages
|
||||
(global[strFetch] as any).polyfill = isPolyfill;
|
||||
(global[STR_FETCH] as any).polyfill = isPolyfill;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1097,7 +1098,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
|
||||
ajaxData.requestHeaders = requestHeaders;
|
||||
|
||||
_createMarkId("fetch", ajaxData);
|
||||
_createMarkId(STR_FETCH, ajaxData);
|
||||
|
||||
return ajaxData;
|
||||
}
|
||||
|
@ -1143,7 +1144,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
ajaxData.responseFinishedTime = dateTimeUtilsNow();
|
||||
ajaxData.status = status;
|
||||
|
||||
_findPerfResourceEntry("fetch", ajaxData, () => {
|
||||
_findPerfResourceEntry(STR_FETCH, ajaxData, () => {
|
||||
const dependency = ajaxData.CreateTrackItem("Fetch", _enableRequestHeaderTracking, getResponse);
|
||||
|
||||
let properties;
|
||||
|
@ -1209,7 +1210,8 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
item: dependency,
|
||||
properties: properties,
|
||||
sysProperties: systemProperties,
|
||||
context: ajaxData ? ajaxData.context : null
|
||||
context: ajaxData ? ajaxData.context : null,
|
||||
aborted: ajaxData ? !!ajaxData.aborted : false
|
||||
};
|
||||
|
||||
result = _processDependencyContainer(core, initializers, details, "initializer");
|
||||
|
|
|
@ -240,7 +240,7 @@ export class ajaxRecord {
|
|||
|
||||
public xhrMonitoringState: XHRMonitoringState;
|
||||
|
||||
// <summary>Determines whether or not JavaScript exception occured in xhr.onreadystatechange code. 1 if occured, otherwise 0.</summary>
|
||||
// <summary>Determines whether or not JavaScript exception occurred in xhr.onreadystatechange code. 1 if occurred, otherwise 0.</summary>
|
||||
public clientFailure: number;
|
||||
|
||||
/**
|
||||
|
@ -339,6 +339,11 @@ export class ajaxRecord {
|
|||
[STR_PROPERTIES]: { HttpMethod: self.method }
|
||||
} as IDependencyTelemetry;
|
||||
|
||||
let props = dependency[STR_PROPERTIES];
|
||||
if (self.aborted) {
|
||||
props.aborted = true;
|
||||
}
|
||||
|
||||
if (self.requestSentTime) {
|
||||
// Set the correct dependency start time
|
||||
dependency.startTime = new Date();
|
||||
|
@ -350,7 +355,6 @@ export class ajaxRecord {
|
|||
|
||||
if (enableRequestHeaderTracking) {
|
||||
if (objKeys(self.requestHeaders).length > 0) {
|
||||
let props = dependency.properties = dependency.properties || {};
|
||||
props.requestHeaders = self.requestHeaders;
|
||||
}
|
||||
}
|
||||
|
@ -367,19 +371,21 @@ export class ajaxRecord {
|
|||
|
||||
if (response.headerMap) {
|
||||
if (objKeys(response.headerMap).length > 0) {
|
||||
let props = dependency.properties = dependency.properties || {};
|
||||
props.responseHeaders = response.headerMap;
|
||||
}
|
||||
}
|
||||
|
||||
if (self.errorStatusText && self.status >= 400) {
|
||||
const responseType = response.type;
|
||||
let props = dependency.properties = dependency.properties || {};
|
||||
if (responseType === "" || responseType === "text") {
|
||||
props.responseText = response.responseText ? response.statusText + " - " + response[strResponseText] : response.statusText;
|
||||
}
|
||||
if (responseType === "json") {
|
||||
props.responseText = response.response ? response.statusText + " - " + JSON.stringify(response.response) : response.statusText;
|
||||
if (self.errorStatusText) {
|
||||
if (self.status >= 400) {
|
||||
const responseType = response.type;
|
||||
if (responseType === "" || responseType === "text") {
|
||||
props.responseText = response.responseText ? response.statusText + " - " + response[strResponseText] : response.statusText;
|
||||
}
|
||||
if (responseType === "json") {
|
||||
props.responseText = response.response ? response.statusText + " - " + JSON.stringify(response.response) : response.statusText;
|
||||
}
|
||||
} else if (self.status === 0) {
|
||||
props.responseText = response.statusText || "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
<!-- <script src="../../../common/Tests/External/require-2.3.6.js"></script> -->
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<script src="../../../common/Tests/External/sinon-2.3.8.js"></script>
|
||||
<script src="../../../common/Tests/External/require-2.3.6.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/ModuleLoader.js"></script>
|
||||
<script src="../../../common/Tests/Selenium/SimpleSyncPromise.js"></script>
|
||||
|
||||
<script>
|
||||
var modules = new ModuleLoader({
|
||||
|
|
Загрузка…
Ссылка в новой задаче