Skip to content

Commit

Permalink
Dynmic Config Change (#49)
Browse files Browse the repository at this point in the history
Update npm-shrinkwrap.json, change dep for dynamic change
  • Loading branch information
siyuniu-ms authored Jun 16, 2023
1 parent 9b9a44c commit 848eade
Show file tree
Hide file tree
Showing 11 changed files with 5,202 additions and 1,696 deletions.
8 changes: 4 additions & 4 deletions applicationinsights-react-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@
"history": "^5.1.0"
},
"dependencies": {
"@microsoft/applicationinsights-shims": "^2.0.2",
"@microsoft/applicationinsights-core-js": "^2.8.14",
"@microsoft/applicationinsights-common": "^2.8.14",
"@microsoft/dynamicproto-js": "^1.1.9"
"@microsoft/applicationinsights-shims": "^3.0.1",
"@microsoft/applicationinsights-core-js": "^3.0.2",
"@microsoft/applicationinsights-common": "^3.0.2",
"@microsoft/dynamicproto-js": "^2.0.2"
},
"peerDependencies": {
"tslib": "*",
Expand Down
2 changes: 1 addition & 1 deletion applicationinsights-react-js/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cleanup from "rollup-plugin-cleanup";
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import { uglify } from "../tools/rollup-plugin-uglify3-js/dist/esm/rollup-plugin-uglify3-js";
import { importCheck } from "@microsoft/applicationinsights-rollup-es3";
import dynamicRemove from "@microsoft/dynamicproto-js/tools/rollup/node/removedynamic";
import dynamicRemove from "@microsoft/dynamicproto-js/tools/rollup";
import { updateDistEsmFiles } from "../tools/updateDistEsm/updateDistEsm";

const version = require("./package.json").version;
Expand Down
48 changes: 30 additions & 18 deletions applicationinsights-react-js/src/ReactPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,23 @@

import dynamicProto from "@microsoft/dynamicproto-js";
import {
AnalyticsPluginIdentifier,
IAppInsights, IConfig, IEventTelemetry, IExceptionTelemetry, IMetricTelemetry, IPageViewTelemetry, ITraceTelemetry
} from "@microsoft/applicationinsights-common";
import {
BaseTelemetryPlugin, IAppInsightsCore, IConfiguration, ICookieMgr, ICustomProperties, IPlugin, IProcessTelemetryContext,
IProcessTelemetryUnloadContext, ITelemetryItem, ITelemetryPlugin, ITelemetryPluginChain, ITelemetryUnloadState, _eInternalMessageId,
_throwInternal, arrForEach, eLoggingSeverity, isFunction, objDefineAccessors, proxyFunctions, safeGetCookieMgr
_throwInternal, arrForEach, eLoggingSeverity, isFunction, proxyFunctions, safeGetCookieMgr, IConfigDefaults, onConfigChange, objDefineAccessors
} from "@microsoft/applicationinsights-core-js";
import {objDeepFreeze} from "@nevware21/ts-utils";

import { History, Location, Update } from "history";

import { IReactExtensionConfig } from './Interfaces/IReactExtensionConfig';
const defaultReactExtensionConfig: IConfigDefaults<IReactExtensionConfig> = objDeepFreeze({
history: { blkVal: true, v: undefined }
});

export default class ReactPlugin extends BaseTelemetryPlugin {
public priority = 185;
public identifier = 'ReactPlugin';
Expand All @@ -25,30 +32,34 @@ export default class ReactPlugin extends BaseTelemetryPlugin {
let _extensionConfig: IReactExtensionConfig;
let _unlisten: any;
let _pageViewTimer: any;
let _pageViewTracked:boolean;

dynamicProto(ReactPlugin, this, (_self, _base) => {
_initDefaults();

_self.initialize = (config: IConfiguration & IConfig, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?:ITelemetryPluginChain) => {
super.initialize(config, core, extensions, pluginChain);
_extensionConfig =
config.extensionConfig && config.extensionConfig[_self.identifier]
? (config.extensionConfig[_self.identifier] as IReactExtensionConfig)
: { history: null };

arrForEach(extensions, ext => {
const identifier = (ext as ITelemetryPlugin).identifier;
if (identifier === 'ApplicationInsightsAnalytics') {
_analyticsPlugin = (ext as any) as IAppInsights;

_self._addHook(onConfigChange(config, (details) => {
let ctx = _self._getTelCtx();
_extensionConfig = ctx.getExtCfg<IReactExtensionConfig>(this.identifier, defaultReactExtensionConfig);
_analyticsPlugin = core.getPlugin<any>(AnalyticsPluginIdentifier)?.plugin as IAppInsights;
if (isFunction(_unlisten)) {
_unlisten();
_unlisten = null;
}
});
if (_extensionConfig.history) {
_addHistoryListener(_extensionConfig.history);
const pageViewTelemetry: IPageViewTelemetry = {
uri: _extensionConfig.history.location.pathname
};
_self.trackPageView(pageViewTelemetry);
}
if (_extensionConfig.history) {
_addHistoryListener(_extensionConfig.history);
if (!_pageViewTracked){
const pageViewTelemetry: IPageViewTelemetry = {
uri: _extensionConfig.history.location.pathname
};
_self.trackPageView(pageViewTelemetry);
_pageViewTracked = true;
}
}
}));
};

_self.getCookieMgr = (): ICookieMgr => {
Expand Down Expand Up @@ -87,6 +98,7 @@ export default class ReactPlugin extends BaseTelemetryPlugin {
_extensionConfig = null;
_unlisten = null;
_pageViewTimer = null;
_pageViewTracked = false;
}

function _getAnalytics() {
Expand Down
107 changes: 98 additions & 9 deletions applicationinsights-react-js/test/ReactAI.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { AppInsightsCore, IConfiguration, DiagnosticLogger, ITelemetryItem, IPlugin } from "@microsoft/applicationinsights-core-js";
import { AppInsightsCore, IConfiguration, DiagnosticLogger, ITelemetryItem, IPlugin, IAppInsightsCore } from "@microsoft/applicationinsights-core-js";
import { IPageViewTelemetry } from "@microsoft/applicationinsights-common";
import ReactPlugin from "../src/ReactPlugin";
import { IReactExtensionConfig } from "../src/Interfaces/IReactExtensionConfig";
import { createBrowserHistory } from "history";

let reactPlugin: ReactPlugin;
let core: AppInsightsCore;
let coreConfig: IConfiguration;
let orgWarn = console && console.warn;

describe("ReactAI", () => {
Expand All @@ -26,19 +27,22 @@ describe("ReactAI", () => {
core = new AppInsightsCore();
core.logger = new DiagnosticLogger();
reactPlugin = new ReactPlugin();
coreConfig = {
instrumentationKey: 'testIkey',
endpointUrl: 'testEndpoint',
extensionConfig: {}
};
}

it("React Configuration: Config options can be passed from root config", () => {
const history = createBrowserHistory();
init();
reactPlugin.initialize({
instrumentationKey: 'instrumentation_key',
extensionConfig: {
[reactPlugin.identifier]: {
history
}
coreConfig.extensionConfig = {
[reactPlugin.identifier]: {
history
}
}, core, []);
}
core.initialize(coreConfig, [ reactPlugin, new ChannelPlugin() ]);
const reactConfig: IReactExtensionConfig = reactPlugin['_extensionConfig'];
expect(reactConfig.history).toEqual(history);
});
Expand Down Expand Up @@ -109,6 +113,90 @@ describe("ReactAI", () => {
jest.runOnlyPendingTimers();
expect(loggerMock).toHaveBeenCalledTimes(1);
});

it("React Dynamic Config: default Config history could be updated", () => {
const history = createBrowserHistory();
jest.useFakeTimers();
init();

const channel = new ChannelPlugin();
const config: IConfiguration = {
instrumentationKey: 'instrumentation_key',
extensionConfig: {
[reactPlugin.identifier]: {
history
},
}
};
core.initialize(config, [reactPlugin, channel]);
// Mock page view track
const reactMock = reactPlugin.trackPageView = jest.fn();
const newHistory = createBrowserHistory();

// Emulate navigation to different URL-addressed pages
history.push("/home", { some: "state" });
history.push("/should-received");
jest.runOnlyPendingTimers();
let id = reactPlugin.identifier;
//change config - history object
core.config.extensionConfig[id].history = newHistory;
jest.advanceTimersByTime(1000)
history.push("/old-history-should-not-received");
jest.runOnlyPendingTimers();
newHistory.push("/new-history-should-received")
jest.runOnlyPendingTimers();

expect(reactPlugin.trackPageView).toHaveBeenCalledTimes(3);
let reactEvent: IPageViewTelemetry = reactMock.mock.calls[0][0]
expect(reactEvent.uri).toBe("/home");
reactEvent = reactMock.mock.calls[1][0]
console.log("answer", reactEvent.uri)
expect(reactEvent.uri).toBe("/should-received");
reactEvent = reactMock.mock.calls[2][0]
expect(reactEvent.uri).toBe("/new-history-should-received")
});

it("React Dynamic Config: Config history could be removed and added", () => {
const history = createBrowserHistory();
jest.useFakeTimers();
init();

const channel = new ChannelPlugin();
const config: IConfiguration = {
instrumentationKey: 'instrumentation_key',
extensionConfig: {
[reactPlugin.identifier]: {
history
},
}
};
core.initialize(config, [reactPlugin, channel]);
// Mock page view track
const reactMock = reactPlugin.trackPageView = jest.fn();

// Emulate navigation to different URL-addressed pages
history.push("/should-received");
jest.runOnlyPendingTimers();
let id = reactPlugin.identifier;
//change config - history remove
core.config.extensionConfig[id].history = undefined;
jest.advanceTimersByTime(1000)
history.push("/removed-history-should-not-received");
jest.runOnlyPendingTimers();
//change config - history added back
core.config.extensionConfig[id].history = history;
jest.advanceTimersByTime(1000)
history.push("/new-history-should-received")
jest.runOnlyPendingTimers();

expect(reactPlugin.trackPageView).toHaveBeenCalledTimes(2);
let reactEvent: IPageViewTelemetry = reactMock.mock.calls[0][0]
expect(reactEvent.uri).toBe("/should-received");
reactEvent = reactMock.mock.calls[1][0]
console.log("answer", reactEvent.uri)
expect(reactEvent.uri).toBe("/new-history-should-received");

});
});

class ChannelPlugin implements IPlugin {
Expand Down Expand Up @@ -149,7 +237,8 @@ class ChannelPlugin implements IPlugin {
// no next setup
}

public initialize = (config: IConfiguration, core: AppInsightsCore, plugin: IPlugin[]) => {
public initialize = (config: IConfiguration, core: IAppInsightsCore, plugin: IPlugin[]) => {
// Mocked - Do Nothing
}

private _processTelemetry(env: ITelemetryItem) {
Expand Down
2 changes: 1 addition & 1 deletion common/Tests/Framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@
"tslib": "*"
},
"dependencies": {
"@microsoft/dynamicproto-js": "^1.1.9"
"@microsoft/dynamicproto-js": "^2.0.2"
}
}
2 changes: 1 addition & 1 deletion common/Tests/Selenium/ModuleLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function loadCommonModules(moduleLoader) {
moduleLoader.add("@microsoft/applicationinsights-shims", "./node_modules/@microsoft/applicationinsights-shims/browser/applicationinsights-shims");

// Load DynamicProto
moduleLoader.add("@microsoft/dynamicproto-js", "./node_modules/@microsoft/dynamicproto-js/lib/dist/umd/dynamicproto-js", true);
moduleLoader.add("@microsoft/dynamicproto-js", "./node_modules/@microsoft/dynamicproto-js/dist/es5/umd/dynamicproto-js", true);
}

function ModuleLoader(config) {
Expand Down
Loading

0 comments on commit 848eade

Please sign in to comment.