Skip to content

Commit bff4519

Browse files
fix(e2e): add telegramMeDelayMs mock behavior for onboarding timing tests (#202)
- Add getDelayMs/sleep utilities to mock-api-core.mjs so individual endpoints can honour a configurable delay set via __admin/behavior. - Wire telegramMeDelayMs into the GET /telegram/me handler so the logout-relogin spec can simulate a slow profile fetch and assert that the onboarding overlay does not fire before the timeout threshold. - Reformat long if-conditions and json() call sites to stay within line length limits (no logic changes). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 565c471 commit bff4519

1 file changed

Lines changed: 122 additions & 25 deletions

File tree

scripts/mock-api-core.mjs

Lines changed: 122 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,16 @@ function getMockTeam() {
8484
createdBy: "test-user-123",
8585
isPersonal: true,
8686
maxMembers: 1,
87-
subscription: { plan, hasActiveSubscription: isActive, planExpiry: expiry },
88-
usage: { dailyTokenLimit: 1000, remainingTokens: 1000, activeSessionCount: 0 },
87+
subscription: {
88+
plan,
89+
hasActiveSubscription: isActive,
90+
planExpiry: expiry,
91+
},
92+
usage: {
93+
dailyTokenLimit: 1000,
94+
remainingTokens: 1000,
95+
activeSessionCount: 0,
96+
},
8997
createdAt: new Date().toISOString(),
9098
updatedAt: new Date().toISOString(),
9199
},
@@ -139,6 +147,15 @@ function tryParseJson(raw) {
139147
}
140148
}
141149

