diff --git a/scripts/e2e/lib/upgrade-survivor/run.sh b/scripts/e2e/lib/upgrade-survivor/run.sh index 1d6aedc6f99e..814bdf9ef490 100644 --- a/scripts/e2e/lib/upgrade-survivor/run.sh +++ b/scripts/e2e/lib/upgrade-survivor/run.sh @@ -72,6 +72,8 @@ update_restart_seconds="" BASELINE_INSTALL_LOG="$ARTIFACT_ROOT/baseline-install.log" UPDATE_JSON="$ARTIFACT_ROOT/update.json" UPDATE_ERR="$ARTIFACT_ROOT/update.err" +POST_UPDATE_VALIDATE_JSON="$ARTIFACT_ROOT/post-update-validate.json" +POST_UPDATE_VALIDATE_ERR="$ARTIFACT_ROOT/post-update-validate.err" DOCTOR_LOG="$ARTIFACT_ROOT/doctor.log" BASELINE_DOCTOR_LOG="$ARTIFACT_ROOT/baseline-doctor.log" GATEWAY_LOG="$ARTIFACT_ROOT/gateway.log" @@ -1386,11 +1388,18 @@ update_candidate() { if [ "$ROOT_MANAGED_VPS" != "1" ]; then update_env+=(OPENCLAW_ALLOW_ROOT=1) fi - if ! openclaw_e2e_maybe_timeout "$COMMAND_TIMEOUT" "${update_env[@]}" openclaw "${update_args[@]}" >"$UPDATE_JSON" 2>"$UPDATE_ERR"; then + local update_status=0 + openclaw_e2e_maybe_timeout "$COMMAND_TIMEOUT" "${update_env[@]}" openclaw "${update_args[@]}" >"$UPDATE_JSON" 2>"$UPDATE_ERR" || update_status=$? + if [ "$update_status" -ne 0 ]; then echo "openclaw update failed" >&2 - openclaw_e2e_print_log "$UPDATE_ERR" >&2 - openclaw_e2e_print_log "$UPDATE_JSON" >&2 - return 1 + local validate_status=0 + openclaw_e2e_maybe_timeout "$COMMAND_TIMEOUT" openclaw config validate --json >"$POST_UPDATE_VALIDATE_JSON" 2>"$POST_UPDATE_VALIDATE_ERR" || validate_status=$? + echo "post-update config validation probe status=$validate_status" >&2 + openclaw_e2e_print_log "$POST_UPDATE_VALIDATE_ERR" >&2 || true + openclaw_e2e_print_log "$POST_UPDATE_VALIDATE_JSON" >&2 || true + openclaw_e2e_print_log "$UPDATE_ERR" >&2 || true + openclaw_e2e_print_log "$UPDATE_JSON" >&2 || true + return "$update_status" fi if [ "$UPDATE_RESTART_MODE" = "auto-auth" ]; then update_end="$(node -e "process.stdout.write(String(Date.now()))")" diff --git a/scripts/e2e/upgrade-survivor-docker.sh b/scripts/e2e/upgrade-survivor-docker.sh index a9245f4bc826..bc312352a91e 100755 --- a/scripts/e2e/upgrade-survivor-docker.sh +++ b/scripts/e2e/upgrade-survivor-docker.sh @@ -465,11 +465,13 @@ update_status=$? set -e if [ "$update_status" -ne 0 ]; then echo "openclaw update failed" >&2 - openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.err >&2 - openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.json >&2 - openclaw_e2e_maybe_timeout "$command_timeout" openclaw config validate --json >/tmp/openclaw-upgrade-survivor-post-update-validate.json 2>/tmp/openclaw-upgrade-survivor-post-update-validate.err || true - openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-post-update-validate.err >&2 - openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-post-update-validate.json >&2 + validate_status=0 + openclaw_e2e_maybe_timeout "$command_timeout" openclaw config validate --json >/tmp/openclaw-upgrade-survivor-post-update-validate.json 2>/tmp/openclaw-upgrade-survivor-post-update-validate.err || validate_status=$? + echo "post-update config validation probe status=$validate_status" >&2 + openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-post-update-validate.err >&2 || true + openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-post-update-validate.json >&2 || true + openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.err >&2 || true + openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.json >&2 || true exit "$update_status" fi if [ -n "${OPENCLAW_CLAWHUB_URL:-}" ]; then diff --git a/test/scripts/docker-build-helper.test.ts b/test/scripts/docker-build-helper.test.ts index c99a0ccaca4c..7fc0967c55a8 100644 --- a/test/scripts/docker-build-helper.test.ts +++ b/test/scripts/docker-build-helper.test.ts @@ -185,6 +185,15 @@ function expectTextToIncludeAll(text: string, snippets: readonly string[]): void } } +function expectTextToIncludeInOrder(text: string, snippets: readonly string[]): void { + let offset = 0; + for (const snippet of snippets) { + const index = text.indexOf(snippet, offset); + expect(index).toBeGreaterThanOrEqual(offset); + offset = index + snippet.length; + } +} + function extractUpgradeSurvivorSupervisor(script: string): string { const match = script.match( /cat >"\$supervisor_script" <<'SUPERVISOR'\n(?[\s\S]*?)\nSUPERVISOR/u, @@ -3284,6 +3293,32 @@ if (starts === 1) { const runner = readFileSync(UPGRADE_SURVIVOR_DOCKER_E2E_PATH, "utf8"); const publishedRunner = readFileSync(UPGRADE_SURVIVOR_RUN_SCRIPT, "utf8"); + expectTextToIncludeInOrder(runner, [ + "update_status=$?", + 'if [ "$update_status" -ne 0 ]; then', + 'echo "openclaw update failed" >&2', + "openclaw config validate --json >/tmp/openclaw-upgrade-survivor-post-update-validate.json", + 'echo "post-update config validation probe status=$validate_status" >&2', + "openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-post-update-validate.err >&2 || true", + "openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-post-update-validate.json >&2 || true", + "openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.err >&2 || true", + "openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.json >&2 || true", + 'exit "$update_status"', + ]); + expectTextToIncludeInOrder(publishedRunner, [ + "local update_status=0", + 'openclaw "${update_args[@]}" >"$UPDATE_JSON" 2>"$UPDATE_ERR" || update_status=$?', + 'if [ "$update_status" -ne 0 ]; then', + 'echo "openclaw update failed" >&2', + 'openclaw config validate --json >"$POST_UPDATE_VALIDATE_JSON"', + 'echo "post-update config validation probe status=$validate_status" >&2', + 'openclaw_e2e_print_log "$POST_UPDATE_VALIDATE_ERR" >&2 || true', + 'openclaw_e2e_print_log "$POST_UPDATE_VALIDATE_JSON" >&2 || true', + 'openclaw_e2e_print_log "$UPDATE_ERR" >&2 || true', + 'openclaw_e2e_print_log "$UPDATE_JSON" >&2 || true', + 'return "$update_status"', + ]); + expectTextToIncludeAll(runner, [ "openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.err", "openclaw_e2e_print_log /tmp/openclaw-upgrade-survivor-update.json", diff --git a/test/vitest/vitest.bundled.config.ts b/test/vitest/vitest.bundled.config.ts index 0fc804b5ced8..b4b1c4823076 100644 --- a/test/vitest/vitest.bundled.config.ts +++ b/test/vitest/vitest.bundled.config.ts @@ -30,8 +30,12 @@ const bundledUnitExcludePatterns = unitTestAdditionalExcludePatterns.filter( ), ); -export default createUnitVitestConfigWithOptions(process.env, { - includePatterns: bundledPluginDependentUnitTestFiles, - extraExcludePatterns: bundledUnitExcludePatterns, - name: "bundled", -}); +export function createBundledVitestConfig(env: Record = process.env) { + return createUnitVitestConfigWithOptions(env, { + includePatterns: bundledPluginDependentUnitTestFiles, + extraExcludePatterns: bundledUnitExcludePatterns, + name: "bundled", + }); +} + +export default createBundledVitestConfig(); diff --git a/test/vitest/vitest.contracts-channel-config.config.ts b/test/vitest/vitest.contracts-channel-config.config.ts index a53a06bc0fd9..4c6fe2e3e860 100644 --- a/test/vitest/vitest.contracts-channel-config.config.ts +++ b/test/vitest/vitest.contracts-channel-config.config.ts @@ -4,11 +4,13 @@ import { createContractsVitestConfig, } from "./vitest.contracts-shared.ts"; -export default createContractsVitestConfig( - channelConfigContractPatterns, - process.env, - process.argv, - { +export function createContractsChannelConfigVitestConfig( + env: Record = process.env, + argv: string[] = process.argv, +) { + return createContractsVitestConfig(channelConfigContractPatterns, env, argv, { name: "contracts-channel-config", - }, -); + }); +} + +export default createContractsChannelConfigVitestConfig(); diff --git a/test/vitest/vitest.contracts-channel-registry.config.ts b/test/vitest/vitest.contracts-channel-registry.config.ts index 9cc0870ad67a..53410150300f 100644 --- a/test/vitest/vitest.contracts-channel-registry.config.ts +++ b/test/vitest/vitest.contracts-channel-registry.config.ts @@ -4,11 +4,13 @@ import { createContractsVitestConfig, } from "./vitest.contracts-shared.ts"; -export default createContractsVitestConfig( - channelRegistryContractPatterns, - process.env, - process.argv, - { +export function createContractsChannelRegistryVitestConfig( + env: Record = process.env, + argv: string[] = process.argv, +) { + return createContractsVitestConfig(channelRegistryContractPatterns, env, argv, { name: "contracts-channel-registry", - }, -); + }); +} + +export default createContractsChannelRegistryVitestConfig(); diff --git a/test/vitest/vitest.contracts-channel-session.config.ts b/test/vitest/vitest.contracts-channel-session.config.ts index dace5c1624ff..9971495ebf7c 100644 --- a/test/vitest/vitest.contracts-channel-session.config.ts +++ b/test/vitest/vitest.contracts-channel-session.config.ts @@ -4,11 +4,13 @@ import { createContractsVitestConfig, } from "./vitest.contracts-shared.ts"; -export default createContractsVitestConfig( - channelSessionContractPatterns, - process.env, - process.argv, - { +export function createContractsChannelSessionVitestConfig( + env: Record = process.env, + argv: string[] = process.argv, +) { + return createContractsVitestConfig(channelSessionContractPatterns, env, argv, { name: "contracts-channel-session", - }, -); + }); +} + +export default createContractsChannelSessionVitestConfig(); diff --git a/test/vitest/vitest.contracts-channel-surface.config.ts b/test/vitest/vitest.contracts-channel-surface.config.ts index f0b313207eee..a524232d3c56 100644 --- a/test/vitest/vitest.contracts-channel-surface.config.ts +++ b/test/vitest/vitest.contracts-channel-surface.config.ts @@ -4,11 +4,13 @@ import { createContractsVitestConfig, } from "./vitest.contracts-shared.ts"; -export default createContractsVitestConfig( - channelSurfaceContractPatterns, - process.env, - process.argv, - { +export function createContractsChannelSurfaceVitestConfig( + env: Record = process.env, + argv: string[] = process.argv, +) { + return createContractsVitestConfig(channelSurfaceContractPatterns, env, argv, { name: "contracts-channel-surface", - }, -); + }); +} + +export default createContractsChannelSurfaceVitestConfig(); diff --git a/test/vitest/vitest.contracts-plugin.config.ts b/test/vitest/vitest.contracts-plugin.config.ts index 463995ec6f55..66ab3da6bb55 100644 --- a/test/vitest/vitest.contracts-plugin.config.ts +++ b/test/vitest/vitest.contracts-plugin.config.ts @@ -1,6 +1,13 @@ // Vitest contracts plugin config wires the contracts plugin test shard. import { createContractsVitestConfig, pluginContractPatterns } from "./vitest.contracts-shared.ts"; -export default createContractsVitestConfig(pluginContractPatterns, process.env, process.argv, { - name: "contracts-plugin", -}); +export function createContractsPluginVitestConfig( + env: Record = process.env, + argv: string[] = process.argv, +) { + return createContractsVitestConfig(pluginContractPatterns, env, argv, { + name: "contracts-plugin", + }); +} + +export default createContractsPluginVitestConfig(); diff --git a/ui/src/app/route-transition.test.ts b/ui/src/app/route-transition.test.ts index e9123262cc10..0ad53c8c10f1 100644 --- a/ui/src/app/route-transition.test.ts +++ b/ui/src/app/route-transition.test.ts @@ -5,7 +5,10 @@ function testDocumentWithOutlet(animate = vi.fn()) { const outlet = document.createElement("openclaw-router-outlet") as HTMLElement & { updateComplete: Promise; }; - outlet.updateComplete = Promise.resolve(); + Object.defineProperty(outlet, "updateComplete", { + configurable: true, + value: Promise.resolve(), + }); outlet.animate = animate; document.body.append(outlet); return {