178 lines
4.6 KiB
JavaScript
178 lines
4.6 KiB
JavaScript
|
|
import assert from "node:assert/strict";
|
||
|
|
import test from "node:test";
|
||
|
|
import {
|
||
|
|
clearFeishuAccessTokenCacheForTests,
|
||
|
|
readFeishuSource,
|
||
|
|
} from "../lib/feishu-client.ts";
|
||
|
|
|
||
|
|
const bindings = {
|
||
|
|
FEISHU_APP_ID: "cli_test",
|
||
|
|
FEISHU_APP_SECRET: "secret_test",
|
||
|
|
};
|
||
|
|
|
||
|
|
function apiResponse(data) {
|
||
|
|
return Response.json({ code: 0, msg: "success", data });
|
||
|
|
}
|
||
|
|
|
||
|
|
function fakeFeishu(options = {}) {
|
||
|
|
const calls = [];
|
||
|
|
const fetchImpl = async (input, init = {}) => {
|
||
|
|
const url = new URL(String(input));
|
||
|
|
calls.push({ url, init });
|
||
|
|
if (url.pathname.endsWith("/tenant_access_token/internal")) {
|
||
|
|
return Response.json({
|
||
|
|
code: 0,
|
||
|
|
msg: "success",
|
||
|
|
tenant_access_token: "tenant-test",
|
||
|
|
expire: 7200,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
if (url.pathname.endsWith("/wiki/v2/spaces/get_node")) {
|
||
|
|
return apiResponse({
|
||
|
|
node: {
|
||
|
|
obj_type: "sheet",
|
||
|
|
obj_token: "spreadsheet-test",
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
if (url.pathname.endsWith("/sheets/query")) {
|
||
|
|
return apiResponse({
|
||
|
|
sheets:
|
||
|
|
options.sheets ??
|
||
|
|
[
|
||
|
|
{
|
||
|
|
sheet_id: "sheet-one",
|
||
|
|
title: "内容池",
|
||
|
|
resource_type: "sheet",
|
||
|
|
hidden: false,
|
||
|
|
grid_properties: { row_count: 20, column_count: 10 },
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
}
|
||
|
|
if (url.pathname.endsWith("/values_batch_get")) {
|
||
|
|
return apiResponse({
|
||
|
|
valueRanges: [
|
||
|
|
{
|
||
|
|
values: [
|
||
|
|
["作品ID", "标题", "标签", "正文", null, null],
|
||
|
|
[
|
||
|
|
7,
|
||
|
|
"一篇测试笔记",
|
||
|
|
"#测试 #KOC",
|
||
|
|
"测试正文",
|
||
|
|
{
|
||
|
|
type: "embed-image",
|
||
|
|
fileToken: "file-token-one",
|
||
|
|
width: 1080,
|
||
|
|
height: 1440,
|
||
|
|
},
|
||
|
|
[
|
||
|
|
{
|
||
|
|
type: "embed-image",
|
||
|
|
fileToken: "file-token-two",
|
||
|
|
width: 1080,
|
||
|
|
height: 1440,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
],
|
||
|
|
[8, "", "", "空标题不会导入"],
|
||
|
|
],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
}
|
||
|
|
throw new Error(`Unexpected request: ${url.pathname}`);
|
||
|
|
};
|
||
|
|
return { calls, fetchImpl };
|
||
|
|
}
|
||
|
|
|
||
|
|
test("resolves a wiki sheet and imports title, body, tags, and all images", async () => {
|
||
|
|
clearFeishuAccessTokenCacheForTests();
|
||
|
|
const { calls, fetchImpl } = fakeFeishu();
|
||
|
|
const source = await readFeishuSource(
|
||
|
|
"https://tenant.feishu.cn/wiki/wiki-test",
|
||
|
|
bindings,
|
||
|
|
fetchImpl,
|
||
|
|
);
|
||
|
|
|
||
|
|
assert.equal(source.spreadsheetToken, "spreadsheet-test");
|
||
|
|
assert.equal(source.sheetId, "sheet-one");
|
||
|
|
assert.equal(source.sheetName, "内容池");
|
||
|
|
assert.equal(source.rows.length, 1);
|
||
|
|
assert.equal(source.rows[0].sourceRow, 7);
|
||
|
|
assert.equal(source.rows[0].body, "测试正文\n\n#测试 #KOC");
|
||
|
|
assert.deepEqual(
|
||
|
|
source.rows[0].images.map((image) => image.fileToken),
|
||
|
|
["file-token-one", "file-token-two"],
|
||
|
|
);
|
||
|
|
assert.deepEqual(source.columns, [
|
||
|
|
"作品ID",
|
||
|
|
"标题",
|
||
|
|
"标签",
|
||
|
|
"正文",
|
||
|
|
"图片1",
|
||
|
|
"图片2",
|
||
|
|
]);
|
||
|
|
const valuesCall = calls.find((call) =>
|
||
|
|
call.url.pathname.endsWith("/values_batch_get"),
|
||
|
|
);
|
||
|
|
assert.equal(valuesCall.url.searchParams.get("ranges"), "sheet-one!A1:J20");
|
||
|
|
});
|
||
|
|
|
||
|
|
test("requires an exact sheet link when a workbook has multiple visible sheets", async () => {
|
||
|
|
clearFeishuAccessTokenCacheForTests();
|
||
|
|
const { fetchImpl } = fakeFeishu({
|
||
|
|
sheets: [
|
||
|
|
{
|
||
|
|
sheet_id: "one",
|
||
|
|
title: "内容A",
|
||
|
|
resource_type: "sheet",
|
||
|
|
hidden: false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
sheet_id: "two",
|
||
|
|
title: "内容B",
|
||
|
|
resource_type: "sheet",
|
||
|
|
hidden: false,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
|
||
|
|
await assert.rejects(
|
||
|
|
readFeishuSource(
|
||
|
|
"https://tenant.feishu.cn/wiki/wiki-test",
|
||
|
|
bindings,
|
||
|
|
fetchImpl,
|
||
|
|
),
|
||
|
|
/包含多个工作表/,
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("rejects a wiki node that is not a spreadsheet", async () => {
|
||
|
|
clearFeishuAccessTokenCacheForTests();
|
||
|
|
const fetchImpl = async (input) => {
|
||
|
|
const url = new URL(String(input));
|
||
|
|
if (url.pathname.endsWith("/tenant_access_token/internal")) {
|
||
|
|
return Response.json({
|
||
|
|
code: 0,
|
||
|
|
msg: "success",
|
||
|
|
tenant_access_token: "tenant-test",
|
||
|
|
expire: 7200,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return apiResponse({
|
||
|
|
node: { obj_type: "docx", obj_token: "document-test" },
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
await assert.rejects(
|
||
|
|
readFeishuSource(
|
||
|
|
"https://tenant.feishu.cn/wiki/wiki-test",
|
||
|
|
bindings,
|
||
|
|
fetchImpl,
|
||
|
|
),
|
||
|
|
/不是电子表格/,
|
||
|
|
);
|
||
|
|
});
|