|
1 |
| -import { getCurrentHub } from '@sentry/core'; |
| 1 | +import { getCurrentHub, Hub } from '@sentry/core'; |
| 2 | +import { Event, Scope } from '@sentry/types'; |
2 | 3 | import { EventType } from 'rrweb';
|
3 | 4 |
|
4 | 5 | import {
|
@@ -747,54 +748,6 @@ describe('Replay', () => {
|
747 | 748 | });
|
748 | 749 | });
|
749 | 750 |
|
750 |
| - // TODO: ... this doesn't really test anything anymore since replay event and recording are sent in the same envelope |
751 |
| - it('does not create replay event if recording upload completely fails', async () => { |
752 |
| - const TEST_EVENT = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 }; |
753 |
| - // Suppress console.errors |
754 |
| - const mockConsole = jest.spyOn(console, 'error').mockImplementation(jest.fn()); |
755 |
| - // fail the first and second requests and pass the third one |
756 |
| - mockSendReplayRequest.mockImplementationOnce(() => { |
757 |
| - throw new Error('Something bad happened'); |
758 |
| - }); |
759 |
| - mockRecord._emitter(TEST_EVENT); |
760 |
| - |
761 |
| - await advanceTimers(5000); |
762 |
| - |
763 |
| - expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); |
764 |
| - |
765 |
| - // Reset console.error mock to minimize the amount of time we are hiding |
766 |
| - // console messages in case an error happens after |
767 |
| - mockConsole.mockClear(); |
768 |
| - expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); |
769 |
| - |
770 |
| - mockSendReplayRequest.mockImplementationOnce(() => { |
771 |
| - throw new Error('Something bad happened'); |
772 |
| - }); |
773 |
| - await advanceTimers(5000); |
774 |
| - expect(replay.sendReplayRequest).toHaveBeenCalledTimes(2); |
775 |
| - |
776 |
| - // next tick should retry and fail |
777 |
| - mockConsole.mockClear(); |
778 |
| - |
779 |
| - mockSendReplayRequest.mockImplementationOnce(() => { |
780 |
| - throw new Error('Something bad happened'); |
781 |
| - }); |
782 |
| - await advanceTimers(10000); |
783 |
| - expect(replay.sendReplayRequest).toHaveBeenCalledTimes(3); |
784 |
| - |
785 |
| - mockSendReplayRequest.mockImplementationOnce(() => { |
786 |
| - throw new Error('Something bad happened'); |
787 |
| - }); |
788 |
| - await advanceTimers(30000); |
789 |
| - expect(replay.sendReplayRequest).toHaveBeenCalledTimes(4); |
790 |
| - |
791 |
| - // No activity has occurred, session's last activity should remain the same |
792 |
| - expect(replay.session?.lastActivity).toBeGreaterThanOrEqual(BASE_TIMESTAMP); |
793 |
| - expect(replay.session?.segmentId).toBe(1); |
794 |
| - |
795 |
| - // TODO: Recording should stop and next event should do nothing |
796 |
| - }); |
797 |
| - |
798 | 751 | it('has correct timestamps when there events earlier than initial timestamp', async function () {
|
799 | 752 | replay.clearSession();
|
800 | 753 | replay.loadSession({ expiry: 0 });
|
@@ -920,3 +873,77 @@ describe('Replay', () => {
|
920 | 873 | expect(replay.flush).toHaveBeenCalledTimes(1);
|
921 | 874 | });
|
922 | 875 | });
|
| 876 | + |
| 877 | +describe('eventProcessors', () => { |
| 878 | + let hub: Hub; |
| 879 | + let scope: Scope; |
| 880 | + |
| 881 | + beforeEach(() => { |
| 882 | + hub = getCurrentHub(); |
| 883 | + scope = hub.pushScope(); |
| 884 | + }); |
| 885 | + |
| 886 | + afterEach(() => { |
| 887 | + hub.popScope(); |
| 888 | + jest.resetAllMocks(); |
| 889 | + }); |
| 890 | + |
| 891 | + it('handles event processors properly', async () => { |
| 892 | + const MUTATED_TIMESTAMP = BASE_TIMESTAMP + 3000; |
| 893 | + |
| 894 | + const { mockRecord } = await resetSdkMock({ |
| 895 | + replayOptions: { |
| 896 | + stickySession: false, |
| 897 | + }, |
| 898 | + }); |
| 899 | + |
| 900 | + const client = hub.getClient()!; |
| 901 | + |
| 902 | + jest.runAllTimers(); |
| 903 | + const mockTransportSend = jest.spyOn(client.getTransport()!, 'send'); |
| 904 | + mockTransportSend.mockReset(); |
| 905 | + |
| 906 | + const handler1 = jest.fn((event: Event): Event | null => { |
| 907 | + event.timestamp = MUTATED_TIMESTAMP; |
| 908 | + |
| 909 | + return event; |
| 910 | + }); |
| 911 | + |
| 912 | + const handler2 = jest.fn((): Event | null => { |
| 913 | + return null; |
| 914 | + }); |
| 915 | + |
| 916 | + scope.addEventProcessor(handler1); |
| 917 | + |
| 918 | + const TEST_EVENT = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 }; |
| 919 | + |
| 920 | + mockRecord._emitter(TEST_EVENT); |
| 921 | + jest.runAllTimers(); |
| 922 | + jest.advanceTimersByTime(1); |
| 923 | + await new Promise(process.nextTick); |
| 924 | + |
| 925 | + expect(mockTransportSend).toHaveBeenCalledTimes(1); |
| 926 | + |
| 927 | + scope.addEventProcessor(handler2); |
| 928 | + |
| 929 | + const TEST_EVENT2 = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 }; |
| 930 | + |
| 931 | + mockRecord._emitter(TEST_EVENT2); |
| 932 | + jest.runAllTimers(); |
| 933 | + jest.advanceTimersByTime(1); |
| 934 | + await new Promise(process.nextTick); |
| 935 | + |
| 936 | + expect(mockTransportSend).toHaveBeenCalledTimes(1); |
| 937 | + |
| 938 | + expect(handler1).toHaveBeenCalledTimes(2); |
| 939 | + expect(handler2).toHaveBeenCalledTimes(1); |
| 940 | + |
| 941 | + // This receives an envelope, which is a deeply nested array |
| 942 | + // We only care about the fact that the timestamp was mutated |
| 943 | + expect(mockTransportSend).toHaveBeenCalledWith( |
| 944 | + expect.arrayContaining([ |
| 945 | + expect.arrayContaining([expect.arrayContaining([expect.objectContaining({ timestamp: MUTATED_TIMESTAMP })])]), |
| 946 | + ]), |
| 947 | + ); |
| 948 | + }); |
| 949 | +}); |
0 commit comments