@marimo-team/frontend 0.24.2-dev129 → 0.24.2-dev2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/frontend",
3
- "version": "0.24.2-dev129",
3
+ "version": "0.24.2-dev2",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -757,19 +757,23 @@ describe("generateDatabaseCode", () => {
757
757
  () =>
758
758
  // @ts-expect-error - Testing invalid input
759
759
  generateDatabaseCode(basePostgres, "polars"),
760
+ "Unsupported library: polars",
760
761
  ],
761
762
  [
762
763
  "throws for invalid port",
763
764
  () => generateDatabaseCode({ ...basePostgres, port: -1 }, "sqlmodel"),
765
+ /port/i,
764
766
  ],
765
767
  [
766
768
  "throws for invalid host",
767
769
  () => generateDatabaseCode({ ...basePostgres, host: "" }, "sqlmodel"),
770
+ /host/i,
768
771
  ],
769
772
  [
770
773
  "throws for port out of range",
771
774
  () =>
772
775
  generateDatabaseCode({ ...basePostgres, port: 65_536 }, "sqlmodel"),
776
+ /port/i,
773
777
  ],
774
778
  [
775
779
  "throws for invalid snowflake account",
@@ -778,6 +782,7 @@ describe("generateDatabaseCode", () => {
778
782
  { ...snowflakeConnection, account: "" },
779
783
  "sqlmodel",
780
784
  ),
785
+ /account/i,
781
786
  ],
782
787
  [
783
788
  "throws for invalid bigquery project",
@@ -786,9 +791,10 @@ describe("generateDatabaseCode", () => {
786
791
  { ...bigqueryConnection, project: "" },
787
792
  "sqlmodel",
788
793
  ),
794
+ /project/i,
789
795
  ],
790
- ])("%s", (_name, fn) => {
791
- expect(fn).toThrow();
796
+ ])("%s", (_name, fn, error) => {
797
+ expect(fn).toThrow(error);
792
798
  });
793
799
  });
794
800
  });
@@ -412,7 +412,7 @@ describe("generateStorageCode", () => {
412
412
  generateStorageCode({ type: "s3", bucket: "" } as StorageConnection, {
413
413
  library: "obstore",
414
414
  }),
415
- ).toThrow();
415
+ ).toThrow(/bucket/);
416
416
  });
417
417
 
418
418
  it("throws for empty GCS bucket", () => {
@@ -420,7 +420,7 @@ describe("generateStorageCode", () => {
420
420
  generateStorageCode({ type: "gcs", bucket: "" } as StorageConnection, {
421
421
  library: "obstore",
422
422
  }),
423
- ).toThrow();
423
+ ).toThrow(/bucket/);
424
424
  });
425
425
 
426
426
  it("throws for empty Azure container", () => {
@@ -433,7 +433,7 @@ describe("generateStorageCode", () => {
433
433
  } as StorageConnection,
434
434
  { library: "obstore" },
435
435
  ),
436
- ).toThrow();
436
+ ).toThrow(/container/);
437
437
  });
438
438
 
439
439
  it("throws for empty Azure account name", () => {
@@ -446,7 +446,7 @@ describe("generateStorageCode", () => {
446
446
  } as StorageConnection,
447
447
  { library: "obstore" },
448
448
  ),
449
- ).toThrow();
449
+ ).toThrow(/account_name/);
450
450
  });
451
451
 
452
452
  it("throws for empty CoreWeave bucket", () => {
@@ -459,7 +459,7 @@ describe("generateStorageCode", () => {
459
459
  } as StorageConnection,
460
460
  { library: "obstore" },
461
461
  ),
462
- ).toThrow();
462
+ ).toThrow(/bucket/);
463
463
  });
464
464
 
465
465
  it("throws for empty CoreWeave region", () => {
@@ -472,7 +472,7 @@ describe("generateStorageCode", () => {
472
472
  } as StorageConnection,
473
473
  { library: "obstore" },
474
474
  ),
475
- ).toThrow();
475
+ ).toThrow(/region/);
476
476
  });
477
477
 
478
478
  it("throws for empty GitHub org", () => {
@@ -481,7 +481,7 @@ describe("generateStorageCode", () => {
481
481
  { type: "github", org: "", repo: "marimo" } as StorageConnection,
482
482
  { library: "fsspec" },
483
483
  ),
484
- ).toThrow();
484
+ ).toThrow(/org/);
485
485
  });
486
486
 
487
487
  it("throws for empty GitHub repo", () => {
@@ -494,7 +494,7 @@ describe("generateStorageCode", () => {
494
494
  } as StorageConnection,
495
495
  { library: "fsspec" },
496
496
  ),
497
- ).toThrow();
497
+ ).toThrow(/repo/);
498
498
  });
499
499
 
500
500
  it("throws when GitHub username is set without token", () => {
@@ -508,7 +508,7 @@ describe("generateStorageCode", () => {
508
508
  },
509
509
  { library: "fsspec" },
510
510
  ),
511
- ).toThrow();
511
+ ).toThrow(/token/);
512
512
  });
513
513
 
