Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* text=auto eol=lf
*.{cmd,bat} text eol=crlf
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
},
"dependencies": {
"@iarna/toml": "^2.2.5",
"@vue/compiler-dom": "^3.5.30",
"json5": "^2.2.3",
"yauzl": "^3.2.1",
"zip-lib": "^1.2.1"
Expand All @@ -72,6 +71,7 @@
"author": "ymkiux",
"license": "Apache-2.0",
"devDependencies": {
"@vue/compiler-dom": "^3.5.30",
"vitepress": "^1.6.4"
}
}
19 changes: 19 additions & 0 deletions tests/unit/agents-modal-guards.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const { createAgentsMethods } = await import(
const { createCodexConfigMethods } = await import(
pathToFileURL(path.join(__dirname, '..', '..', 'web-ui', 'modules', 'app.methods.codex-config.mjs'))
);
const { createI18nMethods } = await import(
pathToFileURL(path.join(__dirname, '..', '..', 'web-ui', 'modules', 'i18n.mjs'))
);

test('closeConfigTemplateModal ignores user close attempts while template apply is busy', () => {
const methods = createCodexConfigMethods({
Expand All @@ -20,7 +23,9 @@ test('closeConfigTemplateModal ignores user close attempts while template apply
}
});
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
showConfigTemplateModal: true,
configTemplateApplying: true,
configTemplateContent: 'draft-template'
Expand Down Expand Up @@ -52,7 +57,9 @@ test('applyConfigTemplate force closes the modal after a successful apply', asyn
}
});
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
showConfigTemplateModal: true,
configTemplateApplying: false,
configTemplateContent: 'draft-template',
Expand Down Expand Up @@ -103,7 +110,9 @@ test('applyConfigTemplate keeps the successful apply result when only the refres
}
});
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
showConfigTemplateModal: true,
configTemplateApplying: false,
configTemplateContent: 'draft-template',
Expand Down Expand Up @@ -161,7 +170,9 @@ test('applyConfigTemplate applies immediately when diff confirm is disabled', as
}
});
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
showConfigTemplateModal: true,
configTemplateApplying: false,
configTemplateContent: 'draft-template',
Expand Down Expand Up @@ -192,7 +203,9 @@ test('runHealthCheck treats backend error payloads as failures', async () => {
}
});
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
providersList: ['alpha'],
speedResults: {},
speedLoading: {},
Expand Down Expand Up @@ -227,7 +240,9 @@ test('runHealthCheck skips Claude speed tests when the primary health check alre
});
let claudeSpeedTestCalls = 0;
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
providersList: ['alpha'],
speedResults: {},
speedLoading: {},
Expand Down Expand Up @@ -276,7 +291,9 @@ test('runHealthCheck preserves backend remote health result while appending spee
}
});
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
providersList: ['alpha', 'beta'],
speedResults: {},
speedLoading: {},
Expand Down Expand Up @@ -324,7 +341,9 @@ test('applyCodexConfigDirect keeps the successful apply result when only the ref
}
});
const context = {
...createI18nMethods(),
...methods,
lang: 'zh',
codexApplying: false,
_pendingCodexApplyOptions: null,
currentProvider: 'alpha',
Expand Down
36 changes: 36 additions & 0 deletions tests/unit/claude-settings-sync.test.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import assert from 'assert';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import { readBundledWebUiScript, readProjectFile } from './helpers/web-ui-source.mjs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const { createI18nMethods } = await import(
pathToFileURL(path.join(__dirname, '..', '..', 'web-ui', 'modules', 'i18n.mjs'))
);

const appSource = readBundledWebUiScript();
const claudeConfigModuleSource = readProjectFile('web-ui/modules/app.methods.claude-config.mjs');

