Repository navigation
Expand file tree
/
Copy pathaccountController.test.js
More file actions
176 lines (139 loc) · 5.78 KB
/
Copy pathaccountController.test.js
File metadata and controls
176 lines (139 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
"use strict";
const express = require("express");
const request = require("supertest");
const accountController = require("../src/controllers/accountController");
const stellarService = require("../src/services/stellarService");
const usernameService = require("../src/services/usernameService");
jest.mock("../src/services/stellarService");
jest.mock("../src/services/usernameService");
function setupApp() {
const app = express();
app.use(express.json());
app.get("/api/accounts/resolve/:username", accountController.resolveUsername);
app.get("/api/accounts/:publicKey/balance", accountController.getBalance);
app.get("/api/accounts/:publicKey", accountController.getAccount);
app.post("/api/accounts/register", accountController.registerUsername);
// Standard error handler resembling the one in server.js
app.use((err, req, res, next) => {
const status = err.status || 500;
const message = err.message || "Internal Server Error";
res.status(status).json({ error: message });
});
return app;
}
describe("accountController", () => {
const app = setupApp();
beforeEach(() => {
jest.clearAllMocks();
});
describe("getAccount", () => {
it("returns account info for a valid public key", async () => {
const mockAccount = { id: "G_VALID", balances: [] };
stellarService.getAccount.mockResolvedValue(mockAccount);
const res = await request(app).get("/api/accounts/G_VALID");
expect(res.status).toBe(200);
expect(res.body).toEqual({
success: true,
data: mockAccount
});
expect(stellarService.getAccount).toHaveBeenCalledWith("G_VALID");
});
it("returns 404 for a nonexistent account", async () => {
const notFoundError = new Error("Account not found");
notFoundError.status = 404;
stellarService.getAccount.mockRejectedValue(notFoundError);
const res = await request(app).get("/api/accounts/G_MISSING");
expect(res.status).toBe(404);
expect(res.body).toEqual({
error: "Account not found"
});
});
it("propagates stellarService errors as the documented error response", async () => {
const serverError = new Error("Stellar network error");
serverError.status = 503;
stellarService.getAccount.mockRejectedValue(serverError);
const res = await request(app).get("/api/accounts/G_ERROR");
expect(res.status).toBe(503);
expect(res.body).toEqual({
error: "Stellar network error"
});
});
});
describe("getBalance", () => {
it("returns balance info for a valid public key", async () => {
stellarService.getXLMBalance.mockResolvedValue("100.00");
const res = await request(app).get("/api/accounts/G_VALID/balance");
expect(res.status).toBe(200);
expect(res.body).toEqual({
success: true,
data: { publicKey: "G_VALID", xlm: "100.00" }
});
expect(stellarService.getXLMBalance).toHaveBeenCalledWith("G_VALID");
});
it("propagates errors from stellarService", async () => {
const err = new Error("Failed to get balance");
err.status = 400;
stellarService.getXLMBalance.mockRejectedValue(err);
const res = await request(app).get("/api/accounts/G_ERROR/balance");
expect(res.status).toBe(400);
expect(res.body).toEqual({ error: "Failed to get balance" });
});
});
describe("registerUsername", () => {
it("returns 400 if username or publicKey is missing", async () => {
const res = await request(app).post("/api/accounts/register").send({ username: "alice" });
expect(res.status).toBe(400);
expect(res.body).toEqual({
success: false,
error: "Username and public key are required"
});
});
it("registers a username successfully", async () => {
usernameService.registerUsername.mockReturnValue({ username: "alice", publicKey: "G_VALID" });
const res = await request(app)
.post("/api/accounts/register")
.send({ username: "alice", publicKey: "G_VALID" });
expect(res.status).toBe(201);
expect(res.body).toEqual({
success: true,
data: { username: "alice", publicKey: "G_VALID" },
message: "Username registered successfully"
});
expect(usernameService.registerUsername).toHaveBeenCalledWith("alice", "G_VALID");
});
it("propagates errors from usernameService", async () => {
usernameService.registerUsername.mockImplementation(() => {
const err = new Error("Username already taken");
err.status = 409;
throw err; // usernameService methods appear to be synchronous in the controller
});
const res = await request(app)
.post("/api/accounts/register")
.send({ username: "bob", publicKey: "G_VALID" });
expect(res.status).toBe(409);
expect(res.body).toEqual({ error: "Username already taken" });
});
});
describe("resolveUsername", () => {
it("resolves a username to its associated public key", async () => {
usernameService.resolveUsername.mockReturnValue({ publicKey: "G_VALID" });
const res = await request(app).get("/api/accounts/resolve/bob");
expect(res.status).toBe(200);
expect(res.body).toEqual({
success: true,
data: { publicKey: "G_VALID" }
});
expect(usernameService.resolveUsername).toHaveBeenCalledWith("bob");
});
it("propagates errors when username cannot be resolved", async () => {
usernameService.resolveUsername.mockImplementation(() => {
const err = new Error("Username not found");
err.status = 404;
throw err;
});
const res = await request(app).get("/api/accounts/resolve/unknown");
expect(res.status).toBe(404);
expect(res.body).toEqual({ error: "Username not found" });
});
});
});