150+
function getDelayMs(key) {
151+
const value = Number(mockBehavior[key] || 0);
152+
return Number.isFinite(value) && value > 0 ? value : 0;
153+
}
154+
155+
function sleep(ms) {
156+
return new Promise((resolve) => setTimeout(resolve, ms));
157+
}
158+
142159
async function handleRequest(req, res) {
143160
const method = req.method ?? "GET";
144161
const url = req.url ?? "/";
@@ -174,7 +191,10 @@ async function handleRequest(req, res) {
174191
if (!keepRequests) clearRequestLog();
175192
json(res, 200, {
176193
success: true,
177-
data: { behavior: getMockBehavior(), requestCount: getRequestLog().length },
194+
data: {
195+
behavior: getMockBehavior(),
196+
requestCount: getRequestLog().length,
197+
},
178198
});
179199
return;
180200
}
@@ -202,7 +222,10 @@ async function handleRequest(req, res) {
202222
return;
203223
}
204224

205-
if (method === "POST" && /^\/telegram\/login-tokens\/[^/]+\/consume\/?$/.test(url)) {
225+
if (
226+
method === "POST" &&
227+
/^\/telegram\/login-tokens\/[^/]+\/consume\/?$/.test(url)
228+
) {
206229
if (mockBehavior.token === "expired") {
207230
json(res, 401, { success: false, error: "Token expired or invalid" });
208231
return;
@@ -225,6 +248,10 @@ async function handleRequest(req, res) {
225248
}
226249

227250
if (method === "GET" && /^\/telegram\/me\/?(\?.*)?$/.test(url)) {
251+
const delayMs = getDelayMs("telegramMeDelayMs");
252+
if (delayMs > 0) {
253+
await sleep(delayMs);
254+
}
228255
if (mockBehavior.telegramMeStatus) {
229256
const status = Number(mockBehavior.telegramMeStatus) || 500;
230257
json(res, status, {
@@ -242,7 +269,10 @@ async function handleRequest(req, res) {
242269
}
243270

244271
if (method === "GET" && /^\/settings\/?(\?.*)?$/.test(url)) {
245-
json(res, 200, { success: true, data: { _id: "e2e-user-1", username: "e2e" } });
272+
json(res, 200, {
273+
success: true,
274+
data: { _id: "e2e-user-1", username: "e2e" },
275+
});
246276
return;
247277
}
248278

@@ -275,7 +305,10 @@ async function handleRequest(req, res) {
275305

276306
// --- Payments / Credits / Billing ---
277307

278-
if (method === "GET" && /^\/payments\/credits\/balance\/?(\?.*)?$/.test(url)) {
308+
if (
309+
method === "GET" &&
310+
/^\/payments\/credits\/balance\/?(\?.*)?$/.test(url)
311+
) {
279312
json(res, 200, {
280313
success: true,
281314
data: { balanceUsd: 10, topUpBalanceUsd: 0, topUpBaselineUsd: 0 },
@@ -364,7 +397,10 @@ async function handleRequest(req, res) {
364397
return;
365398
}
366399

367-
if (method === "GET" && /^\/payments\/credits\/auto-recharge\/?(\?.*)?$/.test(url)) {
400+
if (
401+
method === "GET" &&
402+
/^\/payments\/credits\/auto-recharge\/?(\?.*)?$/.test(url)
403+
) {
368404
json(res, 200, {
369405
success: true,
370406
data: {
@@ -388,7 +424,10 @@ async function handleRequest(req, res) {
388424
return;
389425
}
390426

391-
if (method === "GET" && /^\/payments\/credits\/auto-recharge\/cards\/?(\?.*)?$/.test(url)) {
427+
if (
428+
method === "GET" &&
429+
/^\/payments\/credits\/auto-recharge\/cards\/?(\?.*)?$/.test(url)
430+
) {
392431
json(res, 200, { success: true, data: { cards: [], defaultCardId: null } });
393432
return;
394433
}
@@ -400,7 +439,11 @@ async function handleRequest(req, res) {
400439

401440
if (method === "POST" && /^\/openai\/v1\/chat\/completions\/?$/.test(url)) {
402441
json(res, 200, {
403-
choices: [{ message: { role: "assistant", content: "Hello from e2e mock agent" } }],
442+
choices: [
443+
{
444+
message: { role: "assistant", content: "Hello from e2e mock agent" },
445+
},
446+
],
404447
});
405448
return;
406449
}
@@ -419,10 +462,16 @@ async function handleRequest(req, res) {
419462

420463
if (method === "GET" && /^\/auth\/telegram\/connect\/?(\?.*)?$/.test(url)) {
421464
if (mockBehavior.telegramDuplicate === "true") {
422-
json(res, 409, { success: false, error: "Telegram account already linked to another user" });
465+
json(res, 409, {
466+
success: false,
467+
error: "Telegram account already linked to another user",
468+
});
423469
return;
424470
}
425-
json(res, 200, { success: true, data: { oauthUrl: `${origin}/mock-telegram-oauth` } });
471+
json(res, 200, {
472+
success: true,
473+
data: { oauthUrl: `${origin}/mock-telegram-oauth` },
474+
});
426475
return;
427476
}
428477

@@ -448,36 +497,53 @@ async function handleRequest(req, res) {
448497
json(res, 401, { success: false, error: "OAuth token has expired" });
449498
return;
450499
}
451-
json(res, 200, { success: true, data: { oauthUrl: `${origin}/mock-google-oauth` } });
500+
json(res, 200, {
501+
success: true,
502+
data: { oauthUrl: `${origin}/mock-google-oauth` },
503+
});
452504
return;
453505
}
454506

455507
if (method === "POST" && /^\/telegram\/command\/?$/.test(url)) {
456508
if (mockBehavior.telegramUnauthorized === "true") {
457-
json(res, 403, { success: false, error: "Unauthorized: insufficient permissions" });
509+
json(res, 403, {
510+
success: false,
511+
error: "Unauthorized: insufficient permissions",
512+
});
458513
return;
459514
}
460515
if (mockBehavior.telegramCommandError === "true") {
461516
json(res, 400, { success: false, error: "Invalid command format" });
462517
return;
463518
}
464-
json(res, 200, { success: true, data: { result: "Command executed successfully" } });
519+
json(res, 200, {
520+
success: true,
521+
data: { result: "Command executed successfully" },
522+
});
465523
return;
466524
}
467525

468526
if (method === "GET" && /^\/telegram\/permissions\/?(\?.*)?$/.test(url)) {
469527
const level = mockBehavior.telegramPermission || "read";
470528
json(res, 200, {
471529
success: true,
472-
data: { level, canRead: true, canWrite: level !== "read", canInitiate: level === "admin" },
530+
data: {
531+
level,
532+
canRead: true,
533+
canWrite: level !== "read",
534+
canInitiate: level === "admin",
535+
},
473536
});
474537
return;
475538
}
476539

477540
if (method === "POST" && /^\/telegram\/webhook\/configure\/?$/.test(url)) {
478541
json(res, 200, {
479542
success: true,
480-
data: { webhookUrl: "https://api.example.com/webhook/telegram", active: true },
543+
data: {
544+
webhookUrl: "https://api.example.com/webhook/telegram",
545+
active: true,
546+
},
481547
});
482548
return;
483549
}
@@ -491,7 +557,12 @@ async function handleRequest(req, res) {
491557
const level = mockBehavior.notionPermission || "read";
492558
json(res, 200, {
493559
success: true,
494-
data: { level, canRead: true, canWrite: level !== "read", canCreate: level !== "read" },
560+
data: {
561+
level,
562+
canRead: true,
563+
canWrite: level !== "read",
564+
canCreate: level !== "read",
565+
},
495566
});
496567
return;
497568
}
@@ -500,7 +571,12 @@ async function handleRequest(req, res) {
500571
const level = mockBehavior.gmailPermission || "read";
501572
json(res, 200, {
502573
success: true,
503-
data: { level, canRead: true, canWrite: level !== "read", canInitiate: level === "admin" },
574+
data: {
575+
level,
576+
canRead: true,
577+
canWrite: level !== "read",
578+
canInitiate: level === "admin",
579+
},
504580
});
505581
return;
506582
}
@@ -555,7 +631,10 @@ async function handleRequest(req, res) {
555631
}
556632

557633
if (method === "POST" && /^\/invite\/redeem\/?$/.test(url)) {
558-
json(res, 200, { success: true, data: { message: "Invite code redeemed successfully" } });
634+
json(res, 200, {
635+
success: true,
636+
data: { message: "Invite code redeemed successfully" },
637+
});
559638
return;
560639
}
561640
if (method === "GET" && /^\/invite\/my-codes\/?(\?.*)?$/.test(url)) {
@@ -566,7 +645,10 @@ async function handleRequest(req, res) {
566645
json(res, 200, { success: true, data: { valid: true } });
567646
return;
568647
}
569-
if (method === "POST" && /^\/telegram\/settings\/onboarding-complete\/?$/.test(url)) {
648+
if (
649+
method === "POST" &&
650+
/^\/telegram\/settings\/onboarding-complete\/?$/.test(url)
651+
) {
570652
json(res, 200, { success: true, data: {} });
571653
return;
572654
}
@@ -590,7 +672,8 @@ async function handleRequest(req, res) {
590672
? {
591673
id: "sub_mock_123",
592674
status: "active",
593-
currentPeriodEnd: expiry || new Date(Date.now() + 30 * 86400000).toISOString(),
675+
currentPeriodEnd:
676+
expiry || new Date(Date.now() + 30 * 86400000).toISOString(),
594677
}
595678
: null,
596679
},
@@ -602,15 +685,23 @@ async function handleRequest(req, res) {
602685
// consolidated handlers (with mockBehavior checks). Only the coinbase
603686
// charge-status polling endpoint remains here.
604687

605-
if (method === "GET" && /^\/payments\/coinbase\/charge\/[^/]+\/?(\?.*)?$/.test(url)) {
688+
if (
689+
method === "GET" &&
690+
/^\/payments\/coinbase\/charge\/[^/]+\/?(\?.*)?$/.test(url)
691+
) {
606692
const status = mockBehavior.cryptoStatus || "NEW";
607693
json(res, 200, {
608694
success: true,
609695
data: {
610696
status,
611697
payment: {
612698
status,
613-
amountPaid: status === "UNDERPAID" ? "150.00" : status === "OVERPAID" ? "350.00" : "250.00",
699+
amountPaid:
700+
status === "UNDERPAID"
701+
? "150.00"
702+
: status === "OVERPAID"
703+
? "350.00"
704+
: "250.00",
614705
amountExpected: "250.00",
615706
currency: "USDC",
616707
underpaidAmount: mockBehavior.cryptoUnderpaidAmount || "0",
@@ -622,7 +713,10 @@ async function handleRequest(req, res) {
622713
return;
623714
}
624715

625-
if (method === "GET" && /^\/mock-(telegram|notion|google)-oauth\/?(\?.*)?$/.test(url)) {
716+
if (
717+
method === "GET" &&
718+
/^\/mock-(telegram|notion|google)-oauth\/?(\?.*)?$/.test(url)
719+
) {
626720
html(res, 200, "<html><body><h1>Mock OAuth</h1></body></html>");
627721
return;
628722
}
@@ -633,7 +727,10 @@ async function handleRequest(req, res) {
633727

634728
// Catch-all: fail fast so tests notice missing mock endpoints.
635729
console.log(`[MockServer] UNHANDLED ${method} ${url}`);
636-
json(res, 404, { success: false, error: `Mock server: no handler for ${method} ${url}` });
730+
json(res, 404, {
731+
success: false,
732+
error: `Mock server: no handler for ${method} ${url}`,
733+
});
637734
}
638735

639736
function handleSocketIOMessage(socket, text, sid) {

0 commit comments

Comments
 (0)