@@ -10,31 +10,52 @@ import {
10
10
saveUserSelectedProxy ,
11
11
useProxy ,
12
12
} from "./ProxyContext"
13
- import * as ProxyContextModule from "./ProxyContext "
13
+ import * as ProxyLatency from "./useProxyLatency "
14
14
import {
15
15
renderWithAuth ,
16
16
waitForLoaderToBeRemoved ,
17
17
} from "testHelpers/renderHelpers"
18
18
import { screen } from "@testing-library/react"
19
19
import { server } from "testHelpers/server"
20
- import "testHelpers/localstorage"
21
20
import { rest } from "msw"
22
21
import { Region } from "api/typesGenerated"
22
+ import "testHelpers/localstorage"
23
+ import userEvent from "@testing-library/user-event"
24
+
25
+ // Mock useProxyLatency to use a hard-coded latency. 'jest.mock' must be called
26
+ // here and not inside a unit test.
27
+ jest . mock ( "contexts/useProxyLatency" , ( ) => ( {
28
+ useProxyLatency : ( ) => {
29
+ return hardCodedLatencies
30
+ } ,
31
+ } ) )
32
+
33
+ let hardCodedLatencies : Record < string , ProxyLatency . ProxyLatencyReport > = { }
34
+
35
+ const fakeLatency = ( ms : number ) : ProxyLatency . ProxyLatencyReport => {
36
+ return {
37
+ latencyMS : ms ,
38
+ accurate : true ,
39
+ at : new Date ( ) ,
40
+ }
41
+ }
23
42
24
43
describe ( "ProxyContextGetURLs" , ( ) => {
25
44
it . each ( [
26
- [ "empty" , [ ] , undefined , "" , "" ] ,
45
+ [ "empty" , [ ] , { } , undefined , "" , "" ] ,
27
46
// Primary has no path app URL. Uses relative links
28
47
[
29
48
"primary" ,
30
49
[ MockPrimaryWorkspaceProxy ] ,
50
+ { } ,
31
51
MockPrimaryWorkspaceProxy ,
32
52
"" ,
33
53
MockPrimaryWorkspaceProxy . wildcard_hostname ,
34
54
] ,
35
55
[
36
56
"regions selected" ,
37
57
MockWorkspaceProxies ,
58
+ { } ,
38
59
MockHealthyWildWorkspaceProxy ,
39
60
MockHealthyWildWorkspaceProxy . path_app_url ,
40
61
MockHealthyWildWorkspaceProxy . wildcard_hostname ,
@@ -43,13 +64,15 @@ describe("ProxyContextGetURLs", () => {
43
64
[
44
65
"no selected" ,
45
66
[ MockPrimaryWorkspaceProxy ] ,
67
+ { } ,
46
68
undefined ,
47
69
"" ,
48
70
MockPrimaryWorkspaceProxy . wildcard_hostname ,
49
71
] ,
50
72
[
51
73
"regions no select primary default" ,
52
74
MockWorkspaceProxies ,
75
+ { } ,
53
76
undefined ,
54
77
"" ,
55
78
MockPrimaryWorkspaceProxy . wildcard_hostname ,
@@ -58,16 +81,40 @@ describe("ProxyContextGetURLs", () => {
58
81
[
59
82
"unhealthy selection" ,
60
83
MockWorkspaceProxies ,
84
+ { } ,
61
85
MockUnhealthyWildWorkspaceProxy ,
62
86
"" ,
63
87
MockPrimaryWorkspaceProxy . wildcard_hostname ,
64
88
] ,
65
89
// This should never happen, when there is no primary
66
- [ "no primary" , [ MockHealthyWildWorkspaceProxy ] , undefined , "" , "" ] ,
90
+ [ "no primary" , [ MockHealthyWildWorkspaceProxy ] , { } , undefined , "" , "" ] ,
91
+ // Latency behavior
92
+ [
93
+ "best latency" ,
94
+ MockWorkspaceProxies ,
95
+ {
96
+ [ MockPrimaryWorkspaceProxy . id ] : fakeLatency ( 100 ) ,
97
+ [ MockHealthyWildWorkspaceProxy . id ] : fakeLatency ( 50 ) ,
98
+ // This should be ignored because it's unhealthy
99
+ [ MockUnhealthyWildWorkspaceProxy . id ] : fakeLatency ( 25 ) ,
100
+ // This should be ignored because it is not in the list.
101
+ [ "not a proxy" ] : fakeLatency ( 10 ) ,
102
+ } ,
103
+ undefined ,
104
+ MockHealthyWildWorkspaceProxy . path_app_url ,
105
+ MockHealthyWildWorkspaceProxy . wildcard_hostname ,
106
+ ] ,
67
107
] ) (
68
108
`%p` ,
69
- ( _ , regions , selected , preferredPathAppURL , preferredWildcardHostname ) => {
70
- const preferred = getPreferredProxy ( regions , selected )
109
+ (
110
+ _ ,
111
+ regions ,
112
+ latencies ,
113
+ selected ,
114
+ preferredPathAppURL ,
115
+ preferredWildcardHostname ,
116
+ ) => {
117
+ const preferred = getPreferredProxy ( regions , selected , latencies )
71
118
expect ( preferred . preferredPathAppURL ) . toBe ( preferredPathAppURL )
72
119
expect ( preferred . preferredWildcardHostname ) . toBe (
73
120
preferredWildcardHostname ,
@@ -76,11 +123,6 @@ describe("ProxyContextGetURLs", () => {
76
123
)
77
124
} )
78
125
79
- // interface ProxySelectTest {
80
- // name: string
81
- // actions: ()
82
- // }
83
-
84
126
const TestingComponent = ( ) => {
85
127
return renderWithAuth (
86
128
< ProxyProvider >
@@ -95,7 +137,8 @@ const TestingComponent = () => {
95
137
96
138
// TestingScreen just mounts some components that we can check in the unit test.
97
139
const TestingScreen = ( ) => {
98
- const { proxy, isFetched, isLoading } = useProxy ( )
140
+ const { proxy, userProxy, isFetched, isLoading, clearProxy, setProxy } =
141
+ useProxy ( )
99
142
return (
100
143
< >
101
144
< div data-testid = "isFetched" title = { isFetched . toString ( ) } > </ div >
@@ -104,49 +147,182 @@ const TestingScreen = () => {
104
147
data-testid = "preferredProxy"
105
148
title = { proxy . selectedProxy && proxy . selectedProxy . id }
106
149
> </ div >
150
+ < div data-testid = "userProxy" title = { userProxy && userProxy . id } > </ div >
151
+ < button data-testid = "clearProxy" onClick = { clearProxy } > </ button >
152
+ < div data-testid = "userSelectProxyData" > </ div >
153
+ < button
154
+ data-testid = "userSelectProxy"
155
+ onClick = { ( ) => {
156
+ const data = screen . getByTestId ( "userSelectProxyData" )
157
+ if ( data . innerText ) {
158
+ setProxy ( JSON . parse ( data . innerText ) )
159
+ }
160
+ } }
161
+ > </ button >
107
162
</ >
108
163
)
109
164
}
110
165
111
166
interface ProxyContextSelectionTest {
112
- expSelectedProxyID : string
113
167
regions : Region [ ]
114
168
storageProxy : Region | undefined
169
+ latencies ?: Record < string , ProxyLatency . ProxyLatencyReport >
170
+ afterLoad ?: ( user : typeof userEvent ) => Promise < void >
171
+
172
+ expProxyID : string
173
+ expUserProxyID ?: string
115
174
}
116
175
117
176
describe ( "ProxyContextSelection" , ( ) => {
118
177
beforeEach ( ( ) => {
178
+ // Object.defineProperty(window, "localStorage", { value: localStorageMock })
119
179
window . localStorage . clear ( )
120
180
} )
121
181
182
+ // A way to simulate a user clearing the proxy selection.
183
+ const clearProxyAction = async ( user : typeof userEvent ) : Promise < void > => {
184
+ const clearProxyButton = screen . getByTestId ( "clearProxy" )
185
+ await user . click ( clearProxyButton )
186
+ }
187
+
188
+ const userSelectProxy = (
189
+ proxy : Region ,
190
+ ) : ( ( user : typeof userEvent ) => Promise < void > ) => {
191
+ return async ( user ) : Promise < void > => {
192
+ const selectData = screen . getByTestId ( "userSelectProxyData" )
193
+ selectData . innerText = JSON . stringify ( proxy )
194
+
195
+ const selectProxyButton = screen . getByTestId ( "userSelectProxy" )
196
+ await user . click ( selectProxyButton )
197
+ }
198
+ }
199
+
122
200
it . each ( [
201
+ // Not latency behavior
123
202
[
124
203
"empty" ,
125
204
{
126
- expSelectedProxyID : "" ,
205
+ expProxyID : "" ,
127
206
regions : [ ] ,
128
207
storageProxy : undefined ,
208
+ latencies : { } ,
129
209
} ,
130
210
] ,
131
211
[
132
212
"regions_no_selection" ,
133
213
{
134
- expSelectedProxyID : MockPrimaryWorkspaceProxy . id ,
214
+ expProxyID : MockPrimaryWorkspaceProxy . id ,
135
215
regions : MockWorkspaceProxies ,
136
216
storageProxy : undefined ,
137
217
} ,
138
218
] ,
139
219
[
140
220
"regions_selected_unhealthy" ,
141
221
{
142
- expSelectedProxyID : MockPrimaryWorkspaceProxy . id ,
222
+ expProxyID : MockPrimaryWorkspaceProxy . id ,
143
223
regions : MockWorkspaceProxies ,
144
224
storageProxy : MockUnhealthyWildWorkspaceProxy ,
225
+ expUserProxyID : MockUnhealthyWildWorkspaceProxy . id ,
226
+ } ,
227
+ ] ,
228
+ [
229
+ "regions_selected_healthy" ,
230
+ {
231
+ expProxyID : MockHealthyWildWorkspaceProxy . id ,
232
+ regions : MockWorkspaceProxies ,
233
+ storageProxy : MockHealthyWildWorkspaceProxy ,
234
+ expUserProxyID : MockHealthyWildWorkspaceProxy . id ,
235
+ } ,
236
+ ] ,
237
+ [
238
+ "regions_selected_clear" ,
239
+ {
240
+ expProxyID : MockPrimaryWorkspaceProxy . id ,
241
+ regions : MockWorkspaceProxies ,
242
+ storageProxy : MockHealthyWildWorkspaceProxy ,
243
+ afterLoad : clearProxyAction ,
244
+ expUserProxyID : undefined ,
245
+ } ,
246
+ ] ,
247
+ [
248
+ "regions_make_selection" ,
249
+ {
250
+ expProxyID : MockHealthyWildWorkspaceProxy . id ,
251
+ regions : MockWorkspaceProxies ,
252
+ afterLoad : userSelectProxy ( MockHealthyWildWorkspaceProxy ) ,
253
+ expUserProxyID : MockHealthyWildWorkspaceProxy . id ,
254
+ } ,
255
+ ] ,
256
+ // Latency behavior
257
+ [
258
+ "regions_default_low_latency" ,
259
+ {
260
+ expProxyID : MockHealthyWildWorkspaceProxy . id ,
261
+ regions : MockWorkspaceProxies ,
262
+ storageProxy : undefined ,
263
+ latencies : {
264
+ [ MockPrimaryWorkspaceProxy . id ] : fakeLatency ( 100 ) ,
265
+ [ MockHealthyWildWorkspaceProxy . id ] : fakeLatency ( 50 ) ,
266
+ // This is a trick. It's unhealthy so should be ignored.
267
+ [ MockUnhealthyWildWorkspaceProxy . id ] : fakeLatency ( 25 ) ,
268
+ } ,
269
+ } ,
270
+ ] ,
271
+ [
272
+ // User intentionally selected a high latency proxy.
273
+ "regions_select_high_latency" ,
274
+ {
275
+ expProxyID : MockHealthyWildWorkspaceProxy . id ,
276
+ regions : MockWorkspaceProxies ,
277
+ storageProxy : undefined ,
278
+ afterLoad : userSelectProxy ( MockHealthyWildWorkspaceProxy ) ,
279
+ expUserProxyID : MockHealthyWildWorkspaceProxy . id ,
280
+ latencies : {
281
+ [ MockHealthyWildWorkspaceProxy . id ] : fakeLatency ( 500 ) ,
282
+ [ MockPrimaryWorkspaceProxy . id ] : fakeLatency ( 100 ) ,
283
+ // This is a trick. It's unhealthy so should be ignored.
284
+ [ MockUnhealthyWildWorkspaceProxy . id ] : fakeLatency ( 25 ) ,
285
+ } ,
286
+ } ,
287
+ ] ,
288
+ [
289
+ // Low latency proxy is selected, but it is unhealthy
290
+ "regions_select_unhealthy_low_latency" ,
291
+ {
292
+ expProxyID : MockPrimaryWorkspaceProxy . id ,
293
+ regions : MockWorkspaceProxies ,
294
+ storageProxy : MockUnhealthyWildWorkspaceProxy ,
295
+ expUserProxyID : MockUnhealthyWildWorkspaceProxy . id ,
296
+ latencies : {
297
+ [ MockHealthyWildWorkspaceProxy . id ] : fakeLatency ( 500 ) ,
298
+ [ MockPrimaryWorkspaceProxy . id ] : fakeLatency ( 100 ) ,
299
+ // This is a trick. It's unhealthy so should be ignored.
300
+ [ MockUnhealthyWildWorkspaceProxy . id ] : fakeLatency ( 25 ) ,
301
+ } ,
145
302
} ,
146
303
] ,
147
304
] as [ string , ProxyContextSelectionTest ] [ ] ) (
148
305
`%s` ,
149
- async ( _ , { expSelectedProxyID, regions, storageProxy } ) => {
306
+ async (
307
+ _ ,
308
+ {
309
+ expUserProxyID,
310
+ expProxyID : expSelectedProxyID ,
311
+ regions,
312
+ storageProxy,
313
+ latencies = { } ,
314
+ afterLoad,
315
+ } ,
316
+ ) => {
317
+ // Mock the latencies
318
+ hardCodedLatencies = latencies
319
+
320
+ // jest.mock("contexts/useProxyLatency", () => ({
321
+ // useProxyLatency: () => {
322
+ // return latencies
323
+ // },
324
+ // }))
325
+
150
326
// Initial selection if present
151
327
if ( storageProxy ) {
152
328
saveUserSelectedProxy ( storageProxy )
@@ -167,6 +343,11 @@ describe("ProxyContextSelection", () => {
167
343
TestingComponent ( )
168
344
await waitForLoaderToBeRemoved ( )
169
345
346
+ const user = userEvent . setup ( )
347
+ if ( afterLoad ) {
348
+ await afterLoad ( user )
349
+ }
350
+
170
351
await screen . findByTestId ( "isFetched" ) . then ( ( x ) => {
171
352
expect ( x . title ) . toBe ( "true" )
172
353
} )
@@ -176,17 +357,9 @@ describe("ProxyContextSelection", () => {
176
357
await screen . findByTestId ( "preferredProxy" ) . then ( ( x ) => {
177
358
expect ( x . title ) . toBe ( expSelectedProxyID )
178
359
} )
179
-
180
- // const { proxy, proxies, isFetched, isLoading, proxyLatencies } = useProxy()
181
- // expect(isLoading).toBe(false)
182
- // expect(isFetched).toBe(true)
183
-
184
- // expect(x).toBe(2)
185
- // const preferred = getPreferredProxy(regions, selected)
186
- // expect(preferred.preferredPathAppURL).toBe(preferredPathAppURL)
187
- // expect(preferred.preferredWildcardHostname).toBe(
188
- // preferredWildcardHostname,
189
- // )
360
+ await screen . findByTestId ( "userProxy" ) . then ( ( x ) => {
361
+ expect ( x . title ) . toBe ( expUserProxyID || "" )
362
+ } )
190
363
} ,
191
364
)
192
365
} )
0 commit comments