mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 05:20:46 +08:00
79 lines
3.9 KiB
JavaScript
79 lines
3.9 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { readFile } from 'node:fs/promises';
|
|
import test from 'node:test';
|
|
|
|
const CLIENT_URL = new URL('../../../plugin-src/client/channels/dingtalk/index.js', import.meta.url);
|
|
const STYLES_URL = new URL('../../../plugin-src/client/channels/dingtalk/styles.js', import.meta.url);
|
|
|
|
test('standalone client exports a reusable settings component and registration', async () => {
|
|
const source = await readFile(CLIENT_URL, 'utf8');
|
|
assert.match(source, /export const name = 'dingtalk-settings'/);
|
|
assert.match(source, /export const inject = \['slots', 'connection'\]/);
|
|
assert.match(source, /export function DingtalkSettingsTab\(\{ rpcCall \}\)/);
|
|
assert.match(source, /export function apply\(ctx\)/);
|
|
assert.match(source, /ctx\.connection\.rpc\.call\(DINGTALK_RPC_CHANNEL/);
|
|
assert.match(source, /id: 'dingtalk'/);
|
|
assert.match(source, /label: '钉钉'/);
|
|
});
|
|
|
|
test('QR guidance describes the complete official DingTalk authorization flow', async () => {
|
|
const source = await readFile(CLIENT_URL, 'utf8');
|
|
assert.match(source, /使用已加入企业\/组织的钉钉账号扫描左侧二维码/);
|
|
assert.match(source, /如果钉钉提示尚未加入组织/);
|
|
assert.match(source, /在授权页点击“一键创建新机器人”/);
|
|
assert.match(source, /保持本页打开,等待机器人自动连接/);
|
|
assert.doesNotMatch(source, /OpenClaw 品牌|ddt-brandNotice/);
|
|
assert.match(source, /safeQrSource\(provision\.qrCodeDataUrl\)/);
|
|
assert.doesNotMatch(source, /verificationUrl|打开备用链接/);
|
|
assert.doesNotMatch(source, /dangerouslySetInnerHTML|window\.open\(/);
|
|
});
|
|
|
|
test('the settings page has no local sender approval workflow', async () => {
|
|
const source = await readFile(CLIENT_URL, 'utf8');
|
|
assert.match(source, /payload: \{ botId: account\.botId, confirm: true \}/);
|
|
assert.doesNotMatch(source, /SenderAccess|approveSender|revokeSender|待批准|已批准|批准使用/);
|
|
});
|
|
|
|
test('the client uses an isolated compact and accessible DingTalk style namespace', async () => {
|
|
const [source, styles] = await Promise.all([
|
|
readFile(CLIENT_URL, 'utf8'),
|
|
readFile(STYLES_URL, 'utf8'),
|
|
]);
|
|
assert.doesNotMatch(source, /\bdxw-|\bbxf-/);
|
|
assert.doesNotMatch(styles, /\bdxw-|\bbxf-/);
|
|
assert.match(styles, /\.ddt-page \{/);
|
|
assert.match(styles, /--ddt-accent: #1677ff/);
|
|
assert.match(styles, /@media \(max-width: 720px\)/);
|
|
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)/);
|
|
assert.match(source, /aria-live': 'polite'/);
|
|
assert.match(source, /role: 'alertdialog'/);
|
|
});
|
|
|
|
test('the QR card responds to its plugin panel width instead of the browser viewport', async () => {
|
|
const styles = await readFile(STYLES_URL, 'utf8');
|
|
assert.match(styles, /container-type: inline-size/);
|
|
assert.match(
|
|
styles,
|
|
/@container \(max-width: 680px\)[\s\S]*\.ddt-qrLayout \{ grid-template-columns: minmax\(0, 1fr\); justify-items: center;/,
|
|
);
|
|
assert.match(styles, /\.ddt-qrFrame \{[^\n]*width: min\(270px, 100%\)/);
|
|
assert.match(styles, /\.ddt-countdown \{ width: min\(270px, 100%\)/);
|
|
assert.match(styles, /\.ddt-qrLayout \{[^\n]*align-items: start;/);
|
|
assert.match(styles, /\.ddt-qrColumn \{ width: 100%; min-width: 0; \}/);
|
|
assert.match(styles, /\.ddt-qrCopy \{ min-width: 0; overflow-wrap: anywhere; \}/);
|
|
});
|
|
|
|
test('bot cards do not reserve a row for repeated channel metrics', async () => {
|
|
const styles = await readFile(STYLES_URL, 'utf8');
|
|
assert.doesNotMatch(styles, /\.ddt-metrics|\.ddt-metric/);
|
|
});
|
|
|
|
test('the narrow-panel toolbar keeps all three controls on one row', async () => {
|
|
const styles = await readFile(STYLES_URL, 'utf8');
|
|
assert.match(
|
|
styles,
|
|
/@container \(max-width: 680px\)[\s\S]*\.ddt-tools \{ width: 100%; flex-wrap: nowrap; gap: 6px; \}/,
|
|
);
|
|
assert.match(styles, /\.ddt-tools \.ddt-badge \{ min-height: 34px;/);
|
|
assert.match(styles, /\.ddt-tools \.ddt-button \{[^\n]*white-space: nowrap;/);
|
|
});
|