514
514
  it("throws when GitHub token is set without username", () => {
@@ -522,7 +522,7 @@ describe("generateStorageCode", () => {
522
522
  },
523
523
  { library: "fsspec" },
524
524
  ),
525
- ).toThrow();
525
+ ).toThrow("Username and access token are required together");
526
526
  });
527
527
  });
528
528
  });
@@ -592,7 +592,7 @@ describe("staged cell generation", () => {
592
592
  type: "data-notebook-cells-completion",
593
593
  data: { cells },
594
594
  }),
595
- ).toThrow();
595
+ ).toThrow(/cells/i);
596
596
  });
597
597
 
598
598
  it("should create cells from a validated completion", () => {
@@ -44,7 +44,7 @@ describe("streamCompletionText", () => {
44
44
  data: { code: 42 },
45
45
  });
46
46
 
47
- await expect(streamCompletionText(response)).rejects.toThrow();
47
+ await expect(streamCompletionText(response)).rejects.toThrow(/code/);
48
48
  });
49
49
 
50
50
  it("rejects a partial completion without successful final validation", async () => {
@@ -698,7 +698,7 @@ describe("RuntimeManager", () => {
698
698
  it("should throw for invalid URLs", () => {
699
699
  expect(() => {
700
700
  new RuntimeManager({ url: "not-a-url", lazy: true });
701
- }).toThrow();
701
+ }).toThrow("Invalid runtime URL");
702
702
  });
703
703
 
704
704
  it("should handle http to ws conversion correctly", () => {
@@ -177,7 +177,7 @@ describe("patchFetch", () => {
177
177
  .mockImplementation(Functions.NOOP);
178
178
 
179
179
  // This should fallback to original fetch and potentially fail
180
- await expect(window.fetch("invalid://url")).rejects.toThrow();
180
+ await expect(window.fetch("invalid://url")).rejects.toThrow(/fetch|url/i);
181
181
 
182
182
  unpatch();
183
183
  loggerSpy.mockRestore();
@@ -276,7 +276,9 @@ describe("patchVegaLoader - loader.load", () => {
276
276
  it("should handle missing virtual files gracefully in loader.load", async () => {
277
277
  const loader = createLoader();
278
278
  const unpatch = patchVegaLoader(loader, {});
279
- await expect(loader.load("/non-existent-file.json")).rejects.toThrow();
279
+ await expect(loader.load("/non-existent-file.json")).rejects.toThrow(
280
+ /fetch|file|load/i,
281
+ );
280
282
  unpatch();
281
283
  });
282
284
 
@@ -592,9 +594,9 @@ describe("maybeGetVirtualFile utility function", () => {
592
594
  const unpatch = patchFetch(virtualFiles);
593
595
 
594
596
  // This file:// URL doesn't contain @file/, so it should fallback to original fetch
595
- await expect(
596
- window.fetch("file:///simple/path/test.txt"),
597
- ).rejects.toThrow();
597
+ await expect(window.fetch("file:///simple/path/test.txt")).rejects.toThrow(
598
+ /fetch|file/i,
599
+ );
598
600
 
599
601
  unpatch();
600
602
  });
@@ -99,7 +99,9 @@ describe("WidgetRegistry models", () => {
99
99
  const model = new Model<ModelState>({ count: 0 }, createMockComm());
100
100
  registry.setModel(testId, model);
101
101
  registry.delete(testId);
102
- await expect(registry.getModel(testId)).rejects.toThrow();
102
+ await expect(registry.getModel(testId)).rejects.toThrow(
103
+ `Model not found for key: ${testId}`,
104
+ );
103
105
  });
104
106
 
105
107
  it("should handle widget messages", async () => {
@@ -148,7 +150,9 @@ describe("WidgetRegistry models", () => {
148
150
  model_id: testId,
149
151
  message: { method: "close" },
150
152
  });
151
- await expect(registry.getModel(testId)).rejects.toThrow();
153
+ await expect(registry.getModel(testId)).rejects.toThrow(
154
+ `Model not found for key: ${testId}`,
155
+ );
152
156
  });
153
157
 
154
158
  describe("static mode", () => {
@@ -116,7 +116,7 @@ describe("WidgetDefRegistry", () => {
116
116
  it("should remove from cache on import failure so retry creates new promise", async () => {
117
117
  const promise1 = getModule(registry, "http://localhost/a.js", "fail-hash");
118
118
  // The URL is rejected by the trusted-URL validator.
119
- await expect(promise1).rejects.toThrow();
119
+ await expect(promise1).rejects.toThrow(/untrusted/i);
120
120
  // After failure, cache should be cleared, so next call creates a new promise
121
121
  const promise2 = getModule(registry, "http://localhost/a.js", "fail-hash");
122
122
  expect(promise1).not.toBe(promise2);
@@ -106,7 +106,7 @@ describe("arrays", () => {
106
106
  });
107
107
 
108
108
  it("should throw for arrays of different lengths", () => {
109
- expect(() => Arrays.zip([1, 2], ["a"])).toThrow();
109
+ expect(() => Arrays.zip([1, 2], ["a"])).toThrow(/same length/i);
110
110
  });
111
111
 
112
112
  it("should handle empty arrays", () => {
@@ -558,7 +558,9 @@ describe("CollapsibleTree", () => {
558
558
  expect(collapsed.after("four")).toBeUndefined();
559
559
 
560
560
  // Should throw for collapsed children that aren't top-level
561
- expect(() => collapsed.after("three")).toThrow();
561
+ expect(() => collapsed.after("three")).toThrow(
562
+ "Node three not found in tree. Valid ids: one,two,four",
563
+ );
562
564
  });
563
565
 
564
566
  it("handles before correctly", () => {
@@ -585,7 +587,9 @@ describe("CollapsibleTree", () => {
585
587
  expect(collapsed.before("one")).toBeUndefined();
586
588
 
587
589
  // Should throw for collapsed children that aren't top-level
588
- expect(() => collapsed.before("three")).toThrow();
590
+ expect(() => collapsed.before("three")).toThrow(
591
+ "Node three not found in tree. Valid ids: one,two,four",
592
+ );
589
593
  });
590
594
 
591
595
  it("handles slice on empty tree", () => {
@@ -704,8 +708,8 @@ describe("CollapsibleTree edge cases", () => {
704
708
  expect(tree.first()).toBe("A");
705
709
  expect(tree.last()).toBe("D");
706
710
  tree = CollapsibleTree.from([]);
707
- expect(() => tree.first()).toThrow();
708
- expect(() => tree.last()).toThrow();
711
+ expect(() => tree.first()).toThrow("Node at index 0 not found in tree");
712
+ expect(() => tree.last()).toThrow("Node at index -1 not found in tree");
709
713
  });
710
714
 
711
715
  it("handles inOrderIds with nested structure", () => {
@@ -1045,7 +1049,9 @@ describe("MultiColumn", () => {
1045
1049
  "Cell Z1 not found in any column",
1046
1050
  );
1047
1051
  expect(multiColumn.colLength).toBeGreaterThan(2);
1048
- expect(() => multiColumn.delete("123" as CellColumnId)).toThrow();
1052
+ expect(() => multiColumn.delete("123" as CellColumnId)).toThrow(
1053
+ /Column 123 not found/,
1054
+ );
1049
1055
  });
1050
1056
 
1051
1057
  it("checks if it's empty", () => {
@@ -1070,7 +1076,7 @@ describe("MultiColumn", () => {
1070
1076
  expect(multiColumn.at(1)?.topLevelIds).toEqual(["B1", "B2"]);
1071
1077
  expect(multiColumn.atOrThrow(1).topLevelIds).toEqual(["B1", "B2"]);
1072
1078
  expect(multiColumn.at(5)).toBeUndefined();
1073
- expect(() => multiColumn.atOrThrow(5)).toThrow();
1079
+ expect(() => multiColumn.atOrThrow(5)).toThrow("Column 5 not found");
1074
1080
  });
1075
1081
 
1076
1082
  it("handles moving the last item in a column", () => {
@@ -5,9 +5,15 @@ import { mapWithConcurrency, Semaphore } from "../semaphore";
5
5
 
6
6
  describe("Semaphore", () => {
7
7
  it("rejects invalid permit counts", () => {
8
- expect(() => new Semaphore(0)).toThrow();
9
- expect(() => new Semaphore(-1)).toThrow();
10
- expect(() => new Semaphore(1.5)).toThrow();
8
+ expect(() => new Semaphore(0)).toThrow(
9
+ "Semaphore permits must be a positive integer, got 0",
10
+ );
11
+ expect(() => new Semaphore(-1)).toThrow(
12
+ "Semaphore permits must be a positive integer, got -1",
13
+ );
14
+ expect(() => new Semaphore(1.5)).toThrow(
15
+ "Semaphore permits must be a positive integer, got 1.5",
16
+ );
11
17
  });
12
18
 
13
19
  it("resolves run() with the function's value", async () => {
@@ -203,8 +209,12 @@ describe("mapWithConcurrency", () => {
203
209
  });
204
210
 
205
211
  it("throws on invalid concurrency, even for empty input", () => {
206
- expect(() => mapWithConcurrency([1, 2, 3], 0, async (n) => n)).toThrow();
207
- expect(() => mapWithConcurrency([], 0, async (n: number) => n)).toThrow();
212
+ expect(() => mapWithConcurrency([1, 2, 3], 0, async (n) => n)).toThrow(
213
+ "Semaphore permits must be a positive integer, got 0",
214
+ );
215
+ expect(() => mapWithConcurrency([], 0, async (n: number) => n)).toThrow(
216
+ "Semaphore permits must be a positive integer, got 0",
217
+ );
208
218
  });
209
219
 
210
220
  it("passes the index to fn", async () => {
@@ -20,7 +20,9 @@ describe("Strings", () => {
20
20
  });
21
21
 
22
22
  it("throws for non-string input", () => {
23
- expect(() => Strings.startCase(123 as unknown as string)).toThrow();
23
+ expect(() => Strings.startCase(123 as unknown as string)).toThrow(
24
+ /string/i,
25
+ );
24
26
  });
25
27
  });
26
28