@quenty/brio 14.29.1 → 14.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -504
- package/deploy.nevermore.json +10 -0
- package/package.json +3 -3
- package/src/Shared/RxBrioUtils.spec.lua +444 -2
- package/test/default.project.json +25 -0
- package/test/scripts/Server/ServerMain.server.lua +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/brio",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.30.0",
|
|
4
4
|
"description": "Brios wrap an object and either are alive or dead",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@quenty/loader": "10.11.0",
|
|
33
33
|
"@quenty/maid": "3.9.0",
|
|
34
34
|
"@quenty/nevermore-test-runner": "1.4.0",
|
|
35
|
-
"@quenty/rx": "13.28.
|
|
35
|
+
"@quenty/rx": "13.28.2",
|
|
36
36
|
"@quenty/signal": "7.13.0",
|
|
37
37
|
"@quenty/steputils": "3.6.3",
|
|
38
38
|
"@quenty/table": "3.9.2",
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "f4a374a0a294ee8900aa5cb68ab138b0acf3e0ae"
|
|
45
45
|
}
|
|
@@ -10,6 +10,7 @@ local require = (require :: any)(
|
|
|
10
10
|
local Brio = require("Brio")
|
|
11
11
|
local Jest = require("Jest")
|
|
12
12
|
local Observable = require("Observable")
|
|
13
|
+
local Rx = require("Rx")
|
|
13
14
|
local RxBrioUtils = require("RxBrioUtils")
|
|
14
15
|
|
|
15
16
|
local describe = Jest.Globals.describe
|
|
@@ -34,8 +35,8 @@ end)
|
|
|
34
35
|
describe("RxBrioUtils.combineLatest({ value = Observable(Brio(5)) })", function()
|
|
35
36
|
it("should execute immediately", function()
|
|
36
37
|
local observe = RxBrioUtils.combineLatest({
|
|
37
|
-
value = Observable.new(function(
|
|
38
|
-
|
|
38
|
+
value = Observable.new(function(innerSub)
|
|
39
|
+
innerSub:Fire(Brio.new(5))
|
|
39
40
|
end),
|
|
40
41
|
otherValue = 25,
|
|
41
42
|
})
|
|
@@ -123,3 +124,444 @@ describe("RxBrioUtils.flatCombineLatest", function()
|
|
|
123
124
|
sub:Destroy()
|
|
124
125
|
end)
|
|
125
126
|
end)
|
|
127
|
+
|
|
128
|
+
describe("RxBrioUtils.switchToBrio", function()
|
|
129
|
+
it("should wrap a plain value in a brio", function()
|
|
130
|
+
local result
|
|
131
|
+
local sub = Observable.new(function(innerSub)
|
|
132
|
+
innerSub:Fire(42)
|
|
133
|
+
end)
|
|
134
|
+
:Pipe({
|
|
135
|
+
RxBrioUtils.switchToBrio(),
|
|
136
|
+
})
|
|
137
|
+
:Subscribe(function(brio)
|
|
138
|
+
result = brio
|
|
139
|
+
end)
|
|
140
|
+
|
|
141
|
+
expect(result).never.toBeNil()
|
|
142
|
+
expect(Brio.isBrio(result)).toEqual(true)
|
|
143
|
+
expect(result:IsDead()).toEqual(false)
|
|
144
|
+
expect(result:GetValue()).toEqual(42)
|
|
145
|
+
|
|
146
|
+
sub:Destroy()
|
|
147
|
+
end)
|
|
148
|
+
|
|
149
|
+
it("should wrap multiple plain values, packing them into a brio", function()
|
|
150
|
+
local result
|
|
151
|
+
local sub = Observable.new(function(innerSub)
|
|
152
|
+
innerSub:Fire("a", "b")
|
|
153
|
+
end)
|
|
154
|
+
:Pipe({
|
|
155
|
+
RxBrioUtils.switchToBrio(),
|
|
156
|
+
})
|
|
157
|
+
:Subscribe(function(brio)
|
|
158
|
+
result = brio
|
|
159
|
+
end)
|
|
160
|
+
|
|
161
|
+
expect(result).never.toBeNil()
|
|
162
|
+
expect(Brio.isBrio(result)).toEqual(true)
|
|
163
|
+
expect(result:IsDead()).toEqual(false)
|
|
164
|
+
|
|
165
|
+
local a, b = result:GetValue()
|
|
166
|
+
expect(a).toEqual("a")
|
|
167
|
+
expect(b).toEqual("b")
|
|
168
|
+
|
|
169
|
+
sub:Destroy()
|
|
170
|
+
end)
|
|
171
|
+
|
|
172
|
+
it("should clone an input brio instead of forwarding it directly", function()
|
|
173
|
+
local inputBrio = Brio.new(99)
|
|
174
|
+
local result
|
|
175
|
+
local sub = Observable.new(function(innerSub)
|
|
176
|
+
innerSub:Fire(inputBrio)
|
|
177
|
+
end)
|
|
178
|
+
:Pipe({
|
|
179
|
+
RxBrioUtils.switchToBrio(),
|
|
180
|
+
})
|
|
181
|
+
:Subscribe(function(brio)
|
|
182
|
+
result = brio
|
|
183
|
+
end)
|
|
184
|
+
|
|
185
|
+
expect(result).never.toBeNil()
|
|
186
|
+
expect(Brio.isBrio(result)).toEqual(true)
|
|
187
|
+
expect(result:GetValue()).toEqual(99)
|
|
188
|
+
-- Should be a clone, not the same object
|
|
189
|
+
expect(result).never.toEqual(inputBrio)
|
|
190
|
+
|
|
191
|
+
sub:Destroy()
|
|
192
|
+
inputBrio:Kill()
|
|
193
|
+
end)
|
|
194
|
+
|
|
195
|
+
it("should kill the previous brio when a new value is emitted", function()
|
|
196
|
+
local doFire
|
|
197
|
+
local results = {}
|
|
198
|
+
local sub = Observable.new(function(innerSub)
|
|
199
|
+
doFire = function(...)
|
|
200
|
+
innerSub:Fire(...)
|
|
201
|
+
end
|
|
202
|
+
end)
|
|
203
|
+
:Pipe({
|
|
204
|
+
RxBrioUtils.switchToBrio(),
|
|
205
|
+
})
|
|
206
|
+
:Subscribe(function(brio)
|
|
207
|
+
table.insert(results, brio)
|
|
208
|
+
end)
|
|
209
|
+
|
|
210
|
+
doFire(1)
|
|
211
|
+
doFire(2)
|
|
212
|
+
|
|
213
|
+
expect(#results).toEqual(2)
|
|
214
|
+
expect(results[1]:IsDead()).toEqual(true)
|
|
215
|
+
expect(results[2]:IsDead()).toEqual(false)
|
|
216
|
+
expect(results[2]:GetValue()).toEqual(2)
|
|
217
|
+
|
|
218
|
+
sub:Destroy()
|
|
219
|
+
end)
|
|
220
|
+
|
|
221
|
+
it("should kill the previous brio even when the new value is filtered by predicate", function()
|
|
222
|
+
local doFire
|
|
223
|
+
local results = {}
|
|
224
|
+
local sub = Observable.new(function(innerSub)
|
|
225
|
+
doFire = function(...)
|
|
226
|
+
innerSub:Fire(...)
|
|
227
|
+
end
|
|
228
|
+
end)
|
|
229
|
+
:Pipe({
|
|
230
|
+
RxBrioUtils.switchToBrio(function(value)
|
|
231
|
+
return value ~= "skip"
|
|
232
|
+
end),
|
|
233
|
+
})
|
|
234
|
+
:Subscribe(function(brio)
|
|
235
|
+
table.insert(results, brio)
|
|
236
|
+
end)
|
|
237
|
+
|
|
238
|
+
doFire("keep")
|
|
239
|
+
expect(#results).toEqual(1)
|
|
240
|
+
expect(results[1]:IsDead()).toEqual(false)
|
|
241
|
+
|
|
242
|
+
doFire("skip") -- predicate rejects, but should still kill previous
|
|
243
|
+
expect(#results).toEqual(1)
|
|
244
|
+
expect(results[1]:IsDead()).toEqual(true)
|
|
245
|
+
|
|
246
|
+
sub:Destroy()
|
|
247
|
+
end)
|
|
248
|
+
|
|
249
|
+
it("should ignore dead brios from the source", function()
|
|
250
|
+
local deadBrio = Brio.new(10)
|
|
251
|
+
deadBrio:Kill()
|
|
252
|
+
|
|
253
|
+
local result
|
|
254
|
+
local fireCount = 0
|
|
255
|
+
local sub = Rx.of(deadBrio)
|
|
256
|
+
:Pipe({
|
|
257
|
+
RxBrioUtils.switchToBrio(),
|
|
258
|
+
})
|
|
259
|
+
:Subscribe(function(brio)
|
|
260
|
+
result = brio
|
|
261
|
+
fireCount = fireCount + 1
|
|
262
|
+
end)
|
|
263
|
+
|
|
264
|
+
expect(fireCount).toEqual(0)
|
|
265
|
+
expect(result).toBeNil()
|
|
266
|
+
|
|
267
|
+
sub:Destroy()
|
|
268
|
+
end)
|
|
269
|
+
|
|
270
|
+
it("should kill clone when the source brio dies", function()
|
|
271
|
+
local inputBrio = Brio.new(5)
|
|
272
|
+
local result
|
|
273
|
+
local sub = Observable.new(function(innerSub)
|
|
274
|
+
innerSub:Fire(inputBrio)
|
|
275
|
+
end)
|
|
276
|
+
:Pipe({
|
|
277
|
+
RxBrioUtils.switchToBrio(),
|
|
278
|
+
})
|
|
279
|
+
:Subscribe(function(brio)
|
|
280
|
+
result = brio
|
|
281
|
+
end)
|
|
282
|
+
|
|
283
|
+
expect(result).never.toBeNil()
|
|
284
|
+
expect(result:IsDead()).toEqual(false)
|
|
285
|
+
|
|
286
|
+
inputBrio:Kill()
|
|
287
|
+
expect(result:IsDead()).toEqual(true)
|
|
288
|
+
|
|
289
|
+
sub:Destroy()
|
|
290
|
+
end)
|
|
291
|
+
|
|
292
|
+
it("should kill the last brio on unsubscribe", function()
|
|
293
|
+
local result
|
|
294
|
+
local sub = Observable.new(function(innerSub)
|
|
295
|
+
innerSub:Fire(77)
|
|
296
|
+
end)
|
|
297
|
+
:Pipe({
|
|
298
|
+
RxBrioUtils.switchToBrio(),
|
|
299
|
+
})
|
|
300
|
+
:Subscribe(function(brio)
|
|
301
|
+
result = brio
|
|
302
|
+
end)
|
|
303
|
+
|
|
304
|
+
expect(result).never.toBeNil()
|
|
305
|
+
expect(result:IsDead()).toEqual(false)
|
|
306
|
+
|
|
307
|
+
sub:Destroy()
|
|
308
|
+
expect(result:IsDead()).toEqual(true)
|
|
309
|
+
end)
|
|
310
|
+
|
|
311
|
+
it("should propagate failure from source", function()
|
|
312
|
+
local failed = false
|
|
313
|
+
local failMsg
|
|
314
|
+
local sub = Observable.new(function(innerSub)
|
|
315
|
+
innerSub:Fail("test error")
|
|
316
|
+
end)
|
|
317
|
+
:Pipe({
|
|
318
|
+
RxBrioUtils.switchToBrio(),
|
|
319
|
+
})
|
|
320
|
+
:Subscribe(function() end, function(err)
|
|
321
|
+
failed = true
|
|
322
|
+
failMsg = err
|
|
323
|
+
end)
|
|
324
|
+
|
|
325
|
+
expect(failed).toEqual(true)
|
|
326
|
+
expect(failMsg).toEqual("test error")
|
|
327
|
+
|
|
328
|
+
sub:Destroy()
|
|
329
|
+
end)
|
|
330
|
+
|
|
331
|
+
it("should propagate completion from source", function()
|
|
332
|
+
local completed = false
|
|
333
|
+
local sub = Observable.new(function(innerSub)
|
|
334
|
+
innerSub:Complete()
|
|
335
|
+
end)
|
|
336
|
+
:Pipe({
|
|
337
|
+
RxBrioUtils.switchToBrio(),
|
|
338
|
+
})
|
|
339
|
+
:Subscribe(function() end, function() end, function()
|
|
340
|
+
completed = true
|
|
341
|
+
end)
|
|
342
|
+
|
|
343
|
+
expect(completed).toEqual(true)
|
|
344
|
+
|
|
345
|
+
sub:Destroy()
|
|
346
|
+
end)
|
|
347
|
+
|
|
348
|
+
it("should apply predicate to plain values", function()
|
|
349
|
+
local doFire
|
|
350
|
+
local results = {}
|
|
351
|
+
local sub = Observable.new(function(innerSub)
|
|
352
|
+
doFire = function(...)
|
|
353
|
+
innerSub:Fire(...)
|
|
354
|
+
end
|
|
355
|
+
end)
|
|
356
|
+
:Pipe({
|
|
357
|
+
RxBrioUtils.switchToBrio(function(value)
|
|
358
|
+
return value > 10
|
|
359
|
+
end),
|
|
360
|
+
})
|
|
361
|
+
:Subscribe(function(brio)
|
|
362
|
+
table.insert(results, brio)
|
|
363
|
+
end)
|
|
364
|
+
|
|
365
|
+
doFire(5)
|
|
366
|
+
expect(#results).toEqual(0)
|
|
367
|
+
|
|
368
|
+
doFire(15)
|
|
369
|
+
expect(#results).toEqual(1)
|
|
370
|
+
expect(results[1]:GetValue()).toEqual(15)
|
|
371
|
+
|
|
372
|
+
doFire(3)
|
|
373
|
+
expect(#results).toEqual(1)
|
|
374
|
+
expect(results[1]:IsDead()).toEqual(true)
|
|
375
|
+
|
|
376
|
+
sub:Destroy()
|
|
377
|
+
end)
|
|
378
|
+
|
|
379
|
+
it("should apply predicate to unwrapped brio values", function()
|
|
380
|
+
local doFire
|
|
381
|
+
local results = {}
|
|
382
|
+
local sub = Observable.new(function(innerSub)
|
|
383
|
+
doFire = function(...)
|
|
384
|
+
innerSub:Fire(...)
|
|
385
|
+
end
|
|
386
|
+
end)
|
|
387
|
+
:Pipe({
|
|
388
|
+
RxBrioUtils.switchToBrio(function(value)
|
|
389
|
+
return value > 10
|
|
390
|
+
end),
|
|
391
|
+
})
|
|
392
|
+
:Subscribe(function(brio)
|
|
393
|
+
table.insert(results, brio)
|
|
394
|
+
end)
|
|
395
|
+
|
|
396
|
+
doFire(Brio.new(5))
|
|
397
|
+
expect(#results).toEqual(0)
|
|
398
|
+
|
|
399
|
+
doFire(Brio.new(20))
|
|
400
|
+
expect(#results).toEqual(1)
|
|
401
|
+
expect(results[1]:GetValue()).toEqual(20)
|
|
402
|
+
|
|
403
|
+
sub:Destroy()
|
|
404
|
+
end)
|
|
405
|
+
|
|
406
|
+
it("should handle rapid succession of emissions correctly", function()
|
|
407
|
+
local doFire
|
|
408
|
+
local results = {}
|
|
409
|
+
local sub = Observable.new(function(innerSub)
|
|
410
|
+
doFire = function(...)
|
|
411
|
+
innerSub:Fire(...)
|
|
412
|
+
end
|
|
413
|
+
end)
|
|
414
|
+
:Pipe({
|
|
415
|
+
RxBrioUtils.switchToBrio(),
|
|
416
|
+
})
|
|
417
|
+
:Subscribe(function(brio)
|
|
418
|
+
table.insert(results, brio)
|
|
419
|
+
end)
|
|
420
|
+
|
|
421
|
+
for i = 1, 100 do
|
|
422
|
+
doFire(i)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
expect(#results).toEqual(100)
|
|
426
|
+
|
|
427
|
+
-- All but last should be dead
|
|
428
|
+
for i = 1, 99 do
|
|
429
|
+
expect(results[i]:IsDead()).toEqual(true)
|
|
430
|
+
end
|
|
431
|
+
expect(results[100]:IsDead()).toEqual(false)
|
|
432
|
+
expect(results[100]:GetValue()).toEqual(100)
|
|
433
|
+
|
|
434
|
+
sub:Destroy()
|
|
435
|
+
end)
|
|
436
|
+
|
|
437
|
+
it("should handle interleaved brio and plain value emissions", function()
|
|
438
|
+
local doFire
|
|
439
|
+
local results = {}
|
|
440
|
+
local sub = Observable.new(function(innerSub)
|
|
441
|
+
doFire = function(...)
|
|
442
|
+
innerSub:Fire(...)
|
|
443
|
+
end
|
|
444
|
+
end)
|
|
445
|
+
:Pipe({
|
|
446
|
+
RxBrioUtils.switchToBrio(),
|
|
447
|
+
})
|
|
448
|
+
:Subscribe(function(brio)
|
|
449
|
+
table.insert(results, brio)
|
|
450
|
+
end)
|
|
451
|
+
|
|
452
|
+
local inputBrio = Brio.new("from-brio")
|
|
453
|
+
doFire("plain")
|
|
454
|
+
doFire(inputBrio)
|
|
455
|
+
doFire("plain-again")
|
|
456
|
+
|
|
457
|
+
expect(#results).toEqual(3)
|
|
458
|
+
expect(results[1]:IsDead()).toEqual(true)
|
|
459
|
+
expect(results[2]:IsDead()).toEqual(true)
|
|
460
|
+
expect(results[3]:IsDead()).toEqual(false)
|
|
461
|
+
expect(results[3]:GetValue()).toEqual("plain-again")
|
|
462
|
+
|
|
463
|
+
sub:Destroy()
|
|
464
|
+
end)
|
|
465
|
+
|
|
466
|
+
it("should handle source brio dying while subscribed then new emission", function()
|
|
467
|
+
local doFire
|
|
468
|
+
local results = {}
|
|
469
|
+
local sub = Observable.new(function(innerSub)
|
|
470
|
+
doFire = function(...)
|
|
471
|
+
innerSub:Fire(...)
|
|
472
|
+
end
|
|
473
|
+
end)
|
|
474
|
+
:Pipe({
|
|
475
|
+
RxBrioUtils.switchToBrio(),
|
|
476
|
+
})
|
|
477
|
+
:Subscribe(function(brio)
|
|
478
|
+
table.insert(results, brio)
|
|
479
|
+
end)
|
|
480
|
+
|
|
481
|
+
local brio1 = Brio.new("first")
|
|
482
|
+
doFire(brio1)
|
|
483
|
+
expect(#results).toEqual(1)
|
|
484
|
+
expect(results[1]:IsDead()).toEqual(false)
|
|
485
|
+
|
|
486
|
+
-- Source brio dies externally
|
|
487
|
+
brio1:Kill()
|
|
488
|
+
expect(results[1]:IsDead()).toEqual(true)
|
|
489
|
+
|
|
490
|
+
-- New emission should still work
|
|
491
|
+
doFire("second")
|
|
492
|
+
expect(#results).toEqual(2)
|
|
493
|
+
expect(results[2]:IsDead()).toEqual(false)
|
|
494
|
+
expect(results[2]:GetValue()).toEqual("second")
|
|
495
|
+
|
|
496
|
+
sub:Destroy()
|
|
497
|
+
end)
|
|
498
|
+
|
|
499
|
+
it("should handle subscriber causing re-emission during fire", function()
|
|
500
|
+
-- Race condition: subscriber fires a new value during the callback
|
|
501
|
+
local doFire
|
|
502
|
+
local results = {}
|
|
503
|
+
local reEmitted = false
|
|
504
|
+
|
|
505
|
+
local sub = Observable.new(function(innerSub)
|
|
506
|
+
doFire = function(...)
|
|
507
|
+
innerSub:Fire(...)
|
|
508
|
+
end
|
|
509
|
+
end)
|
|
510
|
+
:Pipe({
|
|
511
|
+
RxBrioUtils.switchToBrio(),
|
|
512
|
+
})
|
|
513
|
+
:Subscribe(function(brio)
|
|
514
|
+
table.insert(results, brio)
|
|
515
|
+
|
|
516
|
+
-- On first emission, synchronously emit another value
|
|
517
|
+
if not reEmitted then
|
|
518
|
+
reEmitted = true
|
|
519
|
+
doFire("re-emitted")
|
|
520
|
+
end
|
|
521
|
+
end)
|
|
522
|
+
|
|
523
|
+
doFire("initial")
|
|
524
|
+
|
|
525
|
+
expect(#results).toEqual(2)
|
|
526
|
+
-- The initial brio should be dead because re-emission killed it
|
|
527
|
+
expect(results[1]:IsDead()).toEqual(true)
|
|
528
|
+
-- The re-emitted brio should be alive
|
|
529
|
+
expect(results[2]:IsDead()).toEqual(false)
|
|
530
|
+
expect(results[2]:GetValue()).toEqual("re-emitted")
|
|
531
|
+
|
|
532
|
+
sub:Destroy()
|
|
533
|
+
end)
|
|
534
|
+
|
|
535
|
+
it("should not emit when predicate is provided and all values are rejected", function()
|
|
536
|
+
local doFire
|
|
537
|
+
local fireCount = 0
|
|
538
|
+
|
|
539
|
+
local sub = Observable.new(function(innerSub)
|
|
540
|
+
doFire = function(...)
|
|
541
|
+
innerSub:Fire(...)
|
|
542
|
+
end
|
|
543
|
+
end)
|
|
544
|
+
:Pipe({
|
|
545
|
+
RxBrioUtils.switchToBrio(function()
|
|
546
|
+
return false
|
|
547
|
+
end),
|
|
548
|
+
})
|
|
549
|
+
:Subscribe(function()
|
|
550
|
+
fireCount = fireCount + 1
|
|
551
|
+
end)
|
|
552
|
+
|
|
553
|
+
doFire(1)
|
|
554
|
+
doFire(2)
|
|
555
|
+
doFire(Brio.new(3))
|
|
556
|
+
|
|
557
|
+
expect(fireCount).toEqual(0)
|
|
558
|
+
|
|
559
|
+
sub:Destroy()
|
|
560
|
+
end)
|
|
561
|
+
|
|
562
|
+
it("should error with non-function predicate", function()
|
|
563
|
+
expect(function()
|
|
564
|
+
RxBrioUtils.switchToBrio("bad" :: any)
|
|
565
|
+
end).toThrow()
|
|
566
|
+
end)
|
|
567
|
+
end)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "BrioTest",
|
|
3
|
+
"globIgnorePaths": [
|
|
4
|
+
"**/.package-lock.json",
|
|
5
|
+
"**/.pnpm",
|
|
6
|
+
"**/.pnpm-workspace-state-v1.json",
|
|
7
|
+
"**/.modules.yaml",
|
|
8
|
+
"**/.ignored",
|
|
9
|
+
"**/.ignored_*"
|
|
10
|
+
],
|
|
11
|
+
"tree": {
|
|
12
|
+
"$className": "DataModel",
|
|
13
|
+
"ServerScriptService": {
|
|
14
|
+
"$properties": {
|
|
15
|
+
"LoadStringEnabled": true
|
|
16
|
+
},
|
|
17
|
+
"brio": {
|
|
18
|
+
"$path": ".."
|
|
19
|
+
},
|
|
20
|
+
"Script": {
|
|
21
|
+
"$path": "scripts/Server"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
--[[
|
|
2
|
+
@class ServerMain
|
|
3
|
+
]]
|
|
4
|
+
local ServerScriptService = game:GetService("ServerScriptService")
|
|
5
|
+
|
|
6
|
+
local root = ServerScriptService.brio
|
|
7
|
+
local loader = root:FindFirstChild("LoaderUtils", true).Parent
|
|
8
|
+
local require = require(loader).bootstrapGame(root)
|
|
9
|
+
|
|
10
|
+
local NevermoreTestRunnerUtils = require("NevermoreTestRunnerUtils")
|
|
11
|
+
if NevermoreTestRunnerUtils.runTestsIfNeededAsync(root) then
|
|
12
|
+
return
|
|
13
|
+
end
|