This commit is contained in:
Sebastian 2022-12-22 18:40:38 -03:00
parent 6fd7756329
commit 5c84c32736
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
7 changed files with 569 additions and 1204 deletions

View File

@ -20,7 +20,11 @@ import { useEffect } from "preact/hooks";
import useSWR from "swr"; import useSWR from "swr";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState({ accountLabel, pageNumber, balanceValue }: Props): State { export function useComponentState({
accountLabel,
pageNumber,
balanceValue,
}: Props): State {
const { data, error, mutate } = useSWR( const { data, error, mutate } = useSWR(
`access-api/accounts/${accountLabel}/transactions?page=${pageNumber}`, `access-api/accounts/${accountLabel}/transactions?page=${pageNumber}`,
); );
@ -39,40 +43,41 @@ export function useComponentState({ accountLabel, pageNumber, balanceValue }: Pr
error: { error: {
hasError: true, hasError: true,
operational: false, operational: false,
message: `Transactions page ${pageNumber} was not found.` message: `Transactions page ${pageNumber} was not found.`,
} },
} };
case 401: case 401:
return { return {
status: "loading-error", status: "loading-error",
error: { error: {
hasError: true, hasError: true,
operational: false, operational: false,
message: "Wrong credentials given." message: "Wrong credentials given.",
} },
} };
default: default:
return { return {
status: "loading-error", status: "loading-error",
error: { error: {
hasError: true, hasError: true,
operational: false, operational: false,
message: `Transaction page ${pageNumber} could not be retrieved.` message: `Transaction page ${pageNumber} could not be retrieved.`,
} as any } as any,
} };
} }
} }
if (!data) { if (!data) {
return { return {
status: "loading", status: "loading",
error: undefined error: undefined,
} };
} }
const transactions = data.transactions.map((item: unknown) => { const transactions = data.transactions.map((item: unknown) => {
if (!item || typeof item !== "object" || if (
!item ||
typeof item !== "object" ||
!("direction" in item) || !("direction" in item) ||
!("creditorIban" in item) || !("creditorIban" in item) ||
!("debtorIban" in item) || !("debtorIban" in item) ||
@ -86,12 +91,12 @@ export function useComponentState({ accountLabel, pageNumber, balanceValue }: Pr
} }
const anyItem = item as any; const anyItem = item as any;
if ( if (
!(typeof anyItem.creditorIban === 'string') || !(typeof anyItem.creditorIban === "string") ||
!(typeof anyItem.debtorIban === 'string') || !(typeof anyItem.debtorIban === "string") ||
!(typeof anyItem.date === 'string') || !(typeof anyItem.date === "string") ||
!(typeof anyItem.subject === 'string') || !(typeof anyItem.subject === "string") ||
!(typeof anyItem.currency === 'string') || !(typeof anyItem.currency === "string") ||
!(typeof anyItem.amount === 'string') !(typeof anyItem.amount === "string")
) { ) {
return; return;
} }
@ -109,11 +114,11 @@ export function useComponentState({ accountLabel, pageNumber, balanceValue }: Pr
? `${dateParse[3]}/${dateParse[2]} ${dateParse[1]}` ? `${dateParse[3]}/${dateParse[2]} ${dateParse[1]}`
: undefined; : undefined;
const date = parse(dateStr ?? "", "dd/MM yyyy", new Date()) const date = parse(dateStr ?? "", "dd/MM yyyy", new Date());
const when: AbsoluteTime = { const when: AbsoluteTime = {
t_ms: date.getTime() t_ms: date.getTime(),
} };
const amount = Amounts.parse(`${anyItem.currency}:${anyItem.amount}`); const amount = Amounts.parse(`${anyItem.currency}:${anyItem.amount}`);
const subject = anyItem.subject; const subject = anyItem.subject;
return { return {
@ -122,7 +127,7 @@ export function useComponentState({ accountLabel, pageNumber, balanceValue }: Pr
when, when,
amount, amount,
subject, subject,
} };
}); });
return { return {

View File

@ -26,149 +26,157 @@ import { TRANSACTION_API_EXAMPLE } from "../../endpoints.js";
import { Props } from "./index.js"; import { Props } from "./index.js";
import { useComponentState } from "./state.js"; import { useComponentState } from "./state.js";
describe("Transaction states", () => { describe("Transaction states", () => {
it("should query backend and render transactions", async () => { it("should query backend and render transactions", async () => {
const env = new SwrMockEnvironment(); const env = new SwrMockEnvironment();
const props: Props = { const props: Props = {
accountLabel: "myAccount", accountLabel: "myAccount",
pageNumber: 0 pageNumber: 0,
} };
env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_FIRST_PAGE, { env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_FIRST_PAGE, {
response: { response: {
"transactions": [ transactions: [
{ {
"creditorIban": "DE159593", creditorIban: "DE159593",
"creditorBic": "SANDBOXX", creditorBic: "SANDBOXX",
"creditorName": "exchange company", creditorName: "exchange company",
"debtorIban": "DE118695", debtorIban: "DE118695",
"debtorBic": "SANDBOXX", debtorBic: "SANDBOXX",
"debtorName": "Name unknown", debtorName: "Name unknown",
"amount": "1", amount: "1",
"currency": "KUDOS", currency: "KUDOS",
"subject": "Taler Withdrawal N588V8XE9TR49HKAXFQ20P0EQ0EYW2AC9NNANV8ZP5P59N6N0410", subject:
"date": "2022-12-12Z", "Taler Withdrawal N588V8XE9TR49HKAXFQ20P0EQ0EYW2AC9NNANV8ZP5P59N6N0410",
"uid": "8PPFR9EM", date: "2022-12-12Z",
"direction": "DBIT", uid: "8PPFR9EM",
"pmtInfId": null, direction: "DBIT",
"msgId": null pmtInfId: null,
msgId: null,
}, },
{ {
"creditorIban": "DE159593", creditorIban: "DE159593",
"creditorBic": "SANDBOXX", creditorBic: "SANDBOXX",
"creditorName": "exchange company", creditorName: "exchange company",
"debtorIban": "DE118695", debtorIban: "DE118695",
"debtorBic": "SANDBOXX", debtorBic: "SANDBOXX",
"debtorName": "Name unknown", debtorName: "Name unknown",
"amount": "5.00", amount: "5.00",
"currency": "KUDOS", currency: "KUDOS",
"subject": "HNEWWT679TQC5P1BVXJS48FX9NW18FWM6PTK2N80Z8GVT0ACGNK0", subject: "HNEWWT679TQC5P1BVXJS48FX9NW18FWM6PTK2N80Z8GVT0ACGNK0",
"date": "2022-12-07Z", date: "2022-12-07Z",
"uid": "7FZJC3RJ", uid: "7FZJC3RJ",
"direction": "DBIT", direction: "DBIT",
"pmtInfId": null, pmtInfId: null,
"msgId": null msgId: null,
}, },
{ {
"creditorIban": "DE118695", creditorIban: "DE118695",
"creditorBic": "SANDBOXX", creditorBic: "SANDBOXX",
"creditorName": "Name unknown", creditorName: "Name unknown",
"debtorIban": "DE579516", debtorIban: "DE579516",
"debtorBic": "SANDBOXX", debtorBic: "SANDBOXX",
"debtorName": "The Bank", debtorName: "The Bank",
"amount": "100", amount: "100",
"currency": "KUDOS", currency: "KUDOS",
"subject": "Sign-up bonus", subject: "Sign-up bonus",
"date": "2022-12-07Z", date: "2022-12-07Z",
"uid": "I31A06J8", uid: "I31A06J8",
"direction": "CRDT", direction: "CRDT",
"pmtInfId": null, pmtInfId: null,
"msgId": null msgId: null,
} },
] ],
} },
}); });
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ const hookBehavior = await tests.hookBehaveLikeThis(
({ status, error }) => { useComponentState,
props,
[
({ status, error }) => {
expect(status).equals("loading");
expect(error).undefined;
},
({ status, error }) => {
expect(status).equals("ready");
expect(error).undefined;
},
],
env.buildTestingContext(),
);
expect(status).equals("loading"); expect(hookBehavior).deep.eq({ result: "ok" });
expect(error).undefined;
},
({ status, error }) => {
expect(status).equals("ready"); expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
expect(error).undefined;
},
], env.buildTestingContext())
expect(hookBehavior).deep.eq({ result: "ok" })
expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" })
}); });
it("should show error message on not found", async () => { it("should show error message on not found", async () => {
const env = new SwrMockEnvironment(); const env = new SwrMockEnvironment();
const props: Props = { const props: Props = {
accountLabel: "myAccount", accountLabel: "myAccount",
pageNumber: 0 pageNumber: 0,
} };
env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_NOT_FOUND, {}); env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_NOT_FOUND, {});
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ const hookBehavior = await tests.hookBehaveLikeThis(
({ status, error }) => { useComponentState,
expect(status).equals("loading"); props,
expect(error).undefined; [
}, ({ status, error }) => {
({ status, error }) => { expect(status).equals("loading");
expect(status).equals("loading-error"); expect(error).undefined;
expect(error).deep.eq({ },
hasError: true, ({ status, error }) => {
operational: false, expect(status).equals("loading-error");
message: "Transactions page 0 was not found." expect(error).deep.eq({
}); hasError: true,
}, operational: false,
], env.buildTestingContext()) message: "Transactions page 0 was not found.",
});
},
],
env.buildTestingContext(),
);
expect(hookBehavior).deep.eq({ result: "ok" }) expect(hookBehavior).deep.eq({ result: "ok" });
expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" }) expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
}); });
it("should show error message on server error", async () => { it("should show error message on server error", async () => {
const env = new SwrMockEnvironment(false); const env = new SwrMockEnvironment(false);
const props: Props = { const props: Props = {
accountLabel: "myAccount", accountLabel: "myAccount",
pageNumber: 0 pageNumber: 0,
} };
env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_ERROR, {}); env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_ERROR, {});
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ const hookBehavior = await tests.hookBehaveLikeThis(
({ status, error }) => { useComponentState,
expect(status).equals("loading"); props,
expect(error).undefined; [
}, ({ status, error }) => {
({ status, error }) => { expect(status).equals("loading");
expect(status).equals("loading-error"); expect(error).undefined;
expect(error).deep.equal({ },
hasError: true, ({ status, error }) => {
operational: false, expect(status).equals("loading-error");
message: "Transaction page 0 could not be retrieved." expect(error).deep.equal({
}); hasError: true,
}, operational: false,
], env.buildTestingContext()) message: "Transaction page 0 could not be retrieved.",
});
},
],
env.buildTestingContext(),
);
expect(hookBehavior).deep.eq({ result: "ok" }) expect(hookBehavior).deep.eq({ result: "ok" });
expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" }) expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
}); });
}); });

