gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant-backoffice] 01/01: Adapt tests to new changes.


From: gnunet
Subject: [taler-merchant-backoffice] 01/01: Adapt tests to new changes.
Date: Sat, 19 Feb 2022 10:56:09 +0100

This is an automated email from the git hooks/post-receive script.

ms pushed a commit to branch master
in repository merchant-backoffice.

commit 838ec0ff5e7331fa4c969837189702bbe6d8d3e4
Author: MS <ms@taler.net>
AuthorDate: Sat Feb 19 10:53:32 2022 +0100

    Adapt tests to new changes.
---
 packages/bank/src/pages/home/index.tsx    |  60 +++++-------
 packages/bank/tests/__tests__/homepage.js | 152 ++++++++++++++++++------------
 2 files changed, 115 insertions(+), 97 deletions(-)

diff --git a/packages/bank/src/pages/home/index.tsx 
b/packages/bank/src/pages/home/index.tsx
index 7318cf3..32aed84 100644
--- a/packages/bank/src/pages/home/index.tsx
+++ b/packages/bank/src/pages/home/index.tsx
@@ -509,18 +509,8 @@ async function createWithdrawalCall(
   try {
     const { username, password } = backendState;
     let headers = prepareHeaders(username, password);
-    /**
-     * NOTE: tests show that when a same object is being
-     * POSTed, caching might prevent same requests from being
-     * made.  Hence, trying to POST twice the same amount might
-     * get silently ignored.
-     *
-     * headers.append("cache-control", "no-store");
-     * headers.append("cache-control", "no-cache");
-     * headers.append("pragma", "no-cache");
-     * */
 
-    // Backend URL must have been stored _with_ a final slash.
+    // Let bank generate withdraw URI:
     const url = new URL(
       `access-api/accounts/${backendState.username}/withdrawals`,
       backendState.url
@@ -562,8 +552,7 @@ async function loginCall(
   req: CredentialsRequestType,
   /**
    * FIXME: figure out if the two following
-   * functions can be retrieved somewhat from
-   * the state.
+   * functions can be retrieved from the state.
    */
   backendStateSetter: StateUpdater<BackendStateTypeOpt>,
   pageStateSetter: StateUpdater<PageStateType>
@@ -572,10 +561,7 @@ async function loginCall(
   /**
    * Optimistically setting the state as 'logged in', and
    * let the Account component request the balance to check
-   * whether the credentials are valid.  If not, then Account
-   * will switch the state back to 'logged out' (and the user
-   * will see again the login/register form).
-   */
+   * whether the credentials are valid.  */
   pageStateSetter((prevState) => ({ ...prevState, isLoggedIn: true }));
   let baseUrl = getRootPath();
   if (!baseUrl.endsWith('/')) {
@@ -635,7 +621,7 @@ async function registrationCall(
     return;
   }
   if (!res.ok) {
-    const errorRaw = JSON.stringify(await res.json());
+    const errorRaw = await res.text();
     console.log(`New registration gave response error (${res.status})`, 
errorRaw);
     pageStateSetter((prevState) => ({
       ...prevState,
@@ -717,7 +703,7 @@ function TalerWithdrawal(Props: any): VNode {
       submitAmount = submitAmount.replace(",", "."); // tolerating comma 
instead of point.
       const re = RegExp(amountRegex)
       if (!re.test(submitAmount)) {
-       console.log("Not withdrawing invalid amount", submitAmount);
+       console.log(`Not withdrawing invalid amount '${submitAmount}'.`);
         return;
       }
       console.log("Valid amount", submitAmount);
@@ -842,9 +828,11 @@ function Transactions(Props: any): VNode {
       }
     }
   }
-  if (!data) return <p>"Transactions page loading..."</p>;
-
-  console.log("History data", data);
+  if (!data) {
+    console.log(`History data of ${accountLabel} not arrived`);
+    return <p>"Transactions page loading..."</p>;
+  }
+  console.log(`History data of ${accountLabel}`, data);
   return <ul>{
     data.transactions.map(function(item: any) {
       const sign = item.direction == "DBIT" ? "-" : "";
@@ -934,6 +922,7 @@ function Account(Props: any): VNode {
    * the outcome.
    */
   if (talerWithdrawUri) {
+    console.log(`Showing withdraw URI: ${talerWithdrawUri}`);
     return (<Fragment>
       <p>Scan the following QR code, and then confirm!</p>
       <div>{QR({text: talerWithdrawUri})}</div>
@@ -1006,6 +995,7 @@ function SWRWithoutCredentials(Props: any): VNode {
  * Show histories of public accounts.
  */
 function PublicHistories(Props: any): VNode {
+  const [showAccount, setShowAccount] = useState<string | undefined>();
   const { data, error } = useSWR("access-api/public-accounts")
   if (typeof error !== "undefined") {
     console.log("account error", error);
@@ -1019,14 +1009,14 @@ function PublicHistories(Props: any): VNode {
     }
   }
   if (!data) return <p>Waiting public accounts list...</p>
-  var txs = {};
+  var txs: any = {};
   var accountsBar = [];
+
+  // Ask first story of all the public accounts.
   for (const account of data.publicAccounts) {
     console.log("Asking transactions for", account.accountLabel)
     accountsBar.push(
-      <li>
-        <a onClick={() => <PublicAccounts showAccount={account.accountLabel} 
/>}>{account.accountLabel}</a>
-      </li>
+      <li><a onClick={() => 
setShowAccount(account.accountLabel)}>{account.accountLabel}</a></li>
     );
     txs[account.accountLabel] = 
       <div>{account.accountLabel} latest transactions:
@@ -1037,14 +1027,13 @@ function PublicHistories(Props: any): VNode {
    * Show the account specified in the props, or just one
    * from the list if that's not given.
    */
-  var showAccount = Props.showAccount
-  if (typeof showAccount === "undefined" && keys(txs).length > 0) {
-    showAccount = keys(txs).pop()
-  }
-
+  if (typeof showAccount === "undefined" && Object.keys(txs).length > 0)
+    setShowAccount(Object.keys(txs).pop());
+  console.log(`Public history tab: ${showAccount}`);
   return <Fragment>
     <ul>{accountsBar}</ul>
     {typeof showAccount !== "undefined" ? txs[showAccount] : <p>No public 
transactions found.</p>}
+    {Props.children}
   </Fragment>;
 }
 
@@ -1070,10 +1059,11 @@ export function BankHome(): VNode {
 
   if (pageState.showPublicHistories) {
     return (<SWRWithoutCredentials baseUrl={getRootPath()}>
-      <PublicHistories />
-      <a onClick={() => {
-        pageStateSetter((prevState: PageStateType) =>
-          ({...prevState, showPublicHistories: false}))}}>Go back</a>
+      <PublicHistories>
+        <a onClick={() => {
+          pageStateSetter((prevState: PageStateType) =>
+            ({...prevState, showPublicHistories: false}))}}>Go back</a>
+      </PublicHistories>
     </SWRWithoutCredentials>);
   }
 
diff --git a/packages/bank/tests/__tests__/homepage.js 
b/packages/bank/tests/__tests__/homepage.js
index 039bab1..9ea0ed4 100644
--- a/packages/bank/tests/__tests__/homepage.js
+++ b/packages/bank/tests/__tests__/homepage.js
@@ -26,35 +26,21 @@ beforeAll(() => {
   global.Storage.prototype.setItem = jest.fn((key, value) => {})
 })
 
-/**
- * Insert username and password into the registration
- * form and returns the submit button.  NOTE: the username
- * must be given always fresh, as it acts as a SWR key and
- * therefore might prevent calls from being made, because of
- * caching reasons.  That is not a problem per-se but can
- * disrupt ".toHaveLastBeenCalledWith()"-like asserts.
- *
- * Return the username and the submit button.
- */
 function fillCredentialsForm() {
   const username = Math.random().toString().substring(2);
   const u = screen.getByPlaceholderText("username");
   const p = screen.getByPlaceholderText("password");
   fireEvent.input(u, {target: {value: username}})
   fireEvent.input(p, {target: {value: "bar"}})
-  const signupButton = screen.getByText("Sign up");
-  const signinButton = screen.getByText("Sign in");
+  const signinButton = screen.getByText("Login");
   return {
     username: username,
-    signupButton: signupButton,
     signinButton: signinButton
   };
 }
 fetchMock.enableMocks();
 
-function signUp(context) {
-  render(<BankHome />);
-  const { username, signupButton } = fillCredentialsForm();
+function mockSuccessLoginOrRegistration() {
   fetch.once("{}", {
     status: 200
   }).once(JSON.stringify({
@@ -64,13 +50,31 @@ function signUp(context) {
     },
     paytoUri: "payto://iban/123/ABC"
   }))
-  fireEvent.click(signupButton);
+}
+
+/**
+ * Render homepage -> navigate to register page -> submit registration.
+ * 'webMock' is called before submission to mock the server response
+ */
+function signUp(context, webMock) {
+  render(<BankHome />);
+  const registerPage = screen.getByText("Register!");
+  fireEvent.click(registerPage);
+  const username = Math.random().toString().substring(2);
+  const u = screen.getByPlaceholderText("username");
+  const p = screen.getByPlaceholderText("password");
+  fireEvent.input(u, {target: {value: username}})
+  fireEvent.input(p, {target: {value: "bar"}})
+  const registerButton = screen.getByText("Register");
+  webMock();
+  fireEvent.click(registerButton);
   context.username = username;
+  return context;
 }
 
 describe("wire transfer", () => {
   beforeEach(() => {
-    signUp({}); // context unused
+    signUp({}, mockSuccessLoginOrRegistration); // context unused
   })
   test("Wire transfer success", async () => {
     const transferButton = screen.getByText("Create wire transfer");
@@ -98,14 +102,16 @@ describe("withdraw", () => {
     cleanup();
   })
 
+
+  let context = {};
   // Register and land on the profile page.
   beforeEach(() => {
-    signUp(context); 
+    context = signUp(context, mockSuccessLoginOrRegistration); 
   })
 
-  let context = {username: null};
-
   test("network failure before withdrawal creation", async () => {
+    const a = screen.getAllByPlaceholderText("amount")[0];
+    fireEvent.input(a, {target: {value: "10"}});
     let withdrawButton = screen.getByText("Charge Taler wallet");
     // mock network failure.
     fetch.mockReject("API is down");
@@ -114,6 +120,8 @@ describe("withdraw", () => {
   })
 
   test("HTTP response error upon withdrawal creation", async () => {
+    const a = screen.getAllByPlaceholderText("amount")[0];
+    fireEvent.input(a, {target: {value: "10,0"}});
     let withdrawButton = screen.getByText("Charge Taler wallet");
     fetch.once("{}", {status: 404});
     fireEvent.click(withdrawButton);
@@ -121,6 +129,8 @@ describe("withdraw", () => {
   })
 
   test("Abort withdrawal", async () => {
+    const a = screen.getAllByPlaceholderText("amount")[0];
+    fireEvent.input(a, {target: {value: "10,0"}});
     let withdrawButton = screen.getByText("Charge Taler wallet");
     fetch.once(JSON.stringify({
       taler_withdraw_uri: "taler://withdraw/foo",
@@ -143,7 +153,9 @@ describe("withdraw", () => {
   })
 
   test("Successful withdrawal creation and confirmation", async () => {
-    let withdrawButton = screen.getByText("Charge Taler wallet");
+    const a = screen.getAllByPlaceholderText("amount")[0];
+    fireEvent.input(a, {target: {value: "10,0"}});
+    let withdrawButton = await screen.findByText("Charge Taler wallet");
     fetch.once(JSON.stringify({
       taler_withdraw_uri: "taler://withdraw/foo",
       withdrawal_id: "foo"
@@ -151,12 +163,11 @@ describe("withdraw", () => {
     /**
      * After triggering a withdrawal, check if the taler://withdraw URI
      * rendered, and confirm if so.  Lastly, check that a success message
-     * appeared on the screen.
-     */
+     * appeared on the screen.  */
     fireEvent.click(withdrawButton);
     expect(fetch).toHaveBeenCalledWith(
       
`http://localhost/demobanks/default/access-api/accounts/${context.username}/withdrawals`,
-      expect.objectContaining({body: JSON.stringify({amount: "EUR:5"})})
+      expect.objectContaining({body: JSON.stringify({amount: "EUR:10.0"})})
     )
     // assume wallet POSTed the payment details.
     const confirmButton = await screen.findByText("confirm withdrawal", 
{exact: false})
@@ -221,7 +232,11 @@ describe("home page", () => {
     cleanup();
   })
   test("public histories", async () => {
-    // Mock list of public accounts.
+    render(<BankHome />);
+    /**
+     * Mock list of public accounts.  'bar' is
+     * the shown account, since it occupies the last
+     * position (and SPA picks it via the 'pop()' method) */
     fetch.once(JSON.stringify({
       "publicAccounts" : [ {
         "balance" : "EUR:1",
@@ -281,53 +296,80 @@ describe("home page", () => {
        date: "2000-01-01"
       }]
     }))
-    render(<BankHome />);
+
+    // Navigate to dedicate public histories page.
+    const publicTxsPage = screen.getByText("transactions");
+    fireEvent.click(publicTxsPage);
+
     /**
-     * Check that transacions data appears on the page.
+     * Check that transactions data appears on the page.
      */
     await screen.findByText("reimbursement", {exact: false});
-    await screen.findByText("refund", {exact: false});
     await screen.findByText("bonus", {exact: false});
-    await screen.findByText("donation", {exact: false});
-
+    /**
+     * The transactions below should not appear, because only
+     * one public account renders.
+     */
+    await waitFor(() => expect(
+      screen.queryByText("refund", {exact: false})).not.toBeInTheDocument());
+    await waitFor(() => expect(
+      screen.queryByText("donation", {exact: false})).not.toBeInTheDocument());
+    /**
+     * First HTTP mock:
+     */
     await expect(fetch).toHaveBeenCalledWith(
       "http://localhost/demobanks/default/access-api/public-accounts";
     )
+    /**
+     * Only expecting this request (second mock), as SWR doesn't let
+     * the unshown history request to the backend:
+     */
     await expect(fetch).toHaveBeenCalledWith(
-      
"http://localhost/demobanks/default/access-api/accounts/foo/transactions?page=0";
+      
"http://localhost/demobanks/default/access-api/accounts/bar/transactions?page=0";
     )
+    /**
+     * Switch tab:
+     */
+    let fooTab = await screen.findByText("foo", {exact: false});
+    fireEvent.click(fooTab);
+    /**
+     * Last two HTTP mocks should render now:
+     */
+    await screen.findByText("refund", {exact: false});
+    await screen.findByText("donation", {exact: false});
+
+    // Expect SWR to have requested 'foo' history
+    // (consuming the last HTTP mock):
     await expect(fetch).toHaveBeenCalledWith(
-      
"http://localhost/demobanks/default/access-api/accounts/bar/transactions?page=0";
+      
"http://localhost/demobanks/default/access-api/accounts/foo/transactions?page=0";
     )
+    let backButton = await screen.findByText("Go back", {exact: false});
+    fireEvent.click(backButton);
+    await waitFor(() => expect(
+      screen.queryByText("donation", {exact: false})).not.toBeInTheDocument());
+    await screen.findByText("welcome to eufin bank", {exact: false})
   })
 
   // check page informs about the current balance
   // after a successful registration.
 
   test("new registration response error 404", async () => {
-    render(<BankHome />);
-    let { username, signupButton } = fillCredentialsForm();
-    fetch.mockResponseOnce("Not found", {status: 404})
-    fireEvent.click(signupButton);
+    var context = signUp({}, () => fetch.mockResponseOnce("Not found", 
{status: 404}));
     await screen.findByText("has a problem", {exact: false});
     expect(fetch).toHaveBeenCalledWith(
       "http://localhost/demobanks/default/access-api/testing/register";,
       expect.objectContaining(
-        {body: JSON.stringify({username: username, password: "bar"}), method: 
"POST"},
+        {body: JSON.stringify({username: context.username, password: "bar"}), 
method: "POST"},
     ))
   })
 
   test("registration network failure", async () => {
-    render(<BankHome />);
-    const { username, signupButton } = fillCredentialsForm();
-    // Mocking network failure.
-    fetch.mockReject("API is down");
-    fireEvent.click(signupButton);
+    let context = signUp({}, ()=>fetch.mockReject("API is down"));
     await screen.findByText("has a problem", {exact: false});
     expect(fetch).toHaveBeenCalledWith(
       "http://localhost/demobanks/default/access-api/testing/register";,
       expect.objectContaining(
-        {body: JSON.stringify({username: username, password: "bar"}), method: 
"POST"}
+        {body: JSON.stringify({username: context.username, password: "bar"}), 
method: "POST"}
       ))
   })
   
@@ -391,7 +433,7 @@ describe("home page", () => {
       `http://localhost/demobanks/default/access-api/accounts/${username}`,
       expect.anything()
     )
-    await screen.findByText("balance is EUR:10", {exact: false})
+    await screen.findByText("balance is 10 EUR", {exact: false})
     // The two transactions in the history mocked above.
     await screen.findByText("refund", {exact: false})
     await screen.findByText("donation", {exact: false})
@@ -402,26 +444,12 @@ describe("home page", () => {
   })
 
   test("registration success", async () => {
-    render(<BankHome />);
-    const { username, signupButton } = fillCredentialsForm();
-    /**
-     * Mock successful registration and balance request.
-     */
-    fetch.once("{}", {
-      status: 200
-    }).once(JSON.stringify({
-      balance: {
-        amount: "EUR:10",
-       credit_debit_indicator: "credit"
-      },
-      paytoUri: "payto://iban/123/ABC"
-    }))
-    fireEvent.click(signupButton);
+    let context = signUp({}, mockSuccessLoginOrRegistration);
     /**
      * Tests that a balance is shown after the successful
      * registration.
      */
-    await screen.findByText("balance is EUR:10", {exact: false})
+    await screen.findByText("balance is 10 EUR", {exact: false})
     /**
      * The expectation below tests whether the account
      * balance was requested after the successful registration.
@@ -431,7 +459,7 @@ describe("home page", () => {
       expect.anything() // no need to match auth headers.
     )
     expect(fetch).toHaveBeenCalledWith(
-      `http://localhost/demobanks/default/access-api/accounts/${username}`,
+      
`http://localhost/demobanks/default/access-api/accounts/${context.username}`,
       expect.anything() // no need to match auth headers.
     )
   })

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]