Files
tyx_AI_xhs/tests/api/wp4-04-location.test.ts

53 lines
3.3 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { mkdtempSync, rmSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { createApp } from "../../apps/api/src/app.js";
import { MockAmapAdapter } from "../../apps/api/src/amap-adapter.js";
import { RegistrationService } from "../../apps/api/src/registration.js";
import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js";
const resources: Array<{ close: () => Promise<void> | void }> = [];
const roots: string[] = [];
afterEach(async () => {
for (const resource of resources.splice(0).reverse()) await resource.close();
for (const root of roots.splice(0)) rmSync(root, { force: true, recursive: true });
});
function registrationFixture() {
const directory = mkdtempSync(join(tmpdir(), "dada-wp4-04-"));
roots.push(directory);
const registration = new RegistrationService({
challengePepper: Buffer.alloc(32, 2), currentPrivacyNoticeVersion: "2026-07-24",
databasePath: join(directory, "dada.sqlite3"), invitePepper: Buffer.alloc(32, 3), resend: new MockResendAdapter(), sessionPepper: Buffer.alloc(32, 4),
});
resources.push({ close: () => registration.close() });
const userId = "00000000-0000-4000-8000-000000000831";
registration.database.prepare("INSERT INTO users (user_id, normalized_email, role, status, counts_toward_stage_limit, registration_id, created_at) VALUES (?, 'location@example.invalid', 'user', 'active', 1, ?, ?)").run(userId, crypto.randomUUID(), Date.now());
registration.database.prepare("INSERT INTO user_profiles (user_id, creator_name, social_id) VALUES (?, 'Location User', '@location')").run(userId);
registration.database.prepare("INSERT INTO credit_accounts (user_id, available_balance, reserved_balance, updated_at) VALUES (?, 10, 0, ?)").run(userId, Date.now());
const session = registration.issueAuthenticatedSession(userId, "user");
return { registration, session };
}
describe("TASK-WP4-04 location adapter API", () => {
it("requires mutation auth and forwards only coordinates to the local mock adapter", async () => {
const fixture = registrationFixture();
const amap = new MockAmapAdapter();
const app = await createApp({ amap, browserGate: false, registration: fixture.registration });
resources.push({ close: () => app.close() });
const csrf = fixture.registration.issueUserCsrfToken(fixture.session.sessionToken);
const response = await app.inject({
headers: { cookie: `dada_session=${fixture.session.sessionToken}`, host: "127.0.0.1:43121", origin: "http://127.0.0.1:43121", "x-csrf-token": csrf },
method: "POST", payload: { latitude: 27.9943, longitude: 120.6994 }, url: "/api/v1/location/reverse-geocode",
});
expect(response.statusCode).toBe(200);
expect(response.json()).toEqual({ formatted_value: "模拟地点 27.9943, 120.6994", service_mode: "mock", status: "resolved" });
expect(amap.calls).toEqual([{ latitude: 27.9943, longitude: 120.6994 }]);
const anonymous = await app.inject({ headers: { host: "127.0.0.1:43121", origin: "http://127.0.0.1:43121", "x-csrf-token": "anonymous-csrf-fixture-000000000000000000000000" }, method: "POST", payload: { latitude: 27.9943, longitude: 120.6994 }, url: "/api/v1/location/reverse-geocode" });
expect(anonymous.statusCode).toBe(401);
expect(amap.calls).toHaveLength(1);
});
});