mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-18 16:30:58 +00:00
chore: merge master into dev/4.11.x
This commit is contained in:
@@ -34,12 +34,26 @@ test('normalizes only single-line text fields in a dynamic form save snapshot',
|
||||
{ name: 'multiline', type: 'text', default: '' },
|
||||
{ name: 'string-list', type: 'array[string]', default: [] },
|
||||
{ name: 'count', type: 'integer', default: 0 },
|
||||
{
|
||||
name: 'model',
|
||||
type: 'model-fallback-selector',
|
||||
default: { primary: '', fallbacks: [], reasoning: {} },
|
||||
},
|
||||
];
|
||||
const values = {
|
||||
'single-line': '\t hello world \n',
|
||||
multiline: ' keep multiline whitespace \n',
|
||||
'string-list': [' first ', ' second '],
|
||||
count: 3,
|
||||
model: {
|
||||
primary: 'primary-model',
|
||||
fallbacks: ['fallback-model'],
|
||||
reasoning: {
|
||||
'primary-model': 'high',
|
||||
'fallback-model': 'provider_default',
|
||||
'removed-model': 'medium',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepEqual(normalizeDynamicFormValuesForSave(specs, values), {
|
||||
@@ -47,5 +61,12 @@ test('normalizes only single-line text fields in a dynamic form save snapshot',
|
||||
multiline: ' keep multiline whitespace \n',
|
||||
'string-list': [' first ', ' second '],
|
||||
count: 3,
|
||||
model: {
|
||||
primary: 'primary-model',
|
||||
fallbacks: ['fallback-model'],
|
||||
reasoning: {
|
||||
'primary-model': 'high',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readdirSync, readFileSync } from 'node:fs';
|
||||
import test from 'node:test';
|
||||
|
||||
const localeDir = new URL('../../src/i18n/locales/', import.meta.url);
|
||||
const localeFiles = readdirSync(localeDir).filter((name) =>
|
||||
name.endsWith('.ts'),
|
||||
);
|
||||
|
||||
const deprecatedAccountCopy = [
|
||||
/Initialize with Space/i,
|
||||
/Login with Space/i,
|
||||
/Logging in with Space/i,
|
||||
/Space login/i,
|
||||
/Space accounts?/i,
|
||||
/Bind Space Account/i,
|
||||
/Authorize with Space/i,
|
||||
/通过 Space 登录/,
|
||||
/使用 Space 登录/,
|
||||
/Space 登录/,
|
||||
/Space 账户/,
|
||||
/Space 帳戶/,
|
||||
/绑定 Space/,
|
||||
/綁定 Space/,
|
||||
/Space アカウント/,
|
||||
/Space でログイン/,
|
||||
/cuenta de Space/i,
|
||||
/cuentas de Space/i,
|
||||
/cuenta Space/i,
|
||||
/tài khoản Space/i,
|
||||
/บัญชี Space/,
|
||||
/аккаунт(?:ов|а)? Space/i,
|
||||
/аккаунт Space/i,
|
||||
];
|
||||
|
||||
test('user-facing account authentication copy uses LangBot Account terminology', () => {
|
||||
const violations = [];
|
||||
|
||||
for (const file of localeFiles) {
|
||||
const source = readFileSync(new URL(file, localeDir), 'utf8');
|
||||
for (const pattern of deprecatedAccountCopy) {
|
||||
if (pattern.test(source)) violations.push(`${file}: ${pattern}`);
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(violations, []);
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
const root = process.cwd();
|
||||
const dialogPath = path.join(
|
||||
root,
|
||||
'src/app/home/components/qrcode-login/QrCodeLoginDialog.tsx',
|
||||
);
|
||||
const localeDir = path.join(root, 'src/i18n/locales');
|
||||
|
||||
const dialogSource = fs.readFileSync(dialogPath, 'utf8');
|
||||
|
||||
test('QR credential exchanges preserve the active Workspace scope', () => {
|
||||
assert.match(dialogSource, /getActiveWorkspaceUuid/);
|
||||
assert.match(
|
||||
dialogSource,
|
||||
/sessionWorkspaceUuidRef\.current = workspaceUuid/,
|
||||
);
|
||||
assert.match(
|
||||
dialogSource,
|
||||
/const workspaceUuid = sessionWorkspaceUuidRef\.current/,
|
||||
);
|
||||
assert.match(dialogSource, /sessionApiBaseRef\.current = cfg\.apiBase/);
|
||||
assert.match(
|
||||
dialogSource,
|
||||
/`\$\{baseUrlRef\.current\}\$\{sessionApiBaseRef\.current\}\/\$\{sessionIdRef\.current\}`/,
|
||||
);
|
||||
assert.match(dialogSource, /'X-Workspace-Id': workspaceUuid/);
|
||||
|
||||
const workspaceHeaderUses = dialogSource.match(
|
||||
/'X-Workspace-Id': workspaceUuid/g,
|
||||
);
|
||||
assert.equal(
|
||||
workspaceHeaderUses?.length,
|
||||
4,
|
||||
'start, poll, expiry cleanup, and dialog cleanup must all retain Workspace scope',
|
||||
);
|
||||
});
|
||||
|
||||
test('WeChat QR login never reuses Feishu progress copy', () => {
|
||||
const weixinConfig = dialogSource.match(
|
||||
/weixin:\s*\{[\s\S]*?apiBase:\s*'\/api\/v1\/platform\/adapters\/weixin\/login'/,
|
||||
)?.[0];
|
||||
assert.ok(weixinConfig, 'WeChat platform config is missing');
|
||||
assert.match(weixinConfig, /connectingKey:\s*'weixin\.connecting'/);
|
||||
assert.match(weixinConfig, /waitingKey:\s*'weixin\.waitingForScan'/);
|
||||
assert.match(weixinConfig, /retryKey:\s*'weixin\.retry'/);
|
||||
assert.doesNotMatch(weixinConfig, /feishu\./);
|
||||
|
||||
for (const locale of [
|
||||
'en-US.ts',
|
||||
'es-ES.ts',
|
||||
'ja-JP.ts',
|
||||
'ru-RU.ts',
|
||||
'th-TH.ts',
|
||||
'vi-VN.ts',
|
||||
'zh-Hans.ts',
|
||||
'zh-Hant.ts',
|
||||
]) {
|
||||
const source = fs.readFileSync(path.join(localeDir, locale), 'utf8');
|
||||
const block = source.match(/weixin:\s*\{[\s\S]*?\n\s*\},/)?.[0];
|
||||
assert.ok(block, `${locale} is missing the WeChat locale block`);
|
||||
for (const key of ['connecting', 'waitingForScan', 'retry']) {
|
||||
assert.match(
|
||||
block,
|
||||
new RegExp(`\\b${key}:`),
|
||||
`${locale} is missing weixin.${key}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user