-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add time on site #975
Conversation
src/foregroundTimeTracker.ts
Outdated
} | ||
|
||
private handleVisibilityChange(): void { | ||
if (document.hidden) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we abstract the document out? could this be some sort of "visibility handler"?
src/foregroundTimeTracker.ts
Outdated
|
||
private startTracking(): void { | ||
if (!document.hidden) { | ||
this.startTime = performance.now(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check for existence of it
src/foregroundTimeTracker.ts
Outdated
this.isActive = true; | ||
setInterval(() => { | ||
console.log(this.totalTime); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}); | |
}, 1000); |
61c2f16
to
32d51dd
Compare
944f03a
to
dba55e2
Compare
src/foregroundTimeTracker.ts
Outdated
public startTime: number = 0; | ||
public totalTime: number = 0; | ||
|
||
constructor(apiKey: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Technically this isn't really the apiKey
but a timerKey
since it doesn't make a call to the api. I'm not adamant about this though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true and actually i should pass in the workspaceToken
which we use for our general storage as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually seems like when i try to use workspaceToken
that I need to instantiate the foreground timer in the store which is when the workspaceToken
i available. so for now i'm going to keep using it as the apikey but call it the timerKey
in line. this is a small detail that I think we can discuss once the other PRs are in.
src/mp-instance.ts
Outdated
@@ -66,6 +67,7 @@ export type IntegrationDelays = Dictionary<boolean>; | |||
// https://go.mparticle.com/work/SQDSDKS-6949 | |||
export interface IMParticleWebSDKInstance extends MParticleWebSDK { | |||
// Private Properties | |||
_timer: ForegroundTimer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_timer
is too generic. I would call this something like _foregroundTimer
, _timeOnSiteTimer
or something relevant to the use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good call. this was originally just a filler to get a POC going. i'll update now
src/sessionManager.ts
Outdated
@@ -132,6 +132,7 @@ export default function SessionManager( | |||
}); | |||
|
|||
mpInstance._Store.nullifySession(); | |||
mpInstance._timer.resetTimer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing that you're adding this here, I would think we should also add it to the Messages.InformationMessages.NoSessionToEnd
and Messages.InformationMessages.AbandonEndSession
lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good call
jest.restoreAllMocks(); | ||
}); | ||
|
||
// in Jest, document.hidden by default is false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would put this comment in the beforeEach
section
4b4edcb
to
2b671dd
Compare
2b671dd
to
77175f9
Compare
src/foregroundTimeTracker.ts
Outdated
window.addEventListener('storage', this.syncAcrossTabs); | ||
this.startTracking(); | ||
|
||
// TODO: this is just to ensure when we load it in an app we can see the timer updates in the console |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sustained Engineering: There could be some value in adding our debug logger here so that if debug === true
, we can fire this log. I'm fine with it being a ticket for later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i decided to move this ahead, because by calling getForegroundTime
we end up calling updateTotalTime
and i just don't want it to create unintended consequences.
test/src/tests-batchUploader.ts
Outdated
@@ -136,11 +137,11 @@ describe('batch uploader', () => { | |||
fetchMock.restore(); | |||
}); | |||
|
|||
it('should reject batches without events', (done) => { | |||
it.only('should reject batches without events', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you still need this?
test/src/tests-batchUploader.ts
Outdated
@@ -155,6 +156,8 @@ describe('batch uploader', () => { | |||
}; | |||
|
|||
const actualBatch = batchValidator.returnBatch(baseEvent); | |||
console.log('actualBatch.events[0]'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you still need this?
test/src/tests-batchUploader.ts
Outdated
@@ -174,12 +177,11 @@ describe('batch uploader', () => { | |||
); | |||
|
|||
expect(actualBatchResult.events.length).to.equal(1); | |||
console.log('actualBatchResult.events[0]') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you still need this?
}); | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to repeat this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
each describe block should have this, right? i'm being extra cautious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC describe blocks should inherit from their parents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah. from testing it looks like you're right
}); | ||
|
||
describe('constructor', () => { | ||
let tracker: ForegroundTimeTracker; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see you using this in this block.
let tracker: ForegroundTimeTracker; |
|
||
it('should call startTracking if the document is not hidden', () => { | ||
Object.defineProperty(document, 'hidden', { value: false }); | ||
const startTrackingSpy = jest.spyOn(ForegroundTimeTracker.prototype as any, 'startTracking'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should avoid using any
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was trying a few different things, including creating an IForegroundTimeTracker
, but was running into issues because there are a lot of private methods in the ForegroundTimeTracker
. let's sync in the morning
expect(startTrackingSpy).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should not call startTracking is the document is not hidden', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it('should not call startTracking is the document is not hidden', () => { | |
it('should not call startTracking if the document is hidden', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great catch! copy and paste error
}); | ||
|
||
it('should call handleVisibilityChange when visibility changes', () => { | ||
const spy = jest.spyOn(tracker as any, 'handleVisibilityChange'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. These should not be any
.
expect(syncSpy).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should update totalTime when newValue is passed', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I would rewrite the test string to reference something other than newValue
since it isn't obvious as to what this value is for.
}); | ||
}); | ||
|
||
describe('addHandlers', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We should follow the convention be of .
when referring to a class method’s name and #
when referring to an instance method’s name.
9f43d29
to
f4c35a2
Compare
package.json
Outdated
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "@mparticle/web-sdk", | |||
"version": "2.32.3", | |||
"version": "2.32.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was committed accidentally.
package-lock.json
Outdated
@@ -1,12 +1,12 @@ | |||
{ | |||
"name": "@mparticle/web-sdk", | |||
"version": "2.32.3", | |||
"version": "2.32.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was committed accidentally.
CHANGELOG.md
Outdated
@@ -1,3 +1,10 @@ | |||
## [2.32.4](https://github.com/mParticle/mparticle-web-sdk/compare/v2.32.3...v2.32.4) (2025-02-10) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was committed accidentally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this is because i didn't rebase the feature branch properly. this should be good now
src/sessionManager.ts
Outdated
@@ -132,17 +132,20 @@ export default function SessionManager( | |||
}); | |||
|
|||
mpInstance._Store.nullifySession(); | |||
mpInstance._Store.timeOnSiteTimer.resetTimer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mpInstance._Store.timeOnSiteTimer.resetTimer(); | |
mpInstance._Store.timeOnSiteTimer?.resetTimer(); |
src/sessionManager.ts
Outdated
// - the SDK's store is not enabled because mParticle.setOptOut was called | ||
// - the devToken is undefined | ||
// - webviewBridgeEnabled is set to false | ||
mpInstance.Logger.verbose( | ||
Messages.InformationMessages.AbandonEndSession | ||
); | ||
mpInstance._Store.timeOnSiteTimer.resetTimer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mpInstance._Store.timeOnSiteTimer.resetTimer(); | |
mpInstance._Store.timeOnSiteTimer?.resetTimer(); |
src/sessionManager.ts
Outdated
@@ -155,6 +158,8 @@ export default function SessionManager( | |||
mpInstance.Logger.verbose( | |||
Messages.InformationMessages.NoSessionToEnd | |||
); | |||
mpInstance._Store.timeOnSiteTimer.resetTimer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mpInstance._Store.timeOnSiteTimer.resetTimer(); | |
mpInstance._Store.timeOnSiteTimer?.resetTimer(); |
src/sessionManager.ts
Outdated
@@ -180,6 +185,8 @@ export default function SessionManager( | |||
mpInstance._Store.nullifySession(); | |||
} | |||
} | |||
|
|||
mpInstance._Store.timeOnSiteTimer.resetTimer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mpInstance._Store.timeOnSiteTimer.resetTimer(); | |
mpInstance._Store.timeOnSiteTimer?.resetTimer(); |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🖖
# [2.33.0](v2.32.5...v2.33.0) (2025-02-13) ### Features * Add time on site ([#975](#975)) ([3645120](3645120))
Instructions
development
Summary
This initial PR gets a class for Foreground
Testing Plan
Reference Issue (For mParticle employees only. Ignore if you are an outside contributor)