@@ -2,174 +2,15 @@ import * as sentryCore from '@sentry/core';
2
2
import * as sentryHub from '@sentry/hub' ;
3
3
import { Hub } from '@sentry/hub' ;
4
4
import { Transaction } from '@sentry/tracing' ;
5
- import { Baggage } from '@sentry/types' ;
5
+ import { Baggage , Event } from '@sentry/types' ;
6
6
import { SentryError } from '@sentry/utils' ;
7
7
import * as http from 'http' ;
8
- import * as net from 'net' ;
9
8
10
- import { Event , Request , User } from '../src' ;
11
9
import { NodeClient } from '../src/client' ;
12
- import {
13
- errorHandler ,
14
- ExpressRequest ,
15
- extractRequestData ,
16
- parseRequest ,
17
- requestHandler ,
18
- tracingHandler ,
19
- } from '../src/handlers' ;
10
+ import { errorHandler , requestHandler , tracingHandler } from '../src/handlers' ;
20
11
import * as SDK from '../src/sdk' ;
21
12
import { getDefaultNodeClientOptions } from './helper/node-client-options' ;
22
13
23
- describe ( 'parseRequest' , ( ) => {
24
- let mockReq : { [ key : string ] : any } ;
25
-
26
- beforeEach ( ( ) => {
27
- mockReq = {
28
- baseUrl : '/routerMountPath' ,
29
- body : 'foo' ,
30
- cookies : { test : 'test' } ,
31
- headers : {
32
- host : 'mattrobenolt.com' ,
33
- } ,
34
- method : 'POST' ,
35
- originalUrl : '/routerMountPath/subpath/specificValue?querystringKey=querystringValue' ,
36
- path : '/subpath/specificValue' ,
37
- query : {
38
- querystringKey : 'querystringValue' ,
39
- } ,
40
- route : {
41
- path : '/subpath/:parameterName' ,
42
- stack : [
43
- {
44
- name : 'parameterNameRouteHandler' ,
45
- } ,
46
- ] ,
47
- } ,
48
- url : '/subpath/specificValue?querystringKey=querystringValue' ,
49
- user : {
50
- custom_property : 'foo' ,
51
-
52
- id : 123 ,
53
- username : 'tobias' ,
54
- } ,
55
- } ;
56
- } ) ;
57
-
58
- describe ( 'parseRequest.user properties' , ( ) => {
59
- const DEFAULT_USER_KEYS = [ 'id' , 'username' , 'email' ] ;
60
- const CUSTOM_USER_KEYS = [ 'custom_property' ] ;
61
-
62
- test ( 'parseRequest.user only contains the default properties from the user' , ( ) => {
63
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest ) ;
64
- expect ( Object . keys ( parsedRequest . user as User ) ) . toEqual ( DEFAULT_USER_KEYS ) ;
65
- } ) ;
66
-
67
- test ( 'parseRequest.user only contains the custom properties specified in the options.user array' , ( ) => {
68
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest , {
69
- user : CUSTOM_USER_KEYS ,
70
- } ) ;
71
- expect ( Object . keys ( parsedRequest . user as User ) ) . toEqual ( CUSTOM_USER_KEYS ) ;
72
- } ) ;
73
-
74
- test ( 'parseRequest.user doesnt blow up when someone passes non-object value' , ( ) => {
75
- const parsedRequest : Event = parseRequest (
76
- { } ,
77
- {
78
- ...mockReq ,
79
- // @ts -ignore user is not assignable to object
80
- user : 'wat' ,
81
- } ,
82
- ) ;
83
- expect ( Object . keys ( parsedRequest . user as User ) ) . toEqual ( [ ] ) ;
84
- } ) ;
85
- } ) ;
86
-
87
- describe ( 'parseRequest.ip property' , ( ) => {
88
- test ( 'can be extracted from req.ip' , ( ) => {
89
- const parsedRequest : Event = parseRequest (
90
- { } ,
91
- {
92
- ...mockReq ,
93
- ip : '123' ,
94
- } as ExpressRequest ,
95
- {
96
- ip : true ,
97
- } ,
98
- ) ;
99
- expect ( parsedRequest . user ! . ip_address ) . toEqual ( '123' ) ;
100
- } ) ;
101
-
102
- test ( 'can extract from req.connection.remoteAddress' , ( ) => {
103
- const parsedRequest : Event = parseRequest (
104
- { } ,
105
- {
106
- ...mockReq ,
107
- connection : {
108
- remoteAddress : '321' ,
109
- } as net . Socket ,
110
- } as ExpressRequest ,
111
- {
112
- ip : true ,
113
- } ,
114
- ) ;
115
- expect ( parsedRequest . user ! . ip_address ) . toEqual ( '321' ) ;
116
- } ) ;
117
- } ) ;
118
-
119
- describe ( 'parseRequest.request properties' , ( ) => {
120
- test ( 'parseRequest.request only contains the default set of properties from the request' , ( ) => {
121
- const DEFAULT_REQUEST_PROPERTIES = [ 'cookies' , 'data' , 'headers' , 'method' , 'query_string' , 'url' ] ;
122
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest ) ;
123
- expect ( Object . keys ( parsedRequest . request as Request ) ) . toEqual ( DEFAULT_REQUEST_PROPERTIES ) ;
124
- } ) ;
125
-
126
- test ( 'parseRequest.request only contains the specified properties in the options.request array' , ( ) => {
127
- const INCLUDED_PROPERTIES = [ 'data' , 'headers' , 'query_string' , 'url' ] ;
128
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest , {
129
- request : INCLUDED_PROPERTIES ,
130
- } ) ;
131
- expect ( Object . keys ( parsedRequest . request as Request ) ) . toEqual ( INCLUDED_PROPERTIES ) ;
132
- } ) ;
133
-
134
- test ( 'parseRequest.request skips `body` property for GET and HEAD requests' , ( ) => {
135
- expect ( parseRequest ( { } , mockReq as ExpressRequest , { } ) . request ) . toHaveProperty ( 'data' ) ;
136
- expect ( parseRequest ( { } , { ...mockReq , method : 'GET' } as ExpressRequest , { } ) . request ) . not . toHaveProperty ( 'data' ) ;
137
- expect ( parseRequest ( { } , { ...mockReq , method : 'HEAD' } as ExpressRequest , { } ) . request ) . not . toHaveProperty ( 'data' ) ;
138
- } ) ;
139
- } ) ;
140
-
141
- describe ( 'parseRequest.transaction property' , ( ) => {
142
- test ( 'extracts method and full route path by default`' , ( ) => {
143
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest ) ;
144
- expect ( parsedRequest . transaction ) . toEqual ( 'POST /routerMountPath/subpath/:parameterName' ) ;
145
- } ) ;
146
-
147
- test ( 'extracts method and full path by default when mountpoint is `/`' , ( ) => {
148
- mockReq . originalUrl = mockReq . originalUrl . replace ( '/routerMountpath' , '' ) ;
149
- mockReq . baseUrl = '' ;
150
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest ) ;
151
- // "sub"path is the full path here, because there's no router mount path
152
- expect ( parsedRequest . transaction ) . toEqual ( 'POST /subpath/:parameterName' ) ;
153
- } ) ;
154
-
155
- test ( 'fallback to method and `originalUrl` if route is missing' , ( ) => {
156
- delete mockReq . route ;
157
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest ) ;
158
- expect ( parsedRequest . transaction ) . toEqual ( 'POST /routerMountPath/subpath/specificValue' ) ;
159
- } ) ;
160
-
161
- test ( 'can extract path only instead if configured' , ( ) => {
162
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest , { transaction : 'path' } ) ;
163
- expect ( parsedRequest . transaction ) . toEqual ( '/routerMountPath/subpath/:parameterName' ) ;
164
- } ) ;
165
-
166
- test ( 'can extract handler name instead if configured' , ( ) => {
167
- const parsedRequest : Event = parseRequest ( { } , mockReq as ExpressRequest , { transaction : 'handler' } ) ;
168
- expect ( parsedRequest . transaction ) . toEqual ( 'parameterNameRouteHandler' ) ;
169
- } ) ;
170
- } ) ;
171
- } ) ;
172
-
173
14
describe ( 'requestHandler' , ( ) => {
174
15
const headers = { ears : 'furry' , nose : 'wet' , tongue : 'spotted' , cookie : 'favorite=zukes' } ;
175
16
const method = 'wagging' ;
@@ -270,7 +111,7 @@ describe('requestHandler', () => {
270
111
} ) ;
271
112
} ) ;
272
113
273
- it ( 'patches `res.end` when `flushTimeout` is specified' , ( ) => {
114
+ it ( 'patches `res.end` when `flushTimeout` is specified' , done => {
274
115
const flush = jest . spyOn ( SDK , 'flush' ) . mockResolvedValue ( true ) ;
275
116
276
117
const sentryRequestMiddleware = requestHandler ( { flushTimeout : 1337 } ) ;
@@ -280,10 +121,11 @@ describe('requestHandler', () => {
280
121
setImmediate ( ( ) => {
281
122
expect ( flush ) . toHaveBeenCalledWith ( 1337 ) ;
282
123
expect ( res . finished ) . toBe ( true ) ;
124
+ done ( ) ;
283
125
} ) ;
284
126
} ) ;
285
127
286
- it ( 'prevents errors thrown during `flush` from breaking the response' , async ( ) => {
128
+ it ( 'prevents errors thrown during `flush` from breaking the response' , done => {
287
129
jest . spyOn ( SDK , 'flush' ) . mockRejectedValue ( new SentryError ( 'HTTP Error (429)' ) ) ;
288
130
289
131
const sentryRequestMiddleware = requestHandler ( { flushTimeout : 1337 } ) ;
@@ -292,6 +134,7 @@ describe('requestHandler', () => {
292
134
293
135
setImmediate ( ( ) => {
294
136
expect ( res . finished ) . toBe ( true ) ;
137
+ done ( ) ;
295
138
} ) ;
296
139
} ) ;
297
140
} ) ;
@@ -530,181 +373,6 @@ describe('tracingHandler', () => {
530
373
} ) ;
531
374
} ) ;
532
375
533
- describe ( 'extractRequestData()' , ( ) => {
534
- describe ( 'default behaviour' , ( ) => {
535
- test ( 'node' , ( ) => {
536
- expect (
537
- extractRequestData ( {
538
- headers : { host : 'example.com' } ,
539
- method : 'GET' ,
540
- secure : true ,
541
- originalUrl : '/' ,
542
- } ) ,
543
- ) . toEqual ( {
544
- cookies : { } ,
545
- headers : {
546
- host : 'example.com' ,
547
- } ,
548
- method : 'GET' ,
549
- query_string : null ,
550
- url : 'https://example.com/' ,
551
- } ) ;
552
- } ) ;
553
-
554
- test ( 'degrades gracefully without request data' , ( ) => {
555
- expect ( extractRequestData ( { } ) ) . toEqual ( {
556
- cookies : { } ,
557
- headers : { } ,
558
- method : undefined ,
559
- query_string : null ,
560
- url : 'http://<no host>' ,
561
- } ) ;
562
- } ) ;
563
- } ) ;
564
-
565
- describe ( 'cookies' , ( ) => {
566
- it ( 'uses `req.cookies` if available' , ( ) => {
567
- expect (
568
- extractRequestData (
569
- {
570
- cookies : { foo : 'bar' } ,
571
- } ,
572
- [ 'cookies' ] ,
573
- ) ,
574
- ) . toEqual ( {
575
- cookies : { foo : 'bar' } ,
576
- } ) ;
577
- } ) ;
578
-
579
- it ( 'parses the cookie header' , ( ) => {
580
- expect (
581
- extractRequestData (
582
- {
583
- headers : {
584
- cookie : 'foo=bar;' ,
585
- } ,
586
- } ,
587
- [ 'cookies' ] ,
588
- ) ,
589
- ) . toEqual ( {
590
- cookies : { foo : 'bar' } ,
591
- } ) ;
592
- } ) ;
593
-
594
- it ( 'falls back if no cookies are defined' , ( ) => {
595
- expect ( extractRequestData ( { } , [ 'cookies' ] ) ) . toEqual ( {
596
- cookies : { } ,
597
- } ) ;
598
- } ) ;
599
- } ) ;
600
-
601
- describe ( 'data' , ( ) => {
602
- it ( 'includes data from `req.body` if available' , ( ) => {
603
- expect (
604
- extractRequestData (
605
- {
606
- method : 'POST' ,
607
- headers : { 'Content-Type' : 'application/x-www-form-urlencoded' } ,
608
- body : 'foo=bar' ,
609
- } ,
610
- [ 'data' ] ,
611
- ) ,
612
- ) . toEqual ( {
613
- data : 'foo=bar' ,
614
- } ) ;
615
- } ) ;
616
-
617
- it ( 'encodes JSON body contents back to a string' , ( ) => {
618
- expect (
619
- extractRequestData (
620
- {
621
- method : 'POST' ,
622
- headers : { 'Content-Type' : 'application/json' } ,
623
- body : { foo : 'bar' } ,
624
- } ,
625
- [ 'data' ] ,
626
- ) ,
627
- ) . toEqual ( {
628
- data : '{"foo":"bar"}' ,
629
- } ) ;
630
- } ) ;
631
- } ) ;
632
-
633
- describe ( 'query_string' , ( ) => {
634
- it ( 'parses the query parms from the url' , ( ) => {
635
- expect (
636
- extractRequestData (
637
- {
638
- headers : { host : 'example.com' } ,
639
- secure : true ,
640
- originalUrl : '/?foo=bar' ,
641
- } ,
642
- [ 'query_string' ] ,
643
- ) ,
644
- ) . toEqual ( {
645
- query_string : 'foo=bar' ,
646
- } ) ;
647
- } ) ;
648
-
649
- it ( 'gracefully degrades if url cannot be determined' , ( ) => {
650
- expect ( extractRequestData ( { } , [ 'query_string' ] ) ) . toEqual ( {
651
- query_string : null ,
652
- } ) ;
653
- } ) ;
654
- } ) ;
655
-
656
- describe ( 'url' , ( ) => {
657
- test ( 'express/koa' , ( ) => {
658
- expect (
659
- extractRequestData (
660
- {
661
- host : 'example.com' ,
662
- protocol : 'https' ,
663
- url : '/' ,
664
- } ,
665
- [ 'url' ] ,
666
- ) ,
667
- ) . toEqual ( {
668
- url : 'https://example.com/' ,
669
- } ) ;
670
- } ) ;
671
-
672
- test ( 'node' , ( ) => {
673
- expect (
674
- extractRequestData (
675
- {
676
- headers : { host : 'example.com' } ,
677
- secure : true ,
678
- originalUrl : '/' ,
679
- } ,
680
- [ 'url' ] ,
681
- ) ,
682
- ) . toEqual ( {
683
- url : 'https://example.com/' ,
684
- } ) ;
685
- } ) ;
686
- } ) ;
687
-
688
- describe ( 'custom key' , ( ) => {
689
- it ( 'includes the custom key if present' , ( ) => {
690
- expect (
691
- extractRequestData (
692
- {
693
- httpVersion : '1.1' ,
694
- } ,
695
- [ 'httpVersion' ] ,
696
- ) ,
697
- ) . toEqual ( {
698
- httpVersion : '1.1' ,
699
- } ) ;
700
- } ) ;
701
-
702
- it ( 'gracefully degrades if the custom key is missing' , ( ) => {
703
- expect ( extractRequestData ( { } , [ 'httpVersion' ] ) ) . toEqual ( { } ) ;
704
- } ) ;
705
- } ) ;
706
- } ) ;
707
-
708
376
describe ( 'errorHandler()' , ( ) => {
709
377
const headers = { ears : 'furry' , nose : 'wet' , tongue : 'spotted' , cookie : 'favorite=zukes' } ;
710
378
const method = 'wagging' ;
0 commit comments