1
+ const request = require ( "supertest" ) ;
2
+ const sinon = require ( "sinon" ) ;
3
+ const nock = require ( "nock" ) ;
4
+ const {
5
+ initializeWebServer,
6
+ stopWebServer
7
+ } = require ( "../../../example-application/api-under-test" ) ;
8
+ const OrderRepository = require ( "../../../example-application/data-access/order-repository" ) ;
9
+
10
+ let expressApp ;
11
+ let sinonSandbox ;
12
+
13
+ beforeAll ( async ( done ) => {
14
+ // ️️️✅ Best Practice: Place the backend under test within the same process
15
+ expressApp = await initializeWebServer ( ) ;
16
+ // ️️️✅ Best Practice: Ensure that this component is isolated by preventing unknown calls except for the Api-Under-Test
17
+ nock . disableNetConnect ( ) ;
18
+ nock . enableNetConnect ( '127.0.0.1' ) ;
19
+
20
+ // ️️️✅ Best Practice: use a sandbox for test doubles for proper clean-up between tests
21
+ sinonSandbox = sinon . createSandbox ( ) ;
22
+
23
+ done ( ) ;
24
+ } ) ;
25
+
26
+ afterAll ( async ( done ) => {
27
+ // ️️️✅ Best Practice: Clean-up resources after each run
28
+ await stopWebServer ( ) ;
29
+ done ( ) ;
30
+ } ) ;
31
+
32
+ beforeEach ( ( ) => {
33
+ // ️️️✅ Best Practice: Isolate the service under test by intercepting requests to 3rd party services
34
+ nock ( "http://localhost/user/" ) . get ( `/1` ) . reply ( 200 , {
35
+ id : 1 ,
36
+ name : "John" ,
37
+ } )
38
+
39
+ if ( sinonSandbox ) {
40
+ sinonSandbox . restore ( ) ;
41
+ }
42
+ } ) ;
43
+
44
+ afterEach ( ( ) => {
45
+ // ️️️✅ Best Practice: Clean nock interceptors between tests
46
+ nock . cleanAll ( ) ;
47
+ } )
48
+
49
+ // ️️️✅ Best Practice: Structure tests
50
+ describe ( "/api" , ( ) => {
51
+ describe ( "POST /orders" , ( ) => {
52
+ test ( "When adding a new valid order , Then should get back 200 response" , async ( ) => {
53
+ //Arrange
54
+ const orderToAdd = {
55
+ userId : 1 ,
56
+ productId : 2 ,
57
+ mode : "approved" ,
58
+ } ;
59
+
60
+ //Act
61
+ // ➿ Nock intercepts the request for users service as declared in the BeforeAll function
62
+ const orderAddResult = await request ( expressApp ) . post ( "/order" ) . send ( orderToAdd ) ;
63
+
64
+ //Assert
65
+ expect ( orderAddResult . status ) . toBe ( 200 ) ;
66
+ } ) ;
67
+
68
+ test ( "When the user does not exist, return http 404" , async ( ) => {
69
+ //Arrange
70
+ // ️️️✅ Best Practice: Simulate 3rd party service responses to test different scenarios like 404, 422 or 500.
71
+ // Use specific params (like ids) to easily bypass the beforeEach interceptor.
72
+ nock ( "http://localhost/user/" ) . get ( `/7` ) . reply ( 404 , {
73
+ message : "User does not exist" ,
74
+ code : "nonExisting" ,
75
+ } ) ;
76
+ const orderToAdd = {
77
+ userId : 7 ,
78
+ productId : 2 ,
79
+ mode : "draft" ,
80
+ } ;
81
+
82
+ //Act
83
+ const orderAddResult = await request ( expressApp )
84
+ . post ( "/order" )
85
+ . send ( orderToAdd )
86
+
87
+ //Assert
88
+ expect ( orderAddResult . status ) . toBe ( 404 ) ;
89
+ } ) ;
90
+
91
+ test ( "When order failed, send mail to admin" , async ( ) => {
92
+ //Arrange
93
+ process . env . SEND_MAILS = "true" ;
94
+ sinonSandbox . stub ( OrderRepository . prototype , "addOrder" ) . throws ( new Error ( "Unknown error" ) ) ;
95
+ // ️️️✅ Best Practice: Intercept requests for 3rd party services to eliminate undesired side effects like emails or SMS
96
+ // ️️️✅ Best Practice: Specify the body when you need to make sure you call the 3rd party service as expected
97
+ const scope = nock ( "https://mailer.com" )
98
+ . post ( '/send' , {
99
+ subject : / ^ (? ! \s * $ ) .+ / ,
100
+ body : / ^ (? ! \s * $ ) .+ / ,
101
+ recipientAddress : / ^ [ \w -\. ] + @ ( [ \w - ] + \. ) + [ \w - ] { 2 , 4 } $ / ,
102
+ } )
103
+ . reply ( 202 ) ;
104
+ const orderToAdd = {
105
+ userId : 1 ,
106
+ productId : 2 ,
107
+ mode : "approved" ,
108
+ } ;
109
+
110
+ //Act
111
+ await request ( expressApp ) . post ( "/order" ) . send ( orderToAdd ) ;
112
+
113
+ //Assert
114
+ // ️️️✅ Best Practice: Assert that the app called the mailer service appropriately
115
+ expect ( scope . isDone ( ) ) . toBe ( true ) ;
116
+ } ) ;
117
+ } ) ;
118
+ } ) ;
0 commit comments