fix the skip event calculation (#242)

This commit is contained in:
yz-yu
2026-04-01 12:00:00 +08:00
committed by GitHub
parent ae71cf106a
commit a8b493799b
5 changed files with 67 additions and 20 deletions

View File

@@ -216,10 +216,10 @@ export class Replayer {
* @param timeOffset number * @param timeOffset number
*/ */
public play(timeOffset = 0) { public play(timeOffset = 0) {
if (this.service.state.value == 'ended') { if (this.service.state.value === 'ended') {
this.service.send({ type: 'REPLAY'}); this.service.send({ type: 'REPLAY' });
} }
if (this.service.state.value == 'paused') { if (this.service.state.value === 'paused') {
this.service.send({ type: 'RESUME', payload: { timeOffset } }); this.service.send({ type: 'RESUME', payload: { timeOffset } });
} else { } else {
this.service.send({ type: 'PLAY', payload: { timeOffset } }); this.service.send({ type: 'PLAY', payload: { timeOffset } });

View File

@@ -79,27 +79,37 @@ export type PlayerState =
* If the array have multiple meta and fullsnapshot events, * If the array have multiple meta and fullsnapshot events,
* return the events from last meta to the end. * return the events from last meta to the end.
*/ */
export function getLastSession(events: eventWithTime[]): eventWithTime[] { export function getLastSession(
const lastSession: eventWithTime[] = []; events: eventWithTime[],
baselineTime: number,
let hasFullSnapshot = false; ): eventWithTime[] {
let hasMeta = false; let startMetaIdx: number | null = null;
let endMetaIdx: number | null = null;
for (let idx = events.length - 1; idx >= 0; idx--) { for (let idx = events.length - 1; idx >= 0; idx--) {
const event = events[idx]; const event = events[idx];
lastSession.unshift(event);
if (event.type === EventType.FullSnapshot) {
hasFullSnapshot = true;
}
if (event.type === EventType.Meta) { if (event.type === EventType.Meta) {
hasMeta = true; if (event.timestamp > baselineTime) {
endMetaIdx = idx;
} else {
startMetaIdx = idx;
}
} }
if (hasFullSnapshot && hasMeta) { if (startMetaIdx !== null) {
break; break;
} }
} }
return lastSession; // baseline time is less than first meta event
if (startMetaIdx === null && endMetaIdx !== null) {
startMetaIdx = endMetaIdx;
endMetaIdx = null;
}
return events.slice(
startMetaIdx ?? 0,
endMetaIdx === null ? events.length : endMetaIdx + 1,
);
} }
type PlayerAssets = { type PlayerAssets = {
@@ -198,12 +208,13 @@ export function createPlayerService(
play(ctx) { play(ctx) {
const { timer, events, baselineTime, lastPlayedEvent } = ctx; const { timer, events, baselineTime, lastPlayedEvent } = ctx;
timer.clear(); timer.clear();
const neededEvents = getLastSession(events); const neededEvents = getLastSession(events, baselineTime);
const actions = new Array<actionWithDelay>(); const actions = new Array<actionWithDelay>();
for (const event of neededEvents) { for (const event of neededEvents) {
if ( if (
lastPlayedEvent && lastPlayedEvent &&
lastPlayedEvent.timestamp > baselineTime &&
(event.timestamp <= lastPlayedEvent.timestamp || (event.timestamp <= lastPlayedEvent.timestamp ||
event === lastPlayedEvent) event === lastPlayedEvent)
) { ) {

View File

@@ -336,6 +336,8 @@ export type playerConfig = {
}; };
export type playerMetaData = { export type playerMetaData = {
startTime: number;
endTime: number;
totalTime: number; totalTime: number;
}; };

View File

@@ -6,14 +6,43 @@ import { EventType } from '../src/types';
const events = sampleEvents.filter( const events = sampleEvents.filter(
(e) => ![EventType.DomContentLoaded, EventType.Load].includes(e.type), (e) => ![EventType.DomContentLoaded, EventType.Load].includes(e.type),
); );
const nextEvents = events.map((e) => ({
...e,
timestamp: e.timestamp + 1000,
}));
const nextNextEvents = nextEvents.map((e) => ({
...e,
timestamp: e.timestamp + 1000,
}));
describe('get last session', () => { describe('get last session', () => {
it('will return all the events when there is only one session', () => { it('will return all the events when there is only one session', () => {
expect(getLastSession(events)).to.deep.equal(events); expect(getLastSession(events, events[0].timestamp)).to.deep.equal(events);
}); });
it('will return last session when there is more than one in the events', () => { it('will return last session when there is more than one in the events', () => {
const multiple = events.concat(events).concat(events); const multiple = events.concat(nextEvents).concat(nextNextEvents);
expect(getLastSession(multiple)).to.deep.equal(events); expect(
getLastSession(
multiple,
nextNextEvents[nextNextEvents.length - 1].timestamp,
),
).to.deep.equal(nextNextEvents);
});
it('will return last session when baseline time is future time', () => {
const multiple = events.concat(nextEvents).concat(nextNextEvents);
expect(
getLastSession(
multiple,
nextNextEvents[nextNextEvents.length - 1].timestamp + 1000,
),
).to.deep.equal(nextNextEvents);
});
it('will return first session when baseline time is previous time', () => {
expect(getLastSession(events, events[0].timestamp - 1000)).to.deep.equal(
events,
);
}); });
}); });

View File

@@ -6,6 +6,7 @@ import * as puppeteer from 'puppeteer';
import { expect } from 'chai'; import { expect } from 'chai';
import { Suite } from 'mocha'; import { Suite } from 'mocha';
import { launchPuppeteer, sampleEvents as events } from './utils'; import { launchPuppeteer, sampleEvents as events } from './utils';
import { EventType } from '../src/types';
interface ISuite extends Suite { interface ISuite extends Suite {
code: string; code: string;
@@ -59,7 +60,11 @@ describe('replayer', function (this: ISuite) {
replayer.play(); replayer.play();
replayer['timer']['actions'].length; replayer['timer']['actions'].length;
`); `);
expect(actionLength).to.equal(events.length); expect(actionLength).to.equal(
events.filter(
(e) => ![EventType.DomContentLoaded, EventType.Load].includes(e.type),
).length,
);
}); });
it('will clean actions when pause', async () => { it('will clean actions when pause', async () => {