Port PR #8410 to dev: Track online/offline status change#8411
Port PR #8410 to dev: Track online/offline status change#8411
Conversation
Co-authored-by: tnorling <5307810+tnorling@users.noreply.github.com>
Co-authored-by: tnorling <5307810+tnorling@users.noreply.github.com>
…tion-library-for-js into copilot/port-changes-to-dev-branch
There was a problem hiding this comment.
Pull request overview
Ports telemetry enhancements to track browser online/offline status in performance events, extending msal-common’s PerformanceEvent and wiring capture/increment logic into msal-browser’s telemetry and controller flows.
Changes:
- Add
startOnlineStatusandonlineStatusChangeCounttoPerformanceEvent(and API review output). - Capture
navigator.onLineatBrowserPerformanceClient.startMeasurement()and track online/offline transitions during relevantStandardControlleroperations. - Add/change tests and add Beachball changefiles for
@azure/msal-commonand@azure/msal-browser.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| package-lock.json | Lockfile metadata changes (appears unrelated to telemetry changes). |
| lib/msal-common/src/telemetry/performance/PerformanceEvent.ts | Adds new performance telemetry fields for online status. |
| lib/msal-common/apiReview/msal-common.api.md | Updates API review output to include the new fields. |
| lib/msal-browser/src/telemetry/BrowserPerformanceClient.ts | Captures startOnlineStatus at measurement start. |
| lib/msal-browser/src/controllers/StandardController.ts | Adds online/offline listener tracking and increments onlineStatusChangeCount. |
| lib/msal-browser/test/telemetry/BrowserPerformanceClient.spec.ts | Adds/updates tests for online status capture. |
| change/@azure-msal-common-6ffbe68f-0ad5-41ae-94a3-401210f04254.json | Beachball changefile for @azure/msal-common. |
| change/@azure-msal-browser-064efeaa-53d7-4265-a60b-0fe45d1835e2.json | Beachball changefile for @azure/msal-browser. |
Comments suppressed due to low confidence (1)
lib/msal-browser/src/controllers/StandardController.ts:2091
- State change listeners are added before
initializeSilentRequestis awaited, but they are only removed in the.finallyattached to theresultpromise later. IfinitializeSilentRequestrejects/throws, execution exits early andremoveStateChangeListenersis never called, leaking the listeners (now 3 listeners instead of 1). Wrap the listener lifecycle in atry/finally(or ensure removal on theawaitfailure path) so listeners are always cleaned up.
this.addStateChangeListeners(trackStateChange);
const silentRequest = await invokeAsync(
initializeSilentRequest,
BrowserPerformanceEvents.InitializeSilentRequest,
this.logger,
this.performanceClient,
request.correlationId
)(request, account, this.config, this.performanceClient, this.logger);
| "Perf: Visibility change detected in ", | ||
| measurement.event.name | ||
| ); | ||
| measurement.increment({ | ||
| visibilityChangeCount: 1, | ||
| }); | ||
| } else if (event.type === "online") { | ||
| this.logger.info( | ||
| "Perf: Online status change detected in ", | ||
| measurement.event.name | ||
| ); | ||
| measurement.increment({ | ||
| onlineStatusChangeCount: 1, | ||
| }); | ||
| } else if (event.type === "offline") { | ||
| this.logger.info( | ||
| "Perf: Offline status change detected in ", | ||
| measurement.event.name |
There was a problem hiding this comment.
Logger.info's second parameter is a correlationId, but here measurement.event.name is being passed as that argument. This will log an incorrect correlationId and makes log correlation/debugging unreliable. Include measurement.event.name in the message string instead, and pass measurement.event.correlationId (or another real correlation id) as the second argument.
| "Perf: Visibility change detected in ", | |
| measurement.event.name | |
| ); | |
| measurement.increment({ | |
| visibilityChangeCount: 1, | |
| }); | |
| } else if (event.type === "online") { | |
| this.logger.info( | |
| "Perf: Online status change detected in ", | |
| measurement.event.name | |
| ); | |
| measurement.increment({ | |
| onlineStatusChangeCount: 1, | |
| }); | |
| } else if (event.type === "offline") { | |
| this.logger.info( | |
| "Perf: Offline status change detected in ", | |
| measurement.event.name | |
| `Perf: Visibility change detected in ${measurement.event.name}`, | |
| measurement.event.correlationId | |
| ); | |
| measurement.increment({ | |
| visibilityChangeCount: 1, | |
| }); | |
| } else if (event.type === "online") { | |
| this.logger.info( | |
| `Perf: Online status change detected in ${measurement.event.name}`, | |
| measurement.event.correlationId | |
| ); | |
| measurement.increment({ | |
| onlineStatusChangeCount: 1, | |
| }); | |
| } else if (event.type === "offline") { | |
| this.logger.info( | |
| `Perf: Offline status change detected in ${measurement.event.name}`, | |
| measurement.event.correlationId |
| it("captures online status at measurement start", () => { | ||
| jest.spyOn( | ||
| Object.getPrototypeOf(navigator), | ||
| "onLine", | ||
| "get" | ||
| ).mockReturnValue(true); | ||
| }); | ||
|
|
||
| it("includes network information in performance event result", () => { |
There was a problem hiding this comment.
The new test captures online status at measurement start sets up a spy but never starts a measurement or asserts on the result, so it doesn't validate behavior and will pass even if startOnlineStatus is broken. Fold this setup/assertion into a real measurement (or remove the test) and ensure the spy is applied in the same test that asserts the field.
| it("captures online status at measurement start", () => { | |
| jest.spyOn( | |
| Object.getPrototypeOf(navigator), | |
| "onLine", | |
| "get" | |
| ).mockReturnValue(true); | |
| }); | |
| it("includes network information in performance event result", () => { | |
| it("includes network information in performance event result", () => { | |
| jest.spyOn( | |
| Object.getPrototypeOf(navigator), | |
| "onLine", | |
| "get" | |
| ).mockReturnValue(true); |
| @@ -125,6 +133,7 @@ describe("BrowserPerformanceClient.ts", () => { | |||
|
|
|||
| const result = measurement.end(); | |||
|
|
|||
| expect(result?.startOnlineStatus).toBe(true); | |||
| expect(result?.networkEffectiveType).toBe("4g"); | |||
| expect(result?.networkRtt).toBe(50); | |||
There was a problem hiding this comment.
This test expects startOnlineStatus to be true but doesn't mock navigator.onLine in this test. Because jest.restoreAllMocks() runs after each test, the spy created in the prior test won't be active here, making this assertion environment-dependent/flaky. Mock navigator.onLine (or define the property) within this test (or in a beforeEach) before calling startMeasurement.
startOnlineStatusandonlineStatusChangeCountfields toPerformanceEventtype inmsal-commonBrowserPerformanceClientto addgetOnlineStatus()method and capturestartOnlineStatusinstartMeasurementStandardControllerevent listener management: renamed methods, addedaddStateChangeListeners/removeStateChangeListenershelpers; addedonlineStatusChangeCounttrackingBrowserPerformanceClient.spec.tsmsal-common.api.mdto include new fields@azure/msal-browserand@azure/msal-common🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.