-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add telemetry API and initial set of events (#2922)
* Initial commit * Clean up * Add telemetry dimensions * Fix type checking * Add metrics * Update doc * Update doc * Doc and flush * Flush design * Clean up * Clean up * Clean up * Fix ESLint * Clean up * Clean up * Add tests * Clean up * Add tests * Update timeout * Add trackException * Clean up * Auto send exception * Send to useTrackException * Add README.md * Add entry * Add entry * Apply PR suggestions * Add references * Apply suggestions from code review Co-Authored-By: Corina <14900841+corinagum@users.noreply.github.com> * Apply PR suggestions * Prettier * Update signature * Prettier * Fix ESLint * Clean up ErrorBoundary * Update description * Clean up * Add tests * Apply suggestions from code review Co-Authored-By: TJ Durnford <tjdford@gmail.com> * Apply PR suggestions * Apply PR suggestions * Refactor to useTracker Co-authored-by: Corina <14900841+corinagum@users.noreply.github.com> Co-authored-by: TJ Durnford <tjdford@gmail.com>
- Loading branch information
1 parent
39a3b41
commit 1ac2aaa
Showing
29 changed files
with
2,058 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { timeouts } from '../constants.json'; | ||
|
||
import uiConnected from '../setup/conditions/uiConnected'; | ||
|
||
jest.setTimeout(timeouts.test); | ||
|
||
describe('useTrackDimension', () => { | ||
let driver; | ||
let pageObjects; | ||
|
||
beforeEach(async () => { | ||
const setup = await setupWebDriver({ | ||
props: { | ||
onTelemetry: event => { | ||
const { data, dimensions, duration, error, name, type } = event; | ||
|
||
name !== 'init' && | ||
(window.WebChatTest.telemetryMeasurements || (window.WebChatTest.telemetryMeasurements = [])).push({ | ||
data, | ||
dimensions, | ||
duration, | ||
error, | ||
name, | ||
type | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
driver = setup.driver; | ||
pageObjects = setup.pageObjects; | ||
|
||
await driver.wait(uiConnected(), timeouts.directLine); | ||
}); | ||
|
||
test('should track string dimension', async () => { | ||
await pageObjects.runHook('useTrackDimension', [], trackDimension => trackDimension('hello', 'aloha')); | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent('ping')); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements.length)).resolves.toBe(1); | ||
|
||
await pageObjects.runHook('useTrackDimension', [], trackDimension => trackDimension('hello')); | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent('ping2')); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"hello": "aloha", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"name": "ping", | ||
"type": "event", | ||
}, | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"name": "ping2", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should not track invalid dimension name', async () => { | ||
await pageObjects.runHook('useTrackDimension', [], trackDimension => trackDimension(123, 'hello')); | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent('ping')); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"name": "ping", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should not track invalid dimension value', async () => { | ||
await pageObjects.runHook('useTrackDimension', [], trackDimension => trackDimension('hello', 123)); | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent('ping')); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"name": "ping", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import { timeouts } from '../constants.json'; | ||
|
||
import uiConnected from '../setup/conditions/uiConnected'; | ||
|
||
jest.setTimeout(timeouts.test); | ||
|
||
describe('useTrackEvent', () => { | ||
let driver; | ||
let pageObjects; | ||
|
||
beforeEach(async () => { | ||
const setup = await setupWebDriver({ | ||
props: { | ||
onTelemetry: event => { | ||
const { data, dimensions, duration, error, level, name, type } = event; | ||
|
||
name !== 'init' && | ||
(window.WebChatTest.telemetryMeasurements || (window.WebChatTest.telemetryMeasurements = [])).push({ | ||
data, | ||
dimensions, | ||
duration, | ||
error, | ||
level, | ||
name, | ||
type | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
driver = setup.driver; | ||
pageObjects = setup.pageObjects; | ||
|
||
await driver.wait(uiConnected(), timeouts.directLine); | ||
}); | ||
|
||
test('should track simple event', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent('hello')); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"level": "info", | ||
"name": "hello", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should track simple event using info explicitly', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent.info('hello')); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"level": "info", | ||
"name": "hello", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should track numeric event', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent.warn('hello', 123)); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": 123, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"level": "warn", | ||
"name": "hello", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should track numeric event', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent.debug('hello', 'aloha')); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": "aloha", | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"level": "debug", | ||
"name": "hello", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should track complex event', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent.error('hello', { one: 1, hello: 'aloha' })); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": Object { | ||
"hello": "aloha", | ||
"one": 1, | ||
}, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": null, | ||
"level": "error", | ||
"name": "hello", | ||
"type": "event", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should not track event with boolean data', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent('hello', true)); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toBeFalsy(); | ||
}); | ||
|
||
test('should not track event with incompatible complex data', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent('hello', { truthy: true })); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toBeFalsy(); | ||
}); | ||
|
||
test('should not track event with invalid name', async () => { | ||
await pageObjects.runHook('useTrackEvent', [], trackEvent => trackEvent(123)); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toBeFalsy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { timeouts } from '../constants.json'; | ||
|
||
import uiConnected from '../setup/conditions/uiConnected'; | ||
|
||
jest.setTimeout(timeouts.test); | ||
|
||
describe('useTrackException', () => { | ||
let driver; | ||
let pageObjects; | ||
|
||
beforeEach(async () => { | ||
const setup = await setupWebDriver({ | ||
props: { | ||
onTelemetry: event => { | ||
const { data, dimensions, duration, error, fatal, name, type } = event; | ||
|
||
name !== 'init' && | ||
(window.WebChatTest.telemetryMeasurements || (window.WebChatTest.telemetryMeasurements = [])).push({ | ||
data, | ||
dimensions, | ||
duration, | ||
error: error.message, | ||
fatal, | ||
name, | ||
type | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
driver = setup.driver; | ||
pageObjects = setup.pageObjects; | ||
|
||
await driver.wait(uiConnected(), timeouts.directLine); | ||
}); | ||
|
||
test('should track exception', async () => { | ||
await pageObjects.runHook('useTrackException', [], trackException => trackException(new Error('artificial error'))); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": "artificial error", | ||
"fatal": true, | ||
"name": null, | ||
"type": "exception", | ||
}, | ||
] | ||
`); | ||
}); | ||
|
||
test('should track non-fatal exception', async () => { | ||
await pageObjects.runHook('useTrackException', [], trackException => | ||
trackException(new Error('non-fatal error'), false) | ||
); | ||
|
||
await expect(driver.executeScript(() => window.WebChatTest.telemetryMeasurements)).resolves.toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"data": null, | ||
"dimensions": Object { | ||
"capability:downscaleImage:workerType": "web worker", | ||
"prop:locale": "en-US", | ||
"prop:speechRecognition": "false", | ||
"prop:speechSynthesis": "false", | ||
}, | ||
"duration": null, | ||
"error": "non-fatal error", | ||
"fatal": false, | ||
"name": null, | ||
"type": "exception", | ||
}, | ||
] | ||
`); | ||
}); | ||
}); |
Oops, something went wrong.