fix(auth): fallback to dev auth.json for E2E tests

web_search and data tools authenticate via auth.json (sid + deviceId).
When SMC_DATA_DIR is set (e.g. for E2E tests), the auth file may not
exist in the custom dir. Now getLocalAuth() falls back to
~/.super-multica-dev/auth.json, which is created by pnpm dev:local
Desktop login and valid for the dev backend (api-dev.copilothub.ai).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jiayuan Zhang 2026-02-15 16:37:26 +08:00
parent 1ffa8b1389
commit 75fac3a2d7
4 changed files with 30 additions and 7 deletions

View file

@ -232,6 +232,7 @@ After running, the Coding Agent should:
- **`SMC_DATA_DIR=~/.super-multica-e2e`** isolates E2E test sessions from dev (`~/.super-multica-dev`) and production (`~/.super-multica`) data. Always set this.
- **`MULTICA_API_URL=https://api-dev.copilothub.ai`** is required for `web_search` and `data` tools. Without it, these tools fail with `MULTICA_API_URL is required`.
- **Auth for `web_search`/`data`**: These tools need dev backend auth. The auth store auto-falls back to `~/.super-multica-dev/auth.json`. If missing, run `pnpm dev:local` first and log in through the Desktop app.
- Default provider is `kimi-coding`. Override with `--provider`.
- Run-log and session data are at `~/.super-multica-e2e/sessions/{sessionId}/`
- Detailed guide with feature-specific test playbooks: `docs/e2e-testing-guide.md`

View file

@ -23,6 +23,7 @@ This approach is superior to static assertions because:
3. **Default provider**: `kimi-coding` (Kimi Code, free tier available). Can override with `--provider`
4. **`MULTICA_API_URL`**: Required for `web_search` and `data` tools. Set to `https://api-dev.copilothub.ai` for dev environment. Without this, web search and financial data tools will fail with `MULTICA_API_URL is required`
5. **`SMC_DATA_DIR`**: Set to `~/.super-multica-e2e` to isolate E2E test sessions from dev (`~/.super-multica-dev`) and production (`~/.super-multica`) data. Without this, test sessions pollute the production sessions directory
6. **Dev auth for `web_search`/`data` tools**: These tools authenticate via `auth.json` (session ID + device ID). The auth store automatically falls back to `~/.super-multica-dev/auth.json` when the E2E data dir has no auth. If `~/.super-multica-dev/auth.json` doesn't exist, run `pnpm dev:local` first and log in through the Desktop app to create it
## Running a Test

View file

@ -19,7 +19,7 @@ export function getAuthHeaders(context?: string): Record<string, string> {
if (!auth) {
const suffix = context ? ` ${context}` : "";
throw new Error(
`Not logged in. Please sign in via the Desktop app${suffix}.`,
`Not logged in${suffix}. Sign in via the Desktop app, or run pnpm dev:local and log in there.`,
);
}
return {

View file

@ -1,18 +1,16 @@
import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { DATA_DIR } from "@multica/utils";
const AUTH_FILE_PATH = join(DATA_DIR, "auth.json");
const DEV_AUTH_FILE_PATH = join(homedir(), ".super-multica-dev", "auth.json");
export type LocalAuthData = { sid: string; deviceId: string };
/**
* Read sid and deviceId from ~/.super-multica/auth.json.
* Returns null if the file is missing, unreadable, or incomplete.
*/
export function getLocalAuth(): LocalAuthData | null {
function tryReadAuth(filePath: string): LocalAuthData | null {
try {
const raw = readFileSync(AUTH_FILE_PATH, "utf8").trim();
const raw = readFileSync(filePath, "utf8").trim();
if (!raw) return null;
const data = JSON.parse(raw);
@ -32,3 +30,26 @@ export function getLocalAuth(): LocalAuthData | null {
return null;
}
}
/**
* Read sid and deviceId from auth.json.
*
* Lookup order:
* 1. {DATA_DIR}/auth.json (current data dir, respects SMC_DATA_DIR)
* 2. ~/.super-multica-dev/auth.json (dev environment fallback
* allows E2E tests and other custom SMC_DATA_DIR setups to
* share the dev auth created by `pnpm dev:local`)
*
* Returns null if no valid auth is found.
*/
export function getLocalAuth(): LocalAuthData | null {
const primary = tryReadAuth(AUTH_FILE_PATH);
if (primary) return primary;
// Fallback to dev auth when using a custom data dir (e.g. E2E tests)
if (AUTH_FILE_PATH !== DEV_AUTH_FILE_PATH) {
return tryReadAuth(DEV_AUTH_FILE_PATH);
}
return null;
}