Skip to content

Commit

Permalink
AI Beta: Minor bug fixes and additional debug info (#1787)
Browse files Browse the repository at this point in the history
  • Loading branch information
MSNev committed Mar 21, 2022
1 parent f2d1625 commit 31fc481
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 58 deletions.
114 changes: 78 additions & 36 deletions common/Tests/Framework/src/AITestClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ export class AITestClass {

/** The instance of the currently running suite. */
public static currentTestClass: AITestClass;
public static currentTestInfo: TestCase|TestCaseAsync;
public static currentTestInfo: TestCase | TestCaseAsync;

/** Turns on/off sinon's fake implementation of XMLHttpRequest. On by default. */
public sandboxConfig: any = {};

public static orgSetTimeout: (handler: Function, timeout?: number) => number;
public static orgClearTimeout: (handle?: number) => void;
public static orgSetTimeout: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timeout;
public static orgClearTimeout: (timeoutId: NodeJS.Timeout) => void;
public static orgObjectDefineProperty = Object.defineProperty;

/**** Sinon methods and properties ***/
Expand Down Expand Up @@ -139,14 +139,6 @@ export class AITestClass {
* Use this method to call unload / teardown so the SDK can remove it's own events before being validated
*/
public testFinishedCleanup() {
this._onDoneFuncs.forEach((fn) => {
try {
fn();
} catch (e) {
// Do nothing during cleanup
}
});
this._onDoneFuncs = [];
}

/** Method called after each test method has completed and after the test sandbox has been cleanup up.
Expand Down Expand Up @@ -177,9 +169,20 @@ export class AITestClass {
testInfo.autoComplete = true;
}

if (!testInfo.orgClearTimeout) {
// Set as the real clearTimeout (as _testStarting and enable sinon fake timers)
testInfo.orgClearTimeout = clearTimeout;
}

if (!testInfo.orgSetTimeout) {
// Set as the real setTimeout (as _testStarting and enable sinon fake timers)
testInfo.orgSetTimeout = setTimeout;
}

// Create a wrapper around the test method so we can do test initilization and cleanup.
const testMethod = (assert: any) => {
const done = assert.async();
const self = this;

// Save off the instance of the currently running suite.
AITestClass.currentTestClass = this;
Expand All @@ -189,37 +192,45 @@ export class AITestClass {
const orgClearTimeout = clearTimeout;
const orgSetTimeout = setTimeout;

AITestClass.orgSetTimeout = (handler: Function, timeout?: number) => {
return orgSetTimeout(handler, timeout);
AITestClass.orgSetTimeout = (handler: (...args: any[]) => void, timeout: number, ...args: any[]) => {
if (AITestClass.currentTestInfo && AITestClass.currentTestInfo.orgSetTimeout) {
return AITestClass.currentTestInfo.orgSetTimeout.call(null, handler, timeout, args);
}

orgSetTimeout(handler, timeout, args);
};

AITestClass.orgClearTimeout = (handler: number) => {
orgClearTimeout(handler);
AITestClass.orgClearTimeout = (timeoutId: NodeJS.Timeout) => {
if (AITestClass.currentTestInfo && AITestClass.currentTestInfo.orgClearTimeout) {
AITestClass.currentTestInfo.orgClearTimeout.call(null, timeoutId);
} else {
orgClearTimeout(timeoutId);
}
};

let useFakeServer = testInfo.useFakeServer;
if (useFakeServer === undefined) {
useFakeServer = this.useFakeServer;
useFakeServer = self.useFakeServer;
}

if (useFakeServer) {
this._hookXhr();
self._hookXhr();
}

if (testInfo.useFakeTimers) {
this.clock = sinon.useFakeTimers();
self.clock = sinon.useFakeTimers();
}

if (this.isEmulatingEs3) {
this._emulateEs3();
if (self.isEmulatingEs3) {
self._emulateEs3();
}

if (testInfo.assertNoEvents === undefined) {
testInfo.assertNoEvents = this.assertNoEvents;
testInfo.assertNoEvents = self.assertNoEvents;
}

if (testInfo.assertNoHooks === undefined) {
testInfo.assertNoHooks = this.assertNoHooks;
testInfo.assertNoHooks = self.assertNoHooks;
}

// Run the test.
Expand All @@ -230,12 +241,7 @@ export class AITestClass {
let stepIndex = 0;

const testDone = () => {
this._onDoneFuncs.forEach((fn) => {
fn();
});
this._onDoneFuncs = [];

self.testFinishedCleanup();
self._testFinishedCleanup();

if (testInfo.assertNoEvents) {
self._assertEventsRemoved();
Expand Down Expand Up @@ -337,7 +343,7 @@ export class AITestClass {
} catch (ex) {
console.error("Failed: Unexpected Exception: " + ex);
Assert.ok(false, "Unexpected Exception: " + ex);
this._testCompleted(true);
self._testCompleted(true);

// done is QUnit callback indicating the end of the test
done();
Expand All @@ -358,6 +364,16 @@ export class AITestClass {
throw new Error("Must specify 'test' method in testInfo context in registerTestcase call");
}

if (!testInfo.orgClearTimeout) {
// Set as the real clearTimeout (as _testStarting and enable sinon fake timers)
testInfo.orgClearTimeout = clearTimeout;
}

if (!testInfo.orgSetTimeout) {
// Set as the real setTimeout (as _testStarting and enable sinon fake timers)
testInfo.orgSetTimeout = setTimeout;
}

// Create a wrapper around the test method so we can do test initilization and cleanup.
const testMethod = (assert: any) => {
// Treating all tests as async, so there is no issues with mixing them
Expand All @@ -369,7 +385,7 @@ export class AITestClass {
AITestClass.currentTestInfo = testInfo;

function _testFinished(failed?: boolean) {
self.testFinishedCleanup();
self._testFinishedCleanup();

if (testInfo.assertNoEvents) {
self._assertEventsRemoved();
Expand All @@ -387,12 +403,20 @@ export class AITestClass {
const orgClearTimeout = clearTimeout;
const orgSetTimeout = setTimeout;

AITestClass.orgSetTimeout = (handler: Function, timeout?: number) => {
return orgSetTimeout(handler, timeout);
AITestClass.orgSetTimeout = (handler: (...args: any[]) => void, timeout: number, ...args: any[]) => {
if (AITestClass.currentTestInfo && AITestClass.currentTestInfo.orgSetTimeout) {
return AITestClass.currentTestInfo.orgSetTimeout.call(null, handler, timeout, args);
}

orgSetTimeout(handler, timeout, args);
};

AITestClass.orgClearTimeout = (handler: number) => {
orgClearTimeout(handler);
AITestClass.orgClearTimeout = (timeoutId: NodeJS.Timeout) => {
if (AITestClass.currentTestInfo && AITestClass.currentTestInfo.orgClearTimeout) {
AITestClass.currentTestInfo.orgClearTimeout.call(null, timeoutId);
} else {
orgClearTimeout(timeoutId);
}
};

let useFakeServer = testInfo.useFakeServer;
Expand Down Expand Up @@ -813,8 +837,8 @@ export class AITestClass {
this._assertRemoveHooks(XMLHttpRequest, "XHR");
this._assertRemoveHooks(window, "window");
this._assertRemoveFuncHooks(window.fetch, "fetch");
this._assertRemoveFuncHooks(window.onerror, "onerror");
this._assertRemoveFuncHooks(window.onunhandledrejection, "onunhandledrejection");
this._assertRemoveFuncHooks(window.onerror, "window.onerror");
this._assertRemoveFuncHooks(window.onunhandledrejection, "window.onunhandledrejection");
}

/** Called when the test is starting. */
Expand Down Expand Up @@ -861,6 +885,19 @@ export class AITestClass {
this.testInitialize();
}

private _testFinishedCleanup() {
this._onDoneFuncs.forEach((fn) => {
try {
fn();
} catch (e) {
// Do nothing during cleanup
}
});
this._onDoneFuncs = [];

this.testFinishedCleanup();
}

/** Called when the test is completed. */
private _testCompleted(failed?: boolean) {
this._unhookXhr();
Expand Down Expand Up @@ -901,11 +938,16 @@ export class AITestClass {
(this.sandbox as any).verifyAndRestore();
}

this.sandbox = null;

this.testCleanup();

// Clear the instance of the currently running suite.
AITestClass.currentTestClass = null;
AITestClass.currentTestInfo = null;

AITestClass.orgSetTimeout = null;
AITestClass.orgClearTimeout = null;
}

private _assertRemoveFuncHooks(fn:any, targetName: string) {
Expand Down
7 changes: 7 additions & 0 deletions common/Tests/Framework/src/TestCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export class TestCase {
* Automatically assert that all hooks have been removed
*/
assertNoHooks?: boolean;


orgSetTimeout?: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timeout;
orgClearTimeout?: (timeoutId: NodeJS.Timeout) => void;
}

export const enum StepResult {
Expand Down Expand Up @@ -78,4 +82,7 @@ export interface TestCaseAsync {
* Automatically assert that all hooks have been removed
*/
assertNoHooks?: boolean;

orgSetTimeout?: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timeout;
orgClearTimeout?: (timeoutId: NodeJS.Timeout) => void;
}
1 change: 1 addition & 0 deletions common/Tests/Selenium/ExceptionHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ function ExceptionHelper(config) {
return {
capture: capturePageOnError,
captureStrict: captureStrictPageOnError,
restore: restoreOnError,
throw: throwPageException,
throwCors: throwCorsException,
throwStrict: throwStrictException,
Expand Down
19 changes: 0 additions & 19 deletions common/config/rush/npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions extensions/applicationinsights-dependencies-js/src/ajax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
let isPolyfill = (fetch as any).polyfill;
if (_config.disableFetchTracking === false) {
_addHook(InstrumentFunc(global, strFetch, {
ns: _evtNamespace,
// Add request hook
req: (callDetails: IInstrumentCallDetails, input, init) => {
let fetchData: ajaxRecord;
Expand Down Expand Up @@ -472,6 +473,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
// the workaround is to add a polyfill property to your fetch implementation before initializing
// App Insights
_addHook(InstrumentFunc(global, strFetch, {
ns: _evtNamespace,
req: (callDetails: IInstrumentCallDetails, input, init) => {
// Just call so that we record any disabled URL
_isDisabledRequest(null, input, init);
Expand All @@ -494,6 +496,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
if (_supportsAjaxMonitoring(_self) && !_xhrInitialized) {
// Instrument open
_hookProto(XMLHttpRequest, "open", {
ns: _evtNamespace,
req: (args:IInstrumentCallDetails, method:string, url:string, async?:boolean) => {
let xhr = args.inst as XMLHttpRequestInstrumented;
let ajaxData = xhr[strAjaxData];
Expand All @@ -513,6 +516,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu

// Instrument send
_hookProto(XMLHttpRequest, "send", {
ns: _evtNamespace,
req: (args:IInstrumentCallDetails, context?: Document | BodyInit | null) => {
let xhr = args.inst as XMLHttpRequestInstrumented;
let ajaxData = xhr[strAjaxData];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Assert, AITestClass } from "@microsoft/ai-test-framework";
import * as pako from "pako";

export class AppInsightsCoreSizeCheck extends AITestClass {
private readonly MAX_DEFLATE_SIZE = 17;
private readonly MAX_DEFLATE_SIZE = 18;
private readonly rawFilePath = "../dist/applicationinsights-core-js.min.js";
private readonly prodFilePath = "../browser/applicationinsights-core-js.min.js";

Expand Down
Loading

0 comments on commit 31fc481

Please sign in to comment.