123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- import {initializeOrg} from 'sentry-test/initializeOrg';
- import {reactHooks} from 'sentry-test/reactTestingLibrary';
- import fetchReplayClicks from 'sentry/utils/replays/fetchReplayClicks';
- import useInitialTimeOffsetMs from 'sentry/utils/replays/hooks/useInitialTimeOffsetMs';
- import {useLocation} from 'sentry/utils/useLocation';
- jest.mock('sentry/utils/useLocation');
- jest.mock('sentry/utils/replays/fetchReplayClicks');
- const MockUseLocation = useLocation as jest.MockedFunction<typeof useLocation>;
- const MockFetchReplayClicks = fetchReplayClicks as jest.MockedFunction<
- typeof fetchReplayClicks
- >;
- const {organization, project} = initializeOrg();
- const replay = TestStubs.ReplayRecord();
- const NOON = '2023-04-14T12:00:00';
- const FIVE_PAST_NOON = '2023-04-14T12:05:00';
- function mockQuery(query: Record<string, string>) {
- MockUseLocation.mockReturnValue({
- pathname: '',
- search: '',
- query,
- hash: '',
- state: undefined,
- action: 'PUSH',
- key: '',
- });
- }
- describe('useInitialTimeOffsetMs', () => {
- beforeEach(() => {
- MockUseLocation.mockClear();
- MockFetchReplayClicks.mockClear();
- });
- describe('fromOffset', () => {
- it('should return an offset, in ms, if `t` exists in the query', async () => {
- const offsetInSeconds = 23;
- mockQuery({t: String(offsetInSeconds)});
- const {result, waitForNextUpdate} = reactHooks.renderHook(useInitialTimeOffsetMs, {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: undefined,
- },
- });
- await waitForNextUpdate();
- expect(result.current).toBe(23 * 1000);
- });
- it('should prefer reading `t` over the other qs params', async () => {
- const offsetInSeconds = 23;
- mockQuery({
- t: String(offsetInSeconds),
- event_t: FIVE_PAST_NOON,
- query: 'click.tag:button',
- });
- const {result, waitForNextUpdate} = reactHooks.renderHook(useInitialTimeOffsetMs, {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: undefined,
- },
- });
- await waitForNextUpdate();
- expect(result.current).toBe(23 * 1000);
- expect(MockFetchReplayClicks).toHaveBeenCalledTimes(0);
- });
- });
- describe('fromEventTimestamp', () => {
- it('should calculate the difference between an event timestamp and the replay start timestamp', async () => {
- const noon = '2023-04-14T12:00:00';
- const fivePastNoon = '2023-04-14T12:05:00';
- mockQuery({event_t: fivePastNoon});
- const {result, waitForNextUpdate} = reactHooks.renderHook(useInitialTimeOffsetMs, {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: new Date(noon).getTime(),
- },
- });
- await waitForNextUpdate();
- // Expecting 5 minutes difference, in ms
- expect(result.current).toBe(5 * 60 * 1000);
- });
- it('should return 0 offset if there is no replayStartTimetsamp, then recalculate when the startTimestamp appears', async () => {
- mockQuery({event_t: FIVE_PAST_NOON});
- const {result, rerender, waitForNextUpdate} = reactHooks.renderHook(
- useInitialTimeOffsetMs,
- {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: undefined,
- },
- }
- );
- await waitForNextUpdate();
- expect(result.current).toBe(0);
- rerender({
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: new Date(NOON).getTime(),
- });
- await waitForNextUpdate();
- // Expecting 5 minutes difference, in ms
- expect(result.current).toBe(5 * 60 * 1000);
- });
- it('should prefer reading `event_t` over the other search query params', async () => {
- mockQuery({
- event_t: FIVE_PAST_NOON,
- query: 'click.tag:button',
- });
- MockFetchReplayClicks.mockResolvedValue({
- fetchError: undefined,
- pageLinks: '',
- clicks: [],
- });
- const {result, waitForNextUpdate} = reactHooks.renderHook(useInitialTimeOffsetMs, {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: new Date(NOON).getTime(),
- },
- });
- await waitForNextUpdate();
- expect(result.current).toBe(5 * 60 * 1000);
- expect(MockFetchReplayClicks).toHaveBeenCalledTimes(0);
- });
- });
- describe('fromListPageQuery', () => {
- it('should skip this strategy if there is no `click.*` term in the query', async () => {
- mockQuery({query: 'user.email:*@sentry.io'});
- const {result, waitForNextUpdate} = reactHooks.renderHook(useInitialTimeOffsetMs, {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: new Date(NOON).getTime(),
- },
- });
- await waitForNextUpdate();
- expect(MockFetchReplayClicks).toHaveBeenCalledTimes(0);
- expect(result.current).toBe(0);
- });
- it('should request a list of click results, and calculate the offset from the first result', async () => {
- mockQuery({query: 'click.tag:button'});
- MockFetchReplayClicks.mockResolvedValue({
- fetchError: undefined,
- pageLinks: '',
- clicks: [{node_id: 7, timestamp: FIVE_PAST_NOON}],
- });
- const {result, waitForNextUpdate} = reactHooks.renderHook(useInitialTimeOffsetMs, {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: new Date(NOON).getTime(),
- },
- });
- await waitForNextUpdate();
- expect(MockFetchReplayClicks).toHaveBeenCalledTimes(1);
- // Expecting 5 minutes difference, in ms
- expect(result.current).toBe(5 * 60 * 1000);
- });
- it('should not call call fetch twice when props change', async () => {
- mockQuery({query: 'click.tag:button'});
- MockFetchReplayClicks.mockResolvedValue({
- fetchError: undefined,
- pageLinks: '',
- clicks: [{node_id: 7, timestamp: FIVE_PAST_NOON}],
- });
- const {result, rerender, waitForNextUpdate} = reactHooks.renderHook(
- useInitialTimeOffsetMs,
- {
- initialProps: {
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: undefined,
- },
- }
- );
- await waitForNextUpdate();
- expect(MockFetchReplayClicks).toHaveBeenCalledTimes(0);
- expect(result.current).toBe(0);
- rerender({
- orgSlug: organization.slug,
- replaySlug: `${project.slug}:${replay.id}`,
- replayStartTimestampMs: new Date(NOON).getTime(),
- });
- await waitForNextUpdate();
- expect(MockFetchReplayClicks).toHaveBeenCalledTimes(1);
- expect(result.current).toBe(5 * 60 * 1000);
- });
- });
- });
|