@assistant-ui/react-generative-ui 0.0.13 → 0.0.14
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/dist/JSONGenerativeUI.client.d.ts +5 -0
- package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.client.js +12 -3
- package/dist/JSONGenerativeUI.client.js.map +1 -1
- package/dist/slack/constants.d.ts +11 -4
- package/dist/slack/constants.d.ts.map +1 -1
- package/dist/slack/constants.js +11 -4
- package/dist/slack/constants.js.map +1 -1
- package/dist/slack/fromSlackBlocks.js +2 -2
- package/dist/slack/toSlackBlocks.d.ts.map +1 -1
- package/dist/slack/toSlackBlocks.js +111 -17
- package/dist/slack/toSlackBlocks.js.map +1 -1
- package/dist/slack/types.d.ts +7 -1
- package/dist/slack/types.d.ts.map +1 -1
- package/dist/teams/constants.d.ts +9 -2
- package/dist/teams/constants.d.ts.map +1 -1
- package/dist/teams/constants.js +10 -3
- package/dist/teams/constants.js.map +1 -1
- package/dist/teams/toAdaptiveCard.d.ts +10 -2
- package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
- package/dist/teams/toAdaptiveCard.js +50 -13
- package/dist/teams/toAdaptiveCard.js.map +1 -1
- package/dist/teams/toTeamsAttachments.d.ts.map +1 -1
- package/dist/teams/toTeamsAttachments.js +18 -11
- package/dist/teams/toTeamsAttachments.js.map +1 -1
- package/dist/teams/types.d.ts +11 -2
- package/dist/teams/types.d.ts.map +1 -1
- package/dist/vocabulary/layout.js +2 -1
- package/dist/vocabulary/layout.js.map +1 -1
- package/package.json +3 -3
- package/src/JSONGenerativeUI.client.tsx +13 -5
- package/src/JSONGenerativeUI.test.tsx +21 -2
- package/src/slack/constants.ts +11 -3
- package/src/slack/toSlackBlocks.test.ts +374 -8
- package/src/slack/toSlackBlocks.ts +181 -24
- package/src/slack/types.ts +7 -1
- package/src/teams/constants.ts +10 -2
- package/src/teams/toAdaptiveCard.test.ts +204 -10
- package/src/teams/toAdaptiveCard.ts +79 -15
- package/src/teams/toTeamsAttachments.test.ts +47 -2
- package/src/teams/toTeamsAttachments.ts +17 -11
- package/src/teams/types.ts +11 -2
- package/src/vocabulary/layout.test.tsx +16 -1
- package/src/vocabulary/layout.tsx +4 -1
|
@@ -328,6 +328,21 @@ describe("toSlackBlocks", () => {
|
|
|
328
328
|
});
|
|
329
329
|
|
|
330
330
|
describe("Select", () => {
|
|
331
|
+
it("reports options dropped for want of a string label and value", () => {
|
|
332
|
+
const { blocks, warnings } = toSlackBlocks({
|
|
333
|
+
$type: "Select",
|
|
334
|
+
options: [{ label: "ok", value: "a" }, { label: "bad" }, "nope"],
|
|
335
|
+
});
|
|
336
|
+
const select = (blocks[0] as SlackActionsBlock)
|
|
337
|
+
.elements[0] as SlackStaticSelectElement;
|
|
338
|
+
expect(select.options).toHaveLength(1);
|
|
339
|
+
expect(warnings).toContainEqual({
|
|
340
|
+
code: "dropped",
|
|
341
|
+
component: "Select",
|
|
342
|
+
detail: "2 options were dropped for want of a string label and value.",
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
331
346
|
it("converts options and placeholder", () => {
|
|
332
347
|
const { blocks } = toSlackBlocks({
|
|
333
348
|
$type: "Select",
|
|
@@ -579,6 +594,18 @@ describe("toSlackBlocks", () => {
|
|
|
579
594
|
});
|
|
580
595
|
|
|
581
596
|
describe("RadioGroup", () => {
|
|
597
|
+
it("names RadioGroup when the same option loss happens there", () => {
|
|
598
|
+
const { warnings } = toSlackBlocks({
|
|
599
|
+
$type: "RadioGroup",
|
|
600
|
+
options: [{ label: "ok", value: "a" }, { label: "bad" }],
|
|
601
|
+
});
|
|
602
|
+
expect(warnings).toContainEqual({
|
|
603
|
+
code: "dropped",
|
|
604
|
+
component: "RadioGroup",
|
|
605
|
+
detail: "1 option was dropped for want of a string label and value.",
|
|
606
|
+
});
|
|
607
|
+
});
|
|
608
|
+
|
|
582
609
|
const options = [
|
|
583
610
|
{ label: "Small", value: "s" },
|
|
584
611
|
{ label: "Large", value: "l" },
|
|
@@ -1118,7 +1145,7 @@ describe("toSlackBlocks", () => {
|
|
|
1118
1145
|
expect(warnings).toContainEqual({
|
|
1119
1146
|
code: "dropped",
|
|
1120
1147
|
component: "Carousel",
|
|
1121
|
-
detail: "
|
|
1148
|
+
detail: "1 non-card child was dropped.",
|
|
1122
1149
|
});
|
|
1123
1150
|
});
|
|
1124
1151
|
|
|
@@ -1148,10 +1175,215 @@ describe("toSlackBlocks", () => {
|
|
|
1148
1175
|
],
|
|
1149
1176
|
},
|
|
1150
1177
|
]);
|
|
1178
|
+
expect(warnings).toContainEqual({
|
|
1179
|
+
code: "fallback",
|
|
1180
|
+
component: "Card",
|
|
1181
|
+
detail: "A card inside a carousel was reshaped to title and body.",
|
|
1182
|
+
});
|
|
1183
|
+
expect(warnings.some((warning) => warning.code === "dropped")).toBe(
|
|
1184
|
+
false,
|
|
1185
|
+
);
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
it("does not report a Caption as lost, since its text reaches the body", () => {
|
|
1189
|
+
const { blocks, warnings } = toSlackBlocks({
|
|
1190
|
+
$type: "Carousel",
|
|
1191
|
+
children: [
|
|
1192
|
+
{
|
|
1193
|
+
$type: "Card",
|
|
1194
|
+
title: "Plan",
|
|
1195
|
+
children: [
|
|
1196
|
+
{ $type: "Text", value: "body" },
|
|
1197
|
+
{ $type: "Caption", value: "fine print" },
|
|
1198
|
+
{ $type: "Divider" },
|
|
1199
|
+
],
|
|
1200
|
+
},
|
|
1201
|
+
],
|
|
1202
|
+
});
|
|
1203
|
+
const card = (blocks[0] as SlackCarouselBlock).elements[0];
|
|
1204
|
+
expect(card?.body).toEqual({ type: "mrkdwn", text: "body\nfine print" });
|
|
1205
|
+
expect(warnings.some((warning) => warning.code === "dropped")).toBe(
|
|
1206
|
+
false,
|
|
1207
|
+
);
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
it("reports the images and controls a reshaped card really loses", () => {
|
|
1211
|
+
const { blocks, warnings } = toSlackBlocks({
|
|
1212
|
+
$type: "Carousel",
|
|
1213
|
+
children: [
|
|
1214
|
+
{
|
|
1215
|
+
$type: "Card",
|
|
1216
|
+
title: "Plan",
|
|
1217
|
+
confirm: { label: "Buy", $action: { type: "buy" } },
|
|
1218
|
+
children: [
|
|
1219
|
+
{ $type: "Image", src: "hero.png", alt: "hero" },
|
|
1220
|
+
{ $type: "Text", value: "body" },
|
|
1221
|
+
{ $type: "Caption", value: "fine print" },
|
|
1222
|
+
{ $type: "Divider" },
|
|
1223
|
+
],
|
|
1224
|
+
},
|
|
1225
|
+
],
|
|
1226
|
+
});
|
|
1227
|
+
const card = (blocks[0] as SlackCarouselBlock).elements[0];
|
|
1228
|
+
expect(card?.hero_image).toBeUndefined();
|
|
1229
|
+
expect(card?.actions).toBeUndefined();
|
|
1230
|
+
expect(card?.body).toEqual({ type: "mrkdwn", text: "body\nfine print" });
|
|
1231
|
+
expect(warnings).toContainEqual({
|
|
1232
|
+
code: "fallback",
|
|
1233
|
+
component: "Card",
|
|
1234
|
+
detail: "A card inside a carousel was reshaped to title and body.",
|
|
1235
|
+
});
|
|
1236
|
+
expect(warnings).toContainEqual({
|
|
1237
|
+
code: "dropped",
|
|
1238
|
+
component: "Card",
|
|
1239
|
+
detail: "A reshaped carousel card's images and controls were dropped.",
|
|
1240
|
+
});
|
|
1241
|
+
});
|
|
1242
|
+
|
|
1243
|
+
it.each([
|
|
1244
|
+
["tables", { $type: "Table", columns: [{ label: "A" }], rows: [["1"]] }],
|
|
1245
|
+
["charts", { $type: "Chart", series: [] }],
|
|
1246
|
+
[
|
|
1247
|
+
"images",
|
|
1248
|
+
{ $type: "ListViewItem", children: [{ $type: "Image", src: "x.png" }] },
|
|
1249
|
+
],
|
|
1250
|
+
[
|
|
1251
|
+
"controls",
|
|
1252
|
+
{
|
|
1253
|
+
$type: "ListViewItem",
|
|
1254
|
+
children: [{ $type: "Button", label: "Go", $action: { type: "go" } }],
|
|
1255
|
+
},
|
|
1256
|
+
],
|
|
1257
|
+
["controls", { $type: "Select", options: [{ label: "A", value: "a" }] }],
|
|
1258
|
+
["controls", { $type: "Input", name: "email", label: "Email" }],
|
|
1259
|
+
[
|
|
1260
|
+
"controls",
|
|
1261
|
+
{ $type: "Form", children: [{ $type: "Text", value: "inner" }] },
|
|
1262
|
+
],
|
|
1263
|
+
[
|
|
1264
|
+
"controls",
|
|
1265
|
+
{
|
|
1266
|
+
$type: "Card",
|
|
1267
|
+
title: "nested",
|
|
1268
|
+
confirm: { label: "Buy", $action: { type: "buy" } },
|
|
1269
|
+
},
|
|
1270
|
+
],
|
|
1271
|
+
])(
|
|
1272
|
+
"reports %s that a reshape cannot carry, however deep",
|
|
1273
|
+
(kind, child) => {
|
|
1274
|
+
const { warnings } = toSlackBlocks({
|
|
1275
|
+
$type: "Carousel",
|
|
1276
|
+
children: [
|
|
1277
|
+
{
|
|
1278
|
+
$type: "Card",
|
|
1279
|
+
title: "Plan",
|
|
1280
|
+
children: [
|
|
1281
|
+
{ $type: "Text", value: "b" },
|
|
1282
|
+
child,
|
|
1283
|
+
{ $type: "Divider" },
|
|
1284
|
+
],
|
|
1285
|
+
},
|
|
1286
|
+
],
|
|
1287
|
+
});
|
|
1288
|
+
expect(warnings).toContainEqual({
|
|
1289
|
+
code: "dropped",
|
|
1290
|
+
component: "Card",
|
|
1291
|
+
detail: `A reshaped carousel card's ${kind} were dropped.`,
|
|
1292
|
+
});
|
|
1293
|
+
},
|
|
1294
|
+
);
|
|
1295
|
+
|
|
1296
|
+
it("scans below a child whose text the reshape consumes", () => {
|
|
1297
|
+
const { warnings } = toSlackBlocks({
|
|
1298
|
+
$type: "Carousel",
|
|
1299
|
+
children: [
|
|
1300
|
+
{
|
|
1301
|
+
$type: "Card",
|
|
1302
|
+
title: "Plan",
|
|
1303
|
+
children: [
|
|
1304
|
+
{
|
|
1305
|
+
$type: "Text",
|
|
1306
|
+
value: "body",
|
|
1307
|
+
children: [{ $type: "Image", src: "x.png" }],
|
|
1308
|
+
},
|
|
1309
|
+
{ $type: "Divider" },
|
|
1310
|
+
],
|
|
1311
|
+
},
|
|
1312
|
+
],
|
|
1313
|
+
});
|
|
1314
|
+
expect(warnings).toContainEqual({
|
|
1315
|
+
code: "dropped",
|
|
1316
|
+
component: "Card",
|
|
1317
|
+
detail: "A reshaped carousel card's images were dropped.",
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1320
|
+
|
|
1321
|
+
it("does not report a ListViewItem whose action renders no accessory", () => {
|
|
1322
|
+
const { warnings } = toSlackBlocks({
|
|
1323
|
+
$type: "Carousel",
|
|
1324
|
+
children: [
|
|
1325
|
+
{
|
|
1326
|
+
$type: "Card",
|
|
1327
|
+
title: "Plan",
|
|
1328
|
+
children: [
|
|
1329
|
+
{ $type: "Text", value: "body" },
|
|
1330
|
+
{ $type: "ListViewItem", title: "row", $action: "open" },
|
|
1331
|
+
{ $type: "Divider" },
|
|
1332
|
+
],
|
|
1333
|
+
},
|
|
1334
|
+
],
|
|
1335
|
+
});
|
|
1336
|
+
expect(warnings.some((warning) => warning.code === "dropped")).toBe(
|
|
1337
|
+
false,
|
|
1338
|
+
);
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
it("does not report an action on a node that renders no control", () => {
|
|
1342
|
+
const { warnings } = toSlackBlocks({
|
|
1343
|
+
$type: "Carousel",
|
|
1344
|
+
children: [
|
|
1345
|
+
{
|
|
1346
|
+
$type: "Card",
|
|
1347
|
+
title: "Plan",
|
|
1348
|
+
children: [
|
|
1349
|
+
{
|
|
1350
|
+
$type: "Box",
|
|
1351
|
+
$action: { type: "open" },
|
|
1352
|
+
children: [{ $type: "Text", value: "body" }],
|
|
1353
|
+
},
|
|
1354
|
+
{ $type: "Divider" },
|
|
1355
|
+
],
|
|
1356
|
+
},
|
|
1357
|
+
],
|
|
1358
|
+
});
|
|
1359
|
+
expect(warnings.some((warning) => warning.code === "dropped")).toBe(
|
|
1360
|
+
false,
|
|
1361
|
+
);
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1364
|
+
it("clamps a reshaped card's title and body instead of slicing them silently", () => {
|
|
1365
|
+
const { warnings } = toSlackBlocks({
|
|
1366
|
+
$type: "Carousel",
|
|
1367
|
+
children: [
|
|
1368
|
+
{
|
|
1369
|
+
$type: "Card",
|
|
1370
|
+
title: "t".repeat(CARD_TITLE_CAP + 10),
|
|
1371
|
+
children: [
|
|
1372
|
+
{ $type: "Text", value: "b".repeat(CARD_BODY_CAP + 10) },
|
|
1373
|
+
{ $type: "Fact", label: "L", value: "V" },
|
|
1374
|
+
],
|
|
1375
|
+
},
|
|
1376
|
+
],
|
|
1377
|
+
});
|
|
1151
1378
|
expect(warnings).toContainEqual({
|
|
1152
1379
|
code: "clamped",
|
|
1153
1380
|
component: "Card",
|
|
1154
|
-
detail:
|
|
1381
|
+
detail: `title was clamped to ${CARD_TITLE_CAP} characters.`,
|
|
1382
|
+
});
|
|
1383
|
+
expect(warnings).toContainEqual({
|
|
1384
|
+
code: "clamped",
|
|
1385
|
+
component: "Card",
|
|
1386
|
+
detail: `body was clamped to ${CARD_BODY_CAP} characters.`,
|
|
1155
1387
|
});
|
|
1156
1388
|
});
|
|
1157
1389
|
|
|
@@ -1360,6 +1592,27 @@ describe("toSlackBlocks", () => {
|
|
|
1360
1592
|
});
|
|
1361
1593
|
|
|
1362
1594
|
describe("Table", () => {
|
|
1595
|
+
it.each([["A"], [{}], [{ label: 42 }]])(
|
|
1596
|
+
"keeps an unlabeled column's position in the header and reports it: %j",
|
|
1597
|
+
(column) => {
|
|
1598
|
+
const { blocks, warnings } = toSlackBlocks({
|
|
1599
|
+
$type: "Table",
|
|
1600
|
+
columns: [column, { label: "B" }],
|
|
1601
|
+
rows: [["1", "2"]],
|
|
1602
|
+
});
|
|
1603
|
+
const table = blocks[0] as SlackDataTableBlock;
|
|
1604
|
+
expect(table.rows[0]).toEqual([
|
|
1605
|
+
{ type: "raw_text", text: "" },
|
|
1606
|
+
{ type: "raw_text", text: "B" },
|
|
1607
|
+
]);
|
|
1608
|
+
expect(warnings).toContainEqual({
|
|
1609
|
+
code: "dropped",
|
|
1610
|
+
component: "Table",
|
|
1611
|
+
detail: "1 column header was left blank for want of a string label.",
|
|
1612
|
+
});
|
|
1613
|
+
},
|
|
1614
|
+
);
|
|
1615
|
+
|
|
1363
1616
|
it("converts columns and rows into a header-first rows array with typed cells", () => {
|
|
1364
1617
|
const { blocks } = toSlackBlocks({
|
|
1365
1618
|
$type: "Table",
|
|
@@ -1433,7 +1686,7 @@ describe("toSlackBlocks", () => {
|
|
|
1433
1686
|
});
|
|
1434
1687
|
|
|
1435
1688
|
it(`clamps rows to fit the ${DATA_TABLE_CHAR_BUDGET}-character table budget, always keeping the header row`, () => {
|
|
1436
|
-
const bigCell = "z".repeat(
|
|
1689
|
+
const bigCell = "z".repeat(Math.ceil(DATA_TABLE_CHAR_BUDGET / 5));
|
|
1437
1690
|
const rows = Array.from({ length: 6 }, (_, r) => [`row${r}`, bigCell]);
|
|
1438
1691
|
const { blocks, warnings } = toSlackBlocks({
|
|
1439
1692
|
$type: "Table",
|
|
@@ -1454,10 +1707,11 @@ describe("toSlackBlocks", () => {
|
|
|
1454
1707
|
});
|
|
1455
1708
|
|
|
1456
1709
|
it("shares the character budget across multiple data-table blocks in one payload", () => {
|
|
1457
|
-
const
|
|
1710
|
+
const secondValue = "second";
|
|
1711
|
+
const filler = "f".repeat(DATA_TABLE_CHAR_BUDGET - secondValue.length);
|
|
1458
1712
|
const { blocks, warnings } = toSlackBlocks([
|
|
1459
1713
|
{ $type: "Table", columns: [{ label: "A" }], rows: [[filler]] },
|
|
1460
|
-
{ $type: "Table", columns: [{ label: "B" }], rows: [[
|
|
1714
|
+
{ $type: "Table", columns: [{ label: "B" }], rows: [[secondValue]] },
|
|
1461
1715
|
]);
|
|
1462
1716
|
const first = blocks[0] as SlackDataTableBlock;
|
|
1463
1717
|
const second = blocks[1] as SlackDataTableBlock;
|
|
@@ -1510,6 +1764,41 @@ describe("toSlackBlocks", () => {
|
|
|
1510
1764
|
const table = blocks[0] as SlackDataTableBlock;
|
|
1511
1765
|
expect(table.rows).toHaveLength(2);
|
|
1512
1766
|
});
|
|
1767
|
+
|
|
1768
|
+
it("emits Slack's documented ceiling of 200 data rows unclamped", () => {
|
|
1769
|
+
const { blocks, warnings } = toSlackBlocks({
|
|
1770
|
+
$type: "Table",
|
|
1771
|
+
columns: [{ label: "n" }],
|
|
1772
|
+
rows: Array.from({ length: 200 }, (_, r) => [String(r)]),
|
|
1773
|
+
});
|
|
1774
|
+
const table = blocks[0] as SlackDataTableBlock;
|
|
1775
|
+
expect(table.rows).toHaveLength(201);
|
|
1776
|
+
expect(warnings).toEqual([]);
|
|
1777
|
+
});
|
|
1778
|
+
|
|
1779
|
+
it("emits Slack's documented ceiling of 20,000 characters and clamps at 20,001", () => {
|
|
1780
|
+
const atBudget = toSlackBlocks({
|
|
1781
|
+
$type: "Table",
|
|
1782
|
+
columns: [{ label: "h" }],
|
|
1783
|
+
rows: [["c".repeat(19999)]],
|
|
1784
|
+
});
|
|
1785
|
+
expect((atBudget.blocks[0] as SlackDataTableBlock).rows).toHaveLength(2);
|
|
1786
|
+
expect(atBudget.warnings).toEqual([]);
|
|
1787
|
+
|
|
1788
|
+
const overBudget = toSlackBlocks({
|
|
1789
|
+
$type: "Table",
|
|
1790
|
+
columns: [{ label: "h" }],
|
|
1791
|
+
rows: [["c".repeat(20000)]],
|
|
1792
|
+
});
|
|
1793
|
+
expect((overBudget.blocks[0] as SlackDataTableBlock).rows).toHaveLength(
|
|
1794
|
+
1,
|
|
1795
|
+
);
|
|
1796
|
+
expect(overBudget.warnings).toContainEqual({
|
|
1797
|
+
code: "clamped",
|
|
1798
|
+
component: "Table",
|
|
1799
|
+
detail: "rows were clamped to fit the 20000-character table budget.",
|
|
1800
|
+
});
|
|
1801
|
+
});
|
|
1513
1802
|
});
|
|
1514
1803
|
|
|
1515
1804
|
describe("Markdown", () => {
|
|
@@ -1575,6 +1864,65 @@ describe("toSlackBlocks", () => {
|
|
|
1575
1864
|
});
|
|
1576
1865
|
|
|
1577
1866
|
describe("ListView and ListViewItem", () => {
|
|
1867
|
+
it("forwards a discarded child's own dropped warning and counts it", () => {
|
|
1868
|
+
const { warnings } = toSlackBlocks({
|
|
1869
|
+
$type: "ListView",
|
|
1870
|
+
children: [
|
|
1871
|
+
{ $type: "Mystery" },
|
|
1872
|
+
{ $type: "ListViewItem", children: { $type: "Text", value: "row" } },
|
|
1873
|
+
],
|
|
1874
|
+
});
|
|
1875
|
+
expect(warnings).toContainEqual({
|
|
1876
|
+
code: "dropped",
|
|
1877
|
+
component: "Mystery",
|
|
1878
|
+
detail: "Unknown component type was dropped.",
|
|
1879
|
+
});
|
|
1880
|
+
expect(warnings).toContainEqual({
|
|
1881
|
+
code: "dropped",
|
|
1882
|
+
component: "ListView",
|
|
1883
|
+
detail: "1 non-item child was dropped.",
|
|
1884
|
+
});
|
|
1885
|
+
});
|
|
1886
|
+
|
|
1887
|
+
it("does not let a discarded child spend the markdown budget", () => {
|
|
1888
|
+
const { blocks, warnings } = toSlackBlocks([
|
|
1889
|
+
{
|
|
1890
|
+
$type: "ListView",
|
|
1891
|
+
children: [
|
|
1892
|
+
{ $type: "Markdown", value: "x".repeat(MARKDOWN_TEXT_BUDGET) },
|
|
1893
|
+
{
|
|
1894
|
+
$type: "ListViewItem",
|
|
1895
|
+
children: { $type: "Text", value: "row" },
|
|
1896
|
+
},
|
|
1897
|
+
],
|
|
1898
|
+
},
|
|
1899
|
+
{ $type: "Markdown", value: "**real**" },
|
|
1900
|
+
]);
|
|
1901
|
+
expect(blocks[blocks.length - 1]).toEqual({
|
|
1902
|
+
type: "markdown",
|
|
1903
|
+
text: "**real**",
|
|
1904
|
+
});
|
|
1905
|
+
expect(warnings.some((warning) => warning.component === "Markdown")).toBe(
|
|
1906
|
+
false,
|
|
1907
|
+
);
|
|
1908
|
+
});
|
|
1909
|
+
|
|
1910
|
+
it("reports a non-item child it filters out", () => {
|
|
1911
|
+
const { blocks, warnings } = toSlackBlocks({
|
|
1912
|
+
$type: "ListView",
|
|
1913
|
+
children: [
|
|
1914
|
+
{ $type: "Text", value: "stray" },
|
|
1915
|
+
{ $type: "ListViewItem", children: { $type: "Text", value: "Kept" } },
|
|
1916
|
+
],
|
|
1917
|
+
});
|
|
1918
|
+
expect(blocks).toHaveLength(1);
|
|
1919
|
+
expect(warnings).toContainEqual({
|
|
1920
|
+
code: "dropped",
|
|
1921
|
+
component: "ListView",
|
|
1922
|
+
detail: "1 non-item child was dropped.",
|
|
1923
|
+
});
|
|
1924
|
+
});
|
|
1925
|
+
|
|
1578
1926
|
it("renders each item as a section, separated by dividers", () => {
|
|
1579
1927
|
const { blocks } = toSlackBlocks({
|
|
1580
1928
|
$type: "ListView",
|
|
@@ -1887,8 +2235,26 @@ describe("toSlackBlocks", () => {
|
|
|
1887
2235
|
expect(warnings).toContainEqual({
|
|
1888
2236
|
code: "clamped",
|
|
1889
2237
|
component: "Root",
|
|
1890
|
-
detail: "nodes deeper than
|
|
1891
|
-
});
|
|
2238
|
+
detail: "nodes deeper than 32 levels were dropped.",
|
|
2239
|
+
});
|
|
2240
|
+
});
|
|
2241
|
+
|
|
2242
|
+
it("reports the depth detail at the level it actually starts dropping", () => {
|
|
2243
|
+
const chain = (levels: number) => {
|
|
2244
|
+
let node: unknown = { $type: "Caption", value: "x" };
|
|
2245
|
+
for (let i = 0; i < levels; i++) {
|
|
2246
|
+
node = { $type: "Card", children: [node] };
|
|
2247
|
+
}
|
|
2248
|
+
return node;
|
|
2249
|
+
};
|
|
2250
|
+
const dropped = (node: unknown) =>
|
|
2251
|
+
toSlackBlocks(node).warnings.some((warning) =>
|
|
2252
|
+
warning.detail.includes("deeper than"),
|
|
2253
|
+
);
|
|
2254
|
+
expect(dropped(chain(32))).toBe(false);
|
|
2255
|
+
expect(dropped(chain(33))).toBe(true);
|
|
2256
|
+
expect(dropped([chain(31)])).toBe(false);
|
|
2257
|
+
expect(dropped([chain(32)])).toBe(true);
|
|
1892
2258
|
});
|
|
1893
2259
|
});
|
|
1894
2260
|
});
|
|
@@ -1922,7 +2288,7 @@ describe("toSlackBlocks data_table integrity", () => {
|
|
|
1922
2288
|
it("drops a table whose header row alone exceeds the character budget", () => {
|
|
1923
2289
|
const { blocks, warnings } = toSlackBlocks({
|
|
1924
2290
|
$type: "Table",
|
|
1925
|
-
columns: [{ label: "h".repeat(
|
|
2291
|
+
columns: [{ label: "h".repeat(DATA_TABLE_CHAR_BUDGET + 1) }],
|
|
1926
2292
|
rows: [["x"]],
|
|
1927
2293
|
});
|
|
1928
2294
|
expect(blocks).toEqual([]);
|