View File

@ -14,4 +14,4 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
export * as tx from "./Transactions/stories.js"; export * as tx from "./Transactions/stories.js";

View File

@ -27,11 +27,11 @@ export const TRANSACTION_API_EXAMPLE = {
LIST_ERROR: { LIST_ERROR: {
method: "get" as const, method: "get" as const,
url: "access-api/accounts/myAccount/transactions?page=0", url: "access-api/accounts/myAccount/transactions?page=0",
code: 500 code: 500,
}, },
LIST_NOT_FOUND: { LIST_NOT_FOUND: {
method: "get" as const, method: "get" as const,
url: "access-api/accounts/myAccount/transactions?page=0", url: "access-api/accounts/myAccount/transactions?page=0",
code: 404 code: 404,
} },
} };

View File

@ -20,7 +20,10 @@
*/ */
import { StateUpdater } from "preact/hooks"; import { StateUpdater } from "preact/hooks";
import { useLocalStorage, useNotNullLocalStorage } from "@gnu-taler/web-util/lib/index.browser"; import {
useLocalStorage,
useNotNullLocalStorage,
} from "@gnu-taler/web-util/lib/index.browser";
export type ValueOrFunction<T> = T | ((p: T) => T); export type ValueOrFunction<T> = T | ((p: T) => T);
const calculateRootPath = () => { const calculateRootPath = () => {

File diff suppressed because it is too large Load Diff

View File

@ -24,12 +24,11 @@ import { parseGroupImport } from "@gnu-taler/web-util/lib/index.browser";
import * as pages from "./pages/index.stories.js"; import * as pages from "./pages/index.stories.js";
import * as components from "./components/index.examples.js"; import * as components from "./components/index.examples.js";
import { h as create } from "preact" import { h as create } from "preact";
import { render as renderToString } from "preact-render-to-string"; import { render as renderToString } from "preact-render-to-string";
setupI18n("en", { en: {} }); setupI18n("en", { en: {} });
describe("All the examples:", () => { describe("All the examples:", () => {
const cms = parseGroupImport({ pages, components }); const cms = parseGroupImport({ pages, components });
cms.forEach((group) => { cms.forEach((group) => {
@ -38,8 +37,11 @@ describe("All the examples:", () => {
describe(`Component ${component.name}:`, () => { describe(`Component ${component.name}:`, () => {
component.examples.forEach((example) => { component.examples.forEach((example) => {
it(`should render example: ${example.name}`, () => { it(`should render example: ${example.name}`, () => {
const vdom = create(example.render.component, example.render.props) const vdom = create(
const html = renderToString(vdom) example.render.component,
example.render.props,
);
const html = renderToString(vdom);
// console.log(html) // console.log(html)
}); });
}); });