gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] 01/11: bank: implement login


From: gnunet
Subject: [taler-merchant-backoffice] 01/11: bank: implement login
Date: Mon, 20 Dec 2021 17:44:59 +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 6924c5d75e6db30c7fad9b762f23fb6d78c95700
Author: ms <ms@taler.net>
AuthorDate: Fri Dec 17 23:04:25 2021 +0100

    bank: implement login
---
 packages/bank/src/pages/home/index.tsx    | 92 +++++++++++++++++++++++++------
 packages/bank/tests/__tests__/homepage.js | 55 ++++++++++++++----
 2 files changed, 120 insertions(+), 27 deletions(-)

diff --git a/packages/bank/src/pages/home/index.tsx 
b/packages/bank/src/pages/home/index.tsx
index 9ed70ea..04f01cb 100644
--- a/packages/bank/src/pages/home/index.tsx
+++ b/packages/bank/src/pages/home/index.tsx
@@ -21,7 +21,7 @@ interface BackendStateType {
 /**
  * Request body of /register.
  */
-interface RegistrationRequestType {
+interface CredentialsRequestType {
   username: string;
   password: string;
 }
@@ -181,6 +181,34 @@ async function createWithdrawalOperation(
   }
 }
 
+async function loginCall(
+  req: CredentialsRequestType,
+  /**
+   * FIXME: figure out if the two following
+   * functions can be retrieved somewhat from
+   * the state.
+   */
+  backendStateSetter: StateUpdater<BackendStateTypeOpt>,
+  pageStateSetter: StateUpdater<PageStateType>
+) {
+
+  /**
+   * 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).
+   */
+  pageStateSetter((prevState) => ({ ...prevState, isLoggedIn: true }));
+  backendStateSetter((prevState) => ({
+    ...prevState,
+    url: getRootPath(),
+    username: req.username,
+    password: req.password,
+  }));
+}
+
+
 /**
  * This function requests /register.
  *
@@ -189,7 +217,7 @@ async function createWithdrawalOperation(
  * the page's (to indicate a successful login or a problem).
  */
 async function registrationCall(
-  req: RegistrationRequestType,
+  req: CredentialsRequestType,
   /**
    * FIXME: figure out if the two following
    * functions can be retrieved somewhat from
@@ -213,8 +241,13 @@ async function registrationCall(
     return;
   }
   if (!res.ok) {
+    const errorRaw = await res.text();
     console.log(`New registration gave response error (${res.status})`, 
res.statusText);
-    pageStateSetter((prevState) => ({ ...prevState, hasError: true }));
+    pageStateSetter((prevState) => ({
+      ...prevState,
+      hasError: true,
+      error: errorRaw
+    }));
   } else {
     console.log("Credentials are valid");
     pageStateSetter((prevState) => ({ ...prevState, isLoggedIn: true }));
@@ -237,8 +270,20 @@ async function registrationCall(
 function Account(props: any) {
   const { talerWithdrawUri, accountLabel } = props;
   const { data, error } = useSWR(`accounts/${props.accountLabel}`);
-  if (typeof error != "undefined") {
-    return <p>Account information could not be retrieved</p>
+  console.log("account data", data);
+  console.log("account error", error);
+  if (typeof error !== "undefined") {
+    switch(error.status) {
+      case 404: {
+        return <p>Username was not found</p>
+      }
+      case 401: {
+        return <p>Wrong credentials given</p>
+      }
+      default: {
+        return <p>Account information could not be retrieved.</p>
+      }
+    }
   }
   if (!data) return <p>Retrieving the profile page...</p>;
   /**
@@ -274,7 +319,14 @@ function SWRWithCredentials(props: any): VNode {
     <SWRConfig
       value={{
         fetcher: (url) =>
-          fetch(backendUrl + url || "", { headers: headers }).then((r) => 
r.json()),
+          fetch(backendUrl + url || "", { headers: headers }).then(
+           (r) => {
+             if (!r.ok) {
+               throw {status: r.status, json: r.json()};
+             }
+              return r.json()
+           }
+         ),
       }}
     >
       {props.children}
@@ -337,17 +389,16 @@ export function BankHome(): VNode {
      */
   }
 
-  var registrationData: RegistrationRequestType;
+  var submitData: CredentialsRequestType;
   return (
     <div>
-      <p>Sign up!</p>
       <input
         type="text"
         placeholder="username"
         required
         onInput={(e): void => {
-          registrationData = {
-            ...registrationData,
+          submitData = {
+            ...submitData,
             username: e.currentTarget.value,
           };
         }}
@@ -357,8 +408,8 @@ export function BankHome(): VNode {
         placeholder="password"
         required
         onInput={(e): void => {
-          registrationData = {
-            ...registrationData,
+          submitData = {
+            ...submitData,
             password: e.currentTarget.value,
           };
         }}
@@ -367,13 +418,22 @@ export function BankHome(): VNode {
       <button
         onClick={() => {
           registrationCall(
-            registrationData,
+            submitData,
             backendStateSetter,
             pageStateSetter
           );
-        }}
-      >
-        Submit
+        }}>
+        Sign up
+      </button>
+      <button
+        onClick={() => {
+          loginCall(
+            submitData,
+            backendStateSetter,
+            pageStateSetter
+          );
+        }}>
+        Sign in 
       </button>
     </div>
   );
diff --git a/packages/bank/tests/__tests__/homepage.js 
b/packages/bank/tests/__tests__/homepage.js
index 03a909d..46c6ae8 100644
--- a/packages/bank/tests/__tests__/homepage.js
+++ b/packages/bank/tests/__tests__/homepage.js
@@ -16,14 +16,19 @@ import fetchMock from "jest-fetch-mock";
  *
  * Return the username and the submit button.
  */
-function fillRegistrationForm() {
+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 submitButton = screen.getByText("Submit");
-  return {username: username, submitButton: submitButton};
+  const signupButton = screen.getByText("Sign up");
+  const signinButton = screen.getByText("Sign in");
+  return {
+    username: username,
+    signupButton: signupButton,
+    signinButton: signinButton
+  };
 }
 fetchMock.enableMocks();
 
@@ -36,7 +41,7 @@ describe("withdraw", () => {
   // Register and land on the profile page.
   beforeEach(() => {
     render(<BankHome />);
-    const { username, submitButton } = fillRegistrationForm();
+    const { username, signupButton } = fillCredentialsForm();
     fetch.once("{}", {
       status: 200
     }).once(JSON.stringify({
@@ -46,7 +51,7 @@ describe("withdraw", () => {
       },
       paytoUri: "payto://iban/123/ABC"
     }))
-    fireEvent.click(submitButton);
+    fireEvent.click(signupButton);
   })
 
   test("network failure before withdrawal creation", async () => {
@@ -84,9 +89,9 @@ describe("home page", () => {
 
   test("new registration response error 404", async () => {
     render(<BankHome />);
-    let { username, submitButton } = fillRegistrationForm();
+    let { username, signupButton } = fillCredentialsForm();
     fetch.mockResponseOnce("Not found", {status: 404})
-    fireEvent.click(submitButton);
+    fireEvent.click(signupButton);
     await screen.findByText("has a problem", {exact: false});
     expect(fetch).toHaveBeenCalledWith(
       "http://localhost/testing/register";,
@@ -96,10 +101,10 @@ describe("home page", () => {
 
   test("registration network failure", async () => {
     render(<BankHome />);
-    const { username, submitButton } = fillRegistrationForm();
+    const { username, signupButton } = fillCredentialsForm();
     // Mocking network failure.
     fetch.mockReject("API is down");
-    fireEvent.click(submitButton);
+    fireEvent.click(signupButton);
     await screen.findByText("has a problem", {exact: false});
     expect(fetch).toHaveBeenCalledWith(
       "http://localhost/testing/register";,
@@ -107,9 +112,37 @@ describe("home page", () => {
     )
   })
   
+  test("login non existent user", async () => {
+    render(<BankHome />);
+    const { username, signinButton } = fillCredentialsForm();
+    fetch.once("{}", {status: 404});
+    fireEvent.click(signinButton);
+    await screen.findByText("username was not found", {exact: false})
+  })
+  test("login wrong credentials", async () => {
+    render(<BankHome />);
+    const { username, signinButton } = fillCredentialsForm();
+    fetch.once("{}", {status: 401});
+    fireEvent.click(signinButton);
+    await screen.findByText("wrong credentials given", {exact: false})
+  })
+  test("login success", async () => {
+    render(<BankHome />);
+    const { username, signinButton } = fillCredentialsForm();
+    fetch.once(JSON.stringify({
+      balance: {
+        amount: "EUR:10",
+       credit_debit_indicator: "credit"
+      },
+      paytoUri: "payto://iban/123/ABC"
+    }))
+    fireEvent.click(signinButton);
+    await screen.findByText("balance is EUR:10", {exact: false})
+  })
+
   test("registration success", async () => {
     render(<BankHome />);
-    const { username, submitButton } = fillRegistrationForm();
+    const { username, signupButton } = fillCredentialsForm();
     /**
      * Mock successful registration and balance request.
      */
@@ -122,7 +155,7 @@ describe("home page", () => {
       },
       paytoUri: "payto://iban/123/ABC"
     }))
-    fireEvent.click(submitButton);
+    fireEvent.click(signupButton);
     /**
      * Tests that a balance is shown after the successful
      * registration.

-- 
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]