Expand Down Expand Up @@ -224,7 +233,10 @@ test('addClaudeConfig requires a visible model value before saving', () => {
const addClaudeConfig = instantiateFunction(source, 'addClaudeConfig');
const messages = [];
let saveCount = 0;
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
newClaudeConfig: {
name: 'Claude Test',
apiKey: 'sk-test',
Expand Down Expand Up @@ -256,7 +268,10 @@ ${extractMethodAsFunction(appSource, 'claudeConfigFieldError')}`;
${extractMethodAsFunction(appSource, 'canSubmitClaudeConfig')}`;
const claudeConfigFieldError = instantiateFunction(fieldErrorSource, 'claudeConfigFieldError');
const canSubmitClaudeConfig = instantiateFunction(canSubmitSource, 'canSubmitClaudeConfig');
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
newClaudeConfig: {
name: 'Existing',
apiKey: '',
Expand Down Expand Up @@ -297,7 +312,10 @@ ${extractMethodAsFunction(appSource, 'claudeConfigFieldError')}`;
${extractMethodAsFunction(appSource, 'canSubmitClaudeConfig')}`;
const claudeConfigFieldError = instantiateFunction(fieldErrorSource, 'claudeConfigFieldError');
const canSubmitClaudeConfig = instantiateFunction(canSubmitSource, 'canSubmitClaudeConfig');
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
newClaudeConfig: { name: '', apiKey: '', baseUrl: '', model: '' },
editingConfig: {
name: 'Imported Auth Token',
Expand Down Expand Up @@ -350,7 +368,10 @@ test('addClaudeConfig trims and persists the entered model', () => {
let saveCount = 0;
let closed = false;
let refreshed = false;
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
newClaudeConfig: {
name: 'Claude Test',
apiKey: 'sk-test',
Expand Down Expand Up @@ -548,7 +569,10 @@ test('saveAndApplyConfig writes the edited Claude model through apply api', asyn
let saveCount = 0;
let closed = false;
let refreshCount = 0;
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
editingConfig: {
name: 'UI Claude Use',
apiKey: 'sk-test',
Expand Down Expand Up @@ -607,7 +631,10 @@ test('saveAndApplyConfig saves external credential config without api key', asyn
let saveCount = 0;
let closed = false;
let refreshCount = 0;
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
editingConfig: {
name: 'Imported Auth Token',
apiKey: '',
Expand Down Expand Up @@ -654,7 +681,10 @@ test('applyClaudeConfig reports informative message for external credential only

const messages = [];
let refreshCount = 0;
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
claudeConfigs: {
imported: {
apiKey: '',
Expand Down Expand Up @@ -689,7 +719,10 @@ test('onClaudeModelChange applies external credential config without api key', (
let updateCount = 0;
const applyCalls = [];
const messages = [];
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
currentClaudeConfig: 'imported',
currentClaudeModel: ' claude-opus-4-6 ',
claudeConfigs: {
Expand Down Expand Up @@ -735,7 +768,10 @@ test('onClaudeModelChange still requires api key when no external credential is
let updateCount = 0;
const applyCalls = [];
const messages = [];
const i18nMethods = createI18nMethods();
const context = {
...i18nMethods,
lang: 'zh',
currentClaudeConfig: 'local',
currentClaudeModel: ' claude-opus-4-6 ',
claudeConfigs: {
Expand Down
5 changes: 5 additions & 0 deletions tests/unit/openclaw-persist-regression.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const __dirname = path.dirname(__filename);
const { createOpenclawPersistMethods, DEFAULT_OPENCLAW_CONFIG_NAME } = await import(
pathToFileURL(path.join(__dirname, '..', '..', 'web-ui', 'modules', 'app.methods.openclaw-persist.mjs'))
);
const { createI18nMethods } = await import(
pathToFileURL(path.join(__dirname, '..', '..', 'web-ui', 'modules', 'i18n.mjs'))
);

function deferred() {
let resolve;
Expand All @@ -21,7 +24,9 @@ function deferred() {

function createContext(methods, overrides = {}) {
return {
...createI18nMethods(),
...methods,
lang: 'zh',
openclawConfigs: {
saved: {
content: 'saved-local'
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/provider-switch-regression.test.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import assert from 'assert';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import {
captureCurrentBundledAppOptions,
withGlobalOverrides
} from './helpers/web-ui-app-options.mjs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const { createI18nMethods } = await import(
pathToFileURL(path.join(__dirname, '..', '..', 'web-ui', 'modules', 'i18n.mjs'))
);

const currentAppOptions = await captureCurrentBundledAppOptions();
const currentMethods = currentAppOptions.methods;
const currentComputed = currentAppOptions.computed;
Expand All @@ -13,6 +22,8 @@ function createProviderSwitchContext() {
const messages = [];

return {
...createI18nMethods(),
lang: 'zh',
currentProvider: 'alpha',
currentModel: 'alpha-model',
models: ['alpha-model'],
Expand Down Expand Up @@ -58,6 +69,8 @@ function createProviderSwitchContext() {
function createProviderUpdateContext() {
const messages = [];
return {
...createI18nMethods(),
lang: 'zh',
editingProvider: {
name: 'alpha',
url: ' https://api.example.com/v1 ',
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/providers-validation.test.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import assert from 'assert';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import { createProvidersMethods } from '../../web-ui/modules/app.methods.providers.mjs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const { createI18nMethods } = await import(
pathToFileURL(path.join(__dirname, '..', '..', 'web-ui', 'modules', 'i18n.mjs'))
);

function createContext(overrides = {}, apiImpl = async () => ({ success: true })) {
const messages = [];
const loadAllCalls = [];
const methods = createProvidersMethods({ api: apiImpl });
const context = {
...createI18nMethods(),
lang: 'zh',
providersList: [],
codexAuthProfiles: [],
showAddModal: true,
Expand Down
Loading
Loading