trackPageView improvements for 1DS (#635)
* Add pageTags to IPageViewTelemetry. Add argument CustomProperties to trackPageView API. * increment version for package.json * clean up the confusing code in PageViewManager.trackPageView * add test framework for applicationinsights-analytics. add 1 test to ensure it can run successfully * Stashing changes * fix build errors * update IPageViewTelemetry * bug fixes * code review feedback * update package * fixes
This commit is contained in:
Родитель
7584ac6bbf
Коммит
e1c1c6aead
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "applicationinsights-common",
|
||||
"version": "0.0.49",
|
||||
"version": "0.0.51",
|
||||
"description": "Microsoft Application Insights Common JavaScript Library - AMD version",
|
||||
"main": "./bundle/applicationinsights-common.js",
|
||||
"types": "./bundle/applicationinsights-common.d.ts",
|
||||
|
@ -11,6 +11,6 @@
|
|||
"registry": "https://mseng.pkgs.visualstudio.com/_packaging/ApplicationInsights-Team/npm/registry"
|
||||
},
|
||||
"dependencies": {
|
||||
"applicationinsights-core-js": "0.0.39"
|
||||
"applicationinsights-core-js": "0.0.51"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "applicationinsights-common",
|
||||
"version": "0.0.36",
|
||||
"version": "0.0.38",
|
||||
"description": "Microsoft Application Insights Common JavaScript Library - CommonJs version",
|
||||
"main": "bundle/applicationinsights-common.js",
|
||||
"types": "bundle/applicationinsights-common.d.ts",
|
||||
|
@ -12,9 +12,9 @@
|
|||
"typescript": "2.5.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://mseng.pkgs.visualstudio.com/_packaging/ApplicationInsights-Team/npm/registry"
|
||||
"registry": "https://mseng.pkgs.visualstudio.com/_packaging/ApplicationInsights-Team/npm/registry"
|
||||
},
|
||||
"dependencies": {
|
||||
"applicationinsights-core-js": "0.0.26"
|
||||
"applicationinsights-core-js": "0.0.50"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
"target": "es5",
|
||||
"alwaysStrict": true,
|
||||
"declaration": true,
|
||||
"outDir": "../bundle",
|
||||
"rootDir": "./AppInsightsCommon"
|
||||
"outDir": "./bundle",
|
||||
"rootDir": "./"
|
||||
},
|
||||
"files": []
|
||||
}
|
|
@ -11,6 +11,6 @@
|
|||
"registry": "https://mseng.pkgs.visualstudio.com/_packaging/ApplicationInsights-Team/npm/registry"
|
||||
},
|
||||
"dependencies": {
|
||||
"applicationinsights-core-js": "0.0.39"
|
||||
"applicationinsights-core-js": "0.0.51"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { IPageViewTelemetry } from "./IPageViewTelemetry";
|
||||
|
||||
export interface IAppInsights {
|
||||
trackPageView(pageView: IPageViewTelemetry);
|
||||
trackPageView(pageView: IPageViewTelemetry, customProperties: { [key: string]: any });
|
||||
}
|
|
@ -3,32 +3,37 @@
|
|||
*/
|
||||
export interface IPageViewTelemetry {
|
||||
/*
|
||||
* name The string you used as the name in startTrackPage. Defaults to the document title.
|
||||
* name String - The string you used as the name in startTrackPage. Defaults to the document title.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/*
|
||||
* url String - a relative or absolute URL that identifies the page or other item. Defaults to the window location.
|
||||
*/
|
||||
url: string;
|
||||
name?: string;
|
||||
|
||||
/*
|
||||
* id String - unique identifier for the page view
|
||||
*/
|
||||
id: string;
|
||||
* uri String - a relative or absolute URL that identifies the page or other item. Defaults to the window location.
|
||||
*/
|
||||
uri?: string;
|
||||
|
||||
/*
|
||||
* referrerUri String - source page where current page is loaded from
|
||||
*/
|
||||
referrerUri?: string;
|
||||
|
||||
* refUri String - the URL of the source page where current page is loaded from
|
||||
*/
|
||||
refUri?: string;
|
||||
|
||||
/*
|
||||
* duration number - the number of milliseconds it took to load the page. Defaults to undefined. If set to default value, page load time is calculated internally.
|
||||
*/
|
||||
duration?: number;
|
||||
|
||||
|
||||
/*
|
||||
* properties map[string, any] - additional data used to filter pages and metrics in the portal.
|
||||
* pageType String - page type
|
||||
*/
|
||||
customDimensions?: { [key: string]: any };
|
||||
pageType?: string;
|
||||
|
||||
/*
|
||||
* isLoggedIn - boolean is user logged in
|
||||
*/
|
||||
isLoggedIn?: boolean;
|
||||
|
||||
/*
|
||||
* property bag to contain an extension to domain properties - extension to Part B
|
||||
*/
|
||||
pageTags?: { [key: string]: any };
|
||||
}
|
|
@ -6,7 +6,7 @@ import { IOperation } from './Context/IOperation';
|
|||
import { ISample } from './Context/ISample';
|
||||
import { IUser } from './Context/IUser';
|
||||
import { ISession } from './Context/ISession';
|
||||
import { IEnvelope } from 'applicationinsights-common';
|
||||
import { ITelemetryItem } from 'applicationinsights-core-js';
|
||||
|
||||
export interface ITelemetryContext {
|
||||
/**
|
||||
|
@ -52,5 +52,5 @@ export interface ITelemetryContext {
|
|||
/**
|
||||
* Tracks telemetry object.
|
||||
*/
|
||||
track(envelope: IEnvelope);
|
||||
track(envelope: ITelemetryItem);
|
||||
}
|
|
@ -5,17 +5,17 @@ import {
|
|||
_InternalLogging, LoggingSeverity,
|
||||
_InternalMessageId, Util,
|
||||
Data, Envelope,
|
||||
Trace, PageViewPerformance, PageView }
|
||||
from "applicationinsights-common";
|
||||
Trace, PageViewPerformance, PageView, DataSanitizer
|
||||
} from "applicationinsights-common";
|
||||
|
||||
import { PageViewManager, IAppInsightsInternal } from "./Telemetry/PageViewManager";
|
||||
import { AppInsightsCore, IPlugin, IConfiguration, IAppInsightsCore } from "applicationinsights-core-js";
|
||||
import { AppInsightsCore, IPlugin, IConfiguration, IAppInsightsCore, CoreUtils } from "applicationinsights-core-js";
|
||||
import { TelemetryContext } from "./TelemetryContext";
|
||||
import { PageVisitTimeManager } from "./Telemetry/PageVisitTimeManager";
|
||||
import { IAppInsights } from "../JavascriptSDK.Interfaces/IAppInsights";
|
||||
import { CoreUtils } from "JavaScriptSDK/CoreUtils";
|
||||
import { IPageViewTelemetry } from "../JavascriptSDK.Interfaces/IPageViewTelemetry";
|
||||
import { ITelemetryConfig } from "../JavaScriptSDK.Interfaces/ITelemetryConfig";
|
||||
import { TelemetryItemCreator } from "./TelemetryItemCreator";
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -67,36 +67,20 @@ export class ApplicationInsights implements IAppInsights, IPlugin, IAppInsightsI
|
|||
if (this.config.isStorageUseDisabled) {
|
||||
Util.disableStorage();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs that a page or other item was viewed.
|
||||
* @param IPageViewTelemetry The string you used as the name in startTrackPage. Defaults to the document title.
|
||||
* @param IPageViewTelemetry The string you used as the name in startTrackPage. Defaults to the document title.
|
||||
* @param customProperties Additional data used to filter events and metrics. Defaults to empty.
|
||||
*/
|
||||
public trackPageView(pageView: IPageViewTelemetry) {
|
||||
public trackPageView(pageView: IPageViewTelemetry, customProperties?: { [key: string]: any }) {
|
||||
try {
|
||||
|
||||
let properties: Object = {};
|
||||
let measurements: Object = {};
|
||||
if (pageView.customDimensions) {
|
||||
for (var key in pageView.customDimensions) {
|
||||
if (pageView.customDimensions.hasOwnProperty(key)) {
|
||||
if (typeof pageView.customDimensions[key] === 'number') {
|
||||
measurements[key] = pageView.customDimensions[key];
|
||||
} else {
|
||||
properties[key] = pageView.customDimensions[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._pageViewManager.trackPageView(pageView.name, pageView.url, properties, measurements, pageView.duration);
|
||||
this._pageViewManager.trackPageView(pageView, customProperties);
|
||||
|
||||
if (this.config.autoTrackPageVisitTime) {
|
||||
this._pageVisitTimeManager.trackPreviousPageVisit(pageView.name, pageView.url);
|
||||
this._pageVisitTimeManager.trackPreviousPageVisit(pageView.name, pageView.uri);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
_InternalLogging.throwInternal(
|
||||
LoggingSeverity.CRITICAL,
|
||||
|
@ -106,22 +90,24 @@ export class ApplicationInsights implements IAppInsights, IPlugin, IAppInsightsI
|
|||
}
|
||||
}
|
||||
|
||||
public sendPageViewInternal(name?: string, url?: string, duration?: number, properties?: Object, measurements?: Object) {
|
||||
var pageView = new PageView(name, url, duration, properties, measurements, this.context.operation.id);
|
||||
var data = new Data<PageView>(PageView.dataType, pageView);
|
||||
var envelope = new Envelope(data, PageView.envelopeType);
|
||||
public sendPageViewInternal(pageView: IPageViewTelemetry, properties?: { [key: string]: any }) {
|
||||
let telemetryItem = TelemetryItemCreator.createItem(pageView, PageView.dataType, PageView.envelopeType, properties);
|
||||
|
||||
this.context.track(envelope);
|
||||
this.context.track(telemetryItem);
|
||||
|
||||
// reset ajaxes counter
|
||||
this._trackAjaxAttempts = 0;
|
||||
}
|
||||
|
||||
public sendPageViewPerformanceInternal(pageViewPerformance: PageViewPerformance) {
|
||||
// TODO: Commenting out for now as we this package only supports pageViewTelemetry. Added task
|
||||
// https://mseng.visualstudio.com/AppInsights/_workitems/edit/1310811
|
||||
/*
|
||||
var pageViewPerformanceData = new Data<PageViewPerformance>(
|
||||
PageViewPerformance.dataType, pageViewPerformance);
|
||||
var pageViewPerformanceEnvelope = new Envelope(pageViewPerformanceData, PageViewPerformance.envelopeType);
|
||||
this.context.track(pageViewPerformanceEnvelope);
|
||||
*/
|
||||
}
|
||||
|
||||
private _initialize(config: IConfiguration, core: IAppInsightsCore, extensions: IPlugin[]) {
|
||||
|
@ -147,6 +133,10 @@ export class ApplicationInsights implements IAppInsights, IPlugin, IAppInsightsI
|
|||
|
||||
this._pageViewManager = new PageViewManager(this, this.config.overridePageViewDuration, this._core);
|
||||
|
||||
/*
|
||||
TODO: renable this trackEvent once we support trackEvent in this package. Created task to track this:
|
||||
https://mseng.visualstudio.com/AppInsights/_workitems/edit/1310833
|
||||
|
||||
// initialize event timing
|
||||
this._eventTracking = new Timing("trackEvent");
|
||||
this._eventTracking.action = (name?: string, url?: string, duration?: number, properties?: Object, measurements?: Object) => {
|
||||
|
@ -159,19 +149,29 @@ export class ApplicationInsights implements IAppInsights, IPlugin, IAppInsightsI
|
|||
measurements["duration"] = duration;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var event = new Event(name, properties, measurements);
|
||||
var data = new Data<Event>(Event.dataType, event);
|
||||
var envelope = new Envelope(data, Event.envelopeType);
|
||||
|
||||
this.context.track(envelope);
|
||||
}
|
||||
*/
|
||||
|
||||
/* TODO re-enable once we add support for startTrackPage. Task to track this:
|
||||
https://mseng.visualstudio.com/AppInsights/1DS-Web/_workitems/edit/1305304
|
||||
// initialize page view timing
|
||||
this._pageTracking = new Timing("trackPageView");
|
||||
this._pageTracking.action = (name, url, duration, properties, measurements) => {
|
||||
this.sendPageViewInternal(name, url, duration, properties, measurements);
|
||||
let pageViewItem: IPageViewTelemetry = {
|
||||
name: name,
|
||||
uri: url,
|
||||
duration: duration,
|
||||
};
|
||||
this.sendPageViewInternal(pageViewItem, properties);
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { Envelope } from 'applicationinsights-common';
|
||||
import { ISample } from '../../JavascriptSDK.Interfaces/Context/ISample';
|
||||
import { IEnvelope, _InternalLogging, _InternalMessageId, LoggingSeverity } from 'applicationinsights-common';
|
||||
import { ITelemetryItem } from 'applicationinsights-core-js';
|
||||
|
||||
export class Sample implements ISample {
|
||||
public sampleRate: number;
|
||||
|
@ -26,7 +27,7 @@ export class Sample implements ISample {
|
|||
/**
|
||||
* Determines if an envelope is sampled in (i.e. will be sent) or not (i.e. will be dropped).
|
||||
*/
|
||||
public isSampledIn(envelope: IEnvelope): boolean {
|
||||
public isSampledIn(envelope: ITelemetryItem): boolean {
|
||||
// return true as sampling will move to different extension
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { PageViewData, PageViewPerformance,
|
||||
_InternalLogging, LoggingSeverity,
|
||||
_InternalMessageId, Util, IChannelControlsAI } from 'applicationinsights-common';
|
||||
import { IAppInsightsCore } from 'applicationinsights-core-js';
|
||||
import {
|
||||
PageViewData, PageViewPerformance,
|
||||
_InternalLogging, LoggingSeverity,
|
||||
_InternalMessageId, Util, IChannelControlsAI
|
||||
} from 'applicationinsights-common';
|
||||
import { IAppInsightsCore, CoreUtils } from 'applicationinsights-core-js';
|
||||
import { IPageViewTelemetry } from "../../JavascriptSDK.Interfaces/IPageViewTelemetry";
|
||||
|
||||
/**
|
||||
* Internal interface to pass appInsights object to subcomponents without coupling
|
||||
*/
|
||||
export interface IAppInsightsInternal {
|
||||
sendPageViewInternal(name?: string, url?: string, duration?: number, properties?: Object, measurements?: Object);
|
||||
sendPageViewInternal(pageViewItem: IPageViewTelemetry, properties?: Object);
|
||||
sendPageViewPerformanceInternal(pageViewPerformance: PageViewPerformance);
|
||||
}
|
||||
|
||||
|
@ -37,81 +40,92 @@ export class PageViewManager {
|
|||
/**
|
||||
* Currently supported cases:
|
||||
* 1) (default case) track page view called with default parameters, overridePageViewDuration = false. Page view is sent with page view performance when navigation timing data is available.
|
||||
* If navigation timing is not supported then page view is sent right away with undefined duration. Page view performance is not sent.
|
||||
* a. If navigation timing is not supported then page view is sent right away with undefined duration. Page view performance is not sent.
|
||||
* 2) overridePageViewDuration = true, custom duration provided. Custom duration is used, page view sends right away.
|
||||
* 3) overridePageViewDuration = true. Page view is sent right away, duration is time spent from page load till now (or undefined if navigation timing is not supported).
|
||||
* 3) overridePageViewDuration = true, custom duration NOT provided. Page view is sent right away, duration is time spent from page load till now (or undefined if navigation timing is not supported).
|
||||
* 4) overridePageViewDuration = false, custom duration is provided. Page view is sent right away with custom duration.
|
||||
*
|
||||
* In all cases page view performance is sent once (only for the 1st call of trackPageView), or not sent if navigation timing is not supported.
|
||||
*/
|
||||
public trackPageView(name?: string, url?: string, properties?: Object, measurements?: Object, duration?: number) {
|
||||
// ensure we have valid values for the required fields
|
||||
if (typeof name !== "string") {
|
||||
name = window.document && window.document.title || "";
|
||||
public trackPageView(pageView: IPageViewTelemetry, customProperties?: { [key: string]: any }) {
|
||||
let name = pageView.name;
|
||||
if (CoreUtils.isNullOrUndefined(name) || typeof name !== "string") {
|
||||
pageView.name = window.document && window.document.title || "";
|
||||
}
|
||||
|
||||
if (typeof url !== "string") {
|
||||
url = window.location && window.location.href || "";
|
||||
let uri = pageView.uri;
|
||||
if (CoreUtils.isNullOrUndefined(uri) || typeof uri !== "string") {
|
||||
pageView.uri = window.location && window.location.href || "";
|
||||
}
|
||||
|
||||
var pageViewSent = false;
|
||||
var customDuration = undefined;
|
||||
|
||||
if (PageViewPerformance.isPerformanceTimingSupported()) {
|
||||
var start = PageViewPerformance.getPerformanceTiming().navigationStart;
|
||||
customDuration = PageViewPerformance.getDuration(start, +new Date);
|
||||
|
||||
if (!PageViewPerformance.shouldCollectDuration(customDuration)) {
|
||||
customDuration = undefined;
|
||||
}
|
||||
} else {
|
||||
this.appInsights.sendPageViewInternal(
|
||||
name,
|
||||
url,
|
||||
!isNaN(duration) ? duration : undefined,
|
||||
properties,
|
||||
measurements);
|
||||
this._channel.flush();
|
||||
pageViewSent = true;
|
||||
}
|
||||
|
||||
if (!pageViewSent && (this.overridePageViewDuration || !isNaN(duration))) {
|
||||
// 1, 2, 4 cases
|
||||
this.appInsights.sendPageViewInternal(
|
||||
name,
|
||||
url,
|
||||
!isNaN(duration) ? duration : customDuration,
|
||||
properties,
|
||||
measurements);
|
||||
this._channel.flush();
|
||||
pageViewSent = true;
|
||||
}
|
||||
|
||||
var maxDurationLimit = 60000;
|
||||
|
||||
// case 1a. if performance timing is not supported by the browser, send the page view telemetry with the duration provided by the user. If the user
|
||||
// do not provide the duration, set duration to undefined
|
||||
// Also this is case 4
|
||||
if (!PageViewPerformance.isPerformanceTimingSupported()) {
|
||||
this.appInsights.sendPageViewInternal(
|
||||
pageView,
|
||||
customProperties);
|
||||
this._channel.flush();
|
||||
|
||||
// no navigation timing (IE 8, iOS Safari 8.4, Opera Mini 8 - see http://caniuse.com/#feat=nav-timing)
|
||||
_InternalLogging.throwInternal(
|
||||
LoggingSeverity.WARNING,
|
||||
_InternalMessageId.NavigationTimingNotSupported,
|
||||
"trackPageView: navigation timing API used for calculation of page duration is not supported in this browser. This page view will be collected without duration and timing info.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var pageViewSent = false;
|
||||
var customDuration = undefined;
|
||||
|
||||
// if the performance timing is supported by the browser, calculate the custom duration
|
||||
var start = PageViewPerformance.getPerformanceTiming().navigationStart;
|
||||
customDuration = PageViewPerformance.getDuration(start, +new Date);
|
||||
if (!PageViewPerformance.shouldCollectDuration(customDuration)) {
|
||||
customDuration = undefined;
|
||||
}
|
||||
|
||||
// if the user has provided duration, send a page view telemetry with the provided duration. Otherwise, if
|
||||
// overridePageViewDuration is set to true, send a page view telemetry with the custom duration calculated earlier
|
||||
let duration = pageView.duration
|
||||
if (this.overridePageViewDuration || !isNaN(duration)) {
|
||||
if (isNaN(duration)) {
|
||||
// case 3
|
||||
pageView.duration = customDuration
|
||||
}
|
||||
// case 2
|
||||
this.appInsights.sendPageViewInternal(
|
||||
pageView,
|
||||
customProperties);
|
||||
this._channel.flush();
|
||||
pageViewSent = true;
|
||||
}
|
||||
|
||||
// now try to send the page view performance telemetry
|
||||
var maxDurationLimit = 60000;
|
||||
var handle = setInterval(() => {
|
||||
try {
|
||||
if (PageViewPerformance.isPerformanceTimingDataReady()) {
|
||||
clearInterval(handle);
|
||||
var pageViewPerformance = new PageViewPerformance(name, url, null, properties, measurements);
|
||||
// TODO: For now, sent undefined for measurements in the below code this package only supports pageViewTelemetry. Added task
|
||||
// https://mseng.visualstudio.com/AppInsights/_workitems/edit/1310811
|
||||
var pageViewPerformance = new PageViewPerformance(name, uri, null, customProperties, undefined);
|
||||
|
||||
if (!pageViewPerformance.getIsValid() && !pageViewSent) {
|
||||
// If navigation timing gives invalid numbers, then go back to "override page view duration" mode.
|
||||
// That's the best value we can get that makes sense.
|
||||
this.appInsights.sendPageViewInternal(name, url, customDuration, properties, measurements);
|
||||
pageView.duration = customDuration;
|
||||
this.appInsights.sendPageViewInternal(
|
||||
pageView,
|
||||
customProperties);
|
||||
this._channel.flush();
|
||||
} else {
|
||||
if (!pageViewSent) {
|
||||
this.appInsights.sendPageViewInternal(name, url, pageViewPerformance.getDurationMs(), properties, measurements);
|
||||
pageView.duration = pageViewPerformance.getDurationMs();
|
||||
this.appInsights.sendPageViewInternal(
|
||||
pageView,
|
||||
customProperties);
|
||||
}
|
||||
|
||||
if (!this.pageViewPerformanceSent) {
|
||||
|
@ -120,11 +134,15 @@ export class PageViewManager {
|
|||
}
|
||||
this._channel.flush();
|
||||
}
|
||||
}
|
||||
else if (PageViewPerformance.getDuration(start, +new Date) > maxDurationLimit) {
|
||||
} else if (PageViewPerformance.getDuration(start, +new Date) > maxDurationLimit) {
|
||||
// if performance timings are not ready but we exceeded the maximum duration limit, just log a page view telemetry
|
||||
// with the maximum duration limit. Otherwise, keep waiting until performance timings are ready
|
||||
clearInterval(handle);
|
||||
if (!pageViewSent) {
|
||||
this.appInsights.sendPageViewInternal(name, url, maxDurationLimit, properties, measurements);
|
||||
pageView.duration = maxDurationLimit;
|
||||
this.appInsights.sendPageViewInternal(
|
||||
pageView,
|
||||
customProperties);
|
||||
this._channel.flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import {
|
||||
import {
|
||||
Metric, IEnvelope, ContextTagKeys,
|
||||
RemoteDependencyData, _InternalLogging,
|
||||
RemoteDependencyData, _InternalLogging,
|
||||
_InternalMessageId, LoggingSeverity, Util,
|
||||
Data, PageView } from "applicationinsights-common";
|
||||
Data, PageView
|
||||
} from "applicationinsights-common";
|
||||
import { ITelemetryContext } from '../JavaScriptSDK.Interfaces/ITelemetryContext';
|
||||
import { Application } from './Context/Application';
|
||||
import { Device } from './Context/Device';
|
||||
|
@ -12,7 +13,7 @@ import { Operation } from './Context/Operation';
|
|||
import { Sample } from './Context/Sample';
|
||||
import { User } from './Context/User';
|
||||
import { Session, _SessionManager } from './Context/Session';
|
||||
import { IAppInsightsCore } from "applicationinsights-core-js";
|
||||
import { IAppInsightsCore, ITelemetryItem, CoreUtils } from "applicationinsights-core-js";
|
||||
import { TelemetryItemCreator } from "./TelemetryItemCreator";
|
||||
import { ITelemetryConfig } from "../JavaScriptSDK.Interfaces/ITelemetryConfig";
|
||||
|
||||
|
@ -111,15 +112,15 @@ export class TelemetryContext implements ITelemetryContext {
|
|||
/**
|
||||
* Uses channel to send telemetry object to the endpoint
|
||||
*/
|
||||
public track(envelope: IEnvelope) {
|
||||
if (!envelope) {
|
||||
public track(telemetryItem: ITelemetryItem) {
|
||||
if (CoreUtils.isNullOrUndefined(telemetryItem)) {
|
||||
_InternalLogging.throwInternal(
|
||||
LoggingSeverity.CRITICAL,
|
||||
_InternalMessageId.TrackArgumentsNotSpecified,
|
||||
"cannot call .track() with a null or undefined argument", null, true);
|
||||
} else {
|
||||
// If the envelope is PageView, reset the internal message count so that we can send internal telemetry for the new page.
|
||||
if (envelope.name === PageView.envelopeType) {
|
||||
if (telemetryItem.name === PageView.envelopeType) {
|
||||
_InternalLogging.resetInternalMessageCount();
|
||||
}
|
||||
|
||||
|
@ -130,10 +131,10 @@ export class TelemetryContext implements ITelemetryContext {
|
|||
}
|
||||
}
|
||||
|
||||
this._track(envelope);
|
||||
this._track(telemetryItem);
|
||||
}
|
||||
|
||||
return envelope;
|
||||
return telemetryItem;
|
||||
}
|
||||
|
||||
// Todo: move to separate extension
|
||||
|
@ -159,35 +160,38 @@ export class TelemetryContext implements ITelemetryContext {
|
|||
}
|
||||
}
|
||||
|
||||
private _track(envelope: IEnvelope) {
|
||||
private _track(telemetryItem: ITelemetryItem) {
|
||||
let tagsItem: { [key: string]: any } = {};
|
||||
|
||||
if (this.session) {
|
||||
// If customer set id, apply his context; otherwise apply context generated from cookies
|
||||
if (typeof this.session.id === "string") {
|
||||
this._applySessionContext(envelope, this.session);
|
||||
this._applySessionContext(tagsItem, this.session);
|
||||
} else {
|
||||
this._applySessionContext(envelope, this._sessionManager.automaticSession);
|
||||
this._applySessionContext(tagsItem, this._sessionManager.automaticSession);
|
||||
}
|
||||
}
|
||||
|
||||
this._applyApplicationContext(envelope, this.application);
|
||||
this._applyDeviceContext(envelope, this.device);
|
||||
this._applyInternalContext(envelope, this.internal);
|
||||
this._applyLocationContext(envelope, this.location);
|
||||
this._applySampleContext(envelope, this.sample);
|
||||
this._applyUserContext(envelope, this.user);
|
||||
this._applyOperationContext(envelope, this.operation);
|
||||
// set Part A fields
|
||||
this._applyApplicationContext(tagsItem, this.application);
|
||||
this._applyDeviceContext(tagsItem, this.device);
|
||||
this._applyInternalContext(tagsItem, this.internal);
|
||||
this._applyLocationContext(tagsItem, this.location);
|
||||
this._applySampleContext(tagsItem, this.sample);
|
||||
this._applyUserContext(tagsItem, this.user);
|
||||
this._applyOperationContext(tagsItem, this.operation);
|
||||
telemetryItem.tags.push(tagsItem);
|
||||
|
||||
envelope.iKey = this._config.instrumentationKey();
|
||||
// set instrumentation key
|
||||
telemetryItem.instrumentationKey = this._config.instrumentationKey();
|
||||
|
||||
var doNotSendItem = false;
|
||||
try {
|
||||
|
||||
var telemetryInitializersCount = this._telemetryInitializers.length;
|
||||
for (var i = 0; i < telemetryInitializersCount; ++i) {
|
||||
var telemetryInitializer = this._telemetryInitializers[i];
|
||||
if (telemetryInitializer) {
|
||||
if (telemetryInitializer.apply(null, [envelope]) === false) {
|
||||
if (telemetryInitializer.apply(null, [telemetryItem]) === false) {
|
||||
doNotSendItem = true;
|
||||
break;
|
||||
}
|
||||
|
@ -201,154 +205,151 @@ export class TelemetryContext implements ITelemetryContext {
|
|||
}
|
||||
|
||||
if (!doNotSendItem) {
|
||||
if (envelope.name === Metric.envelopeType ||
|
||||
this.sample.isSampledIn(envelope)) {
|
||||
if (telemetryItem.name === Metric.envelopeType || this.sample.isSampledIn(telemetryItem)) {
|
||||
var iKeyNoDashes = this._config.instrumentationKey().replace(/-/g, "");
|
||||
envelope.name = envelope.name.replace("{0}", iKeyNoDashes);
|
||||
|
||||
let telemetryItem = TelemetryItemCreator.createItem(envelope);
|
||||
telemetryItem.name = telemetryItem.name.replace("{0}", iKeyNoDashes);
|
||||
|
||||
// map and send data
|
||||
this._core.track(telemetryItem);
|
||||
this._core.track(telemetryItem);
|
||||
} else {
|
||||
_InternalLogging.throwInternal(LoggingSeverity.WARNING, _InternalMessageId.TelemetrySampledAndNotSent,
|
||||
"Telemetry is sampled and not sent to the AI service.", { SampleRate: this.sample.sampleRate }, true);
|
||||
}
|
||||
}
|
||||
|
||||
return envelope;
|
||||
return telemetryItem;
|
||||
}
|
||||
|
||||
private _applyApplicationContext(envelope: IEnvelope, appContext: Application) {
|
||||
private _applyApplicationContext(tagsItem: { [key: string]: any }, appContext: Application) {
|
||||
if (appContext) {
|
||||
var tagKeys: ContextTagKeys = new ContextTagKeys();
|
||||
|
||||
if (typeof appContext.ver === "string") {
|
||||
envelope.tags[tagKeys.applicationVersion] = appContext.ver;
|
||||
tagsItem[tagKeys.applicationVersion] = appContext.ver;
|
||||
}
|
||||
if (typeof appContext.build === "string") {
|
||||
envelope.tags[tagKeys.applicationBuild] = appContext.build;
|
||||
tagsItem[tagKeys.applicationBuild] = appContext.build;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _applyDeviceContext(envelope: IEnvelope, deviceContext: Device) {
|
||||
private _applyDeviceContext(tagsItem: { [key: string]: any }, deviceContext: Device) {
|
||||
var tagKeys: ContextTagKeys = new ContextTagKeys();
|
||||
|
||||
if (deviceContext) {
|
||||
if (typeof deviceContext.id === "string") {
|
||||
envelope.tags[tagKeys.deviceId] = deviceContext.id;
|
||||
tagsItem[tagKeys.deviceId] = deviceContext.id;
|
||||
}
|
||||
if (typeof deviceContext.ip === "string") {
|
||||
envelope.tags[tagKeys.deviceIp] = deviceContext.ip;
|
||||
tagsItem[tagKeys.deviceIp] = deviceContext.ip;
|
||||
}
|
||||
if (typeof deviceContext.language === "string") {
|
||||
envelope.tags[tagKeys.deviceLanguage] = deviceContext.language;
|
||||
tagsItem[tagKeys.deviceLanguage] = deviceContext.language;
|
||||
}
|
||||
if (typeof deviceContext.locale === "string") {
|
||||
envelope.tags[tagKeys.deviceLocale] = deviceContext.locale;
|
||||
tagsItem[tagKeys.deviceLocale] = deviceContext.locale;
|
||||
}
|
||||
if (typeof deviceContext.model === "string") {
|
||||
envelope.tags[tagKeys.deviceModel] = deviceContext.model;
|
||||
tagsItem[tagKeys.deviceModel] = deviceContext.model;
|
||||
}
|
||||
if (typeof deviceContext.network !== "undefined") {
|
||||
envelope.tags[tagKeys.deviceNetwork] = deviceContext.network;
|
||||
tagsItem[tagKeys.deviceNetwork] = deviceContext.network;
|
||||
}
|
||||
if (typeof deviceContext.oemName === "string") {
|
||||
envelope.tags[tagKeys.deviceOEMName] = deviceContext.oemName;
|
||||
tagsItem[tagKeys.deviceOEMName] = deviceContext.oemName;
|
||||
}
|
||||
if (typeof deviceContext.os === "string") {
|
||||
envelope.tags[tagKeys.deviceOS] = deviceContext.os;
|
||||
tagsItem[tagKeys.deviceOS] = deviceContext.os;
|
||||
}
|
||||
if (typeof deviceContext.osversion === "string") {
|
||||
envelope.tags[tagKeys.deviceOSVersion] = deviceContext.osversion;
|
||||
tagsItem[tagKeys.deviceOSVersion] = deviceContext.osversion;
|
||||
}
|
||||
if (typeof deviceContext.resolution === "string") {
|
||||
envelope.tags[tagKeys.deviceScreenResolution] = deviceContext.resolution;
|
||||
tagsItem[tagKeys.deviceScreenResolution] = deviceContext.resolution;
|
||||
}
|
||||
if (typeof deviceContext.type === "string") {
|
||||
envelope.tags[tagKeys.deviceType] = deviceContext.type;
|
||||
tagsItem[tagKeys.deviceType] = deviceContext.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _applyInternalContext(envelope: IEnvelope, internalContext: Internal) {
|
||||
private _applyInternalContext(tagsItem: { [key: string]: any }, internalContext: Internal) {
|
||||
if (internalContext) {
|
||||
var tagKeys: ContextTagKeys = new ContextTagKeys();
|
||||
if (typeof internalContext.agentVersion === "string") {
|
||||
envelope.tags[tagKeys.internalAgentVersion] = internalContext.agentVersion;
|
||||
tagsItem[tagKeys.internalAgentVersion] = internalContext.agentVersion;
|
||||
}
|
||||
if (typeof internalContext.sdkVersion === "string") {
|
||||
envelope.tags[tagKeys.internalSdkVersion] = internalContext.sdkVersion;
|
||||
tagsItem[tagKeys.internalSdkVersion] = internalContext.sdkVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _applyLocationContext(envelope: IEnvelope, locationContext: Location) {
|
||||
private _applyLocationContext(tagsItem: { [key: string]: any }, locationContext: Location) {
|
||||
if (locationContext) {
|
||||
var tagKeys: ContextTagKeys = new ContextTagKeys();
|
||||
if (typeof locationContext.ip === "string") {
|
||||
envelope.tags[tagKeys.locationIp] = locationContext.ip;
|
||||
tagsItem[tagKeys.locationIp] = locationContext.ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _applyOperationContext(envelope: IEnvelope, operationContext: Operation) {
|
||||
private _applyOperationContext(tagsItem: { [key: string]: any }, operationContext: Operation) {
|
||||
if (operationContext) {
|
||||
var tagKeys: ContextTagKeys = new ContextTagKeys();
|
||||
if (typeof operationContext.id === "string") {
|
||||
envelope.tags[tagKeys.operationId] = operationContext.id;
|
||||
tagsItem[tagKeys.operationId] = operationContext.id;
|
||||
}
|
||||
if (typeof operationContext.name === "string") {
|
||||
envelope.tags[tagKeys.operationName] = operationContext.name;
|
||||
tagsItem[tagKeys.operationName] = operationContext.name;
|
||||
}
|
||||
if (typeof operationContext.parentId === "string") {
|
||||
envelope.tags[tagKeys.operationParentId] = operationContext.parentId;
|
||||
tagsItem[tagKeys.operationParentId] = operationContext.parentId;
|
||||
}
|
||||
if (typeof operationContext.rootId === "string") {
|
||||
envelope.tags[tagKeys.operationRootId] = operationContext.rootId;
|
||||
tagsItem[tagKeys.operationRootId] = operationContext.rootId;
|
||||
}
|
||||
if (typeof operationContext.syntheticSource === "string") {
|
||||
envelope.tags[tagKeys.operationSyntheticSource] = operationContext.syntheticSource;
|
||||
tagsItem[tagKeys.operationSyntheticSource] = operationContext.syntheticSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _applySampleContext(envelope: IEnvelope, sampleContext: Sample) {
|
||||
private _applySampleContext(tagsItem: { [key: string]: any }, sampleContext: Sample) {
|
||||
if (sampleContext) {
|
||||
envelope.sampleRate = sampleContext.sampleRate;
|
||||
tagsItem.sampleRate = sampleContext.sampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
private _applySessionContext(envelope: IEnvelope, sessionContext: Session) {
|
||||
private _applySessionContext(tags: { [key: string]: any }, sessionContext: Session) {
|
||||
if (sessionContext) {
|
||||
var tagKeys: ContextTagKeys = new ContextTagKeys();
|
||||
if (typeof sessionContext.id === "string") {
|
||||
envelope.tags[tagKeys.sessionId] = sessionContext.id;
|
||||
tags[tagKeys.sessionId] = sessionContext.id;
|
||||
}
|
||||
if (typeof sessionContext.isFirst !== "undefined") {
|
||||
envelope.tags[tagKeys.sessionIsFirst] = sessionContext.isFirst;
|
||||
tags[tagKeys.sessionIsFirst] = sessionContext.isFirst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _applyUserContext(envelope: IEnvelope, userContext: User) {
|
||||
private _applyUserContext(tagsItem: { [key: string]: any }, userContext: User) {
|
||||
if (userContext) {
|
||||
var tagKeys: ContextTagKeys = new ContextTagKeys();
|
||||
if (typeof userContext.accountId === "string") {
|
||||
envelope.tags[tagKeys.userAccountId] = userContext.accountId;
|
||||
tagsItem[tagKeys.userAccountId] = userContext.accountId;
|
||||
}
|
||||
if (typeof userContext.agent === "string") {
|
||||
envelope.tags[tagKeys.userAgent] = userContext.agent;
|
||||
tagsItem[tagKeys.userAgent] = userContext.agent;
|
||||
}
|
||||
if (typeof userContext.id === "string") {
|
||||
envelope.tags[tagKeys.userId] = userContext.id;
|
||||
tagsItem[tagKeys.userId] = userContext.id;
|
||||
}
|
||||
if (typeof userContext.authenticatedId === "string") {
|
||||
envelope.tags[tagKeys.userAuthUserId] = userContext.authenticatedId;
|
||||
tagsItem[tagKeys.userAuthUserId] = userContext.authenticatedId;
|
||||
}
|
||||
if (typeof userContext.storeRegion === "string") {
|
||||
envelope.tags[tagKeys.userStoreRegion] = userContext.storeRegion;
|
||||
tagsItem[tagKeys.userStoreRegion] = userContext.storeRegion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,69 +1,48 @@
|
|||
import { PageView, IEnvelope } from "applicationinsights-common";
|
||||
import { PageView, IEnvelope, Util, DataSanitizer } from "applicationinsights-common";
|
||||
import { ITelemetryItem } from "applicationinsights-core-js";
|
||||
import { CoreUtils } from "JavaScriptSDK/CoreUtils";
|
||||
import { IPageViewTelemetry } from "../JavaScriptSDK.Interfaces/IPageViewTelemetry";
|
||||
|
||||
export interface ITelemetryItemCreator {
|
||||
create(env: IEnvelope) : ITelemetryItem
|
||||
create(pageView: IPageViewTelemetry, baseType: string, envelopeName: string, customProperties?: { [key: string]: any }): ITelemetryItem
|
||||
}
|
||||
|
||||
export class TelemetryItemCreator implements ITelemetryItemCreator {
|
||||
|
||||
private static creator = new TelemetryItemCreator();
|
||||
public static createItem(env: IEnvelope): ITelemetryItem {
|
||||
if (CoreUtils.isNullOrUndefined(env)) {
|
||||
throw Error("Invalid envelope");
|
||||
|
||||
public static createItem(pageView: IPageViewTelemetry, baseType: string, envelopeName: string, customProperties?: { [key: string]: any }): ITelemetryItem {
|
||||
if (CoreUtils.isNullOrUndefined(pageView) ||
|
||||
CoreUtils.isNullOrUndefined(baseType) ||
|
||||
CoreUtils.isNullOrUndefined(envelopeName)) {
|
||||
throw Error("pageView doesn't contain all required fields");
|
||||
};
|
||||
|
||||
return TelemetryItemCreator.creator.create(env);
|
||||
return TelemetryItemCreator.creator.create(pageView, baseType, envelopeName, customProperties);
|
||||
}
|
||||
|
||||
create(env: IEnvelope): ITelemetryItem {
|
||||
if (env.data.baseType === PageView.dataType) {
|
||||
create(pageView: IPageViewTelemetry, baseType: string, envelopeName: string, customProperties?: { [key: string]: any }): ITelemetryItem {
|
||||
envelopeName = DataSanitizer.sanitizeString(envelopeName) || Util.NotSpecified;
|
||||
if (baseType === PageView.dataType) {
|
||||
let item: ITelemetryItem = {
|
||||
name: env.name,
|
||||
timestamp: new Date(env.time),
|
||||
baseType: env.data.baseType,
|
||||
instrumentationKey: env.iKey
|
||||
}
|
||||
name: envelopeName,
|
||||
timestamp: new Date(),
|
||||
instrumentationKey: "", // this will be set in TelemetryContext
|
||||
ctx: {},
|
||||
tags: [],
|
||||
data: {
|
||||
baseType: baseType,
|
||||
baseData: pageView,
|
||||
},
|
||||
};
|
||||
|
||||
item.sytemProperties = {};
|
||||
item.sytemProperties["ver"] = 2;
|
||||
if (env.tags) {
|
||||
for (var property in env.tags) {
|
||||
if (env.tags.hasOwnProperty(property)) {
|
||||
|
||||
item.sytemProperties[property] = env.tags[property]; // part A
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!CoreUtils.isNullOrUndefined(env.data) && !CoreUtils.isNullOrUndefined(env.data.baseData)) {
|
||||
item.domainProperties = {};
|
||||
item.domainProperties["name"] = env.data.baseData.name;
|
||||
item.domainProperties["url"] = env.data.baseData.url;
|
||||
item.domainProperties["duration"] = env.data.baseData.duration;
|
||||
item.domainProperties["id"] = env.data.baseData.id;
|
||||
item.customProperties = {};
|
||||
|
||||
let data = env.data as PageView;
|
||||
let props = data.properties;
|
||||
if (!CoreUtils.isNullOrUndefined(props)) {
|
||||
for (var prop1 in props) {
|
||||
if (props.hasOwnProperty(prop1)) {
|
||||
item.customProperties[prop1] = props[prop1]; // part C
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let measurements = data.measurements;
|
||||
if (!CoreUtils.isNullOrUndefined(measurements)) {
|
||||
for (var prop2 in measurements) {
|
||||
if (measurements.hasOwnProperty(prop2)) {
|
||||
item.customProperties[prop2] = measurements[prop2]; // part C
|
||||
}
|
||||
}
|
||||
// Part C
|
||||
if (!CoreUtils.isNullOrUndefined(customProperties)) {
|
||||
for (var prop in customProperties) {
|
||||
if (customProperties.hasOwnProperty(prop)) {
|
||||
item.data[prop] = customProperties[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/// <reference path="./TestFramework/Common.ts" />
|
||||
/// <reference path="../JavaScriptSDK/ApplicationInsights.ts" />
|
||||
|
||||
import { IConfig, Util } from "applicationinsights-common";
|
||||
import { ApplicationInsights } from "../JavaScriptSDK/ApplicationInsights";
|
||||
|
||||
export class ApplicationInsightsTests extends TestClass {
|
||||
private getAppInsightsSnippet() {
|
||||
var snippet: IConfig = {
|
||||
instrumentationKey: "",
|
||||
endpointUrl: "https://dc.services.visualstudio.com/v2/track",
|
||||
emitLineDelimitedJson: false,
|
||||
accountId: undefined,
|
||||
sessionRenewalMs: 10,
|
||||
sessionExpirationMs: 10,
|
||||
maxBatchSizeInBytes: 1000000,
|
||||
maxBatchInterval: 1,
|
||||
enableDebug: false,
|
||||
disableExceptionTracking: false,
|
||||
disableTelemetry: false,
|
||||
verboseLogging: false,
|
||||
diagnosticLogInterval: 1000,
|
||||
autoTrackPageVisitTime: false,
|
||||
samplingPercentage: 100,
|
||||
disableAjaxTracking: true,
|
||||
overridePageViewDuration: false,
|
||||
maxAjaxCallsPerView: 20,
|
||||
cookieDomain: undefined,
|
||||
disableDataLossAnalysis: true,
|
||||
disableCorrelationHeaders: false,
|
||||
disableFlushOnBeforeUnload: false,
|
||||
enableSessionStorageBuffer: false,
|
||||
isCookieUseDisabled: false,
|
||||
isRetryDisabled: false,
|
||||
isStorageUseDisabled: false,
|
||||
isBeaconApiDisabled: true,
|
||||
appId: undefined,
|
||||
enableCorsCorrelation: false
|
||||
};
|
||||
|
||||
// set default values
|
||||
return snippet;
|
||||
}
|
||||
|
||||
public testInitialize() {
|
||||
this.clock.reset();
|
||||
Util.setCookie('ai_session', "");
|
||||
Util.setCookie('ai_user', "");
|
||||
if (Util.canUseLocalStorage()) {
|
||||
window.localStorage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public testCleanup() {
|
||||
Util.setCookie('ai_session', "");
|
||||
Util.setCookie('ai_user', "");
|
||||
if (Util.canUseLocalStorage()) {
|
||||
window.localStorage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public registerTests() {
|
||||
this.testCase({
|
||||
name: "AppInsightsTests: public members are correct",
|
||||
test: () => {
|
||||
var appInsights = new ApplicationInsights(this.getAppInsightsSnippet());
|
||||
var leTest = (name) => {
|
||||
Assert.ok(name in appInsights, name + " exists");
|
||||
}
|
||||
|
||||
var members = ["config"];
|
||||
while (members.length) {
|
||||
leTest(members.pop());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,44 @@
|
|||
(function myReporter() {
|
||||
|
||||
var reported = false;
|
||||
var a = document.createElement("a");
|
||||
|
||||
document.body.appendChild(a);
|
||||
//your reporter code
|
||||
blanket.customReporter = function (coverage) {
|
||||
blanket.defaultReporter(coverage);
|
||||
|
||||
var styleTags = document.getElementsByTagName("style");
|
||||
|
||||
var styles = "";
|
||||
for (var i = 0; i < styleTags.length; i++) {
|
||||
styles += styleTags[i].outerHTML;
|
||||
}
|
||||
|
||||
var scriptTags = document.getElementsByTagName("body")[0].getElementsByTagName("script");
|
||||
|
||||
var scripts = "";
|
||||
for (var i = 0; i < scriptTags.length; i++) {
|
||||
scripts += scriptTags[i].outerHTML;
|
||||
}
|
||||
|
||||
var title = document.getElementsByTagName("title")[0].text;
|
||||
var documentName = title.replace(/[^\w]/ig, '') + 'Coverage.html';
|
||||
|
||||
var coverageReport = '';
|
||||
coverageReport += '<html>' + '<head>' + styles + "</head><body><h1>" + title.replace(/[^\w\s]/ig, '') + "</h1>" + scripts + document.getElementById("blanket-main").outerHTML + "</body></html>";
|
||||
|
||||
var file = new Blob([coverageReport], { type: 'text/plain' });
|
||||
|
||||
a.href = URL.createObjectURL(file);
|
||||
|
||||
a.download = documentName;
|
||||
|
||||
if (!reported) {
|
||||
a.click();
|
||||
reported = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,723 @@
|
|||
// Type definitions for QUnit 1.10
|
||||
// Project: http://qunitjs.com/
|
||||
// Definitions by: Diullei Gomes <https://github.com/diullei>
|
||||
// DefinitelyTyped: https://github.com/borisyankov/DefinitelyTyped
|
||||
|
||||
|
||||
interface DoneCallbackObject {
|
||||
/**
|
||||
* The number of failed assertions
|
||||
*/
|
||||
failed: number;
|
||||
|
||||
/**
|
||||
* The number of passed assertions
|
||||
*/
|
||||
passed: number;
|
||||
|
||||
/**
|
||||
* The total number of assertions
|
||||
*/
|
||||
total: number;
|
||||
|
||||
/**
|
||||
* The time in milliseconds it took tests to run from start to finish.
|
||||
*/
|
||||
runtime: number;
|
||||
}
|
||||
|
||||
interface LogCallbackObject {
|
||||
/**
|
||||
* The boolean result of an assertion, true means passed, false means failed.
|
||||
*/
|
||||
result: boolean;
|
||||
|
||||
/**
|
||||
* One side of a comparision assertion. Can be undefined when ok() is used.
|
||||
*/
|
||||
actual: Object;
|
||||
|
||||
/**
|
||||
* One side of a comparision assertion. Can be undefined when ok() is used.
|
||||
*/
|
||||
expected: Object;
|
||||
|
||||
/**
|
||||
* A string description provided by the assertion.
|
||||
*/
|
||||
message: string;
|
||||
|
||||
/**
|
||||
* The associated stacktrace, either from an exception or pointing to the source
|
||||
* of the assertion. Depends on browser support for providing stacktraces, so can be
|
||||
* undefined.
|
||||
*/
|
||||
source: string;
|
||||
}
|
||||
|
||||
interface ModuleStartCallbackObject {
|
||||
/**
|
||||
* Name of the next module to run
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ModuleDoneCallbackObject {
|
||||
/**
|
||||
* Name of this module
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The number of failed assertions
|
||||
*/
|
||||
failed: number;
|
||||
|
||||
/**
|
||||
* The number of passed assertions
|
||||
*/
|
||||
passed: number;
|
||||
|
||||
/**
|
||||
* The total number of assertions
|
||||
*/
|
||||
total: number;
|
||||
}
|
||||
|
||||
interface TestDoneCallbackObject {
|
||||
/**
|
||||
* TName of the next test to run
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Name of the current module
|
||||
*/
|
||||
module: string;
|
||||
|
||||
/**
|
||||
* The number of failed assertions
|
||||
*/
|
||||
failed: number;
|
||||
|
||||
/**
|
||||
* The number of passed assertions
|
||||
*/
|
||||
passed: number;
|
||||
|
||||
/**
|
||||
* The total number of assertions
|
||||
*/
|
||||
total: number;
|
||||
|
||||
/**
|
||||
* The total runtime, including setup and teardown
|
||||
*/
|
||||
duration: number;
|
||||
}
|
||||
|
||||
interface TestStartCallbackObject {
|
||||
/**
|
||||
* Name of the next test to run
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Name of the current module
|
||||
*/
|
||||
module: string;
|
||||
}
|
||||
|
||||
interface Config {
|
||||
altertitle: boolean;
|
||||
autostart: boolean;
|
||||
current: Object;
|
||||
reorder: boolean;
|
||||
requireExpects: boolean;
|
||||
testTimeout: number;
|
||||
urlConfig: Array<URLConfigItem>;
|
||||
done: any;
|
||||
}
|
||||
|
||||
interface URLConfigItem {
|
||||
id: string;
|
||||
label: string;
|
||||
tooltip: string;
|
||||
}
|
||||
|
||||
interface LifecycleObject {
|
||||
/**
|
||||
* Runs before each test
|
||||
*/
|
||||
setup?: () => any;
|
||||
|
||||
/**
|
||||
* Runs after each test
|
||||
*/
|
||||
teardown?: () => any;
|
||||
}
|
||||
|
||||
interface QUnitAssert {
|
||||
/* ASSERT */
|
||||
assert: any;
|
||||
current_testEnvironment: any;
|
||||
jsDump: any;
|
||||
|
||||
/**
|
||||
* A deep recursive comparison assertion, working on primitive types, arrays, objects,
|
||||
* regular expressions, dates and functions.
|
||||
*
|
||||
* The deepEqual() assertion can be used just like equal() when comparing the value of
|
||||
* objects, such that { key: value } is equal to { key: value }. For non-scalar values,
|
||||
* identity will be disregarded by deepEqual.
|
||||
*
|
||||
* @param actual Object or Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
deepEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
|
||||
*
|
||||
* The equal assertion uses the simple comparison operator (==) to compare the actual
|
||||
* and expected arguments. When they are equal, the assertion passes: any; otherwise, it fails.
|
||||
* When it fails, both actual and expected values are displayed in the test result,
|
||||
* in addition to a given message.
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
equal(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* An inverted deep recursive comparison assertion, working on primitive types,
|
||||
* arrays, objects, regular expressions, dates and functions.
|
||||
*
|
||||
* The notDeepEqual() assertion can be used just like equal() when comparing the
|
||||
* value of objects, such that { key: value } is equal to { key: value }. For non-scalar
|
||||
* values, identity will be disregarded by notDeepEqual.
|
||||
*
|
||||
* @param actual Object or Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
notDeepEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, checking for inequality.
|
||||
*
|
||||
* The notEqual assertion uses the simple inverted comparison operator (!=) to compare
|
||||
* the actual and expected arguments. When they aren't equal, the assertion passes: any;
|
||||
* otherwise, it fails. When it fails, both actual and expected values are displayed
|
||||
* in the test result, in addition to a given message.
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
notEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
notPropEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
propEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, checking for inequality.
|
||||
*
|
||||
* The notStrictEqual assertion uses the strict inverted comparison operator (!==)
|
||||
* to compare the actual and expected arguments. When they aren't equal, the assertion
|
||||
* passes: any; otherwise, it fails. When it fails, both actual and expected values are
|
||||
* displayed in the test result, in addition to a given message.
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
notStrictEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
|
||||
* Passes if the first argument is truthy.
|
||||
*
|
||||
* The most basic assertion in QUnit, ok() requires just one argument. If the argument
|
||||
* evaluates to true, the assertion passes; otherwise, it fails. If a second message
|
||||
* argument is provided, it will be displayed in place of the result.
|
||||
*
|
||||
* @param state Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
ok(state: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A strict type and value comparison assertion.
|
||||
*
|
||||
* The strictEqual() assertion provides the most rigid comparison of type and value with
|
||||
* the strict equality operator (===)
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
strictEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* Assertion to test if a callback throws an exception when run.
|
||||
*
|
||||
* When testing code that is expected to throw an exception based on a specific set of
|
||||
* circumstances, use throws() to catch the error object for testing and comparison.
|
||||
*
|
||||
* @param block Function to execute
|
||||
* @param expected Error Object to compare
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
throws(block: () => any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* @param block Function to execute
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
throws(block: () => any, message?: string): any;
|
||||
}
|
||||
|
||||
interface QUnitStatic extends QUnitAssert{
|
||||
/* ASYNC CONTROL */
|
||||
|
||||
/**
|
||||
* Start running tests again after the testrunner was stopped. See stop().
|
||||
*
|
||||
* When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
|
||||
*
|
||||
* @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
|
||||
*/
|
||||
start(decrement?: number): any;
|
||||
|
||||
/**
|
||||
* Stop the testrunner to wait for async tests to run. Call start() to continue.
|
||||
*
|
||||
* When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
|
||||
*
|
||||
* On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
|
||||
*
|
||||
* @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
|
||||
*/
|
||||
stop(increment? : number): any;
|
||||
|
||||
/* CALLBACKS */
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever the test suite begins.
|
||||
*
|
||||
* QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
|
||||
* but thats already in use elsewhere and can't be changed.)
|
||||
*
|
||||
* @param callback Callback to execute
|
||||
*/
|
||||
begin(callback: () => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever the test suite ends.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
done(callback: (details: DoneCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever an assertion completes.
|
||||
*
|
||||
* This is one of several callbacks QUnit provides. Its intended for integration scenarios like
|
||||
* PhantomJS or Jenkins. The properties of the details argument are listed below as options.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
log(callback: (details: LogCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a module ends.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
moduleDone(callback: (details: ModuleDoneCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a module begins.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
moduleStart(callback: (details: ModuleStartCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a test ends.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
testDone(callback: (details: TestDoneCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a test begins.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
testStart(callback: (details: TestStartCallbackObject) => any): any;
|
||||
|
||||
/* CONFIGURATION */
|
||||
|
||||
/**
|
||||
* QUnit has a bunch of internal configuration defaults, some of which are
|
||||
* useful to override. Check the description for each option for details.
|
||||
*/
|
||||
config: Config;
|
||||
|
||||
/* TEST */
|
||||
|
||||
/**
|
||||
* Add an asynchronous test to run. The test must include a call to start().
|
||||
*
|
||||
* For testing asynchronous code, asyncTest will automatically stop the test runner
|
||||
* and wait for your code to call start() to continue.
|
||||
*
|
||||
* @param name Title of unit being tested
|
||||
* @param expected Number of assertions in this test
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
asyncTest(name: string, expected: number, test: () => any): any;
|
||||
|
||||
/**
|
||||
* Add an asynchronous test to run. The test must include a call to start().
|
||||
*
|
||||
* For testing asynchronous code, asyncTest will automatically stop the test runner
|
||||
* and wait for your code to call start() to continue.
|
||||
*
|
||||
* @param name Title of unit being tested
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
asyncTest(name: string, test: () => any): any;
|
||||
|
||||
/**
|
||||
* Specify how many assertions are expected to run within a test.
|
||||
*
|
||||
* To ensure that an explicit number of assertions are run within any test, use
|
||||
* expect( number ) to register an expected count. If the number of assertions
|
||||
* run does not match the expected count, the test will fail.
|
||||
*
|
||||
* @param amount Number of assertions in this test.
|
||||
*/
|
||||
expect(amount: number): any;
|
||||
|
||||
/**
|
||||
* Group related tests under a single label.
|
||||
*
|
||||
* All tests that occur after a call to module() will be grouped into that module.
|
||||
* The test names will all be preceded by the module name in the test results.
|
||||
* You can then use that module name to select tests to run.
|
||||
*
|
||||
* @param name Label for this group of tests
|
||||
* @param lifecycle Callbacks to run before and after each test
|
||||
*/
|
||||
module(name: string, lifecycle?: LifecycleObject): any;
|
||||
|
||||
/**
|
||||
* Add a test to run.
|
||||
*
|
||||
* When testing the most common, synchronous code, use test().
|
||||
* The assert argument to the callback contains all of QUnit's assertion methods.
|
||||
* If you are avoiding using any of QUnit's globals, you can use the assert
|
||||
* argument instead.
|
||||
*
|
||||
* @param title Title of unit being tested
|
||||
* @param expected Number of assertions in this test
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
test(title: string, expected: number, test: (assert: QUnitAssert) => any): any;
|
||||
|
||||
/**
|
||||
* @param title Title of unit being tested
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
test(title: string, test: (assert: QUnitAssert) => any): any;
|
||||
|
||||
/**
|
||||
* https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
|
||||
*/
|
||||
equiv(a: any, b: any): any;
|
||||
|
||||
// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
|
||||
raises: any;
|
||||
|
||||
/**
|
||||
* https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L897
|
||||
*/
|
||||
push(result: any, actual: any, expected: any, message: string): any;
|
||||
|
||||
/**
|
||||
* https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L839
|
||||
*/
|
||||
reset(): any;
|
||||
}
|
||||
|
||||
/* ASSERT */
|
||||
|
||||
/**
|
||||
* A deep recursive comparison assertion, working on primitive types, arrays, objects,
|
||||
* regular expressions, dates and functions.
|
||||
*
|
||||
* The deepEqual() assertion can be used just like equal() when comparing the value of
|
||||
* objects, such that { key: value } is equal to { key: value }. For non-scalar values,
|
||||
* identity will be disregarded by deepEqual.
|
||||
*
|
||||
* @param actual Object or Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function deepEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
|
||||
*
|
||||
* The equal assertion uses the simple comparison operator (==) to compare the actual
|
||||
* and expected arguments. When they are equal, the assertion passes: any; otherwise, it fails.
|
||||
* When it fails, both actual and expected values are displayed in the test result,
|
||||
* in addition to a given message.
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function equal(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* An inverted deep recursive comparison assertion, working on primitive types,
|
||||
* arrays, objects, regular expressions, dates and functions.
|
||||
*
|
||||
* The notDeepEqual() assertion can be used just like equal() when comparing the
|
||||
* value of objects, such that { key: value } is equal to { key: value }. For non-scalar
|
||||
* values, identity will be disregarded by notDeepEqual.
|
||||
*
|
||||
* @param actual Object or Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function notDeepEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, checking for inequality.
|
||||
*
|
||||
* The notEqual assertion uses the simple inverted comparison operator (!=) to compare
|
||||
* the actual and expected arguments. When they aren't equal, the assertion passes;
|
||||
* otherwise, it fails. When it fails, both actual and expected values are displayed
|
||||
* in the test result, in addition to a given message.
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function notEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, checking for inequality.
|
||||
*
|
||||
* The notStrictEqual assertion uses the strict inverted comparison operator (!==)
|
||||
* to compare the actual and expected arguments. When they aren't equal, the assertion
|
||||
* passes; otherwise, it fails. When it fails, both actual and expected values are
|
||||
* displayed in the test result, in addition to a given message.
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function notStrictEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
|
||||
* Passes if the first argument is truthy.
|
||||
*
|
||||
* The most basic assertion in QUnit, ok() requires just one argument. If the argument
|
||||
* evaluates to true, the assertion passes; otherwise, it fails. If a second message
|
||||
* argument is provided, it will be displayed in place of the result.
|
||||
*
|
||||
* @param state Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function ok(state: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* A strict type and value comparison assertion.
|
||||
*
|
||||
* The strictEqual() assertion provides the most rigid comparison of type and value with
|
||||
* the strict equality operator (===)
|
||||
*
|
||||
* @param actual Expression being tested
|
||||
* @param expected Known comparison value
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function strictEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* Assertion to test if a callback throws an exception when run.
|
||||
*
|
||||
* When testing code that is expected to throw an exception based on a specific set of
|
||||
* circumstances, use throws() to catch the error object for testing and comparison.
|
||||
*
|
||||
* @param block Function to execute
|
||||
* @param expected Error Object to compare
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function throws(block: () => any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* @param block Function to execute
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
declare function throws(block: () => any, message?: string): any;
|
||||
|
||||
/* ASYNC CONTROL */
|
||||
|
||||
/**
|
||||
* Start running tests again after the testrunner was stopped. See stop().
|
||||
*
|
||||
* When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
|
||||
*
|
||||
* @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
|
||||
*/
|
||||
declare function start(decrement?: number): any;
|
||||
|
||||
/**
|
||||
* Stop the testrunner to wait for async tests to run. Call start() to continue.
|
||||
*
|
||||
* When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
|
||||
*
|
||||
* On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
|
||||
*
|
||||
* @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
|
||||
*/
|
||||
declare function stop(increment? : number): any;
|
||||
|
||||
/* CALLBACKS */
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever the test suite begins.
|
||||
*
|
||||
* QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
|
||||
* but thats already in use elsewhere and can't be changed.)
|
||||
*
|
||||
* @param callback Callback to execute
|
||||
*/
|
||||
declare function begin(callback: () => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever the test suite ends.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
declare function done(callback: (details: DoneCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever an assertion completes.
|
||||
*
|
||||
* This is one of several callbacks QUnit provides. Its intended for integration scenarios like
|
||||
* PhantomJS or Jenkins. The properties of the details argument are listed below as options.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
declare function log(callback: (details: LogCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a module ends.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
declare function moduleDone(callback: (details: ModuleDoneCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a module begins.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
declare function moduleStart(callback: (name: string) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a test ends.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
declare function testDone(callback: (details: TestDoneCallbackObject) => any): any;
|
||||
|
||||
/**
|
||||
* Register a callback to fire whenever a test begins.
|
||||
*
|
||||
* @param callback Callback to execute.
|
||||
*/
|
||||
declare function testStart(callback: (details: TestStartCallbackObject) => any): any;
|
||||
|
||||
/* TEST */
|
||||
|
||||
/**
|
||||
* Add an asynchronous test to run. The test must include a call to start().
|
||||
*
|
||||
* For testing asynchronous code, asyncTest will automatically stop the test runner
|
||||
* and wait for your code to call start() to continue.
|
||||
*
|
||||
* @param name Title of unit being tested
|
||||
* @param expected Number of assertions in this test
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
declare function asyncTest(name: string, expected?: any, test?: () => any): any;
|
||||
|
||||
/**
|
||||
* Add an asynchronous test to run. The test must include a call to start().
|
||||
*
|
||||
* For testing asynchronous code, asyncTest will automatically stop the test runner
|
||||
* and wait for your code to call start() to continue.
|
||||
*
|
||||
* @param name Title of unit being tested
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
declare function asyncTest(name: string, test: () => any): any;
|
||||
|
||||
/**
|
||||
* Specify how many assertions are expected to run within a test.
|
||||
*
|
||||
* To ensure that an explicit number of assertions are run within any test, use
|
||||
* expect( number ) to register an expected count. If the number of assertions
|
||||
* run does not match the expected count, the test will fail.
|
||||
*
|
||||
* @param amount Number of assertions in this test.
|
||||
*/
|
||||
declare function expect(amount: number): any;
|
||||
|
||||
// ** conflict with TypeScript module keyword. Must be used on QUnit namespace
|
||||
//declare var module: (name: string, lifecycle?: LifecycleObject) => any;
|
||||
|
||||
/**
|
||||
* Add a test to run.
|
||||
*
|
||||
* When testing the most common, synchronous code, use test().
|
||||
* The assert argument to the callback contains all of QUnit's assertion methods.
|
||||
* If you are avoiding using any of QUnit's globals, you can use the assert
|
||||
* argument instead.
|
||||
*
|
||||
* @param title Title of unit being tested
|
||||
* @param expected Number of assertions in this test
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
declare function test(title: string, expected: number, test: (assert?: QUnitAssert) => any): any;
|
||||
|
||||
/**
|
||||
* @param title Title of unit being tested
|
||||
* @param test Function to close over assertions
|
||||
*/
|
||||
declare function test(title: string, test: (assert?: QUnitAssert) => any): any;
|
||||
|
||||
declare function notPropEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
declare function propEqual(actual: any, expected: any, message?: string): any;
|
||||
|
||||
// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
|
||||
declare function equiv(a: any, b: any): any;
|
||||
|
||||
// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
|
||||
declare var raises: any;
|
||||
|
||||
/* QUNIT */
|
||||
declare var QUnit: QUnitStatic;
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,434 @@
|
|||
// Type definitions for Sinon 1.16.0
|
||||
// Project: http://sinonjs.org/
|
||||
// Definitions by: William Sears <https://github.com/mrbigdog2u>
|
||||
// Definitions: https://github.com/borisyankov/DefinitelyTyped
|
||||
|
||||
|
||||
interface SinonSpyCallApi {
|
||||
// Properties
|
||||
thisValue: any;
|
||||
args: any[];
|
||||
exception: any;
|
||||
returnValue: any;
|
||||
|
||||
// Methods
|
||||
calledOn(obj: any): boolean;
|
||||
calledWith(...args: any[]): boolean;
|
||||
calledWithExactly(...args: any[]): boolean;
|
||||
calledWithMatch(...args: any[]): boolean;
|
||||
notCalledWith(...args: any[]): boolean;
|
||||
notCalledWithMatch(...args: any[]): boolean;
|
||||
returned(value: any): boolean;
|
||||
threw(): boolean;
|
||||
threw(type: string): boolean;
|
||||
threw(obj: any): boolean;
|
||||
callArg(pos: number): void;
|
||||
callArgOn(pos: number, obj: any, ...args: any[]): void;
|
||||
callArgWith(pos: number, ...args: any[]): void;
|
||||
callArgOnWith(pos: number, obj: any, ...args: any[]): void;
|
||||
yield(...args: any[]): void;
|
||||
yieldOn(obj: any, ...args: any[]): void;
|
||||
yieldTo(property: string, ...args: any[]): void;
|
||||
yieldToOn(property: string, obj: any, ...args: any[]): void;
|
||||
}
|
||||
|
||||
interface SinonSpyCall extends SinonSpyCallApi {
|
||||
calledBefore(call: SinonSpyCall): boolean;
|
||||
calledAfter(call: SinonSpyCall): boolean;
|
||||
calledWithNew(call: SinonSpyCall): boolean;
|
||||
}
|
||||
|
||||
interface SinonSpy extends SinonSpyCallApi {
|
||||
// Properties
|
||||
callCount: number;
|
||||
called: boolean;
|
||||
notCalled: boolean;
|
||||
calledOnce: boolean;
|
||||
calledTwice: boolean;
|
||||
calledThrice: boolean;
|
||||
firstCall: SinonSpyCall;
|
||||
secondCall: SinonSpyCall;
|
||||
thirdCall: SinonSpyCall;
|
||||
lastCall: SinonSpyCall;
|
||||
thisValues: any[];
|
||||
args: any[][];
|
||||
exceptions: any[];
|
||||
returnValues: any[];
|
||||
|
||||
// Methods
|
||||
(...args: any[]): any;
|
||||
calledBefore(anotherSpy: SinonSpy): boolean;
|
||||
calledAfter(anotherSpy: SinonSpy): boolean;
|
||||
calledWithNew(spy: SinonSpy): boolean;
|
||||
withArgs(...args: any[]): SinonSpy;
|
||||
alwaysCalledOn(obj: any): boolean;
|
||||
alwaysCalledWith(...args: any[]): boolean;
|
||||
alwaysCalledWithExactly(...args: any[]): boolean;
|
||||
alwaysCalledWithMatch(...args: any[]): boolean;
|
||||
neverCalledWith(...args: any[]): boolean;
|
||||
neverCalledWithMatch(...args: any[]): boolean;
|
||||
alwaysThrew(): boolean;
|
||||
alwaysThrew(type: string): boolean;
|
||||
alwaysThrew(obj: any): boolean;
|
||||
alwaysReturned(): boolean;
|
||||
invokeCallback(...args: any[]): void;
|
||||
getCall(n: number): SinonSpyCall;
|
||||
reset(): void;
|
||||
printf(format: string, ...args: any[]): string;
|
||||
restore(): void;
|
||||
}
|
||||
|
||||
interface SinonSpyStatic {
|
||||
(): SinonSpy;
|
||||
(func: any): SinonSpy;
|
||||
(obj: any, method: string): SinonSpy;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
spy: SinonSpyStatic;
|
||||
}
|
||||
|
||||
interface SinonStub extends SinonSpy {
|
||||
resetBehavior(): void;
|
||||
returns(obj: any): SinonStub;
|
||||
returnsArg(index: number): SinonStub;
|
||||
throws(type?: string): SinonStub;
|
||||
throws(obj: any): SinonStub;
|
||||
callsArg(index: number): SinonStub;
|
||||
callsArgOn(index: number, context: any): SinonStub;
|
||||
callsArgWith(index: number, ...args: any[]): SinonStub;
|
||||
callsArgOnWith(index: number, context: any, ...args: any[]): SinonStub;
|
||||
callsArgAsync(index: number): SinonStub;
|
||||
callsArgOnAsync(index: number, context: any): SinonStub;
|
||||
callsArgWithAsync(index: number, ...args: any[]): SinonStub;
|
||||
callsArgOnWithAsync(index: number, context: any, ...args: any[]): SinonStub;
|
||||
onCall(n: number): SinonStub;
|
||||
onFirstCall(): SinonStub;
|
||||
onSecondCall(): SinonStub;
|
||||
onThirdCall(): SinonStub;
|
||||
yields(...args: any[]): SinonStub;
|
||||
yieldsOn(context: any, ...args: any[]): SinonStub;
|
||||
yieldsTo(property: string, ...args: any[]): SinonStub;
|
||||
yieldsToOn(property: string, context: any, ...args: any[]): SinonStub;
|
||||
yieldsAsync(...args: any[]): SinonStub;
|
||||
yieldsOnAsync(context: any, ...args: any[]): SinonStub;
|
||||
yieldsToAsync(property: string, ...args: any[]): SinonStub;
|
||||
yieldsToOnAsync(property: string, context: any, ...args: any[]): SinonStub;
|
||||
withArgs(...args: any[]): SinonStub;
|
||||
}
|
||||
|
||||
interface SinonStubStatic {
|
||||
(): SinonStub;
|
||||
(obj: any): SinonStub;
|
||||
(obj: any, method: string): SinonStub;
|
||||
(obj: any, method: string, func: any): SinonStub;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
stub: SinonStubStatic;
|
||||
}
|
||||
|
||||
interface SinonExpectation extends SinonStub {
|
||||
atLeast(n: number): SinonExpectation;
|
||||
atMost(n: number): SinonExpectation;
|
||||
never(): SinonExpectation;
|
||||
once(): SinonExpectation;
|
||||
twice(): SinonExpectation;
|
||||
thrice(): SinonExpectation;
|
||||
exactly(n: number): SinonExpectation;
|
||||
withArgs(...args: any[]): SinonExpectation;
|
||||
withExactArgs(...args: any[]): SinonExpectation;
|
||||
on(obj: any): SinonExpectation;
|
||||
verify(): SinonExpectation;
|
||||
restore(): void;
|
||||
}
|
||||
|
||||
interface SinonExpectationStatic {
|
||||
create(methodName?: string): SinonExpectation;
|
||||
}
|
||||
|
||||
interface SinonMock {
|
||||
expects(method: string): SinonExpectation;
|
||||
restore(): void;
|
||||
verify(): void;
|
||||
}
|
||||
|
||||
interface SinonMockStatic {
|
||||
(): SinonExpectation;
|
||||
(obj: any): SinonMock;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
expectation: SinonExpectationStatic;
|
||||
mock: SinonMockStatic;
|
||||
}
|
||||
|
||||
interface SinonFakeTimers {
|
||||
now: number;
|
||||
create(now: number): SinonFakeTimers;
|
||||
setTimeout(callback: (...args: any[]) => void, timeout: number, ...args: any[]): number;
|
||||
clearTimeout(id: number): void;
|
||||
setInterval(callback: (...args: any[]) => void, timeout: number, ...args: any[]): number;
|
||||
clearInterval(id: number): void;
|
||||
tick(ms: number): number;
|
||||
reset(): void;
|
||||
Date(): Date;
|
||||
Date(year: number): Date;
|
||||
Date(year: number, month: number): Date;
|
||||
Date(year: number, month: number, day: number): Date;
|
||||
Date(year: number, month: number, day: number, hour: number): Date;
|
||||
Date(year: number, month: number, day: number, hour: number, minute: number): Date;
|
||||
Date(year: number, month: number, day: number, hour: number, minute: number, second: number): Date;
|
||||
Date(year: number, month: number, day: number, hour: number, minute: number, second: number, ms: number): Date;
|
||||
restore(): void;
|
||||
|
||||
/**
|
||||
* Simulate the user changing the system clock while your program is running. It changes the 'now' timestamp
|
||||
* without affecting timers, intervals or immediates.
|
||||
* @param now The new 'now' in unix milliseconds
|
||||
*/
|
||||
setSystemTime(now: number): void;
|
||||
/**
|
||||
* Simulate the user changing the system clock while your program is running. It changes the 'now' timestamp
|
||||
* without affecting timers, intervals or immediates.
|
||||
* @param now The new 'now' as a JavaScript Date
|
||||
*/
|
||||
setSystemTime(date: Date): void;
|
||||
}
|
||||
|
||||
interface SinonFakeTimersStatic {
|
||||
(): SinonFakeTimers;
|
||||
(...timers: string[]): SinonFakeTimers;
|
||||
(now: number, ...timers: string[]): SinonFakeTimers;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
useFakeTimers: SinonFakeTimersStatic;
|
||||
clock: SinonFakeTimers;
|
||||
}
|
||||
|
||||
interface SinonFakeUploadProgress {
|
||||
eventListeners: {
|
||||
progress: any[];
|
||||
load: any[];
|
||||
abort: any[];
|
||||
error: any[];
|
||||
};
|
||||
|
||||
addEventListener(event: string, listener: (e: Event) => any): void;
|
||||
removeEventListener(event: string, listener: (e: Event) => any): void;
|
||||
dispatchEvent(event: Event): void;
|
||||
}
|
||||
|
||||
interface SinonFakeXMLHttpRequest {
|
||||
// Properties
|
||||
onCreate: (xhr: SinonFakeXMLHttpRequest) => void;
|
||||
url: string;
|
||||
method: string;
|
||||
requestHeaders: any;
|
||||
requestBody: string;
|
||||
status: number;
|
||||
statusText: string;
|
||||
async: boolean;
|
||||
username: string;
|
||||
password: string;
|
||||
withCredentials: boolean;
|
||||
upload: SinonFakeUploadProgress;
|
||||
responseXML: Document;
|
||||
getResponseHeader(header: string): string;
|
||||
getAllResponseHeaders(): any;
|
||||
|
||||
// Methods
|
||||
restore(): void;
|
||||
useFilters: boolean;
|
||||
addFilter(filter: (method: string, url: string, async: boolean, username: string, password: string) => boolean): void;
|
||||
setResponseHeaders(headers: any): void;
|
||||
setResponseBody(body: string): void;
|
||||
respond(status: number, headers: any, body: string): void;
|
||||
autoRespond(ms: number): void;
|
||||
}
|
||||
|
||||
interface SinonFakeXMLHttpRequestStatic {
|
||||
(): SinonFakeXMLHttpRequest;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
useFakeXMLHttpRequest: SinonFakeXMLHttpRequestStatic;
|
||||
FakeXMLHttpRequest: SinonFakeXMLHttpRequest;
|
||||
}
|
||||
|
||||
interface SinonFakeServer {
|
||||
// Properties
|
||||
autoRespond: boolean;
|
||||
autoRespondAfter: number;
|
||||
fakeHTTPMethods: boolean;
|
||||
getHTTPMethod: (request: SinonFakeXMLHttpRequest) => string;
|
||||
requests: SinonFakeXMLHttpRequest[];
|
||||
respondImmediately: boolean;
|
||||
|
||||
// Methods
|
||||
respondWith(body: string): void;
|
||||
respondWith(response: any[]): void;
|
||||
respondWith(fn: (xhr: SinonFakeXMLHttpRequest) => void): void;
|
||||
respondWith(url: string, body: string): void;
|
||||
respondWith(url: string, response: any[]): void;
|
||||
respondWith(url: string, fn: (xhr: SinonFakeXMLHttpRequest) => void): void;
|
||||
respondWith(method: string, url: string, body: string): void;
|
||||
respondWith(method: string, url: string, response: any[]): void;
|
||||
respondWith(method: string, url: string, fn: (xhr: SinonFakeXMLHttpRequest) => void): void;
|
||||
respondWith(url: RegExp, body: string): void;
|
||||
respondWith(url: RegExp, response: any[]): void;
|
||||
respondWith(url: RegExp, fn: (xhr: SinonFakeXMLHttpRequest) => void): void;
|
||||
respondWith(method: string, url: RegExp, body: string): void;
|
||||
respondWith(method: string, url: RegExp, response: any[]): void;
|
||||
respondWith(method: string, url: RegExp, fn: (xhr: SinonFakeXMLHttpRequest) => void): void;
|
||||
respond(): void;
|
||||
restore(): void;
|
||||
}
|
||||
|
||||
interface SinonFakeServerStatic {
|
||||
create(): SinonFakeServer;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
fakeServer: SinonFakeServerStatic;
|
||||
fakeServerWithClock: SinonFakeServerStatic;
|
||||
}
|
||||
|
||||
interface SinonExposeOptions {
|
||||
prefix?: string;
|
||||
includeFail?: boolean;
|
||||
}
|
||||
|
||||
interface SinonAssert {
|
||||
// Properties
|
||||
failException: string;
|
||||
fail: (message?: string) => void; // Overridable
|
||||
pass: (assertion: any) => void; // Overridable
|
||||
|
||||
// Methods
|
||||
notCalled(spy: SinonSpy): void;
|
||||
called(spy: SinonSpy): void;
|
||||
calledOnce(spy: SinonSpy): void;
|
||||
calledTwice(spy: SinonSpy): void;
|
||||
calledThrice(spy: SinonSpy): void;
|
||||
callCount(spy: SinonSpy, count: number): void;
|
||||
callOrder(...spies: SinonSpy[]): void;
|
||||
calledOn(spy: SinonSpy, obj: any): void;
|
||||
alwaysCalledOn(spy: SinonSpy, obj: any): void;
|
||||
calledWith(spy: SinonSpy, ...args: any[]): void;
|
||||
alwaysCalledWith(spy: SinonSpy, ...args: any[]): void;
|
||||
neverCalledWith(spy: SinonSpy, ...args: any[]): void;
|
||||
calledWithExactly(spy: SinonSpy, ...args: any[]): void;
|
||||
alwaysCalledWithExactly(spy: SinonSpy, ...args: any[]): void;
|
||||
calledWithMatch(spy: SinonSpy, ...args: any[]): void;
|
||||
alwaysCalledWithMatch(spy: SinonSpy, ...args: any[]): void;
|
||||
neverCalledWithMatch(spy: SinonSpy, ...args: any[]): void;
|
||||
threw(spy: SinonSpy): void;
|
||||
threw(spy: SinonSpy, exception: string): void;
|
||||
threw(spy: SinonSpy, exception: any): void;
|
||||
alwaysThrew(spy: SinonSpy): void;
|
||||
alwaysThrew(spy: SinonSpy, exception: string): void;
|
||||
alwaysThrew(spy: SinonSpy, exception: any): void;
|
||||
expose(obj: any, options?: SinonExposeOptions): void;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
assert: SinonAssert;
|
||||
}
|
||||
|
||||
interface SinonMatcher {
|
||||
and(expr: SinonMatcher): SinonMatcher;
|
||||
or(expr: SinonMatcher): SinonMatcher;
|
||||
}
|
||||
|
||||
interface SinonMatch {
|
||||
(value: number): SinonMatcher;
|
||||
(value: string): SinonMatcher;
|
||||
(expr: RegExp): SinonMatcher;
|
||||
(obj: any): SinonMatcher;
|
||||
(callback: (value: any) => boolean): SinonMatcher;
|
||||
any: SinonMatcher;
|
||||
defined: SinonMatcher;
|
||||
truthy: SinonMatcher;
|
||||
falsy: SinonMatcher;
|
||||
bool: SinonMatcher;
|
||||
number: SinonMatcher;
|
||||
string: SinonMatcher;
|
||||
object: SinonMatcher;
|
||||
func: SinonMatcher;
|
||||
array: SinonMatcher;
|
||||
regexp: SinonMatcher;
|
||||
date: SinonMatcher;
|
||||
same(obj: any): SinonMatcher;
|
||||
typeOf(type: string): SinonMatcher;
|
||||
instanceOf(type: any): SinonMatcher;
|
||||
has(property: string, expect?: any): SinonMatcher;
|
||||
hasOwn(property: string, expect?: any): SinonMatcher;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
match: SinonMatch;
|
||||
}
|
||||
|
||||
interface SinonSandboxConfig {
|
||||
injectInto?: any;
|
||||
properties?: string[];
|
||||
useFakeTimers?: any;
|
||||
useFakeServer?: any;
|
||||
}
|
||||
|
||||
interface SinonSandbox {
|
||||
clock: SinonFakeTimers;
|
||||
requests: SinonFakeXMLHttpRequest;
|
||||
server: SinonFakeServer;
|
||||
spy: SinonSpyStatic;
|
||||
stub: SinonStubStatic;
|
||||
mock: SinonMockStatic;
|
||||
useFakeTimers: SinonFakeTimersStatic;
|
||||
useFakeXMLHttpRequest: SinonFakeXMLHttpRequestStatic;
|
||||
useFakeServer(): SinonFakeServer;
|
||||
restore(): void;
|
||||
}
|
||||
|
||||
interface SinonSandboxStatic {
|
||||
create(): SinonSandbox;
|
||||
create(config: SinonSandboxConfig): SinonSandbox;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
sandbox: SinonSandboxStatic;
|
||||
}
|
||||
|
||||
interface SinonTestConfig {
|
||||
injectIntoThis?: boolean;
|
||||
injectInto?: any;
|
||||
properties?: string[];
|
||||
useFakeTimers?: boolean;
|
||||
useFakeServer?: boolean;
|
||||
}
|
||||
|
||||
interface SinonTestWrapper extends SinonSandbox {
|
||||
(...args: any[]): any;
|
||||
}
|
||||
|
||||
interface SinonStatic {
|
||||
config: SinonTestConfig;
|
||||
test(fn: (...args: any[]) => any): SinonTestWrapper;
|
||||
testCase(tests: any): any;
|
||||
}
|
||||
|
||||
// Utility overridables
|
||||
interface SinonStatic {
|
||||
createStubInstance(constructor: any): SinonStub;
|
||||
format(obj: any): string;
|
||||
log(message: string): void;
|
||||
restore(object: any): void;
|
||||
}
|
||||
|
||||
|
||||
declare var sinon: SinonStatic;
|
||||
|
||||
declare module "sinon" {
|
||||
export = sinon;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Cache-control" content="no-Cache" />
|
||||
<title>Tests for Application Insights JavaScript API</title>
|
||||
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-1.23.1.css">
|
||||
<script src="http://sinonjs.org/releases/sinon-2.3.8.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.js"></script>
|
||||
<script src="../../node_modules/applicationinsights-common/bundle/applicationinsights-common.js"></script>
|
||||
<script src="../../node_modules/applicationinsights-core-js/bundle/applicationinsights-core-js.js"></script>
|
||||
<script src="appinsights-analytics.tests.js"></script>
|
||||
|
||||
<script>
|
||||
require.config({
|
||||
paths: {
|
||||
qunit: "../External/qunit-1.23.1",
|
||||
bridge: "../../node_modules/grunt-contrib-qunit/phantomjs/bridge"
|
||||
}
|
||||
});
|
||||
|
||||
require(
|
||||
["qunit", "Tests/Selenium/appinsights-analytics.tests"],
|
||||
function (QUnit, tests) {
|
||||
QUnit.start();
|
||||
tests.runTests();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
<div id="error-message"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,5 @@
|
|||
import { ApplicationInsightsTests } from '../ApplicationInsights.tests';
|
||||
|
||||
export function runTests() {
|
||||
new ApplicationInsightsTests().registerTests();
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/// <reference path="../External/qunit.d.ts" />
|
||||
|
||||
/** Wrapper around QUnit asserts. This class has two purposes:
|
||||
* - Make Assertion methods easy to discover.
|
||||
* - Make them consistent with XUnit assertions in the order of the actual and expected parameter values.
|
||||
*/
|
||||
class Assert {
|
||||
/**
|
||||
* A deep recursive comparison assertion, working on primitive types, arrays, objects,
|
||||
* regular expressions, dates and functions.
|
||||
*
|
||||
* The deepEqual() assertion can be used just like equal() when comparing the value of
|
||||
* objects, such that { key: value } is equal to { key: value }. For non-scalar values,
|
||||
* identity will be disregarded by deepEqual.
|
||||
*
|
||||
* @param expected Known comparison value
|
||||
* @param actual Object or Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static deepEqual(expected: any, actual: any, message?: string): any {
|
||||
return deepEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
|
||||
*
|
||||
* The equal assertion uses the simple comparison operator (==) to compare the actual
|
||||
* and expected arguments. When they are equal, the assertion passes: any; otherwise, it fails.
|
||||
* When it fails, both actual and expected values are displayed in the test result,
|
||||
* in addition to a given message.
|
||||
*
|
||||
* @param expected Known comparison value
|
||||
* @param actual Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static equal(expected: any, actual: any, message?: string): any {
|
||||
return equal(actual, expected, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* An inverted deep recursive comparison assertion, working on primitive types,
|
||||
* arrays, objects, regular expressions, dates and functions.
|
||||
*
|
||||
* The notDeepEqual() assertion can be used just like equal() when comparing the
|
||||
* value of objects, such that { key: value } is equal to { key: value }. For non-scalar
|
||||
* values, identity will be disregarded by notDeepEqual.
|
||||
*
|
||||
* @param expected Known comparison value
|
||||
* @param actual Object or Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static notDeepEqual(expected: any, actual: any, message?: string): any {
|
||||
return notDeepEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, checking for inequality.
|
||||
*
|
||||
* The notEqual assertion uses the simple inverted comparison operator (!=) to compare
|
||||
* the actual and expected arguments. When they aren't equal, the assertion passes: any;
|
||||
* otherwise, it fails. When it fails, both actual and expected values are displayed
|
||||
* in the test result, in addition to a given message.
|
||||
*
|
||||
* @param expected Known comparison value
|
||||
* @param actual Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static notEqual(expected: any, actual: any, message?: string): any {
|
||||
return notEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
public static notPropEqual(expected: any, actual: any, message?: string): any {
|
||||
return notPropEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
public static propEqual(expected: any, actual: any, message?: string): any {
|
||||
return propEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-strict comparison assertion, checking for inequality.
|
||||
*
|
||||
* The notStrictEqual assertion uses the strict inverted comparison operator (!==)
|
||||
* to compare the actual and expected arguments. When they aren't equal, the assertion
|
||||
* passes: any; otherwise, it fails. When it fails, both actual and expected values are
|
||||
* displayed in the test result, in addition to a given message.
|
||||
*
|
||||
* @param expected Known comparison value
|
||||
* @param actual Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static notStrictEqual(expected: any, actual: any, message?: string): any {
|
||||
return notStrictEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A boolean assertion, equivalent to CommonJS's assert.ok() and JUnit's assertTrue().
|
||||
* Passes if the first argument is truthy.
|
||||
*
|
||||
* The most basic assertion in QUnit, ok() requires just one argument. If the argument
|
||||
* evaluates to true, the assertion passes; otherwise, it fails. If a second message
|
||||
* argument is provided, it will be displayed in place of the result.
|
||||
*
|
||||
* @param state Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static ok(state: any, message?: string): any {
|
||||
return ok(state, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A strict type and value comparison assertion.
|
||||
*
|
||||
* The strictEqual() assertion provides the most rigid comparison of type and value with
|
||||
* the strict equality operator (===)
|
||||
*
|
||||
* @param expected Known comparison value
|
||||
* @param actual Expression being tested
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static strictEqual(expected: any, actual: any, message?: string): any {
|
||||
return strictEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertion to test if a callback throws an exception when run.
|
||||
*
|
||||
* When testing code that is expected to throw an exception based on a specific set of
|
||||
* circumstances, use throws() to catch the error object for testing and comparison.
|
||||
*
|
||||
* @param block Function to execute
|
||||
* @param expected Error Object to compare
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static throws(block: () => any, expected: any, message?: string): any;
|
||||
|
||||
/**
|
||||
* @param block Function to execute
|
||||
* @param message A short description of the assertion
|
||||
*/
|
||||
public static throws(block: () => any, message?: string): any;
|
||||
|
||||
public static throws(block: () => any, expected?: any, message?: string): any {
|
||||
return throws(block, expected, message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/// <reference path="../External/sinon.d.ts" />
|
||||
/// <reference path="../External/qunit.d.ts" />
|
||||
/// <reference path="Assert.ts" />
|
||||
/// <reference path="PollingAssert.ts" />
|
||||
/// <reference path="TestClass.ts" />
|
||||
/// <reference path="TestCase.ts" />
|
|
@ -0,0 +1,146 @@
|
|||
/// <reference path="../../JavaScriptSDK/Serializer.ts" />
|
||||
/// <reference path="./TestClass.ts"/>
|
||||
|
||||
class ContractTestHelper extends TestClass {
|
||||
|
||||
public name: string;
|
||||
private initializer: () => Microsoft.ApplicationInsights.ISerializable;
|
||||
|
||||
constructor(initializer: () => Microsoft.ApplicationInsights.ISerializable, name: string) {
|
||||
super();
|
||||
|
||||
this.name = name;
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
/** Method called before the start of each test method */
|
||||
public testInitialize() {
|
||||
}
|
||||
|
||||
/** Method called after each test method has completed */
|
||||
public testCleanup() {
|
||||
}
|
||||
|
||||
public registerTests() {
|
||||
var name = this.name + ": ";
|
||||
this.testCase({
|
||||
name: name + "constructor does not throw errors",
|
||||
test: () => {
|
||||
this.getSubject(this.initializer, this.name);
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: name + "serialization does not throw errors",
|
||||
test: () => {
|
||||
var subject = this.getSubject(this.initializer, this.name);
|
||||
this.serialize(subject, this.name);
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: name + "all required fields are constructed",
|
||||
test: () => {
|
||||
this.allRequiredFieldsAreConstructed(this.initializer, this.name);
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: name + "extra fields are removed upon serialization",
|
||||
test: () => {
|
||||
this.extraFieldsAreRemovedBySerializer(this.initializer, this.name);
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: this.name + "optional fields are not required by the back end",
|
||||
test: () => {
|
||||
this.optionalFieldsAreNotRequired(this.initializer, this.name);
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: this.name + "all fields are serialized if included",
|
||||
test: () => {
|
||||
this.allFieldsAreIncludedIfSpecified(this.initializer, this.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public checkSerializableObject(initializer: () => any, name: string) {
|
||||
this.allRequiredFieldsAreConstructed(initializer, name);
|
||||
this.extraFieldsAreRemovedBySerializer(initializer, name);
|
||||
this.allFieldsAreIncludedIfSpecified(initializer, name);
|
||||
}
|
||||
|
||||
private allRequiredFieldsAreConstructed(initializer: () => any, name: string) {
|
||||
var subject = this.getSubject(initializer, name);
|
||||
for (var field in subject.aiDataContract) {
|
||||
if (subject.aiDataContract[field] & Microsoft.ApplicationInsights.FieldType.Required) {
|
||||
Assert.ok(subject[field] != null, "The required field '" + field + "' is constructed for: '" + name + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extraFieldsAreRemovedBySerializer(initializer: () => any, name: string) {
|
||||
var subject = this.getSubject(initializer, name);
|
||||
|
||||
var extra = "extra";
|
||||
subject[extra + 0] = extra;
|
||||
subject[extra + 1] = extra;
|
||||
subject[extra + 3] = extra;
|
||||
|
||||
var serializedSubject = this.serialize(subject, name);
|
||||
|
||||
for (var field in serializedSubject) {
|
||||
Assert.ok(subject.aiDataContract[field] != null, "The field '" + field + "' exists in the contract for '" + name + "' and was serialized");
|
||||
}
|
||||
}
|
||||
|
||||
private optionalFieldsAreNotRequired(initializer: () => any, name: string) {
|
||||
var subject = this.getSubject(this.initializer, this.name);
|
||||
|
||||
for (var field in subject.aiDataContract) {
|
||||
if (!subject.aiDataContract[field]) {
|
||||
delete subject[field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private allFieldsAreIncludedIfSpecified(initializer: () => any, name: string) {
|
||||
var subject = this.getSubject(this.initializer, this.name);
|
||||
|
||||
for (var field in subject.aiDataContract) {
|
||||
subject[field] = field;
|
||||
}
|
||||
|
||||
var serializedSubject = this.serialize(subject, this.name);
|
||||
|
||||
for (field in subject.aiDataContract) {
|
||||
Assert.ok(serializedSubject[field] === field, "Field '" + field + "' was not serialized" + this.name);
|
||||
}
|
||||
|
||||
for (field in serializedSubject) {
|
||||
Assert.ok(subject.aiDataContract[field] !== undefined, "Field '" + field + "' was included but is not specified in the contract " + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
private serialize(subject: Microsoft.ApplicationInsights.ISerializable, name: string) {
|
||||
var serialized = "";
|
||||
|
||||
try {
|
||||
serialized = Microsoft.ApplicationInsights.Serializer.serialize(subject);
|
||||
} catch (e) {
|
||||
Assert.ok(false, "Failed to serialize '" + name + "'\r\n" + e);
|
||||
}
|
||||
|
||||
return JSON.parse(serialized);
|
||||
}
|
||||
|
||||
private getSubject(construction: () => Microsoft.ApplicationInsights.ISerializable, name: string): any {
|
||||
var subject = construction();
|
||||
Assert.ok(!!subject, "can construct " + name);
|
||||
|
||||
return subject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/// <reference path="../TestFramework/Common.ts" />
|
||||
/// <reference path="../External/jquery.d.ts" />
|
||||
/// <reference path="../../JavaScriptSDK/AppInsights.ts" />
|
||||
/// <reference path="../../JavaScriptSDK/Telemetry/Common/Data.ts" />
|
||||
interface IJSLitmus {
|
||||
test: (name: string, f: Function) => void;
|
||||
stop: () => void;
|
||||
runAll: (e?: Event) => JQueryDeferred<void>;
|
||||
_tests: any[];
|
||||
}
|
||||
|
||||
interface IPerfResult {
|
||||
operationCount: number;
|
||||
timeInMs: number;
|
||||
name: string;
|
||||
opsPerSec: number;
|
||||
period: number;
|
||||
date: number;
|
||||
platform: string;
|
||||
os: string;
|
||||
oneHrDate: number;
|
||||
friendlyDate: string;
|
||||
group: string;
|
||||
millisecondsPerOp: number;
|
||||
microsecondsPerOp: number;
|
||||
secondsPerOp: number;
|
||||
browser: string;
|
||||
}
|
||||
|
||||
declare var JSLitmus: IJSLitmus;
|
||||
|
||||
class PerformanceTestHelper extends TestClass {
|
||||
|
||||
public testCount;
|
||||
public appInsights;
|
||||
public testProperties;
|
||||
public testMeasurements;
|
||||
public results: IPerfResult[];
|
||||
private isDone;
|
||||
|
||||
constructor(timeout?: number) {
|
||||
super();
|
||||
this.testCount = 0;
|
||||
this.synchronouslyLoadJquery();
|
||||
this.results = [];
|
||||
}
|
||||
|
||||
/** Method called before the start of each test method */
|
||||
public testInitialize() {
|
||||
this.useFakeServer = false;
|
||||
sinon.fakeServer["restore"]();
|
||||
|
||||
this.useFakeTimers = false;
|
||||
this.clock.restore();
|
||||
|
||||
this.appInsights = new Microsoft.ApplicationInsights.AppInsights(<any>{
|
||||
instrumentationKey: "3e6a441c-b52b-4f39-8944-f81dd6c2dc46",
|
||||
url: "file:///C:/src/sdk/src/JavaScript/JavaScriptSDK.Tests//E2ETests/ai.js",
|
||||
endpointUrl: "https://dc.services.visualstudio.com/v2/track",
|
||||
maxBatchInterval: 0
|
||||
});
|
||||
|
||||
this.appInsights.context._sender._sender = () => null;
|
||||
this.testProperties = { p1: "val", p2: "val", p3: "val", p4: "val", p5: "val", p6: "val", p7: "val" };
|
||||
this.testMeasurements = { m1: 1, m2: 1, m3: 1, m4: 1, m5: 1, m6: 1, m7: 1, m8: 1, m9: 1 };
|
||||
}
|
||||
|
||||
/** Method called after each test method has completed */
|
||||
public testCleanup() {
|
||||
this.useFakeServer = true;
|
||||
this.useFakeTimers = true;
|
||||
var serializedPerfResults: string = window["perfResults"] || "[]";
|
||||
var perfResults: IPerfResult[] = <any>(JSON.parse(serializedPerfResults));
|
||||
perfResults = perfResults.concat(this.results);
|
||||
window["perfResults"] = JSON.stringify(perfResults);
|
||||
window["perfResultsCsv"] = this.toCsv(perfResults).csv;
|
||||
window["perfResultsCsvHeaders"] = this.toCsv(perfResults).headers;
|
||||
}
|
||||
|
||||
private toCsv(array: any[]) {
|
||||
var headers = "";
|
||||
if (array.length > 0) {
|
||||
var names = [];
|
||||
for (var name in array[0]) {
|
||||
names.push(name);
|
||||
}
|
||||
|
||||
headers = names.join(",");
|
||||
}
|
||||
|
||||
var csv = [];
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
var datum = array[i];
|
||||
var values = [];
|
||||
for (var j = 0; j < names.length; j++) {
|
||||
values.push(datum[names[j]]);
|
||||
}
|
||||
|
||||
csv.push(values.join(","));
|
||||
}
|
||||
|
||||
return { headers: headers, csv: csv.join("\r\n") };
|
||||
}
|
||||
|
||||
public enqueueTest(name: string, action: () => void) {
|
||||
JSLitmus.test(name, (count) => {
|
||||
while (count--) {
|
||||
action();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public runTests() {
|
||||
JSLitmus.runAll().done(() => this.onTestsComplete());
|
||||
}
|
||||
|
||||
public onTestsComplete() {
|
||||
var perfLogging = new Microsoft.ApplicationInsights.AppInsights(<any>{
|
||||
instrumentationKey: "1a6933ad-f260-447f-a2b0-e2233f6658eb",
|
||||
url: "file:///C:/src/sdk/src/JavaScript/JavaScriptSDK.Tests//E2ETests/ai.js",
|
||||
endpointUrl: "http://prodintdataforker.azurewebsites.net/dcservices?intKey=4d93aad0-cf1d-45b7-afc9-14f55504f6d5",
|
||||
sessionRenewalMs: 30 * 60 * 1000,
|
||||
sessionExpirationMs: 24 * 60 * 60 * 1000,
|
||||
maxBatchSizeInBytes: 1000000,
|
||||
maxBatchInterval: 0
|
||||
});
|
||||
|
||||
perfLogging.context._sender._sender = (payload) => {
|
||||
var xhr = new sinon["xhr"].workingXHR();
|
||||
xhr.open("POST", perfLogging.config.endpointUrl, true);
|
||||
xhr.setRequestHeader("Content-type", "application/json");
|
||||
xhr.send(payload);
|
||||
}
|
||||
|
||||
JSLitmus.stop();
|
||||
for (var i = 0; i < JSLitmus._tests.length; i++) {
|
||||
var test = JSLitmus._tests[i];
|
||||
var opsPerSec = test.count / test.time;
|
||||
Assert.ok(true, test.name + " operations per sec:" + opsPerSec);
|
||||
|
||||
var timeInMs = <number>test.time;
|
||||
var date = +new Date;
|
||||
var oneHr = 60 * 60 * 1000;
|
||||
var oneHrDate = Math.floor(date / oneHr) * oneHr;
|
||||
var friendlyDate = new Date(oneHrDate).toISOString();
|
||||
var platform = <string>test.platform;
|
||||
var browser = "internetExplorer";
|
||||
var name = <string>test.name;
|
||||
var group = name.split(".")[0];
|
||||
if (platform.toLowerCase().indexOf("chrome") >= 0) {
|
||||
browser = "chrome";
|
||||
} else if (platform.toLowerCase().indexOf("firefox") >= 0) {
|
||||
browser = "firefox";
|
||||
} else if (platform.toLowerCase().indexOf("safari") >= 0) {
|
||||
browser = "safari";
|
||||
}
|
||||
|
||||
var result: IPerfResult = {
|
||||
name: name,
|
||||
timeInMs: timeInMs,
|
||||
operationCount: 1,
|
||||
opsPerSec: 1 / (timeInMs / 1000),
|
||||
period: 1,
|
||||
date: date,
|
||||
oneHrDate: oneHrDate,
|
||||
friendlyDate: friendlyDate,
|
||||
group: group,
|
||||
platform: platform,
|
||||
browser: browser,
|
||||
os: <string>test.os,
|
||||
millisecondsPerOp: (timeInMs / 1),
|
||||
microsecondsPerOp: (timeInMs / 1) * 1000,
|
||||
secondsPerOp: (timeInMs / 1) / 1000
|
||||
};
|
||||
|
||||
perfLogging.trackMetric(result.name, opsPerSec);
|
||||
var event = new Microsoft.ApplicationInsights.Telemetry.Event(result.name, opsPerSec, result);
|
||||
var data = new Microsoft.ApplicationInsights.Telemetry.Common.Data<Microsoft.ApplicationInsights.Telemetry.Event>(
|
||||
Microsoft.ApplicationInsights.Telemetry.Event.dataType, event);
|
||||
var envelope = new Microsoft.ApplicationInsights.Telemetry.Common.Envelope(data, Microsoft.ApplicationInsights.Telemetry.Event.envelopeType);
|
||||
perfLogging.context.track(envelope);
|
||||
|
||||
this.results.push(result);
|
||||
}
|
||||
|
||||
JSLitmus._tests.length = 0;
|
||||
this.isDone = true;
|
||||
this.testCleanup();
|
||||
}
|
||||
|
||||
public onTimeout() {
|
||||
if (!this.isDone) {
|
||||
Assert.ok(false, "timeout reached");
|
||||
this.onTestsComplete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously loads jquery
|
||||
* we could regress the test suite and develop sublte jquery dependencies in the product code
|
||||
* if jquery were added to all tests as it hides a lot of cross browser weirdness. However,
|
||||
* for these tests it is useful to manipulate the dom to display performance results.
|
||||
*/
|
||||
private synchronouslyLoadJquery() {
|
||||
if (!window["$"]) {
|
||||
// get some kind of XMLHttpRequest
|
||||
var xhrObj = <any>false;
|
||||
if (window["ActiveXObject"]) {
|
||||
xhrObj = <any>new ActiveXObject("Microsoft.XMLHTTP");
|
||||
} else if (window["XMLHttpRequest"]) {
|
||||
xhrObj = <any>new XMLHttpRequest();
|
||||
} else {
|
||||
alert("Please upgrade your browser! Your browser does not support AJAX!");
|
||||
}
|
||||
|
||||
// open and send a synchronous request
|
||||
xhrObj.open('GET', "http://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.js", false);
|
||||
xhrObj.send('');
|
||||
|
||||
// add the returned content to a newly created script tag
|
||||
var script = document.createElement('script');
|
||||
script.type = "text/javascript";
|
||||
script.text = xhrObj.responseText;
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/// <reference path="../External/qunit.d.ts" />
|
||||
/// <reference path="TestClass.ts" />
|
||||
|
||||
class PollingAssert {
|
||||
/**
|
||||
* Starts polling assertion function for a period of time after which it's considered failed.
|
||||
* @param {() => boolean} assertionFunctionReturnsBoolean - funciton returning true if condition passes and false if condition fails. Assertion will be done on this function's result.
|
||||
* @param {string} assertDescription - message shown with the assertion
|
||||
* @param {number} timeoutSeconds - timeout in seconds after which assertion fails
|
||||
* @param {number} pollIntervalMs - polling interval in milliseconds
|
||||
* @returns {(nextTestStep) => void} callback which will be invoked by the TestClass
|
||||
*/
|
||||
public static createPollingAssert(assertionFunctionReturnsBoolean: () => boolean, assertDescription: string, timeoutSeconds: number = 30, pollIntervalMs: number = 500): (nextTestStep) => void {
|
||||
var pollingAssert = (nextTestStep) => {
|
||||
var timeout = new Date(new Date().getTime() + timeoutSeconds * 1000);
|
||||
var polling = () => {
|
||||
if (assertionFunctionReturnsBoolean.apply(this)) {
|
||||
Assert.ok(true, assertDescription);
|
||||
nextTestStep();
|
||||
} else if (timeout < new Date()) {
|
||||
Assert.ok(false, "assert didn't succeed for " + timeout + " seconds: " + assertDescription);
|
||||
nextTestStep();
|
||||
} else {
|
||||
setTimeout(polling, pollIntervalMs);
|
||||
}
|
||||
}
|
||||
setTimeout(polling, pollIntervalMs);
|
||||
}
|
||||
|
||||
pollingAssert[TestClass.isPollingStepFlag] = true;
|
||||
|
||||
return pollingAssert;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/** Defines a test case */
|
||||
class TestCase {
|
||||
/** Name to use for the test case */
|
||||
public name: string;
|
||||
|
||||
/** Test case method */
|
||||
public test: () => void;
|
||||
}
|
||||
|
||||
|
||||
/** Defines a test case */
|
||||
interface TestCaseAsync {
|
||||
/** Name to use for the test case */
|
||||
name: string;
|
||||
|
||||
/** time to wait after pre before invoking post and calling start() */
|
||||
stepDelay: number;
|
||||
|
||||
/** async steps */
|
||||
steps: Array<() => void>;
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/// <reference path="../External/sinon.d.ts" />
|
||||
/// <reference path="../External/qunit.d.ts" />
|
||||
/// <reference path="Assert.ts" />
|
||||
/// <reference path="./TestCase.ts"/>
|
||||
|
||||
class TestClass {
|
||||
|
||||
constructor(name?: string) {
|
||||
QUnit.module(name);
|
||||
}
|
||||
|
||||
public static isPollingStepFlag = "isPollingStep";
|
||||
|
||||
/** The instance of the currently running suite. */
|
||||
public static currentTestClass: TestClass;
|
||||
|
||||
/** Turns on/off sinon's syncronous implementation of setTimeout. On by default. */
|
||||
public useFakeTimers: boolean = true;
|
||||
|
||||
/** Turns on/off sinon's fake implementation of XMLHttpRequest. On by default. */
|
||||
public useFakeServer: boolean = true;
|
||||
|
||||
/** Method called before the start of each test method */
|
||||
public testInitialize() {
|
||||
}
|
||||
|
||||
/** Method called after each test method has completed */
|
||||
public testCleanup() {
|
||||
}
|
||||
|
||||
/** Method in which test class intances should call this.testCase(...) to register each of this suite's tests. */
|
||||
public registerTests() {
|
||||
}
|
||||
|
||||
/** Register an async Javascript unit testcase. */
|
||||
public testCaseAsync(testInfo: TestCaseAsync) {
|
||||
if (!testInfo.name) {
|
||||
throw new Error("Must specify name in testInfo context in registerTestcase call");
|
||||
}
|
||||
|
||||
if (isNaN(testInfo.stepDelay)) {
|
||||
throw new Error("Must specify 'stepDelay' period between pre and post");
|
||||
}
|
||||
|
||||
if (!testInfo.steps) {
|
||||
throw new Error("Must specify 'steps' to take asynchronously");
|
||||
}
|
||||
|
||||
// Create a wrapper around the test method so we can do test initilization and cleanup.
|
||||
var testMethod = (assert) => {
|
||||
var done = assert.async();
|
||||
|
||||
// Save off the instance of the currently running suite.
|
||||
TestClass.currentTestClass = this;
|
||||
|
||||
// Run the test.
|
||||
try {
|
||||
this._testStarting();
|
||||
|
||||
var steps = testInfo.steps;
|
||||
var trigger = () => {
|
||||
if (steps.length) {
|
||||
var step = steps.shift();
|
||||
|
||||
// The callback which activates the next test step.
|
||||
var nextTestStepTrigger = () => {
|
||||
setTimeout(() => {
|
||||
trigger();
|
||||
}, testInfo.stepDelay);
|
||||
};
|
||||
|
||||
// There 2 types of test steps - simple and polling.
|
||||
// Upon completion of the simple test step the next test step will be called.
|
||||
// In case of polling test step the next test step is passed to the polling test step, and
|
||||
// it is responsibility of the polling test step to call the next test step.
|
||||
try {
|
||||
if (step[TestClass.isPollingStepFlag]) {
|
||||
step.call(this, nextTestStepTrigger);
|
||||
} else {
|
||||
step.call(this);
|
||||
nextTestStepTrigger.call(this);
|
||||
}
|
||||
} catch (e) {
|
||||
this._testCompleted();
|
||||
Assert.ok(false, e.toString());
|
||||
|
||||
// done is QUnit callback indicating the end of the test
|
||||
done();
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this._testCompleted();
|
||||
|
||||
// done is QUnit callback indicating the end of the test
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
trigger();
|
||||
} catch (ex) {
|
||||
Assert.ok(false, "Unexpected Exception: " + ex);
|
||||
this._testCompleted(true);
|
||||
|
||||
// done is QUnit callback indicating the end of the test
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
// Register the test with QUnit
|
||||
QUnit.test(testInfo.name, testMethod);
|
||||
}
|
||||
|
||||
/** Register a Javascript unit testcase. */
|
||||
public testCase(testInfo: TestCase) {
|
||||
if (!testInfo.name) {
|
||||
throw new Error("Must specify name in testInfo context in registerTestcase call");
|
||||
}
|
||||
|
||||
if (!testInfo.test) {
|
||||
throw new Error("Must specify 'test' method in testInfo context in registerTestcase call");
|
||||
}
|
||||
|
||||
// Create a wrapper around the test method so we can do test initilization and cleanup.
|
||||
var testMethod = () => {
|
||||
// Save off the instance of the currently running suite.
|
||||
TestClass.currentTestClass = this;
|
||||
|
||||
// Run the test.
|
||||
try {
|
||||
this._testStarting();
|
||||
|
||||
testInfo.test.call(this);
|
||||
|
||||
this._testCompleted();
|
||||
}
|
||||
catch (ex) {
|
||||
Assert.ok(false, "Unexpected Exception: " + ex);
|
||||
this._testCompleted(true);
|
||||
}
|
||||
};
|
||||
|
||||
// Register the test with QUnit
|
||||
test(testInfo.name, testMethod);
|
||||
}
|
||||
|
||||
/** Called when the test is starting. */
|
||||
private _testStarting() {
|
||||
// Initialize the sandbox similar to what is done in sinon.js "test()" override. See note on class.
|
||||
var config = (<any>sinon).getConfig(sinon.config);
|
||||
config.useFakeTimers = this.useFakeTimers;
|
||||
config.useFakeServer = this.useFakeServer;
|
||||
|
||||
config.injectInto = config.injectIntoThis && this || config.injectInto;
|
||||
this.sandbox = sinon.sandbox.create(config);
|
||||
this.server = this.sandbox.server;
|
||||
|
||||
// Allow the derived class to perform test initialization.
|
||||
this.testInitialize();
|
||||
}
|
||||
|
||||
/** Called when the test is completed. */
|
||||
private _testCompleted(failed?: boolean) {
|
||||
if (failed) {
|
||||
// Just cleanup the sandbox since the test has already failed.
|
||||
this.sandbox.restore();
|
||||
}
|
||||
else {
|
||||
// Verify the sandbox and restore.
|
||||
(<any>this.sandbox).verifyAndRestore();
|
||||
}
|
||||
|
||||
this.testCleanup();
|
||||
|
||||
// Clear the instance of the currently running suite.
|
||||
TestClass.currentTestClass = null;
|
||||
}
|
||||
|
||||
/**** Sinon methods and properties ***/
|
||||
|
||||
// These methods and properties are injected by Sinon and will override the implementation here.
|
||||
// These are here purely to make typescript happy.
|
||||
public clock: SinonFakeTimers;
|
||||
public server: SinonFakeServer;
|
||||
public sandbox: SinonSandbox;
|
||||
|
||||
/** Creates an anonymous function that records arguments, this value, exceptions and return values for all calls. */
|
||||
public spy(): SinonSpy;
|
||||
/** Spies on the provided function */
|
||||
public spy(funcToWrap: Function): SinonSpy;
|
||||
/** Creates a spy for object.methodName and replaces the original method with the spy. The spy acts exactly like the original method in all cases. The original method can be restored by calling object.methodName.restore(). The returned spy is the function object which replaced the original method. spy === object.method. */
|
||||
public spy(object: any, methodName: string, func?: Function): SinonSpy;
|
||||
public spy(...args: any[]): SinonSpy { return null; }
|
||||
|
||||
/** Creates an anonymous stub function. */
|
||||
public stub(): SinonStub;
|
||||
/** Stubs all the object's methods. */
|
||||
public stub(object: any): SinonStub;
|
||||
/** Replaces object.methodName with a func, wrapped in a spy. As usual, object.methodName.restore(); can be used to restore the original method. */
|
||||
public stub(object: any, methodName: string, func?: Function): SinonStub;
|
||||
public stub(...args: any[]): SinonStub { return null; }
|
||||
|
||||
/** Creates a mock for the provided object.Does not change the object, but returns a mock object to set expectations on the object's methods. */
|
||||
public mock(object: any): SinonMock { return null; }
|
||||
|
||||
/**** end: Sinon methods and properties ***/
|
||||
|
||||
/** Sends a JSON response to the provided request.
|
||||
* @param request The request to respond to.
|
||||
* @param data Data to respond with.
|
||||
* @param errorCode Optional error code to send with the request, default is 200
|
||||
*/
|
||||
public sendJsonResponse(request: SinonFakeXMLHttpRequest, data: any, errorCode?: number) {
|
||||
if (errorCode === undefined) {
|
||||
errorCode = 200;
|
||||
}
|
||||
|
||||
request.respond(
|
||||
errorCode,
|
||||
{ "Content-Type": "application/json" },
|
||||
JSON.stringify(data));
|
||||
}
|
||||
|
||||
protected setUserAgent(userAgent: string) {
|
||||
Object.defineProperty(window.navigator, 'userAgent',
|
||||
{
|
||||
configurable: true,
|
||||
get: function () {
|
||||
return userAgent;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Configure Sinon
|
||||
sinon.assert.fail = function (msg?) {
|
||||
Assert.ok(false, msg);
|
||||
};
|
||||
|
||||
sinon.assert.pass = function (assertion) {
|
||||
Assert.ok(assertion, "sinon assert");
|
||||
};
|
||||
|
||||
sinon.config = {
|
||||
injectIntoThis: true,
|
||||
injectInto: null,
|
||||
properties: ["spy", "stub", "mock", "clock", "sandbox"],
|
||||
useFakeTimers: true,
|
||||
useFakeServer: true
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "applicationinsights-analytics-js",
|
||||
"version": "0.0.21",
|
||||
"version": "0.0.23",
|
||||
"description": "Microsoft Application Insights Javascript SDK apis",
|
||||
"main": "bundle/applicationinsights-analytics-js.js",
|
||||
"types": "bundle/applicationinsights-analytics-js.d.ts",
|
||||
|
@ -12,6 +12,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"applicationinsights-common": "0.0.49",
|
||||
"applicationinsights-core-js": "0.0.39"
|
||||
"applicationinsights-core-js": "0.0.49"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "applicationinsights-analytics-js",
|
||||
"version": "0.0.22",
|
||||
"description": "Microsoft Application Insights Javascript SDK apis",
|
||||
"main": "bundle/applicationinsights-analytics-js.js",
|
||||
"types": "bundle/applicationinsights-analytics-js.d.ts",
|
||||
"devDependencies": {
|
||||
"typescript": "2.5.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://mseng.pkgs.visualstudio.com/_packaging/ApplicationInsights-Team/npm/registry"
|
||||
},
|
||||
"dependencies": {
|
||||
"applicationinsights-common": "0.0.49",
|
||||
"applicationinsights-core-js": "0.0.49"
|
||||
}
|
||||
}
|
|
@ -7,8 +7,8 @@
|
|||
"target": "es5",
|
||||
"alwaysStrict": true,
|
||||
"declaration": true,
|
||||
"outDir": "../bundle",
|
||||
"rootDir": "./ApplicationInsights"
|
||||
},
|
||||
"outDir": "./bundle",
|
||||
"rootDir": "./"
|
||||
},
|
||||
"files": []
|
||||
}
|
|
@ -4,14 +4,30 @@
|
|||
"description": "Microsoft Application Insights Javascript SDK apis",
|
||||
"main": "bundle/applicationinsights-analytics-js.js",
|
||||
"types": "bundle/applicationinsights-analytics-js.d.ts",
|
||||
"scripts": {
|
||||
"test": "grunt aitests"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Microsoft/ApplicationInsights-JS.git"
|
||||
},
|
||||
"author": "Microsoft Application Insights Team",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Microsoft/ApplicationInsights-js/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "2.5.3"
|
||||
"typescript": "2.5.3",
|
||||
"grunt": "1.0.1",
|
||||
"grunt-contrib-qunit": "2.0.0",
|
||||
"grunt-contrib-uglify": "3.1.0",
|
||||
"grunt-ts": "^6.0.0-beta.15"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://mseng.pkgs.visualstudio.com/_packaging/ApplicationInsights-Team/npm/registry"
|
||||
},
|
||||
"dependencies": {
|
||||
"applicationinsights-common": "0.0.49",
|
||||
"applicationinsights-core-js": "0.0.39"
|
||||
"applicationinsights-common": "0.0.51",
|
||||
"applicationinsights-core-js": "0.0.51"
|
||||
}
|
||||
}
|
||||
|
|
33
gruntfile.js
33
gruntfile.js
|
@ -30,13 +30,13 @@ module.exports = function (grunt) {
|
|||
]
|
||||
},
|
||||
appinsightscjs: {
|
||||
tsconfig:'./ApplicationInsights/cjs/tsconfigcommonjs.json',
|
||||
src: [
|
||||
tsconfig: './ApplicationInsights/cjs/tsconfigcommonjs.json',
|
||||
src: [
|
||||
'ApplicationInsights/JavascriptSDK/*.ts',
|
||||
'ApplicationInsights/JavascriptSDK.Interfaces/*.ts',
|
||||
'ApplicationInsights/*.ts'
|
||||
]
|
||||
},
|
||||
},
|
||||
appinsights: {
|
||||
tsconfig: './tsconfig.json',
|
||||
src: [
|
||||
|
@ -46,13 +46,20 @@ module.exports = function (grunt) {
|
|||
],
|
||||
out: 'ApplicationInsights/amd/bundle/applicationinsights-analytics-js.js',
|
||||
},
|
||||
aisku: {
|
||||
tsconfig: './tsconfig.json',
|
||||
appinsightstests: {
|
||||
tsconfig: './tsconfig.json',
|
||||
src: [
|
||||
'./ApplicationInsights/Tests/Selenium/*.ts'
|
||||
],
|
||||
out: 'ApplicationInsights/Tests/Selenium/appinsights-analytics.tests.js'
|
||||
},
|
||||
aisku: {
|
||||
tsconfig: './tsconfig.json',
|
||||
src: [
|
||||
'AISKU/Init.ts'
|
||||
],
|
||||
],
|
||||
out: 'AISKU/amd/bundle/aisdk-js.js'
|
||||
},
|
||||
},
|
||||
module: {
|
||||
// Use a different tsconfig for building module in order to not generate a declaration file for module, while keeping declaration for other modules
|
||||
tsconfig: './tsconfigmodule.json',
|
||||
|
@ -155,6 +162,17 @@ module.exports = function (grunt) {
|
|||
summaryOnly: true,
|
||||
'--web-security': 'false' // we need this to allow CORS requests in PhantomJS
|
||||
}
|
||||
},
|
||||
aitests: {
|
||||
options: {
|
||||
urls: [
|
||||
'ApplicationInsights/Tests/Selenium/Tests.html'
|
||||
],
|
||||
timeout: 300 * 1000, // 5 min
|
||||
console: false,
|
||||
summaryOnly: true,
|
||||
'--web-security': 'false' // we need this to allow CORS requests in PhantomJS
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -171,6 +189,7 @@ module.exports = function (grunt) {
|
|||
grunt.registerTask("commoncjs", ["ts:commoncjs"]);
|
||||
grunt.registerTask("module", ["ts:module"]);
|
||||
grunt.registerTask("ai", ["ts:appinsights"]);
|
||||
grunt.registerTask("aitests", ["ts:appinsights", "ts:appinsightstests", "qunit:aitests"]);
|
||||
grunt.registerTask("aicjs", ["ts:appinsightscjs"]);
|
||||
grunt.registerTask("aisku", ["ts:aisku"]);
|
||||
grunt.registerTask("test", ["ts:default", "ts:test", "ts:testSchema", "ts:testE2E", "ts:types", "qunit:all"]);
|
||||
|
|
Загрузка…
Ссылка в новой задаче