merchant-backoffice

ZZZ: Inactive/Deprecated
Log | Files | Refs | Submodules | README

commit 6924c5d75e6db30c7fad9b762f23fb6d78c95700
parent aa05541c627b9fb5ee066980292805e6ee84da34
Author: ms <ms@taler.net>
Date:   Fri, 17 Dec 2021 23:04:25 +0100

bank: implement login

Diffstat:
Mpackages/bank/src/pages/home/index.tsx | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mpackages/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 @@ -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 @@ -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.