bd9fad68a7
- Changed `userToken` property to `getUserToken` function in KefuWidgetHostConfig for dynamic token fetching. - Introduced KefuWidgetRuntimeConfig to manage runtime-specific configurations. - Updated readKefuWidgetConfig and setKefuWidgetConfig functions to accommodate new configuration structure. - Enhanced cs-ai-agent-sdk.js to handle user token resolution and frame configuration. - Added tests for dynamic user token retrieval in cs-ai-agent-sdk.test.mjs. - Removed deprecated cs-agent-widget.js file as part of the refactor.
135 lines
3.4 KiB
JavaScript
135 lines
3.4 KiB
JavaScript
import assert from "node:assert/strict"
|
|
import { readFile } from "node:fs/promises"
|
|
import test from "node:test"
|
|
import vm from "node:vm"
|
|
|
|
function createElement(tagName) {
|
|
return {
|
|
tagName,
|
|
children: [],
|
|
dataset: {},
|
|
style: {},
|
|
attributes: {},
|
|
listeners: {},
|
|
parentNode: null,
|
|
contentWindow: {},
|
|
setAttribute(name, value) {
|
|
this.attributes[name] = String(value)
|
|
},
|
|
appendChild(child) {
|
|
child.parentNode = this
|
|
this.children.push(child)
|
|
return child
|
|
},
|
|
removeChild(child) {
|
|
this.children = this.children.filter((item) => item !== child)
|
|
child.parentNode = null
|
|
return child
|
|
},
|
|
addEventListener(type, handler) {
|
|
this.listeners[type] = handler
|
|
},
|
|
click() {
|
|
this.listeners.click?.()
|
|
},
|
|
}
|
|
}
|
|
|
|
async function loadSdk(config) {
|
|
const source = await readFile(new URL("./cs-ai-agent-sdk.js", import.meta.url), "utf8")
|
|
const body = createElement("body")
|
|
const sandbox = {
|
|
URL,
|
|
console,
|
|
fetch: async () => ({
|
|
json: async () => ({
|
|
success: true,
|
|
data: {
|
|
title: "在线客服",
|
|
themeColor: "#2563eb",
|
|
},
|
|
}),
|
|
}),
|
|
document: {
|
|
body,
|
|
currentScript: {
|
|
src: "https://chat.example/sdk/cs-ai-agent-sdk.min.js",
|
|
},
|
|
createElement,
|
|
createElementNS: (_namespace, tagName) => createElement(tagName),
|
|
},
|
|
window: {
|
|
CSAgentConfig: config,
|
|
location: {
|
|
origin: "https://host.example",
|
|
},
|
|
addEventListener() {},
|
|
clearTimeout() {},
|
|
setTimeout(handler) {
|
|
handler()
|
|
return 1
|
|
},
|
|
},
|
|
}
|
|
sandbox.window.window = sandbox.window
|
|
sandbox.window.document = sandbox.document
|
|
sandbox.window.fetch = sandbox.fetch
|
|
sandbox.window.console = console
|
|
sandbox.window.URL = URL
|
|
sandbox.window.setTimeout = sandbox.window.setTimeout
|
|
sandbox.window.clearTimeout = sandbox.window.clearTimeout
|
|
|
|
vm.runInNewContext(source, sandbox)
|
|
await Promise.resolve()
|
|
await Promise.resolve()
|
|
return sandbox
|
|
}
|
|
|
|
async function flushPromises(count = 5) {
|
|
for (let i = 0; i < count; i += 1) {
|
|
await Promise.resolve()
|
|
}
|
|
}
|
|
|
|
test("getChatUrl resolves a fresh userToken for each call", async () => {
|
|
let calls = 0
|
|
const sandbox = await loadSdk({
|
|
channelId: "ch_1",
|
|
baseUrl: "https://api.example",
|
|
getUserToken: async () => `token_${++calls}`,
|
|
})
|
|
|
|
assert.equal(typeof sandbox.window.CSAgentWidget.getChatUrl, "function")
|
|
|
|
const first = await sandbox.window.CSAgentWidget.getChatUrl()
|
|
const second = await sandbox.window.CSAgentWidget.getChatUrl()
|
|
|
|
assert.equal(new URL(first).searchParams.get("userToken"), "token_1")
|
|
assert.equal(new URL(second).searchParams.get("userToken"), "token_2")
|
|
assert.equal(calls, 2)
|
|
})
|
|
|
|
test("launcher click creates chat iframe with a freshly resolved userToken", async () => {
|
|
const sandbox = await loadSdk({
|
|
channelId: "ch_1",
|
|
baseUrl: "https://api.example",
|
|
getUserToken: async () => "click_token",
|
|
})
|
|
await flushPromises()
|
|
const launcher = sandbox.document.body.children.find(
|
|
(child) => child.dataset.csAgentWidget === "launcher"
|
|
)
|
|
|
|
assert.ok(launcher)
|
|
|
|
launcher.click()
|
|
await flushPromises()
|
|
|
|
const frame = sandbox.document.body.children.find(
|
|
(child) => child.dataset.csAgentWidget === "frame"
|
|
)
|
|
|
|
assert.ok(frame)
|
|
assert.equal(new URL(frame.src).searchParams.get("userToken"), "click_token")
|
|
})
|