Skip to content

Commit 405c80f

Browse files
committed
stabilize tests
1 parent 70dacd7 commit 405c80f

File tree

9 files changed

+41
-26
lines changed

9 files changed

+41
-26
lines changed

src/common/config/init-types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* @property {Object} [metrics]
3636
* @property {boolean} [metrics.enabled] - Turn on/off the metrics feature (on by default).
3737
* @property {boolean} [metrics.autoStart] - If true, the agent will automatically start the metrics feature. Otherwise, it will be in a deferred state until the `start` API method is called.
38-
* @property {Array<Object>} [obfuscate] - Array of regexp and corresponding replacement patterns for obfuscating data.
38+
* @property {{regex: regex | string, replacement: string}} [obfuscate] - Array of regexp and corresponding replacement patterns for obfuscating data.
3939
* @property {Object} [page_action]
4040
* @property {boolean} [page_action.enabled] - Must be true to allow PageAction events to be captured.
4141
* @property {Object} [page_view_event]

src/features/session_replay/aggregate/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export class Aggregate extends AggregateBase {
210210
makeHarvestPayload () {
211211
if (this.mode !== MODE.FULL || this.blocked) return // harvests should only be made in FULL mode, and not if the feature is blocked
212212
if (this.shouldCompress && !this.gzipper) return // if compression is enabled, but the libraries have not loaded, wait for them to load
213-
if (!this.recorder || !this.timeKeeper?.ready || !this.recorder.hasSeenSnapshot) return // if the recorder or the timekeeper is not ready, or the recorder has not yet seen a snapshot, do not harvest
213+
if (!this.recorder || !this.timeKeeper?.ready || !(this.recorder.hasSeenSnapshot && this.recorder.hasSeenMeta)) return // if the recorder or the timekeeper is not ready, or the recorder has not yet seen a snapshot, do not harvest
214214

215215
const recorderEvents = this.recorder.getEvents()
216216
// get the event type and use that to trigger another harvest if needed
@@ -241,7 +241,6 @@ export class Aggregate extends AggregateBase {
241241
// TODO -- Gracefully handle the buffer for retries.
242242
if (!this.agentRef.runtime.session.state.sessionReplaySentFirstChunk) this.syncWithSessionManager({ sessionReplaySentFirstChunk: true })
243243
this.recorder.clearBuffer()
244-
if (recorderEvents.type === 'preloaded') this.agentRef.runtime.harvester.triggerHarvestFor(this)
245244

246245
if (!this.agentRef.runtime.session.state.traceHarvestStarted) {
247246
warn(59, JSON.stringify(this.agentRef.runtime.session.state))

src/features/session_replay/shared/recorder.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export class Recorder {
4747
this.backloggedEvents = new RecorderEvents(this.shouldFix)
4848
/** Only set to true once a snapshot node has been processed. Used to block harvests from sending before we know we have a snapshot */
4949
this.hasSeenSnapshot = false
50+
this.hasSeenMeta = false
5051
/** Hold on to the last meta node, so that it can be re-inserted if the meta and snapshot nodes are broken up due to harvesting */
5152
this.lastMeta = false
5253
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
@@ -186,9 +187,9 @@ export class Recorder {
186187
}
187188

188189
// meta event
189-
this.events.hasMeta ||= event.type === RRWEB_EVENT_TYPES.Meta
190+
this.hasSeenMeta ||= this.events.hasMeta ||= event.type === RRWEB_EVENT_TYPES.Meta
190191
// snapshot event
191-
this.events.hasSnapshot ||= this.hasSeenSnapshot ||= event.type === RRWEB_EVENT_TYPES.FullSnapshot
192+
this.hasSeenSnapshot ||= this.events.hasSnapshot ||= event.type === RRWEB_EVENT_TYPES.FullSnapshot
192193

193194
//* dont let the EventBuffer class double evaluate the event data size, it's a performance burden and we have special reasons to do it outside the event buffer */
194195
this.events.add(event, eventBytes)

src/features/utils/aggregate-base.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ export class AggregateBase extends FeatureBase {
176176
* @param {boolean=} result.retry - whether the harvest should be retried
177177
*/
178178
postHarvestCleanup (result = {}) {
179-
const harvestFailed = result.sent && result.retry
180-
if (harvestFailed) this.events.reloadSave(this.harvestOpts)
179+
this.isRetrying = result.sent && result.retry
180+
if (this.isRetrying) this.events.reloadSave(this.harvestOpts)
181181
this.events.clearSave(this.harvestOpts)
182182
}
183183

tests/assets/rrweb-instrumented.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<hr />
5252
<div id="content-editable-div" contenteditable="true">text</div>
5353
<button onclick="moveImage()">Click</button>
54+
<button id="error-click" onclick="1=2">Click for Error</button>
5455
<img src="https://upload.wikimedia.org/wikipedia/commons/d/d7/House_of_Commons_Chamber_1.png" />
5556
<a href="./rrweb-instrumented.html" target="_blank">New Tab</a>
5657
<script>

tests/specs/session-replay/ingest.e2e.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ describe('Session Replay Ingest Behavior', () => {
1717
await browser.url(await browser.testHandle.assetURL('rrweb-instrumented.html', srConfig()))
1818
.then(() => browser.waitForSessionReplayRecording())
1919

20-
expect((await getSR()).events.length).toBeGreaterThan(0)
21-
2220
await sessionReplaysCapture.waitForResult({ totalCount: 2 })
2321

2422
expect((await getSR()).events.length).toEqual(0)
@@ -40,7 +38,7 @@ describe('Session Replay Ingest Behavior', () => {
4038
browser.testHandle.scheduleReply('bamServer', {
4139
test: testBlobReplayRequest,
4240
statusCode: 429
43-
}),
41+
}).then(() => $('body').click()),
4442
sessionReplaysCapture.waitForResult({ timeout: 10000 })
4543
])
4644

tests/specs/session-replay/payload.e2e.js

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,42 +75,53 @@ describe('Session Replay Payload Validation', () => {
7575
})
7676

7777
it('should match expected payload - standard', async () => {
78-
const [[sessionReplayHarvest], { localStorage: { value: session } }] = await Promise.all([
79-
sessionReplaysCapture.waitForResult({ totalCount: 1 }),
78+
const [sessionReplayHarvests, { localStorage: { value: session } }] = await Promise.all([
79+
sessionReplaysCapture.waitForResult({ totalCount: 2 }),
8080
browser.url(await browser.testHandle.assetURL('rrweb-instrumented.html', srConfig()))
8181
.then(() => browser.waitForAgentLoad())
8282
.then(() => browser.getAgentSessionInfo())
8383
])
8484

85+
const firstChunk = sessionReplayHarvests.find(x => x.request.query.attributes.includes('isFirstChunk=true'))
86+
8587
testExpectedReplay({
86-
data: sessionReplayHarvest.request,
88+
data: firstChunk.request,
8789
session,
8890
hasError: false,
8991
hasMeta: true,
9092
hasSnapshot: true,
9193
isFirstChunk: true,
92-
currentUrl: sessionReplayHarvest.request.headers.origin + '/tests/assets/rrweb-instrumented.html'
94+
currentUrl: firstChunk.request.headers.origin + '/tests/assets/rrweb-instrumented.html'
9395
})
9496
})
9597

9698
it('should match expected payload - error', async () => {
97-
const [[sessionReplayHarvest], { localStorage: { value: session } }] = await Promise.all([
98-
sessionReplaysCapture.waitForResult({ totalCount: 1 }),
99+
const [sessionReplayHarvests, { localStorage: { value: session } }] = await Promise.all([
100+
sessionReplaysCapture.waitForResult({ totalCount: 2 }),
99101
browser.url(await browser.testHandle.assetURL('rrweb-instrumented.html', srConfig()))
100102
.then(() => browser.waitForAgentLoad())
101103
.then(() => browser.getAgentSessionInfo())
102104
])
103105

104-
testExpectedReplay({ data: sessionReplayHarvest.request, session, hasError: false, hasMeta: true, hasSnapshot: true, isFirstChunk: true })
106+
const firstChunk = sessionReplayHarvests.find(x => x.request.query.attributes.includes('isFirstChunk=true'))
105107

106-
const [sessionReplayHarvests] = await Promise.all([
108+
testExpectedReplay({
109+
data: firstChunk.request,
110+
session,
111+
hasError: false,
112+
hasMeta: true,
113+
hasSnapshot: true,
114+
isFirstChunk: true
115+
})
116+
117+
const [errorHarvest] = await Promise.all([
107118
sessionReplaysCapture.waitForResult({ timeout: 10000 }),
108119
browser.execute(function () {
109-
newrelic.noticeError(new Error('test'))
120+
document.querySelector('#error-click').click()
110121
})
111122
])
112123

113-
const errorSessionReplayHarvest = sessionReplayHarvests.find(harvest => harvest.request.query.attributes.indexOf('hasError=true') !== -1)
124+
const errorSessionReplayHarvest = errorHarvest.find(harvest => harvest.request.query.attributes.indexOf('hasError=true') !== -1)
114125
testExpectedReplay({ data: errorSessionReplayHarvest.request, session, hasError: true, isFirstChunk: false })
115126
})
116127

tests/specs/session-replay/rrweb-configuration.e2e.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ describe('RRWeb Configuration', () => {
9393

9494
const sessionReplaysHarvests = await sessionReplaysCapture.waitForResult({ timeout: 10000 })
9595
expect(sessionReplaysHarvests.length).toBeGreaterThanOrEqual(1)
96-
expect(decodeAttributes(sessionReplaysHarvests[0].request.query.attributes).hasSnapshot).toEqual(true)
96+
const snapshotHarvest = sessionReplaysHarvests.find(x => decodeAttributes(x.request.query.attributes).hasSnapshot === true)
97+
expect(snapshotHarvest).toBeDefined()
9798

9899
// note: we need to leave text nodes containing only whitespace as-is to avoid adding extraneous '*'
99100
const whitespaceOnlyNodes = JSONPath({ path: '$.[*].request.body.[?(!!@ && @.type===3 && !!@.textContent && @.textContent.match(/^\\s+$/) && ![\'script\',\'link\',\'style\'].includes(@parent.tagName))]', json: sessionReplaysHarvests })
@@ -120,7 +121,8 @@ describe('RRWeb Configuration', () => {
120121

121122
const sessionReplaysHarvests = await sessionReplaysCapture.waitForResult({ timeout: 10000 })
122123
expect(sessionReplaysHarvests.length).toBeGreaterThanOrEqual(1)
123-
expect(decodeAttributes(sessionReplaysHarvests[0].request.query.attributes).hasSnapshot).toEqual(true)
124+
const snapshotHarvest = sessionReplaysHarvests.find(x => decodeAttributes(x.request.query.attributes).hasSnapshot === true)
125+
expect(snapshotHarvest).toBeDefined()
124126

125127
const testNodes = JSONPath({ path: '$.[*].request.body.[?(!!@ && @.type===3 && !!@.textContent && ![\'script\',\'link\',\'style\'].includes(@parent.tagName))]', json: sessionReplaysHarvests })
126128
expect(testNodes.length).toBeGreaterThan(0)
@@ -397,10 +399,12 @@ async function checkSessionReplayInputMasking (sessionReplaysCapture, elements)
397399
// Wait 10 seconds for additional harvests
398400
const sessionReplaysHarvests = await sessionReplaysCapture.waitForResult({ timeout: 10000 })
399401
expect(sessionReplaysHarvests.length).toBeGreaterThanOrEqual(1)
400-
expect(decodeAttributes(sessionReplaysHarvests[0].request.query.attributes).hasSnapshot).toEqual(true)
402+
403+
const snapshotHarvest = sessionReplaysHarvests.find(x => decodeAttributes(x.request.query.attributes).hasSnapshot === true)
404+
expect(snapshotHarvest).toBeDefined()
401405

402406
elements.forEach(el => {
403-
const snapshotNodes = JSONPath({ path: `$.request.body.[?(${el.jsonPathFilter})]`, json: sessionReplaysHarvests[0] })
407+
const snapshotNodes = JSONPath({ path: `$.request.body.[?(${el.jsonPathFilter})]`, json: snapshotHarvest })
404408
expect(snapshotNodes.length).toBeGreaterThanOrEqual(1)
405409

406410
snapshotNodes.forEach(node => {

tests/specs/session-replay/session-state.e2e.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('session manager state behavior', () => {
5050
it('should end recording and clear the buffer', async () => {
5151
const sessionReplayCapture = await browser.testHandle.createNetworkCaptures('bamServer', { test: testBlobReplayRequest })
5252
await browser.enableSessionReplay()
53-
await browser.url(await browser.testHandle.assetURL('rrweb-instrumented.html', { init: { session: { expiresMs: 7500 }, session_replay: { enabled: true } } }))
53+
await browser.url(await browser.testHandle.assetURL('rrweb-instrumented.html', { init: { session_replay: { enabled: true } } }))
5454
.then(() => browser.waitForSessionReplayRecording())
5555

5656
// session has started, replay should have set mode to "FULL"
@@ -66,7 +66,8 @@ describe('session manager state behavior', () => {
6666
})
6767
])
6868

69-
expect(sessionReplayHarvests.length).toEqual(1)
69+
// Shouldnt find the click because the session reset and doesnt force a harvest
70+
expect(sessionReplayHarvests.find(x => x.request.body.find(y => y.type === RRWEB_EVENT_TYPES.IncrementalSnapshot && y.data.x === 0 && y.data.y === 0))).not.toBeTruthy()
7071
})
7172
})
7273

0 commit comments

Comments
 (0)