1
1
import { createServer } from 'http' ;
2
+ import type { IncomingMessage , ServerResponse } from 'http' ;
3
+ import type { NativeCommand , TestResult } from '@libs/E2E/client' ;
4
+ import type { NetworkCacheMap , TestConfig } from '@libs/E2E/types' ;
2
5
import config from '../config' ;
3
6
import * as nativeCommands from '../nativeCommands' ;
4
7
import * as Logger from '../utils/logger' ;
5
8
import Routes from './routes' ;
6
9
7
- const PORT = process . env . PORT || config . SERVER_PORT ;
10
+ type NetworkCache = {
11
+ appInstanceId : string ;
12
+ cache : NetworkCacheMap ;
13
+ } ;
14
+
15
+ type RequestData = TestResult | NativeCommand | NetworkCache ;
16
+
17
+ type TestStartedListener = ( testConfig ?: TestConfig ) => void ;
18
+
19
+ type TestDoneListener = ( ) => void ;
20
+
21
+ type TestResultListener = ( testResult : TestResult ) => void ;
22
+
23
+ type AddListener < TListener > = ( listener : TListener ) => void ;
24
+
25
+ type ServerInstance = {
26
+ setTestConfig : ( testConfig : TestConfig ) => void ;
27
+ addTestStartedListener : AddListener < TestStartedListener > ;
28
+ addTestResultListener : AddListener < TestResultListener > ;
29
+ addTestDoneListener : AddListener < TestDoneListener > ;
30
+ start : ( ) => Promise < void > ;
31
+ stop : ( ) => Promise < Error | undefined > ;
32
+ } ;
33
+
34
+ const PORT = process . env . PORT ?? config . SERVER_PORT ;
8
35
9
36
// Gets the request data as a string
10
- const getReqData = ( req ) => {
37
+ const getReqData = ( req : IncomingMessage ) : Promise < string > => {
11
38
let data = '' ;
12
- req . on ( 'data' , ( chunk ) => {
39
+ req . on ( 'data' , ( chunk : string ) => {
13
40
data += chunk ;
14
41
} ) ;
15
42
@@ -21,16 +48,16 @@ const getReqData = (req) => {
21
48
} ;
22
49
23
50
// Expects a POST request with JSON data. Returns parsed JSON data.
24
- const getPostJSONRequestData = ( req , res ) => {
51
+ const getPostJSONRequestData = < TRequestData extends RequestData > ( req : IncomingMessage , res : ServerResponse < IncomingMessage > ) : Promise < TRequestData | undefined > | undefined => {
25
52
if ( req . method !== 'POST' ) {
26
53
res . statusCode = 400 ;
27
54
res . end ( 'Unsupported method' ) ;
28
55
return ;
29
56
}
30
57
31
- return getReqData ( req ) . then ( ( data ) => {
58
+ return getReqData ( req ) . then ( ( data ) : TRequestData | undefined => {
32
59
try {
33
- return JSON . parse ( data ) ;
60
+ return JSON . parse ( data ) as TRequestData ;
34
61
} catch ( e ) {
35
62
Logger . info ( '❌ Failed to parse request data' , data ) ;
36
63
res . statusCode = 400 ;
@@ -39,9 +66,9 @@ const getPostJSONRequestData = (req, res) => {
39
66
} ) ;
40
67
} ;
41
68
42
- const createListenerState = ( ) => {
43
- const listeners = [ ] ;
44
- const addListener = ( listener ) => {
69
+ const createListenerState = < TListener > ( ) : [ TListener [ ] , AddListener < TListener > ] => {
70
+ const listeners : TListener [ ] = [ ] ;
71
+ const addListener = ( listener : TListener ) => {
45
72
listeners . push ( listener ) ;
46
73
return ( ) => {
47
74
const index = listeners . indexOf ( listener ) ;
@@ -54,20 +81,6 @@ const createListenerState = () => {
54
81
return [ listeners , addListener ] ;
55
82
} ;
56
83
57
- /**
58
- * The test result object that a client might submit to the server.
59
- * @typedef TestResult
60
- * @property {string } name
61
- * @property {number } duration Milliseconds
62
- * @property {string } [error] Optional, if set indicates that the test run failed and has no valid results.
63
- */
64
-
65
- /**
66
- * @callback listener
67
- * @param {TestResult } testResult
68
- */
69
-
70
- // eslint-disable-next-line valid-jsdoc
71
84
/**
72
85
* Creates a new http server.
73
86
* The server just has two endpoints:
@@ -78,35 +91,32 @@ const createListenerState = () => {
78
91
*
79
92
* It returns an instance to which you can add listeners for the test results, and test done events.
80
93
*/
81
- const createServerInstance = ( ) => {
82
- const [ testStartedListeners , addTestStartedListener ] = createListenerState ( ) ;
83
- const [ testResultListeners , addTestResultListener ] = createListenerState ( ) ;
84
- const [ testDoneListeners , addTestDoneListener ] = createListenerState ( ) ;
85
-
86
- let activeTestConfig ;
87
- const networkCache = { } ;
88
-
89
- /**
90
- * @param {TestConfig } testConfig
91
- */
92
- const setTestConfig = ( testConfig ) => {
94
+ const createServerInstance = ( ) : ServerInstance => {
95
+ const [ testStartedListeners , addTestStartedListener ] = createListenerState < TestStartedListener > ( ) ;
96
+ const [ testResultListeners , addTestResultListener ] = createListenerState < TestResultListener > ( ) ;
97
+ const [ testDoneListeners , addTestDoneListener ] = createListenerState < TestDoneListener > ( ) ;
98
+
99
+ let activeTestConfig : TestConfig | undefined ;
100
+ const networkCache : Record < string , NetworkCacheMap > = { } ;
101
+
102
+ const setTestConfig = ( testConfig : TestConfig ) => {
93
103
activeTestConfig = testConfig ;
94
104
} ;
95
105
96
- const server = createServer ( ( req , res ) => {
106
+ const server = createServer ( ( req , res ) : ServerResponse < IncomingMessage > | void => {
97
107
res . statusCode = 200 ;
98
108
switch ( req . url ) {
99
109
case Routes . testConfig : {
100
110
testStartedListeners . forEach ( ( listener ) => listener ( activeTestConfig ) ) ;
101
- if ( activeTestConfig == null ) {
111
+ if ( ! activeTestConfig ) {
102
112
throw new Error ( 'No test config set' ) ;
103
113
}
104
114
return res . end ( JSON . stringify ( activeTestConfig ) ) ;
105
115
}
106
116
107
117
case Routes . testResults : {
108
- getPostJSONRequestData ( req , res ) . then ( ( data ) => {
109
- if ( data == null ) {
118
+ getPostJSONRequestData < TestResult > ( req , res ) ? .then ( ( data ) => {
119
+ if ( ! data ) {
110
120
// The getPostJSONRequestData function already handled the response
111
121
return ;
112
122
}
@@ -128,9 +138,9 @@ const createServerInstance = () => {
128
138
}
129
139
130
140
case Routes . testNativeCommand : {
131
- getPostJSONRequestData ( req , res )
132
- . then ( ( data ) =>
133
- nativeCommands . executeFromPayload ( data . actionName , data . payload ) . then ( ( status ) => {
141
+ getPostJSONRequestData < NativeCommand > ( req , res )
142
+ ? .then ( ( data ) =>
143
+ nativeCommands . executeFromPayload ( data ? .actionName , data ? .payload ) . then ( ( status ) => {
134
144
if ( status ) {
135
145
res . end ( 'ok' ) ;
136
146
return ;
@@ -148,8 +158,8 @@ const createServerInstance = () => {
148
158
}
149
159
150
160
case Routes . testGetNetworkCache : {
151
- getPostJSONRequestData ( req , res ) . then ( ( data ) => {
152
- const appInstanceId = data && data . appInstanceId ;
161
+ getPostJSONRequestData < NetworkCache > ( req , res ) ? .then ( ( data ) => {
162
+ const appInstanceId = data ? .appInstanceId ;
153
163
if ( ! appInstanceId ) {
154
164
res . statusCode = 400 ;
155
165
res . end ( 'Invalid request missing appInstanceId' ) ;
@@ -164,9 +174,9 @@ const createServerInstance = () => {
164
174
}
165
175
166
176
case Routes . testUpdateNetworkCache : {
167
- getPostJSONRequestData ( req , res ) . then ( ( data ) => {
168
- const appInstanceId = data && data . appInstanceId ;
169
- const cache = data && data . cache ;
177
+ getPostJSONRequestData < NetworkCache > ( req , res ) ? .then ( ( data ) => {
178
+ const appInstanceId = data ? .appInstanceId ;
179
+ const cache = data ? .cache ;
170
180
if ( ! appInstanceId || ! cache ) {
171
181
res . statusCode = 400 ;
172
182
res . end ( 'Invalid request missing appInstanceId or cache' ) ;
@@ -192,11 +202,11 @@ const createServerInstance = () => {
192
202
addTestResultListener,
193
203
addTestDoneListener,
194
204
start : ( ) =>
195
- new Promise ( ( resolve ) => {
205
+ new Promise < void > ( ( resolve ) => {
196
206
server . listen ( PORT , resolve ) ;
197
207
} ) ,
198
208
stop : ( ) =>
199
- new Promise ( ( resolve ) => {
209
+ new Promise < Error | undefined > ( ( resolve ) => {
200
210
server . close ( resolve ) ;
201
211
} ) ,
202
212
} ;
0 commit comments