feat: Implement AI Chat Agent, Email Notifications, and UI enhancements
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
|
||||
const BASE_URL = "http://localhost:5001";
|
||||
const MAILHOG_API = "http://localhost:8025/api/v2";
|
||||
|
||||
let cookie = "";
|
||||
|
||||
async function request(method: string, path: string, body?: any) {
|
||||
const headers: any = { "Content-Type": "application/json" };
|
||||
if (cookie) headers["Cookie"] = cookie;
|
||||
|
||||
const res = await fetch(`${BASE_URL}${path}`, {
|
||||
method,
|
||||
headers,
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
});
|
||||
|
||||
const setCookie = res.headers.get("set-cookie");
|
||||
if (setCookie) {
|
||||
cookie = setCookie.split(";")[0];
|
||||
}
|
||||
|
||||
const text = await res.text();
|
||||
try {
|
||||
const data = JSON.parse(text);
|
||||
return { status: res.status, data };
|
||||
} catch {
|
||||
return { status: res.status, data: text };
|
||||
}
|
||||
}
|
||||
|
||||
async function getLatestEmail(toEmail: string) {
|
||||
try {
|
||||
const res = await fetch(`${MAILHOG_API}/messages`);
|
||||
const data = await res.json();
|
||||
// MailHog returns { total: number, count: number, start: number, items: [...] }
|
||||
// items are sorted newest first usually in MailHog UI, but API might vary.
|
||||
// Let's filter by 'To' and take the first one.
|
||||
const messages = data.items;
|
||||
for (const msg of messages) {
|
||||
// Headers is an object like { "To": ["<email>"], ... }
|
||||
// Content.Headers.To
|
||||
const toHeader = msg.Content.Headers.To?.[0];
|
||||
if (toHeader && toHeader.includes(toEmail)) {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch from MailHog:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
console.log("📧 Testing Email Flow...");
|
||||
|
||||
const timestamp = Date.now();
|
||||
const username = `email_user_${timestamp}`;
|
||||
const email = `test_${timestamp}@example.com`;
|
||||
const password = "password123";
|
||||
const newPassword = "newpassword456";
|
||||
|
||||
// 1. Register User
|
||||
console.log(`\n1. Registering user: ${username} (${email})`);
|
||||
let res = await request("POST", "/api/register", { username, password, email });
|
||||
if (res.status === 201 || res.status === 200) {
|
||||
console.log("✅ Registration successful");
|
||||
} else {
|
||||
console.error("❌ Registration failed:", res.data);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 2. Request Password Reset
|
||||
console.log("\n2. Requesting Password Reset...");
|
||||
// Logout first just in case
|
||||
await request("POST", "/api/logout");
|
||||
cookie = ""; // Clear cookie
|
||||
|
||||
res = await request("POST", "/api/auth/forgot-password", { email });
|
||||
if (res.status === 200) {
|
||||
console.log("✅ Reset request sent:", res.data.message);
|
||||
} else {
|
||||
console.error("❌ Reset request failed:", res.data);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 3. Check MailHog
|
||||
console.log("\n3. Checking MailHog for email...");
|
||||
// Wait a bit for email to arrive
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
|
||||
const emailMsg = await getLatestEmail(email);
|
||||
if (emailMsg) {
|
||||
console.log("✅ Email found!", emailMsg.Content.Headers.Subject[0]);
|
||||
} else {
|
||||
console.error("❌ Email NOT found in MailHog!");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 4. Extract Token
|
||||
// We expect a link like: http://localhost:5001/reset-password?token=...
|
||||
// In text body: msg.Content.Body
|
||||
let body = emailMsg.Content.Body;
|
||||
|
||||
// Simple QP decoding for test
|
||||
body = body.replace(/=\r\n/g, '').replace(/=\n/g, '').replace(/=3D/g, '=');
|
||||
|
||||
console.log("DEBUG BODY DECODED:", body);
|
||||
|
||||
const match = body.match(/token=([a-zA-Z0-9-]+)/);
|
||||
if (!match) {
|
||||
console.error("❌ Token not found in email body!");
|
||||
console.log("Body:", body);
|
||||
process.exit(1);
|
||||
}
|
||||
const token = match[1];
|
||||
console.log("✅ Token extracted:", token);
|
||||
|
||||
// 5. Reset Password
|
||||
console.log("\n5. Resetting Password...");
|
||||
res = await request("POST", "/api/auth/reset-password", { token, newPassword });
|
||||
if (res.status === 200) {
|
||||
console.log("✅ Password reset successful");
|
||||
} else {
|
||||
console.error("❌ Password reset failed:", res.data);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 6. Login with New Password
|
||||
console.log("\n6. Logging in with NEW password...");
|
||||
res = await request("POST", "/api/login", { username, password: newPassword });
|
||||
if (res.status === 200) {
|
||||
console.log("✅ Login successful with new password!");
|
||||
} else {
|
||||
console.error("❌ Login failed:", res.data);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 7. Login with OLD Password (should fail)
|
||||
console.log("\n7. Verifying OLD password fails...");
|
||||
res = await request("POST", "/api/login", { username, password });
|
||||
if (res.status === 401) {
|
||||
console.log("✅ Old password rejected correctly.");
|
||||
} else {
|
||||
console.error("❌ Old password SHOULD fail but got:", res.status);
|
||||
}
|
||||
|
||||
console.log("\n🎉 Full Email Flow Test Passed!");
|
||||
}
|
||||
|
||||
run();
|
||||
Reference in New Issue
Block a user