Skip to content

Commit 56daeab

Browse files
authored
Simulate TX UI Test (#1202)
1 parent 045f8c4 commit 56daeab

File tree

2 files changed

+260
-0
lines changed

2 files changed

+260
-0
lines changed

src/app/(sidebar)/transaction/simulate/page.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ export default function SimulateTransaction() {
145145
<>
146146
{simulateTxData ? (
147147
<div
148+
data-testid="simulate-tx-response"
148149
className={`PageBody__content PageBody__scrollable ${simulateTxData?.result?.error ? "PageBody__content--error" : ""}`}
149150
>
150151
<PrettyJson json={simulateTxData} />

tests/simulateTransactionPage.test.ts

+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
import { test, expect } from "@playwright/test";
2+
3+
test.describe("Simulate Transaction Page", () => {
4+
test.beforeEach(async ({ page }) => {
5+
await page.goto("http://localhost:3000/transaction/simulate");
6+
});
7+
8+
test("Loads", async ({ page }) => {
9+
await expect(page.locator("h1")).toHaveText("Simulate Transaction");
10+
});
11+
12+
test.describe("Instruction Leeway Input", () => {
13+
test("error when inputting a non whole number", async ({ page }) => {
14+
const instructionLeewayOn = page.getByLabel("Instruction Leeway");
15+
await instructionLeewayOn.fill("aaa");
16+
await expect(page.getByText("Expected a whole number.")).toBeVisible();
17+
});
18+
19+
test("previous response should be removed when inputting a non whole number", async ({
20+
page,
21+
}) => {
22+
const instructionLeewayOn = page.getByLabel("Instruction Leeway");
23+
24+
// Getting a success response
25+
const xdrInput = page.getByLabel(
26+
"Input a base-64 encoded TransactionEnvelope",
27+
);
28+
const txResponseCard = page.getByTestId("simulate-tx-response");
29+
const simulateTxBtn = page.getByRole("button", {
30+
name: "Simulate transaction",
31+
});
32+
33+
await xdrInput.fill(MOCK_VALID_SUCCESS_TX_XDR_RPC);
34+
35+
expect(simulateTxBtn).toBeEnabled();
36+
37+
// Mock the RPC submission api call
38+
await page.route("https://soroban-testnet.stellar.org", async (route) => {
39+
await route.fulfill({
40+
status: 200,
41+
contentType: "application/json",
42+
body: JSON.stringify({
43+
jsonrpc: "2.0",
44+
id: 1,
45+
result: {
46+
status: "SUCCESS",
47+
},
48+
}),
49+
});
50+
});
51+
52+
const responsePromise = page.waitForResponse(
53+
(response) =>
54+
response.url().includes("soroban-testnet") &&
55+
response.status() === 200,
56+
);
57+
58+
await simulateTxBtn.click();
59+
60+
await responsePromise;
61+
62+
await expect(txResponseCard).toBeVisible();
63+
64+
// Typing in the wrong instruction leeway should remove the previous response
65+
await instructionLeewayOn.fill("aaa");
66+
await expect(page.getByText("Expected a whole number.")).toBeVisible();
67+
68+
await expect(txResponseCard).toBeHidden();
69+
});
70+
71+
test("simulate button to be enabled when inputting a whole number for instruction leeway and the correct format xdr", async ({
72+
page,
73+
}) => {
74+
const simulateTxBtn = page.getByRole("button", {
75+
name: "Simulate transaction",
76+
});
77+
const xdrInput = page.getByLabel(
78+
"Input a base-64 encoded TransactionEnvelope",
79+
);
80+
81+
await expect(simulateTxBtn).toBeDisabled();
82+
83+
const instructionLeewayOn = page.getByLabel("Instruction Leeway");
84+
await instructionLeewayOn.fill("23423423");
85+
86+
// inputting the leeway alone isn't enough to enable the simulate tx button
87+
await expect(simulateTxBtn).toBeDisabled();
88+
89+
await xdrInput.fill(MOCK_VALID_SUCCESS_TX_XDR_RPC);
90+
91+
await expect(simulateTxBtn).toBeEnabled();
92+
});
93+
});
94+
95+
test.describe("Invalid XDR Flow", () => {
96+
test("display an error with a random text", async ({ page }) => {
97+
const invalidXdrMsg = page.getByText(
98+
"Unable to parse input XDR into Transaction Envelope",
99+
);
100+
const xdrInput = page.getByLabel(
101+
"Input a base-64 encoded TransactionEnvelope",
102+
);
103+
await xdrInput.fill("ssdfsdf");
104+
await expect(invalidXdrMsg).toBeVisible();
105+
106+
const simulateTxBtn = page.getByRole("button", {
107+
name: "Simulate transaction",
108+
});
109+
110+
await expect(simulateTxBtn).toBeDisabled();
111+
});
112+
113+
test("display an error with a valid XDR that is not TX Envelope", async ({
114+
page,
115+
}) => {
116+
const invalidXdrMsg = page.getByText(
117+
"Unable to parse input XDR into Transaction Envelope",
118+
);
119+
const xdrInput = page.getByLabel(
120+
"Input a base-64 encoded TransactionEnvelope",
121+
);
122+
const simulateTxBtn = page.getByRole("button", {
123+
name: "Simulate transaction",
124+
});
125+
126+
// Simulate transaction button to be disabled by default
127+
await expect(simulateTxBtn).toBeDisabled();
128+
129+
// Input an XDR in correct format
130+
await xdrInput.fill(MOCK_VALID_FAILED_TX_XDR);
131+
132+
// Simulate transaction button to be enabled since the correct XDR input
133+
await expect(simulateTxBtn).toBeEnabled();
134+
135+
// Input an XDR in unsupported format
136+
await xdrInput.fill(MOCK_SC_VAL_XDR);
137+
138+
// Error message to be visible
139+
await expect(invalidXdrMsg).toBeVisible();
140+
141+
// Simulate transaction button to be disabled
142+
await expect(simulateTxBtn).toBeDisabled();
143+
});
144+
});
145+
146+
test.describe("Valid XDR with a Failed 400 Submission Flow", () => {
147+
test("Submit via RPC", async ({ page }) => {
148+
const xdrInput = page.getByLabel(
149+
"Input a base-64 encoded TransactionEnvelope",
150+
);
151+
const txResponseCard = page.getByTestId("simulate-tx-response");
152+
153+
await xdrInput.fill(MOCK_VALID_FAILED_TX_XDR);
154+
155+
const simulateTxBtn = page.getByRole("button", {
156+
name: "Simulate transaction",
157+
});
158+
159+
await expect(simulateTxBtn).toBeEnabled();
160+
161+
// Mock the RPC submission api call
162+
await page.route("https://soroban-testnet.stellar.org", async (route) => {
163+
await route.fulfill({
164+
status: 400,
165+
contentType: "application/json",
166+
body: JSON.stringify(MOCK_TX_XDR_FAILED_RPC_RESPONSE),
167+
});
168+
});
169+
170+
const responsePromise = page.waitForResponse(
171+
(response) =>
172+
response.url().includes("soroban") && response.status() === 400,
173+
);
174+
175+
await simulateTxBtn.click();
176+
177+
await responsePromise;
178+
179+
await expect(txResponseCard).toBeVisible();
180+
181+
const responseText = await txResponseCard.textContent();
182+
183+
expect(responseText).toContain("ERROR");
184+
});
185+
});
186+
187+
test.describe("Valid XDR with a Successful Submission Flow", () => {
188+
test("Submit via RPC", async ({ page }) => {
189+
const xdrInput = page.getByLabel(
190+
"Input a base-64 encoded TransactionEnvelope",
191+
);
192+
const txResponseCard = page.getByTestId("simulate-tx-response");
193+
const simulateTxBtn = page.getByRole("button", {
194+
name: "Simulate transaction",
195+
});
196+
197+
await xdrInput.fill(MOCK_VALID_SUCCESS_TX_XDR_RPC);
198+
199+
expect(simulateTxBtn).toBeEnabled();
200+
201+
// Mock the RPC submission api call
202+
await page.route("https://soroban-testnet.stellar.org", async (route) => {
203+
await route.fulfill({
204+
status: 200,
205+
contentType: "application/json",
206+
body: JSON.stringify({
207+
jsonrpc: "2.0",
208+
id: 1,
209+
result: {
210+
status: "SUCCESS",
211+
},
212+
}),
213+
});
214+
});
215+
216+
const responsePromise = page.waitForResponse(
217+
(response) =>
218+
response.url().includes("soroban-testnet") &&
219+
response.status() === 200,
220+
);
221+
222+
await simulateTxBtn.click();
223+
224+
await responsePromise;
225+
226+
await expect(txResponseCard).toBeVisible();
227+
228+
const responseText = await txResponseCard.textContent();
229+
230+
expect(responseText).toContain("SUCCESS");
231+
232+
// Omitting the API end result because the test gives inconsistenet results
233+
});
234+
});
235+
});
236+
237+
// =============================================================================
238+
// Mock data
239+
// =============================================================================
240+
const MOCK_SC_VAL_XDR =
241+
"AAAAEQAAAAEAAAAGAAAADwAAAAZhbW91bnQAAAAAAAoAAAAAAAAAAAAACRhOcqAAAAAADwAAAAxib290c3RyYXBwZXIAAAASAAAAARssFqxD/prgmYc9vGkaqslWrGlPINzMYTLc4yqRfO3AAAAADwAAAAxjbG9zZV9sZWRnZXIAAAADAz6ilAAAAA8AAAAIcGFpcl9taW4AAAAKAAAAAAAAAAAAAAARdlkuAAAAAA8AAAAEcG9vbAAAABIAAAABX/a7xfliM8nFgGel6pbCM6fT/kqrHAITNtWZQXgDlIIAAAAPAAAAC3Rva2VuX2luZGV4AAAAAAMAAAAA";
242+
243+
const MOCK_VALID_FAILED_TX_XDR =
244+
"AAAAAgAAAADJrq4b4AopDZibkeBWpDxuWKUcY4FUUNQdIEF3Nm9dkQAAAGQAAAIiAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAACXlGN76T6NQcaUJxbEkH3mi1HHWsHnLqMDdlLl9NlJgQAAAAAAAAAABfXhAAAAAAAAAAAA";
245+
246+
const MOCK_VALID_SUCCESS_TX_XDR_RPC =
247+
"AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA=";
248+
249+
const MOCK_TX_XDR_FAILED_RPC_RESPONSE = {
250+
jsonrpc: "2.0",
251+
id: 1,
252+
result: {
253+
errorResultXdr: "AAAAAAAAAGT////7AAAAAA==",
254+
status: "ERROR",
255+
hash: "794e2073e130dc09d2b7e8b147b51f6ef75ff171c83c603bc8ab4cffa3f341a1",
256+
latestLedger: 1305084,
257+
latestLedgerCloseTime: "1733355115",
258+
},
259+
};

0 commit comments

Comments
 (0)