@serverkgg/bridge 0.1.2 → 0.1.4
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/package.json +3 -2
- package/rules/package.md +65 -0
- package/src/blog/articleFrontmatter.test.ts +10 -10
- package/src/blog/compile.test.ts +9 -9
- package/src/bot/botDeploy.test.ts +16 -16
- package/src/bot/botEnvironment.test.ts +8 -8
- package/src/bot/botIdentity.test.ts +12 -12
- package/src/bot/botPanel.test.ts +13 -13
- package/src/bot/botPanel.ts +4 -4
- package/src/bot/botState.test.ts +3 -3
- package/src/bot/botTerminal.test.ts +5 -5
- package/src/bot/botVariables.test.ts +8 -8
- package/src/bot/detect/botToken.test.ts +6 -6
- package/src/bot/detect/detect.test.ts +21 -21
- package/src/bot/detect/detectTable.test.ts +5 -5
- package/src/bot/detect/envExample.test.ts +2 -2
- package/src/bot/detect/envScan.test.ts +4 -4
- package/src/bot/detect/inferBotPlatform.test.ts +4 -4
- package/src/bot/detect/keys.test.ts +3 -3
- package/src/bot/detect/sensitiveKey.test.ts +5 -5
- package/src/bot/detect/serverkJson.test.ts +5 -5
- package/src/catalogs/curseforge.test.ts +35 -35
- package/src/catalogs/thunderstore.test.ts +9 -9
- package/src/cli/detectTable.test.ts +3 -3
- package/src/cli/link.test.ts +11 -11
- package/src/cli/main.ts +8 -0
- package/src/cli/rules.test.ts +198 -0
- package/src/cli/rules.ts +188 -0
- package/src/cli/validate.test.ts +179 -31
- package/src/cli/validate.ts +44 -0
- package/src/codecs/ini.test.ts +13 -13
- package/src/codecs/javaProperties.test.ts +11 -11
- package/src/codecs/sourceCfg.test.ts +14 -14
- package/src/codecs/xmlProperties.test.ts +10 -10
- package/src/core/bridgePort.test.ts +6 -6
- package/src/core/bridgeUserError.test.ts +4 -4
- package/src/core/bridgeValue.test.ts +5 -5
- package/src/core/describeDownloadFailure.test.ts +12 -12
- package/src/core/describeDownloadFailure.ts +10 -10
- package/src/guides/markdown.test.ts +31 -31
- package/src/install/installStamp.test.ts +9 -9
- package/src/manifest/extension.ts +36 -0
- package/src/manifest/index.ts +1 -0
- package/src/manifest/manifest.test.ts +208 -90
- package/src/manifest/manifest.ts +34 -0
- package/src/net/loopback.test.ts +10 -10
- package/src/presence/rosterSync.test.ts +7 -7
- package/src/probes/a2s.test.ts +5 -5
- package/src/probes/minecraftPing.test.ts +17 -17
- package/src/probes/raknetPing.test.ts +13 -13
- package/src/protocol/bridgePreview.ts +1 -0
- package/src/rcon/rconAccess.test.ts +20 -20
- package/src/rcon/rconAccess.ts +14 -14
- package/src/rcon/rconClient.test.ts +49 -49
- package/src/rcon/rconFrame.test.ts +14 -14
- package/src/rcon/rconIds.test.ts +4 -4
- package/src/rcon/rconWriter.test.ts +6 -6
- package/src/runtime/bridgeActivity.test.ts +15 -15
- package/src/runtime/bridgeBackupLease.test.ts +9 -9
- package/src/runtime/bridgeConfigReader.test.ts +5 -5
- package/src/runtime/bridgeConsoleHandler.test.ts +8 -8
- package/src/runtime/bridgeContext.test.ts +5 -5
- package/src/runtime/bridgeDriver.test.ts +94 -94
- package/src/runtime/bridgeEvents.test.ts +15 -15
- package/src/runtime/bridgeFiles.test.ts +54 -54
- package/src/runtime/bridgeInstall.test.ts +10 -10
- package/src/runtime/bridgeLiveConfig.test.ts +6 -6
- package/src/runtime/bridgePending.test.ts +6 -6
- package/src/runtime/bridgeRedaction.test.ts +16 -16
- package/src/runtime/bridgeRegistry.test.ts +84 -52
- package/src/runtime/bridgeRegistry.ts +2 -2
- package/src/runtime/bridgeServer.test.ts +31 -31
- package/src/runtime/bridgeSetup.test.ts +27 -27
- package/src/runtime/bridgeSetup.ts +1 -1
- package/src/runtime/bridgeSetupHandlers.test.ts +13 -13
- package/src/runtime/bridgeSignal.test.ts +7 -7
- package/src/runtime/bridgeSupervisor.test.ts +42 -42
- package/src/runtime/serve.ts +4 -4
- package/src/steam/avatars.test.ts +13 -13
- package/src/steam/steamApp.test.ts +8 -8
- package/src/steam/steamcmd.test.ts +17 -17
- package/src/steam/steamcmd.ts +4 -4
- package/src/steam/steamcmdNarrator.test.ts +4 -4
- package/src/steam/workshop.test.ts +5 -5
- package/src/utils/changedSettingKeys.test.ts +5 -5
- package/src/utils/describeExecFailure.test.ts +4 -4
- package/src/utils/describeExecFailure.ts +1 -1
- package/src/utils/sameSettingValue.test.ts +7 -7
- package/src/utils/token.test.ts +7 -7
- package/src/wine/protonCommand.test.ts +5 -5
- package/src/wine/wineCommand.test.ts +6 -6
- package/src/wine/winePrefix.test.ts +6 -6
- package/src/wire/activity.test.ts +8 -8
- package/src/wire/panel.test.ts +28 -28
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
2
|
import { BridgeKind, BridgeSetupStepKind, PortJoin, PortProtocol } from "../core";
|
|
3
3
|
import { GuideOpenTab } from "../guides";
|
|
4
4
|
import type { ManifestPort, ManifestPortActivation } from "../manifest";
|
|
@@ -275,7 +275,7 @@ const driverWithTabs = (tabs: number, sections: number): BridgeDriver => ({
|
|
|
275
275
|
});
|
|
276
276
|
|
|
277
277
|
describe("panel caps", () => {
|
|
278
|
-
|
|
278
|
+
it("rejects a collection row action named after a read action", () => {
|
|
279
279
|
const driver = driverWithTabs(1, 1);
|
|
280
280
|
|
|
281
281
|
driver.modules = {
|
|
@@ -296,23 +296,23 @@ describe("panel caps", () => {
|
|
|
296
296
|
);
|
|
297
297
|
});
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
it("takes the tab and section counts the agent mirror accepts", () => {
|
|
300
300
|
expect(() => validateDriver(driverWithTabs(8, 8))).not.toThrow();
|
|
301
301
|
});
|
|
302
302
|
|
|
303
|
-
|
|
303
|
+
it("rejects a ninth tab the agent mirror would drop", () => {
|
|
304
304
|
expect(() => validateDriver(driverWithTabs(9, 1))).toThrow(
|
|
305
305
|
"the panel declares 9 tabs — the platform takes at most 8",
|
|
306
306
|
);
|
|
307
307
|
});
|
|
308
308
|
|
|
309
|
-
|
|
309
|
+
it("rejects a ninth section the agent mirror would drop", () => {
|
|
310
310
|
expect(() => validateDriver(driverWithTabs(1, 9))).toThrow(
|
|
311
311
|
'tab "tab-0" declares 9 sections — the platform takes at most 8',
|
|
312
312
|
);
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
it("rejects a form carrying more fields than the agent mirror accepts", () => {
|
|
316
316
|
const driver = driverWithTabs(1, 1);
|
|
317
317
|
const [tab] = driver.panel?.tabs ?? [];
|
|
318
318
|
const [section] = tab?.sections ?? [];
|
|
@@ -328,7 +328,7 @@ describe("panel caps", () => {
|
|
|
328
328
|
expect(() => validateDriver(driver)).toThrow("declares 33 fields — the platform takes at most 32");
|
|
329
329
|
});
|
|
330
330
|
|
|
331
|
-
|
|
331
|
+
it("rejects a table carrying more columns than the agent mirror accepts", () => {
|
|
332
332
|
const driver = driverWithTabs(1, 1);
|
|
333
333
|
const [tab] = driver.panel?.tabs ?? [];
|
|
334
334
|
|
|
@@ -360,7 +360,7 @@ describe("panel caps", () => {
|
|
|
360
360
|
expect(() => validateDriver(driver)).toThrow("declares 9 columns — the platform takes at most 8");
|
|
361
361
|
});
|
|
362
362
|
|
|
363
|
-
|
|
363
|
+
it("rejects a label longer than the agent mirror accepts", () => {
|
|
364
364
|
const driver = driverWithTabs(1, 1);
|
|
365
365
|
const [tab] = driver.panel?.tabs ?? [];
|
|
366
366
|
|
|
@@ -377,7 +377,7 @@ describe("panel caps", () => {
|
|
|
377
377
|
});
|
|
378
378
|
|
|
379
379
|
describe("actions sections", () => {
|
|
380
|
-
|
|
380
|
+
it("accepts an action the module implements", () => {
|
|
381
381
|
expect(() =>
|
|
382
382
|
validateDriver(
|
|
383
383
|
driverWithActions([
|
|
@@ -393,7 +393,7 @@ describe("actions sections", () => {
|
|
|
393
393
|
).not.toThrow();
|
|
394
394
|
});
|
|
395
395
|
|
|
396
|
-
|
|
396
|
+
it("rejects an action the module does not implement", () => {
|
|
397
397
|
expect(() =>
|
|
398
398
|
validateDriver(
|
|
399
399
|
driverWithActions([
|
|
@@ -406,11 +406,11 @@ describe("actions sections", () => {
|
|
|
406
406
|
).toThrow('declares action "shout", which module "broadcast" does not implement');
|
|
407
407
|
});
|
|
408
408
|
|
|
409
|
-
|
|
409
|
+
it("rejects a section with no actions", () => {
|
|
410
410
|
expect(() => validateDriver(driverWithActions([]))).toThrow("declares no actions");
|
|
411
411
|
});
|
|
412
412
|
|
|
413
|
-
|
|
413
|
+
it("rejects an action carrying more fields than one prompt fits", () => {
|
|
414
414
|
expect(() =>
|
|
415
415
|
validateDriver(
|
|
416
416
|
driverWithActions([
|
|
@@ -431,7 +431,7 @@ describe("actions sections", () => {
|
|
|
431
431
|
).toThrow('action "say" declares 6 fields — at most 5 fit one prompt');
|
|
432
432
|
});
|
|
433
433
|
|
|
434
|
-
|
|
434
|
+
it("rejects a section pointing at a module that is not an actions module", () => {
|
|
435
435
|
const driver = driverWithActions([
|
|
436
436
|
{
|
|
437
437
|
id: "say",
|
|
@@ -449,7 +449,7 @@ describe("actions sections", () => {
|
|
|
449
449
|
expect(() => validateDriver(driver)).toThrow('references "broadcast", which is not an actions module');
|
|
450
450
|
});
|
|
451
451
|
|
|
452
|
-
|
|
452
|
+
it("checks the fields a row action declares", () => {
|
|
453
453
|
const driver = driverWithActions([
|
|
454
454
|
{
|
|
455
455
|
id: "say",
|
|
@@ -510,7 +510,7 @@ describe("actions sections", () => {
|
|
|
510
510
|
});
|
|
511
511
|
|
|
512
512
|
describe("visibleWhen", () => {
|
|
513
|
-
|
|
513
|
+
it("accepts a rule that matches on values", () => {
|
|
514
514
|
expect(() =>
|
|
515
515
|
validateDriver(
|
|
516
516
|
driverWith({
|
|
@@ -523,7 +523,7 @@ describe("visibleWhen", () => {
|
|
|
523
523
|
).not.toThrow();
|
|
524
524
|
});
|
|
525
525
|
|
|
526
|
-
|
|
526
|
+
it("accepts a rule that matches on emptiness", () => {
|
|
527
527
|
expect(() =>
|
|
528
528
|
validateDriver(
|
|
529
529
|
driverWith({
|
|
@@ -543,7 +543,7 @@ describe("visibleWhen", () => {
|
|
|
543
543
|
).not.toThrow();
|
|
544
544
|
});
|
|
545
545
|
|
|
546
|
-
|
|
546
|
+
it("accepts a rule that narrows values inside a presence check", () => {
|
|
547
547
|
expect(() =>
|
|
548
548
|
validateDriver(
|
|
549
549
|
driverWith({
|
|
@@ -557,7 +557,7 @@ describe("visibleWhen", () => {
|
|
|
557
557
|
).not.toThrow();
|
|
558
558
|
});
|
|
559
559
|
|
|
560
|
-
|
|
560
|
+
it("rejects a rule that declares neither values nor empty", () => {
|
|
561
561
|
expect(() =>
|
|
562
562
|
validateDriver(
|
|
563
563
|
driverWith({
|
|
@@ -567,7 +567,7 @@ describe("visibleWhen", () => {
|
|
|
567
567
|
).toThrow('is visible when "MODPACK" matches nothing');
|
|
568
568
|
});
|
|
569
569
|
|
|
570
|
-
|
|
570
|
+
it("rejects an empty values list", () => {
|
|
571
571
|
expect(() =>
|
|
572
572
|
validateDriver(
|
|
573
573
|
driverWith({
|
|
@@ -578,7 +578,7 @@ describe("visibleWhen", () => {
|
|
|
578
578
|
).toThrow('is visible when "MODPACK" matches nothing');
|
|
579
579
|
});
|
|
580
580
|
|
|
581
|
-
|
|
581
|
+
it("checks a field rule as well as a section rule", () => {
|
|
582
582
|
const driver = driverWith({
|
|
583
583
|
variable: "MODPACK",
|
|
584
584
|
empty: true,
|
|
@@ -605,11 +605,11 @@ describe("visibleWhen", () => {
|
|
|
605
605
|
});
|
|
606
606
|
|
|
607
607
|
describe("form preview", () => {
|
|
608
|
-
|
|
608
|
+
it("accepts a variables form pointing at a preview module", () => {
|
|
609
609
|
expect(() => validateDriver(driverWithPreview())).not.toThrow();
|
|
610
610
|
});
|
|
611
611
|
|
|
612
|
-
|
|
612
|
+
it("rejects a preview ref to a module that is not a preview module", () => {
|
|
613
613
|
const driver = driverWithPreview();
|
|
614
614
|
|
|
615
615
|
driver.modules = {
|
|
@@ -622,7 +622,7 @@ describe("form preview", () => {
|
|
|
622
622
|
expect(() => validateDriver(driver)).toThrow('references "transition", which is not a preview module');
|
|
623
623
|
});
|
|
624
624
|
|
|
625
|
-
|
|
625
|
+
it("rejects a preview on a form that writes settings", () => {
|
|
626
626
|
const driver = driverWithPreview();
|
|
627
627
|
const section = formSectionOf(driver);
|
|
628
628
|
|
|
@@ -645,7 +645,7 @@ describe("form preview", () => {
|
|
|
645
645
|
});
|
|
646
646
|
|
|
647
647
|
describe("validatePortActivation", () => {
|
|
648
|
-
|
|
648
|
+
it("accepts a variable a variables form or a catalog section declares", () => {
|
|
649
649
|
expect(() =>
|
|
650
650
|
validatePortActivation(
|
|
651
651
|
[
|
|
@@ -667,7 +667,7 @@ describe("validatePortActivation", () => {
|
|
|
667
667
|
).not.toThrow();
|
|
668
668
|
});
|
|
669
669
|
|
|
670
|
-
|
|
670
|
+
it("rejects a variable nothing in the panel declares", () => {
|
|
671
671
|
expect(() =>
|
|
672
672
|
validatePortActivation(
|
|
673
673
|
[
|
|
@@ -804,11 +804,11 @@ const clearingFormOf = (driver: BridgeDriver) => {
|
|
|
804
804
|
};
|
|
805
805
|
|
|
806
806
|
describe("detail sections", () => {
|
|
807
|
-
|
|
807
|
+
it("accepts a detail section on a detail module", () => {
|
|
808
808
|
expect(() => validateDriver(withNoop(driverWithDetail()))).not.toThrow();
|
|
809
809
|
});
|
|
810
810
|
|
|
811
|
-
|
|
811
|
+
it("rejects a section pointing at a module that is not a detail module", () => {
|
|
812
812
|
const driver = withNoop(driverWithDetail());
|
|
813
813
|
|
|
814
814
|
driver.modules = {
|
|
@@ -822,7 +822,7 @@ describe("detail sections", () => {
|
|
|
822
822
|
expect(() => validateDriver(driver)).toThrow('references "modpackStatus", which is not a detail module');
|
|
823
823
|
});
|
|
824
824
|
|
|
825
|
-
|
|
825
|
+
it("rejects an action the module does not implement", () => {
|
|
826
826
|
const driver = withNoop(driverWithDetail());
|
|
827
827
|
|
|
828
828
|
detailSectionOf(driver).actions = [
|
|
@@ -837,7 +837,7 @@ describe("detail sections", () => {
|
|
|
837
837
|
);
|
|
838
838
|
});
|
|
839
839
|
|
|
840
|
-
|
|
840
|
+
it("rejects a download action, since a detail has no rows to serve", () => {
|
|
841
841
|
const driver = withNoop(driverWithDetail());
|
|
842
842
|
|
|
843
843
|
detailSectionOf(driver).actions = [
|
|
@@ -851,7 +851,7 @@ describe("detail sections", () => {
|
|
|
851
851
|
expect(() => validateDriver(driver)).toThrow('declares action "update" as a download');
|
|
852
852
|
});
|
|
853
853
|
|
|
854
|
-
|
|
854
|
+
it("rejects a related tab the panel does not declare", () => {
|
|
855
855
|
const driver = withNoop(driverWithDetail());
|
|
856
856
|
|
|
857
857
|
detailSectionOf(driver).related = {
|
|
@@ -862,7 +862,7 @@ describe("detail sections", () => {
|
|
|
862
862
|
expect(() => validateDriver(driver)).toThrow('relates to tab "worlds", which the panel does not declare');
|
|
863
863
|
});
|
|
864
864
|
|
|
865
|
-
|
|
865
|
+
it("counts a detail variable as declared for port activation", () => {
|
|
866
866
|
expect(() =>
|
|
867
867
|
validatePortActivation(
|
|
868
868
|
[
|
|
@@ -880,11 +880,11 @@ describe("detail sections", () => {
|
|
|
880
880
|
});
|
|
881
881
|
|
|
882
882
|
describe("form clears", () => {
|
|
883
|
-
|
|
883
|
+
it("accepts a clear of a variable a detail section declares", () => {
|
|
884
884
|
expect(() => validateDriver(withNoop(driverWithDetail()))).not.toThrow();
|
|
885
885
|
});
|
|
886
886
|
|
|
887
|
-
|
|
887
|
+
it("rejects a clear of a variable nothing declares", () => {
|
|
888
888
|
const driver = withNoop(driverWithDetail());
|
|
889
889
|
|
|
890
890
|
clearingFormOf(driver).clears = [
|
|
@@ -899,7 +899,7 @@ describe("form clears", () => {
|
|
|
899
899
|
);
|
|
900
900
|
});
|
|
901
901
|
|
|
902
|
-
|
|
902
|
+
it("rejects a clear of one of the form's own fields", () => {
|
|
903
903
|
const driver = withNoop(driverWithDetail());
|
|
904
904
|
|
|
905
905
|
clearingFormOf(driver).clears = [
|
|
@@ -912,7 +912,7 @@ describe("form clears", () => {
|
|
|
912
912
|
expect(() => validateDriver(driver)).toThrow('clears "MC_VERSION", which is one of its own fields');
|
|
913
913
|
});
|
|
914
914
|
|
|
915
|
-
|
|
915
|
+
it("rejects clears on a form that writes settings", () => {
|
|
916
916
|
const driver = withNoop(driverWithDetail());
|
|
917
917
|
const form = clearingFormOf(driver);
|
|
918
918
|
|
|
@@ -990,16 +990,16 @@ describe("table uploads", () => {
|
|
|
990
990
|
mode,
|
|
991
991
|
});
|
|
992
992
|
|
|
993
|
-
|
|
993
|
+
it("accepts an upload that declares no mode", () => {
|
|
994
994
|
expect(() => validateDriver(driverWithUpload(upload()))).not.toThrow();
|
|
995
995
|
});
|
|
996
996
|
|
|
997
|
-
|
|
997
|
+
it("accepts both declared upload modes", () => {
|
|
998
998
|
expect(() => validateDriver(driverWithUpload(upload(BridgeUploadMode.Archive)))).not.toThrow();
|
|
999
999
|
expect(() => validateDriver(driverWithUpload(upload(BridgeUploadMode.File)))).not.toThrow();
|
|
1000
1000
|
});
|
|
1001
1001
|
|
|
1002
|
-
|
|
1002
|
+
it("rejects an upload mode the platform does not know", () => {
|
|
1003
1003
|
const section = upload("stream" as BridgeUploadMode);
|
|
1004
1004
|
|
|
1005
1005
|
expect(() => validateDriver(driverWithUpload(section))).toThrow('declares an unknown upload mode "stream"');
|
|
@@ -1036,7 +1036,7 @@ describe("the pending module", () => {
|
|
|
1036
1036
|
...overrides,
|
|
1037
1037
|
});
|
|
1038
1038
|
|
|
1039
|
-
|
|
1039
|
+
it("accepts a driver that declares no pending module", () => {
|
|
1040
1040
|
expect(() =>
|
|
1041
1041
|
validateDriver({
|
|
1042
1042
|
install: {
|
|
@@ -1055,11 +1055,11 @@ describe("the pending module", () => {
|
|
|
1055
1055
|
).not.toThrow();
|
|
1056
1056
|
});
|
|
1057
1057
|
|
|
1058
|
-
|
|
1058
|
+
it("accepts a pending module declaring a staging path and one extension", () => {
|
|
1059
1059
|
expect(() => validateDriver(driverWithPending(pendingWith({})))).not.toThrow();
|
|
1060
1060
|
});
|
|
1061
1061
|
|
|
1062
|
-
|
|
1062
|
+
it("rejects a pending module carrying another kind", () => {
|
|
1063
1063
|
const pending = pendingWith({
|
|
1064
1064
|
kind: BridgeKind.Collection as BridgeKind.Pending,
|
|
1065
1065
|
});
|
|
@@ -1069,7 +1069,7 @@ describe("the pending module", () => {
|
|
|
1069
1069
|
);
|
|
1070
1070
|
});
|
|
1071
1071
|
|
|
1072
|
-
|
|
1072
|
+
it("rejects a pending module with no staging path", () => {
|
|
1073
1073
|
expect(() =>
|
|
1074
1074
|
validateDriver(
|
|
1075
1075
|
driverWithPending(
|
|
@@ -1081,7 +1081,7 @@ describe("the pending module", () => {
|
|
|
1081
1081
|
).toThrow("the pending module declares no staging path");
|
|
1082
1082
|
});
|
|
1083
1083
|
|
|
1084
|
-
|
|
1084
|
+
it("rejects a staging path longer than the platform takes", () => {
|
|
1085
1085
|
expect(() =>
|
|
1086
1086
|
validateDriver(
|
|
1087
1087
|
driverWithPending(
|
|
@@ -1093,7 +1093,7 @@ describe("the pending module", () => {
|
|
|
1093
1093
|
).toThrow("the pending module staging path is 129 characters — the platform takes at most 128");
|
|
1094
1094
|
});
|
|
1095
1095
|
|
|
1096
|
-
|
|
1096
|
+
it("rejects a pending module declaring no extensions", () => {
|
|
1097
1097
|
expect(() =>
|
|
1098
1098
|
validateDriver(
|
|
1099
1099
|
driverWithPending(
|
|
@@ -1105,7 +1105,7 @@ describe("the pending module", () => {
|
|
|
1105
1105
|
).toThrow("the pending module declares no extensions");
|
|
1106
1106
|
});
|
|
1107
1107
|
|
|
1108
|
-
|
|
1108
|
+
it("rejects more extensions than the platform takes", () => {
|
|
1109
1109
|
expect(() =>
|
|
1110
1110
|
validateDriver(
|
|
1111
1111
|
driverWithPending(
|
|
@@ -1119,7 +1119,7 @@ describe("the pending module", () => {
|
|
|
1119
1119
|
).toThrow("the pending module declares 9 extensions — the platform takes at most 8");
|
|
1120
1120
|
});
|
|
1121
1121
|
|
|
1122
|
-
|
|
1122
|
+
it("rejects an extension longer than the platform takes", () => {
|
|
1123
1123
|
expect(() =>
|
|
1124
1124
|
validateDriver(
|
|
1125
1125
|
driverWithPending(
|
|
@@ -1133,7 +1133,7 @@ describe("the pending module", () => {
|
|
|
1133
1133
|
).toThrow('the pending module extension "xxxxxxxxxxxxxxxxx" is 17 characters — the platform takes at most 16');
|
|
1134
1134
|
});
|
|
1135
1135
|
|
|
1136
|
-
|
|
1136
|
+
it("reserves the pending module id for the singleton", () => {
|
|
1137
1137
|
expect(() =>
|
|
1138
1138
|
validateDriver({
|
|
1139
1139
|
install: {
|
|
@@ -1245,7 +1245,7 @@ const driverWithFields = (fields: BridgeField[]): BridgeDriver => ({
|
|
|
1245
1245
|
});
|
|
1246
1246
|
|
|
1247
1247
|
describe("the setup singleton", () => {
|
|
1248
|
-
|
|
1248
|
+
it("takes a driver step with both locales", () => {
|
|
1249
1249
|
expect(() =>
|
|
1250
1250
|
validateDriver(
|
|
1251
1251
|
driverWithSetup(
|
|
@@ -1257,11 +1257,11 @@ describe("the setup singleton", () => {
|
|
|
1257
1257
|
).not.toThrow();
|
|
1258
1258
|
});
|
|
1259
1259
|
|
|
1260
|
-
|
|
1260
|
+
it("rejects a setup that declares no steps", () => {
|
|
1261
1261
|
expect(() => validateDriver(driverWithSetup(setupWith([])))).toThrow("the setup module declares no steps");
|
|
1262
1262
|
});
|
|
1263
1263
|
|
|
1264
|
-
|
|
1264
|
+
it("rejects more steps than the platform takes", () => {
|
|
1265
1265
|
expect(() =>
|
|
1266
1266
|
validateDriver(
|
|
1267
1267
|
driverWithSetup(
|
|
@@ -1275,7 +1275,7 @@ describe("the setup singleton", () => {
|
|
|
1275
1275
|
).toThrow("the setup module declares 9 steps — the platform takes at most 8");
|
|
1276
1276
|
});
|
|
1277
1277
|
|
|
1278
|
-
|
|
1278
|
+
it("rejects a step id that is not kebab-case", () => {
|
|
1279
1279
|
expect(() =>
|
|
1280
1280
|
validateDriver(
|
|
1281
1281
|
driverWithSetup(
|
|
@@ -1287,7 +1287,7 @@ describe("the setup singleton", () => {
|
|
|
1287
1287
|
).toThrow('the setup module step id "signIn" must be kebab-case');
|
|
1288
1288
|
});
|
|
1289
1289
|
|
|
1290
|
-
|
|
1290
|
+
it("rejects the same step id twice", () => {
|
|
1291
1291
|
expect(() =>
|
|
1292
1292
|
validateDriver(
|
|
1293
1293
|
driverWithSetup(
|
|
@@ -1300,7 +1300,7 @@ describe("the setup singleton", () => {
|
|
|
1300
1300
|
).toThrow('the setup module declares step "sign-in" more than once');
|
|
1301
1301
|
});
|
|
1302
1302
|
|
|
1303
|
-
|
|
1303
|
+
it("rejects a title that is missing a locale", () => {
|
|
1304
1304
|
expect(() =>
|
|
1305
1305
|
validateDriver(
|
|
1306
1306
|
driverWithSetup(
|
|
@@ -1319,7 +1319,7 @@ describe("the setup singleton", () => {
|
|
|
1319
1319
|
).toThrow('the setup module step "sign-in" title needs both arabic and english text');
|
|
1320
1320
|
});
|
|
1321
1321
|
|
|
1322
|
-
|
|
1322
|
+
it("takes a form step that names an existing form section and its own fields", () => {
|
|
1323
1323
|
expect(() =>
|
|
1324
1324
|
validateDriver(
|
|
1325
1325
|
driverWithSetup(
|
|
@@ -1340,7 +1340,7 @@ describe("the setup singleton", () => {
|
|
|
1340
1340
|
).not.toThrow();
|
|
1341
1341
|
});
|
|
1342
1342
|
|
|
1343
|
-
|
|
1343
|
+
it("rejects a form step that names a section the panel does not declare", () => {
|
|
1344
1344
|
expect(() =>
|
|
1345
1345
|
validateDriver(
|
|
1346
1346
|
driverWithSetup(
|
|
@@ -1360,7 +1360,7 @@ describe("the setup singleton", () => {
|
|
|
1360
1360
|
);
|
|
1361
1361
|
});
|
|
1362
1362
|
|
|
1363
|
-
|
|
1363
|
+
it("rejects a form step that names a field the section does not declare", () => {
|
|
1364
1364
|
expect(() =>
|
|
1365
1365
|
validateDriver(
|
|
1366
1366
|
driverWithSetup(
|
|
@@ -1381,7 +1381,7 @@ describe("the setup singleton", () => {
|
|
|
1381
1381
|
).toThrow('the setup module step "name" names field "PASSWORD", which section "server" does not declare');
|
|
1382
1382
|
});
|
|
1383
1383
|
|
|
1384
|
-
|
|
1384
|
+
it("takes an open step that names an existing panel tab", () => {
|
|
1385
1385
|
expect(() =>
|
|
1386
1386
|
validateDriver(
|
|
1387
1387
|
driverWithSetup(
|
|
@@ -1401,7 +1401,7 @@ describe("the setup singleton", () => {
|
|
|
1401
1401
|
).not.toThrow();
|
|
1402
1402
|
});
|
|
1403
1403
|
|
|
1404
|
-
|
|
1404
|
+
it("rejects an open step that names a panel tab the panel does not declare", () => {
|
|
1405
1405
|
expect(() =>
|
|
1406
1406
|
validateDriver(
|
|
1407
1407
|
driverWithSetup(
|
|
@@ -1421,7 +1421,7 @@ describe("the setup singleton", () => {
|
|
|
1421
1421
|
).toThrow('the setup module step "tune" opens panel tab "world", which the panel does not declare');
|
|
1422
1422
|
});
|
|
1423
1423
|
|
|
1424
|
-
|
|
1424
|
+
it("takes an open step that leaves the panel altogether", () => {
|
|
1425
1425
|
expect(() =>
|
|
1426
1426
|
validateDriver(
|
|
1427
1427
|
driverWithSetup(
|
|
@@ -1440,7 +1440,7 @@ describe("the setup singleton", () => {
|
|
|
1440
1440
|
).not.toThrow();
|
|
1441
1441
|
});
|
|
1442
1442
|
|
|
1443
|
-
|
|
1443
|
+
it("takes a form step over a secret field", () => {
|
|
1444
1444
|
expect(() =>
|
|
1445
1445
|
validateDriver(
|
|
1446
1446
|
driverWithSetup(
|
|
@@ -1461,7 +1461,7 @@ describe("the setup singleton", () => {
|
|
|
1461
1461
|
).not.toThrow();
|
|
1462
1462
|
});
|
|
1463
1463
|
|
|
1464
|
-
|
|
1464
|
+
it("rejects a driver step while the setup exports no submit", () => {
|
|
1465
1465
|
expect(() =>
|
|
1466
1466
|
validateDriver(
|
|
1467
1467
|
driverWithSetup(
|
|
@@ -1473,7 +1473,7 @@ describe("the setup singleton", () => {
|
|
|
1473
1473
|
).toThrow("the setup module declares a driver step but exports no submit");
|
|
1474
1474
|
});
|
|
1475
1475
|
|
|
1476
|
-
|
|
1476
|
+
it("takes a setup with no submit while every step is answered elsewhere", () => {
|
|
1477
1477
|
expect(() =>
|
|
1478
1478
|
validateDriver(
|
|
1479
1479
|
driverWithSetup(
|
|
@@ -1492,7 +1492,7 @@ describe("the setup singleton", () => {
|
|
|
1492
1492
|
).not.toThrow();
|
|
1493
1493
|
});
|
|
1494
1494
|
|
|
1495
|
-
|
|
1495
|
+
it("reserves the setup module id for the singleton", () => {
|
|
1496
1496
|
expect(() =>
|
|
1497
1497
|
validateDriver({
|
|
1498
1498
|
install: {
|
|
@@ -1519,7 +1519,7 @@ describe("the setup singleton", () => {
|
|
|
1519
1519
|
});
|
|
1520
1520
|
|
|
1521
1521
|
describe("field patterns", () => {
|
|
1522
|
-
|
|
1522
|
+
it("takes a pattern on a text field and on a secret one", () => {
|
|
1523
1523
|
expect(() =>
|
|
1524
1524
|
validateDriver(
|
|
1525
1525
|
driverWithFields([
|
|
@@ -1527,8 +1527,8 @@ describe("field patterns", () => {
|
|
|
1527
1527
|
key: "LICENSE_KEY",
|
|
1528
1528
|
control: BridgeControl.Secret,
|
|
1529
1529
|
label: text("Licence key"),
|
|
1530
|
-
pattern: "^
|
|
1531
|
-
patternHint: text("A licence key starts with
|
|
1530
|
+
pattern: "^key_\\w{1,60}_\\w{1,20}$",
|
|
1531
|
+
patternHint: text("A licence key starts with key_"),
|
|
1532
1532
|
},
|
|
1533
1533
|
{
|
|
1534
1534
|
key: "SERVER_NAME",
|
|
@@ -1541,7 +1541,7 @@ describe("field patterns", () => {
|
|
|
1541
1541
|
).not.toThrow();
|
|
1542
1542
|
});
|
|
1543
1543
|
|
|
1544
|
-
|
|
1544
|
+
it("rejects a pattern that is not a regular expression", () => {
|
|
1545
1545
|
expect(() =>
|
|
1546
1546
|
validateDriver(
|
|
1547
1547
|
driverWithFields([
|
|
@@ -1549,14 +1549,14 @@ describe("field patterns", () => {
|
|
|
1549
1549
|
key: "LICENSE_KEY",
|
|
1550
1550
|
control: BridgeControl.Text,
|
|
1551
1551
|
label: text("Licence key"),
|
|
1552
|
-
pattern: "^
|
|
1552
|
+
pattern: "^key_(",
|
|
1553
1553
|
},
|
|
1554
1554
|
]),
|
|
1555
1555
|
),
|
|
1556
|
-
).toThrow('declares pattern "^
|
|
1556
|
+
).toThrow('declares pattern "^key_(", which is not a valid regular expression');
|
|
1557
1557
|
});
|
|
1558
1558
|
|
|
1559
|
-
|
|
1559
|
+
it("takes an alternation whose repeats are all bounded", () => {
|
|
1560
1560
|
expect(() =>
|
|
1561
1561
|
validateDriver(
|
|
1562
1562
|
driverWithFields([
|
|
@@ -1564,14 +1564,14 @@ describe("field patterns", () => {
|
|
|
1564
1564
|
key: "LICENSE_KEY",
|
|
1565
1565
|
control: BridgeControl.Secret,
|
|
1566
1566
|
label: text("Licence key"),
|
|
1567
|
-
pattern: "^(?:
|
|
1567
|
+
pattern: "^(?:key_\\w{1,60}_\\w{1,20}|\\w{32})$",
|
|
1568
1568
|
},
|
|
1569
1569
|
]),
|
|
1570
1570
|
),
|
|
1571
1571
|
).not.toThrow();
|
|
1572
1572
|
});
|
|
1573
1573
|
|
|
1574
|
-
|
|
1574
|
+
it("rejects a pattern that repeats a group which already repeats", () => {
|
|
1575
1575
|
expect(() =>
|
|
1576
1576
|
validateDriver(
|
|
1577
1577
|
driverWithFields([
|
|
@@ -1586,7 +1586,7 @@ describe("field patterns", () => {
|
|
|
1586
1586
|
).toThrow('declares pattern "^(a+)+$", which repeats a group that already repeats');
|
|
1587
1587
|
});
|
|
1588
1588
|
|
|
1589
|
-
|
|
1589
|
+
it("rejects a starred group whose body repeats without a bound", () => {
|
|
1590
1590
|
expect(() =>
|
|
1591
1591
|
validateDriver(
|
|
1592
1592
|
driverWithFields([
|
|
@@ -1601,7 +1601,7 @@ describe("field patterns", () => {
|
|
|
1601
1601
|
).toThrow("repeats a group that already repeats");
|
|
1602
1602
|
});
|
|
1603
1603
|
|
|
1604
|
-
|
|
1604
|
+
it("rejects a pattern longer than the platform takes", () => {
|
|
1605
1605
|
expect(() =>
|
|
1606
1606
|
validateDriver(
|
|
1607
1607
|
driverWithFields([
|
|
@@ -1616,7 +1616,7 @@ describe("field patterns", () => {
|
|
|
1616
1616
|
).toThrow("pattern is 258 characters — the platform takes at most 256");
|
|
1617
1617
|
});
|
|
1618
1618
|
|
|
1619
|
-
|
|
1619
|
+
it("rejects a pattern hint with no pattern to explain", () => {
|
|
1620
1620
|
expect(() =>
|
|
1621
1621
|
validateDriver(
|
|
1622
1622
|
driverWithFields([
|
|
@@ -1624,14 +1624,14 @@ describe("field patterns", () => {
|
|
|
1624
1624
|
key: "LICENSE_KEY",
|
|
1625
1625
|
control: BridgeControl.Text,
|
|
1626
1626
|
label: text("Licence key"),
|
|
1627
|
-
patternHint: text("A licence key starts with
|
|
1627
|
+
patternHint: text("A licence key starts with key_"),
|
|
1628
1628
|
},
|
|
1629
1629
|
]),
|
|
1630
1630
|
),
|
|
1631
1631
|
).toThrow("declares a pattern hint with no pattern to explain");
|
|
1632
1632
|
});
|
|
1633
1633
|
|
|
1634
|
-
|
|
1634
|
+
it("rejects a pattern on a control that never matches one", () => {
|
|
1635
1635
|
expect(() =>
|
|
1636
1636
|
validateDriver(
|
|
1637
1637
|
driverWithFields([
|
|
@@ -1646,7 +1646,7 @@ describe("field patterns", () => {
|
|
|
1646
1646
|
).toThrow('declares a pattern on a "boolean" control — only text and secret controls match one');
|
|
1647
1647
|
});
|
|
1648
1648
|
|
|
1649
|
-
|
|
1649
|
+
it("rejects a secret control that offers options", () => {
|
|
1650
1650
|
expect(() =>
|
|
1651
1651
|
validateDriver(
|
|
1652
1652
|
driverWithFields([
|
|
@@ -1731,7 +1731,7 @@ describe("section placement", () => {
|
|
|
1731
1731
|
return driver;
|
|
1732
1732
|
};
|
|
1733
1733
|
|
|
1734
|
-
|
|
1734
|
+
it("accepts a table placed on the players page", () => {
|
|
1735
1735
|
expect(() =>
|
|
1736
1736
|
validateDriver(
|
|
1737
1737
|
driverWithRoster({
|
|
@@ -1741,19 +1741,19 @@ describe("section placement", () => {
|
|
|
1741
1741
|
).not.toThrow();
|
|
1742
1742
|
});
|
|
1743
1743
|
|
|
1744
|
-
|
|
1744
|
+
it("rejects a form placed on the players page", () => {
|
|
1745
1745
|
expect(() => validateDriver(placedForm(BridgePlace.Players))).toThrow(
|
|
1746
1746
|
'tab "version" section "version" places a form section on players, which that page cannot render',
|
|
1747
1747
|
);
|
|
1748
1748
|
});
|
|
1749
1749
|
|
|
1750
|
-
|
|
1750
|
+
it("rejects a form placed on the overview page", () => {
|
|
1751
1751
|
expect(() => validateDriver(placedForm(BridgePlace.Overview))).toThrow(
|
|
1752
1752
|
"places a form section on overview, which that page cannot render",
|
|
1753
1753
|
);
|
|
1754
1754
|
});
|
|
1755
1755
|
|
|
1756
|
-
|
|
1756
|
+
it("rejects a table placed on the overview page", () => {
|
|
1757
1757
|
expect(() =>
|
|
1758
1758
|
validateDriver(
|
|
1759
1759
|
driverWithRoster({
|
|
@@ -1763,7 +1763,7 @@ describe("section placement", () => {
|
|
|
1763
1763
|
).toThrow('tab "roster" section "online" places a table section on overview, which that page cannot render');
|
|
1764
1764
|
});
|
|
1765
1765
|
|
|
1766
|
-
|
|
1766
|
+
it("accepts an offline row action on a table", () => {
|
|
1767
1767
|
expect(() =>
|
|
1768
1768
|
validateDriver(
|
|
1769
1769
|
driverWithRoster({
|
|
@@ -1780,7 +1780,7 @@ describe("section placement", () => {
|
|
|
1780
1780
|
).not.toThrow();
|
|
1781
1781
|
});
|
|
1782
1782
|
|
|
1783
|
-
|
|
1783
|
+
it("rejects an offline action on an actions section", () => {
|
|
1784
1784
|
expect(() =>
|
|
1785
1785
|
validateDriver(
|
|
1786
1786
|
driverWithActions([
|
|
@@ -1796,7 +1796,7 @@ describe("section placement", () => {
|
|
|
1796
1796
|
);
|
|
1797
1797
|
});
|
|
1798
1798
|
|
|
1799
|
-
|
|
1799
|
+
it("rejects a form help that is missing a locale", () => {
|
|
1800
1800
|
const driver = driverWith(anyVisibleWhen);
|
|
1801
1801
|
|
|
1802
1802
|
formSectionOf(driver).help = {
|
|
@@ -1827,7 +1827,7 @@ describe("the lifecycle module", () => {
|
|
|
1827
1827
|
},
|
|
1828
1828
|
});
|
|
1829
1829
|
|
|
1830
|
-
|
|
1830
|
+
it("accepts an environment resolver", () => {
|
|
1831
1831
|
expect(() =>
|
|
1832
1832
|
validateDriver(
|
|
1833
1833
|
lifecycleDriver({
|
|
@@ -1839,11 +1839,11 @@ describe("the lifecycle module", () => {
|
|
|
1839
1839
|
).not.toThrow();
|
|
1840
1840
|
});
|
|
1841
1841
|
|
|
1842
|
-
|
|
1842
|
+
it("accepts a lifecycle that declares no environment", () => {
|
|
1843
1843
|
expect(() => validateDriver(lifecycleDriver({}))).not.toThrow();
|
|
1844
1844
|
});
|
|
1845
1845
|
|
|
1846
|
-
|
|
1846
|
+
it("accepts each stop signal the bridge sends", () => {
|
|
1847
1847
|
for (const stopSignal of Object.values(BridgeStopSignal)) {
|
|
1848
1848
|
expect(() =>
|
|
1849
1849
|
validateDriver(
|
|
@@ -1855,7 +1855,7 @@ describe("the lifecycle module", () => {
|
|
|
1855
1855
|
}
|
|
1856
1856
|
});
|
|
1857
1857
|
|
|
1858
|
-
|
|
1858
|
+
it("refuses a stop signal the bridge does not send", () => {
|
|
1859
1859
|
expect(() =>
|
|
1860
1860
|
validateDriver(
|
|
1861
1861
|
lifecycleDriver({
|
|
@@ -1865,7 +1865,7 @@ describe("the lifecycle module", () => {
|
|
|
1865
1865
|
).toThrow('the lifecycle module declares stop signal "SIGHUP" — the bridge sends only SIGTERM or SIGINT');
|
|
1866
1866
|
});
|
|
1867
1867
|
|
|
1868
|
-
|
|
1868
|
+
it("accepts a ready timeout from one second to an hour", () => {
|
|
1869
1869
|
for (const readyTimeoutSeconds of [
|
|
1870
1870
|
1,
|
|
1871
1871
|
900,
|
|
@@ -1881,7 +1881,7 @@ describe("the lifecycle module", () => {
|
|
|
1881
1881
|
}
|
|
1882
1882
|
});
|
|
1883
1883
|
|
|
1884
|
-
|
|
1884
|
+
it("refuses a ready timeout outside one second to an hour", () => {
|
|
1885
1885
|
for (const readyTimeoutSeconds of [
|
|
1886
1886
|
0,
|
|
1887
1887
|
3601,
|
|
@@ -1899,7 +1899,7 @@ describe("the lifecycle module", () => {
|
|
|
1899
1899
|
}
|
|
1900
1900
|
});
|
|
1901
1901
|
|
|
1902
|
-
|
|
1902
|
+
it("accepts each lifecycle subject the bridge names", () => {
|
|
1903
1903
|
for (const subject of Object.values(BridgeLifecycleSubject)) {
|
|
1904
1904
|
expect(() =>
|
|
1905
1905
|
validateDriver(
|
|
@@ -1911,7 +1911,7 @@ describe("the lifecycle module", () => {
|
|
|
1911
1911
|
}
|
|
1912
1912
|
});
|
|
1913
1913
|
|
|
1914
|
-
|
|
1914
|
+
it("refuses a lifecycle subject the bridge does not name", () => {
|
|
1915
1915
|
expect(() =>
|
|
1916
1916
|
validateDriver(
|
|
1917
1917
|
lifecycleDriver({
|
|
@@ -1921,7 +1921,7 @@ describe("the lifecycle module", () => {
|
|
|
1921
1921
|
).toThrow('the lifecycle module declares subject "server" — the bridge names only game or bot');
|
|
1922
1922
|
});
|
|
1923
1923
|
|
|
1924
|
-
|
|
1924
|
+
it("refuses an environment that is not a function", () => {
|
|
1925
1925
|
expect(() =>
|
|
1926
1926
|
validateDriver(
|
|
1927
1927
|
lifecycleDriver({
|