diff options
Diffstat (limited to 'packages/anastasis-webui/src')
49 files changed, 889 insertions, 1000 deletions
diff --git a/packages/anastasis-webui/src/components/menu/SideBar.tsx b/packages/anastasis-webui/src/components/menu/SideBar.tsx index 3dac73e04..31bc3c7a7 100644 --- a/packages/anastasis-webui/src/components/menu/SideBar.tsx +++ b/packages/anastasis-webui/src/components/menu/SideBar.tsx @@ -29,7 +29,10 @@ interface Props { } const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "dev"; -const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined; +const GIT_HASH = + typeof __GIT_HASH__ !== "undefined" + ? __GIT_HASH__.substring(0, 7) + : undefined; const VERSION_WITH_HASH = GIT_HASH ? `${VERSION}-${GIT_HASH}` : VERSION; export function Sidebar({ mobile }: Props): VNode { diff --git a/packages/anastasis-webui/src/components/menu/index.tsx b/packages/anastasis-webui/src/components/menu/index.tsx index b1d22eeb4..957ab2977 100644 --- a/packages/anastasis-webui/src/components/menu/index.tsx +++ b/packages/anastasis-webui/src/components/menu/index.tsx @@ -15,7 +15,7 @@ */ import { ComponentChildren, Fragment, h, VNode } from "preact"; -import Match from "preact-router/match"; +import { Match } from "preact-router/match.js"; import { useEffect, useState } from "preact/hooks"; import { NavigationBar } from "./NavigationBar.js"; import { Sidebar } from "./SideBar.js"; diff --git a/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx b/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx index 0339c9ec0..94bce4038 100644 --- a/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx +++ b/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx @@ -22,6 +22,7 @@ import { h, FunctionalComponent } from "preact"; import { useState } from "preact/hooks"; import { DurationPicker as TestedComponent } from "./DurationPicker.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { component: TestedComponent, @@ -31,16 +32,7 @@ export default { }, }; -function createExample<Props>( - Component: FunctionalComponent<Props>, - props: Partial<Props>, -) { - const r = (args: any) => <Component {...args} />; - r.args = props; - return r; -} - -export const Example = createExample(TestedComponent, { +export const Example = tests.createExample(TestedComponent, { days: true, minutes: true, hours: true, diff --git a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts index 3ad563ee6..fcc380775 100644 --- a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts +++ b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts @@ -136,6 +136,7 @@ export interface DiscoveryUiState { export interface AnastasisReducerApi { currentReducerState: ReducerState | undefined; + // FIXME: Explain better! currentError: any; discoveryState: DiscoveryUiState; dismissError: () => void; @@ -302,7 +303,7 @@ export function useAnastasisReducer(): AnastasisReducerApi { }, }); } catch (e) { - throw Error("could not restore the state"); + throw new Error("could not restore the state"); } }, async discoverStart(): Promise<void> { @@ -398,7 +399,7 @@ export function useAnastasisReducer(): AnastasisReducerApi { } class ReducerTxImpl implements ReducerTransactionHandle { - constructor(public transactionState: ReducerState) { } + constructor(public transactionState: ReducerState) {} async transition(action: string, args: any): Promise<ReducerState> { let s: ReducerState; if (remoteReducer) { @@ -409,7 +410,7 @@ class ReducerTxImpl implements ReducerTransactionHandle { this.transactionState = s; // Abort transaction as soon as we transition into an error state. if (this.transactionState.reducer_type === "error") { - throw Error("transition resulted in error"); + throw new Error("transition resulted in error"); } return this.transactionState; } diff --git a/packages/anastasis-webui/src/index.html b/packages/anastasis-webui/src/index.html index 90a795ae3..d64b627e4 100644 --- a/packages/anastasis-webui/src/index.html +++ b/packages/anastasis-webui/src/index.html @@ -32,7 +32,7 @@ /> <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" /> <title>Anastasis</title> - <!-- Entry point for the demobank SPA. --> + <!-- Entry point for the SPA. --> <script type="module" src="index.js"></script> <link rel="stylesheet" href="index.css" /> </head> diff --git a/packages/anastasis-webui/src/index.test.ts b/packages/anastasis-webui/src/index.test.ts index 1a87e3857..2f865bc1d 100644 --- a/packages/anastasis-webui/src/index.test.ts +++ b/packages/anastasis-webui/src/index.test.ts @@ -19,31 +19,64 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { setupI18n } from "@gnu-taler/taler-util"; -import { renderNodeOrBrowser } from "./test-utils.js"; -import * as pages from "./pages/home/index.storiesNo.js"; +import { parseGroupImport } from "@gnu-taler/web-util/browser"; +import * as tests from "@gnu-taler/web-util/testing"; +import * as pages from "./pages/home/index.stories.js"; +import { ComponentChildren, VNode, h as create } from "preact"; +import { AnastasisProvider } from "./context/anastasis.js"; +import { AnastasisReducerApi } from "./hooks/use-anastasis-reducer.js"; +import { ReducerState } from "@gnu-taler/anastasis-core"; setupI18n("en", { en: {} }); -function testThisStory(key: string, st: any): any { - describe(`render examples for ${key}`, () => { - Object.keys(st).forEach((k) => { - const Component = (st as any)[k]; - if (k === "default" || !Component) return; - - it(`example: ${k}`, () => { - renderNodeOrBrowser(Component, Component.args); +describe("All the examples:", () => { + const cms = parseGroupImport({ pages }); + cms.forEach((group) => { + describe(`Example for group "${group.title}":`, () => { + group.list.forEach((component) => { + describe(`Component ${component.name}:`, () => { + component.examples.forEach((example) => { + it(`should render example: ${example.name}`, () => { + tests.renderUI(example.render, DefaultTestingContext); + }); + }); + }); }); }); }); -} - -describe("render every storybook example", () => { - Object.entries(pages).forEach(function testAll([key, value]) { - const st: any = value; - if (Array.isArray(st.default)) { - st.default.forEach(testAll); - } else { - testThisStory(key, st); - } - }); }); + +const noop = async (): Promise<void> => { + return; +}; + +function DefaultTestingContext({ + children, + ...rest +}: { + children: ComponentChildren; +}): VNode { + //some UI example can specify the state of the reducer + const currentReducerState = rest as ReducerState; + const value: AnastasisReducerApi = { + currentReducerState, + discoverMore: noop, + discoverStart: noop, + discoveryState: { + state: "finished", + }, + currentError: undefined, + back: noop, + dismissError: noop, + reset: noop, + runTransaction: noop, + startBackup: noop, + startRecover: noop, + transition: noop, + exportState: () => { + return "{}"; + }, + importState: noop, + }; + return create(AnastasisProvider, { value, children }); +} diff --git a/packages/anastasis-webui/src/index.ts b/packages/anastasis-webui/src/index.ts index d7b2164ab..f614e4f54 100644 --- a/packages/anastasis-webui/src/index.ts +++ b/packages/anastasis-webui/src/index.ts @@ -22,7 +22,7 @@ function main(): void { try { const container = document.getElementById("container"); if (!container) { - throw Error("container not found, can't mount page contents"); + throw new Error("container not found, can't mount page contents"); } render(h(App, {}), container); } catch (e) { diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts index 0ab275f54..ed8301d65 100644 --- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts +++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts @@ -24,7 +24,7 @@ import { WithoutProviderType, WithProviderType } from "./views.js"; export type AuthProvByStatusMap = Record< AuthenticationProviderStatus["status"], (AuthenticationProviderStatus & { url: string })[] -> +>; export type State = NoReducer | InvalidState | WithType | WithoutType; @@ -63,42 +63,69 @@ const map: StateViewMap<State> = { "without-type": WithoutProviderType, }; -export default compose("AddingProviderScreen", useComponentState, map) - +export default compose("AddingProviderScreen", useComponentState, map); +const providerResponseCache = new Map<string, any>(); // `any` is the return type of res.json() export async function testProvider( url: string, expectedMethodType?: string, ): Promise<void> { + const testFatalPrefix = `Encountered a fatal error whilst testing the provider ${url}`; + let configUrl = ""; try { - const response = await fetch(new URL("config", url).href); - const json = await response.json().catch((d) => ({})); - if (!("methods" in json) || !Array.isArray(json.methods)) { - throw Error( - "This provider doesn't have authentication method. Check the provider URL", - ); - } - if (!expectedMethodType) { - return; - } - let found = false; - for (let i = 0; i < json.methods.length && !found; i++) { - found = json.methods[i].type === expectedMethodType; - } - if (!found) { - throw Error( - `This provider does not support authentication method ${expectedMethodType}`, - ); - } + configUrl = new URL("config", url).href; + } catch (error) { + throw new Error(`${testFatalPrefix}: Invalid Provider URL: ${url} +Error: ${error}`); + } + // TODO: look into using core.getProviderInfo :) + const providerHasUrl = providerResponseCache.has(url); + const json = providerHasUrl + ? providerResponseCache.get(url) + : await fetch(configUrl) + .catch((error) => { + throw new Error(`${testFatalPrefix}: Could not connect: ${error} +Please check the URL.`); + }) + .then(async (response) => { + if (!response.ok) + throw new Error( + `${testFatalPrefix}: The server ${response.url} responded with a non-2xx response.`, + ); + try { + return await response.json(); + } catch (error) { + throw new Error( + `${testFatalPrefix}: The server responded with malformed JSON.\nError: ${error}`, + ); + } + }); + if (typeof json !== "object") + throw new Error( + `${testFatalPrefix}: Did not get an object after decoding.`, + ); + if (!("name" in json) || json.name !== "anastasis") { + throw new Error( + `${testFatalPrefix}: The provider does not appear to be an Anastasis provider. Please check the provider's URL.`, + ); + } + if (!("methods" in json) || !Array.isArray(json.methods)) { + throw new Error( + "This provider doesn't have authentication method. Please check the provider's URL and ensure it is properly configured.", + ); + } + if (!providerHasUrl) providerResponseCache.set(url, json); + if (!expectedMethodType) { return; - } catch (e) { - console.log("ERROR testProvider", e); - const error = - e instanceof Error - ? Error( - `There was an error testing this provider, try another one. ${e.message}`, - ) - : Error(`There was an error testing this provider, try another one.`); - throw error; } + let found = false; + for (let i = 0; i < json.methods.length && !found; i++) { + found = json.methods[i].type === expectedMethodType; + } + if (!found) { + throw new Error( + `${testFatalPrefix}: This provider does not support authentication method ${expectedMethodType}`, + ); + } + return; } diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts index 009ab20a2..30e4d750d 100644 --- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts +++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts @@ -25,7 +25,11 @@ interface Props { notifications?: Notification[]; } -export default function useComponentState({ providerType, onCancel, notifications = [] }: Props): State { +export default function useComponentState({ + providerType, + onCancel, + notifications = [], +}: Props): State { const reducer = useAnastasisContext(); const [providerURL, setProviderURL] = useState(""); @@ -39,9 +43,9 @@ export default function useComponentState({ providerType, onCancel, notification const allAuthProviders = !reducer || - !reducer.currentReducerState || - reducer.currentReducerState.reducer_type === "error" || - !reducer.currentReducerState.authentication_providers + !reducer.currentReducerState || + reducer.currentReducerState.reducer_type === "error" || + !reducer.currentReducerState.authentication_providers ? {} : reducer.currentReducerState.authentication_providers; @@ -58,7 +62,12 @@ export default function useComponentState({ providerType, onCancel, notification prev[p.status].push({ ...p, url }); return prev; }, - { "not-contacted": [], disabled: [], error: [], ok: [] } as AuthProvByStatusMap, + { + "not-contacted": [], + disabled: [], + error: [], + ok: [], + } as AuthProvByStatusMap, ); const authProviders = authProvidersByStatus["ok"].map((p) => p.url); @@ -67,14 +76,23 @@ export default function useComponentState({ providerType, onCancel, notification useEffect(() => { if (timeout.current) clearTimeout(timeout.current); timeout.current = setTimeout(async () => { - const url = providerURL.endsWith("/") ? providerURL : providerURL + "/"; - if (!providerURL || authProviders.includes(url)) return; + let url = providerURL; + if (!url || authProviders.includes(url)) return; + if (url && !url.match(/^(https?:)\/\/.+\/(?:config)?$/iu)) + return setError( + "Malformed URL: Must be an HTTP(S) URL ending with a /", + ); + if (url.endsWith("/config")) url = url.substring(0, url.length - 6); try { setTesting(true); await testProvider(url, providerType); setError(""); } catch (e) { if (e instanceof Error) setError(e.message); + else + throw new Error( + `Unexpected Error Type: ${typeof e} - Cannot handle. Error: ${e}`, + ); } setTesting(false); }, 200); @@ -98,19 +116,20 @@ export default function useComponentState({ providerType, onCancel, notification const addProvider = async (provider_url: string): Promise<void> => { await reducer.transition("add_provider", { provider_url }); onCancel(); - } + }; const deleteProvider = async (provider_url: string): Promise<void> => { reducer.transition("delete_provider", { provider_url }); - } + }; let errors = !providerURL ? "Add provider URL" : undefined; let url: string | undefined; - try { - url = new URL("", providerURL).href; - } catch { - errors = "Check the URL"; - } - const _url = url + // We'll validate it in testProvider & via a regex above - there's no need in this :) + // try { + // url = new URL("", providerURL).href; + // } catch { + // errors = "Check the URL"; + // } + const _url = url; if (!!error && !errors) { errors = error; @@ -130,21 +149,19 @@ export default function useComponentState({ providerType, onCancel, notification setProviderURL: async (s: string) => setProviderURL(s), errors, error, - notifications - } + notifications, + }; if (!providerLabel) { return { status: "without-type", - ...commonState - } + ...commonState, + }; } else { return { status: "with-type", providerLabel, - ...commonState - } + ...commonState, + }; } - } - diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/stories.tsx b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/stories.tsx index 268189ed8..548fc01a5 100644 --- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/stories.tsx +++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/stories.tsx @@ -20,7 +20,7 @@ */ import { AuthenticationProviderStatusOk } from "@gnu-taler/anastasis-core"; -import { createExampleWithoutAnastasis } from "../../../utils/index.jsx"; +import * as tests from "@gnu-taler/web-util/testing"; import { WithoutProviderType, WithProviderType } from "./views.jsx"; export default { @@ -34,7 +34,7 @@ export default { }, }; -export const NewProvider = createExampleWithoutAnastasis(WithoutProviderType, { +export const NewProvider = tests.createExample(WithoutProviderType, { authProvidersByStatus: { ok: [ { @@ -57,7 +57,7 @@ export const NewProvider = createExampleWithoutAnastasis(WithoutProviderType, { notifications: [], }); -export const NewProviderWithoutProviderList = createExampleWithoutAnastasis( +export const NewProviderWithoutProviderList = tests.createExample( WithoutProviderType, { authProvidersByStatus: { @@ -70,7 +70,7 @@ export const NewProviderWithoutProviderList = createExampleWithoutAnastasis( }, ); -export const NewSmsProvider = createExampleWithoutAnastasis(WithProviderType, { +export const NewSmsProvider = tests.createExample(WithProviderType, { authProvidersByStatus: { ok: [], "not-contacted": [], @@ -81,7 +81,7 @@ export const NewSmsProvider = createExampleWithoutAnastasis(WithProviderType, { notifications: [], }); -export const NewIBANProvider = createExampleWithoutAnastasis(WithProviderType, { +export const NewIBANProvider = tests.createExample(WithProviderType, { authProvidersByStatus: { ok: [], "not-contacted": [], diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/test.ts b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/test.ts index d051d7c0b..0aebbdc6c 100644 --- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/test.ts +++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/test.ts @@ -20,23 +20,26 @@ */ import { expect } from "chai"; -import { mountHook } from "../../../test-utils.js"; import useComponentState from "./state.js"; +import * as tests from "@gnu-taler/web-util/testing"; describe("AddingProviderScreen states", () => { - it("should have status 'no-balance' when balance is empty", async () => { - const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState({ onCancel: async () => { null } }), - ); - - { - const { status } = getLastResultOrThrow(); - expect(status).equal("no-reducer"); - } - - await assertNoPendingUpdate(); - + it("should not load more if has reach the end", async () => { + const hookBehavior = await tests.hookBehaveLikeThis( + () => { + return useComponentState({ + providerType: "email", + async onCancel() {}, + }); + }, + {}, + [ + ({ status }) => { + expect(status).eq("no-reducer"); + }, + ], + ); + + expect(hookBehavior).deep.eq({ result: "ok" }); }); - }); diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx index 19557a12f..00a42a949 100644 --- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx +++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx @@ -121,13 +121,13 @@ export function WithoutProviderType(props: WithoutType): VNode { <div class="container"> <TextInput label="Provider URL" - placeholder="https://provider.com" + placeholder="https://provider.com/" grabFocus error={props.errors} bind={[props.providerURL, props.setProviderURL]} /> </div> - <p class="block">Example: https://kudos.demo.anastasis.lu</p> + <p class="block">Example: https://kudos.demo.anastasis.lu/</p> {props.testing && <p class="has-text-info">Testing</p>} <div diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx index 38fc1b56b..e6bc5f340 100644 --- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx @@ -20,7 +20,8 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../utils/index.js"; import { AttributeEntryScreen as TestedComponent } from "./AttributeEntryScreen.js"; export default { @@ -35,7 +36,7 @@ export default { }, }; -export const Backup = createExample(TestedComponent, { +export const Backup = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.backupAttributeEditing, required_attributes: [ { @@ -62,7 +63,7 @@ export const Backup = createExample(TestedComponent, { ], } as ReducerState); -export const Recovery = createExample(TestedComponent, { +export const Recovery = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.recoveryAttributeEditing, required_attributes: [ { @@ -89,10 +90,14 @@ export const Recovery = createExample(TestedComponent, { ], } as ReducerState); -export const WithNoRequiredAttribute = createExample(TestedComponent, { - ...reducerStatesExample.backupAttributeEditing, - required_attributes: undefined, -} as ReducerState); +export const WithNoRequiredAttribute = tests.createExample( + TestedComponent, + {}, + { + ...reducerStatesExample.backupAttributeEditing, + required_attributes: undefined, + } as ReducerState, +); const allWidgets = [ "anastasis_gtk_ia_aadhar_in", @@ -123,7 +128,7 @@ function typeForWidget(name: string): string { return "string"; } -export const WithAllPosibleWidget = createExample(TestedComponent, { +export const WithAllPosibleWidget = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.backupAttributeEditing, required_attributes: allWidgets.map((w) => ({ name: w, @@ -134,19 +139,23 @@ export const WithAllPosibleWidget = createExample(TestedComponent, { })), } as ReducerState); -export const WithAutocompleteFeature = createExample(TestedComponent, { - ...reducerStatesExample.backupAttributeEditing, - required_attributes: [ - { - name: "ahv_number", - label: "AHV Number", - type: "string", - uuid: "asdasdsa1", - widget: "wid", - "validation-regex": - "^(756)\\.[0-9]{4}\\.[0-9]{4}\\.[0-9]{2}|(756)[0-9]{10}$", - "validation-logic": "CH_AHV_check", - autocomplete: "???.????.????.??", - }, - ], -} as ReducerState); +export const WithAutocompleteFeature = tests.createExample( + TestedComponent, + {}, + { + ...reducerStatesExample.backupAttributeEditing, + required_attributes: [ + { + name: "ahv_number", + label: "AHV Number", + type: "string", + uuid: "asdasdsa1", + widget: "wid", + "validation-regex": + "^(756)\\.[0-9]{4}\\.[0-9]{4}\\.[0-9]{2}|(756)[0-9]{10}$", + "validation-logic": "CH_AHV_check", + autocomplete: "???.????.????.??", + }, + ], + } as ReducerState, +); diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx index 228186a2d..1f8cea7aa 100644 --- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx @@ -97,13 +97,11 @@ export function AttributeEntryScreen(): VNode { function saveAsPDF(): void { const printWindow = window.open("", "", "height=400,width=800"); const divContents = document.getElementById("printThis"); - const styleContents = document.getElementById("style-id"); - if (!printWindow || !divContents || !styleContents) return; + if (!printWindow || !divContents) return; printWindow.document.write( - "<html><head><title>Anastasis Recovery Document</title><style>", + `<html><head><link rel="stylesheet" href="index.css" /><title>Anastasis Recovery Document</title><style>`, ); - printWindow.document.write(styleContents.innerHTML); printWindow.document.write("</style></head><body> </body></html>"); printWindow.document.close(); printWindow.document.body.appendChild(divContents.cloneNode(true)); @@ -132,6 +130,7 @@ export function AttributeEntryScreen(): VNode { secret will be safely stored. If you forget what you have entered or if there is a misspell you will be unable to recover your secret. <p> + {/* TODO: make this actually work reliably cross-browser lol (opens about:blank for me) */} <a onClick={saveAsPDF}>Save the personal information as PDF</a> </p> </ConfirmModal> diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx index ba48e2d5c..22f8dd697 100644 --- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx @@ -20,7 +20,8 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../utils/index.js"; import { AuthenticationEditorScreen as TestedComponent } from "./AuthenticationEditorScreen.js"; export default { @@ -35,63 +36,72 @@ export default { }, }; -export const InitialState = createExample( +export const InitialState = tests.createExample( TestedComponent, + {}, reducerStatesExample.authEditing, ); -export const OneAuthMethodConfigured = createExample(TestedComponent, { - ...reducerStatesExample.authEditing, - authentication_methods: [ - { - type: "question", - instructions: "what time is it?", - challenge: "asd", - }, - ], -} as ReducerState); +export const OneAuthMethodConfigured = tests.createExample( + TestedComponent, + {}, + { + ...reducerStatesExample.authEditing, + authentication_methods: [ + { + type: "question", + instructions: "what time is it?", + challenge: "asd", + }, + ], + } as ReducerState, +); -export const SomeMoreAuthMethodConfigured = createExample(TestedComponent, { - ...reducerStatesExample.authEditing, - authentication_methods: [ - { - type: "question", - instructions: "what time is it?", - challenge: "asd", - }, - { - type: "question", - instructions: "what time is it?", - challenge: "qwe", - }, - { - type: "sms", - instructions: "what time is it?", - challenge: "asd", - }, - { - type: "email", - instructions: "what time is it?", - challenge: "asd", - }, - { - type: "email", - instructions: "what time is it?", - challenge: "asd", - }, - { - type: "email", - instructions: "what time is it?", - challenge: "asd", - }, - { - type: "email", - instructions: "what time is it?", - challenge: "asd", - }, - ], -} as ReducerState); +export const SomeMoreAuthMethodConfigured = tests.createExample( + TestedComponent, + {}, + { + ...reducerStatesExample.authEditing, + authentication_methods: [ + { + type: "question", + instructions: "what time is it?", + challenge: "asd", + }, + { + type: "question", + instructions: "what time is it?", + challenge: "qwe", + }, + { + type: "sms", + instructions: "what time is it?", + challenge: "asd", + }, + { + type: "email", + instructions: "what time is it?", + challenge: "asd", + }, + { + type: "email", + instructions: "what time is it?", + challenge: "asd", + }, + { + type: "email", + instructions: "what time is it?", + challenge: "asd", + }, + { + type: "email", + instructions: "what time is it?", + challenge: "asd", + }, + ], + } as ReducerState, +); -export const NoAuthMethodProvided = createExample(TestedComponent, { +export const NoAuthMethodProvided = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.authEditing, authentication_providers: {}, authentication_methods: [], diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx index 3018f88dd..54bbc626d 100644 --- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx @@ -241,7 +241,7 @@ export function AuthenticationEditorScreen(): VNode { </p> {authAvailableSet.size > 0 && ( <p class="block"> - We couldn't find provider for some of the authentication + We couldn't find provider for some of the authentication methods. </p> )} diff --git a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx index 8aeaec25c..a51940615 100644 --- a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { BackupFinishedScreen as TestedComponent } from "./BackupFinishedScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Backup finish", @@ -35,17 +36,18 @@ export default { }, }; -export const WithoutName = createExample( +export const WithoutName = tests.createExample( TestedComponent, + {}, reducerStatesExample.backupFinished, ); -export const WithName = createExample(TestedComponent, { +export const WithName = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.backupFinished, secret_name: "super_secret", } as ReducerState); -export const WithDetails = createExample(TestedComponent, { +export const WithDetails = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.backupFinished, secret_name: "super_secret", success_details: { diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx index d2471755a..84df615f3 100644 --- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx @@ -24,8 +24,10 @@ import { RecoveryStates, ReducerState, } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { ChallengeOverviewScreen as TestedComponent } from "./ChallengeOverviewScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { AmountString } from "@gnu-taler/taler-util"; export default { title: "Challenge overview", @@ -39,7 +41,7 @@ export default { }, }; -export const OneUnsolvedPolicy = createExample(TestedComponent, { +export const OneUnsolvedPolicy = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.challengeSelecting, recovery_information: { policies: [[{ uuid: "1" }]], @@ -53,7 +55,7 @@ export const OneUnsolvedPolicy = createExample(TestedComponent, { }, } as ReducerState); -export const SomePoliciesOneSolved = createExample(TestedComponent, { +export const SomePoliciesOneSolved = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.challengeSelecting, recovery_information: { policies: [[{ uuid: "1" }, { uuid: "2" }], [{ uuid: "uuid-3" }]], @@ -82,7 +84,7 @@ export const SomePoliciesOneSolved = createExample(TestedComponent, { }, } as ReducerState); -export const OneBadConfiguredPolicy = createExample(TestedComponent, { +export const OneBadConfiguredPolicy = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.challengeSelecting, recovery_information: { policies: [[{ uuid: "1" }, { uuid: "2" }]], @@ -96,72 +98,76 @@ export const OneBadConfiguredPolicy = createExample(TestedComponent, { }, } as ReducerState); -export const OnePolicyWithAllTheChallenges = createExample(TestedComponent, { - ...reducerStatesExample.challengeSelecting, - recovery_information: { - policies: [ - [ - { uuid: "1" }, - { uuid: "2" }, - { uuid: "3" }, - { uuid: "4" }, - { uuid: "5" }, - { uuid: "6" }, - { uuid: "7" }, - { uuid: "8" }, - ], - ], - challenges: [ - { - instructions: "Does P equals NP?", - type: "question", - uuid: "1", - }, - { - instructions: "SMS to 555-555", - type: "sms", - uuid: "2", - }, - { - instructions: "Email to qwe@asd.com", - type: "email", - uuid: "3", - }, - { - instructions: 'Enter 8 digits code for "Anastasis"', - type: "totp", - uuid: "4", - }, - { - // - instructions: "Wire transfer from ASDXCVQWE123123 with holder Florian", - type: "iban", - uuid: "5", - }, - { - instructions: "Join a video call", - type: "video", //Enter 8 digits code for "Anastasis" - uuid: "7", - }, - {}, - { - instructions: "Letter to address in postal code DE123123", - type: "post", //Enter 8 digits code for "Anastasis" - uuid: "8", - }, - { - instructions: "instruction for an unknown type of challenge", - type: "new-type-of-challenge", - uuid: "6", - }, - ], - }, -} as ReducerState); - -export const OnePolicyWithAllTheChallengesInDifferentState = createExample( +export const OnePolicyWithAllTheChallenges = tests.createExample( TestedComponent, + {}, { ...reducerStatesExample.challengeSelecting, + recovery_information: { + policies: [ + [ + { uuid: "1" }, + { uuid: "2" }, + { uuid: "3" }, + { uuid: "4" }, + { uuid: "5" }, + { uuid: "6" }, + { uuid: "7" }, + { uuid: "8" }, + ], + ], + challenges: [ + { + instructions: "Does P equals NP?", + type: "question", + uuid: "1", + }, + { + instructions: "SMS to 555-555", + type: "sms", + uuid: "2", + }, + { + instructions: "Email to qwe@asd.com", + type: "email", + uuid: "3", + }, + { + instructions: 'Enter 8 digits code for "Anastasis"', + type: "totp", + uuid: "4", + }, + { + // + instructions: + "Wire transfer from ASDXCVQWE123123 with holder Florian", + type: "iban", + uuid: "5", + }, + { + instructions: "Join a video call", + type: "video", //Enter 8 digits code for "Anastasis" + uuid: "7", + }, + {}, + { + instructions: "Letter to address in postal code DE123123", + type: "post", //Enter 8 digits code for "Anastasis" + uuid: "8", + }, + { + instructions: "instruction for an unknown type of challenge", + type: "new-type-of-challenge", + uuid: "6", + }, + ], + }, + } as ReducerState, +); + +export const OnePolicyWithAllTheChallengesInDifferentState = + tests.createExample(TestedComponent, {}, { + ...reducerStatesExample.challengeSelecting, recovery_state: RecoveryStates.ChallengeSelecting, recovery_information: { policies: [ @@ -251,16 +257,16 @@ export const OnePolicyWithAllTheChallengesInDifferentState = createExample( "uuid-8": { state: ChallengeFeedbackStatus.RateLimitExceeded.toString() }, "uuid-9": { state: ChallengeFeedbackStatus.IbanInstructions.toString(), - challenge_amount: "EUR:1", + challenge_amount: "EUR:1" as AmountString, target_iban: "DE12345789000", target_business_name: "Data Loss Incorporated", wire_transfer_subject: "Anastasis 987654321", }, "uuid-10": { state: ChallengeFeedbackStatus.IncorrectAnswer.toString() }, }, - } as ReducerState, -); -export const NoPolicies = createExample( + } as ReducerState); +export const NoPolicies = tests.createExample( TestedComponent, + {}, reducerStatesExample.challengeSelecting, ); diff --git a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx index cd41fe03a..0489e5a11 100644 --- a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../utils/index.js"; import { ChallengePayingScreen as TestedComponent } from "./ChallengePayingScreen.js"; export default { @@ -34,7 +35,8 @@ export default { }, }; -export const Example = createExample( +export const Example = tests.createExample( TestedComponent, + {}, reducerStatesExample.challengePaying, ); diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx index 12a79c56c..646165341 100644 --- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { ContinentSelectionScreen as TestedComponent } from "./ContinentSelectionScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Continent selection", @@ -35,22 +36,24 @@ export default { }, }; -export const BackupSelectContinent = createExample( +export const BackupSelectContinent = tests.createExample( TestedComponent, + {}, reducerStatesExample.backupSelectContinent, ); -export const BackupSelectCountry = createExample(TestedComponent, { +export const BackupSelectCountry = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.backupSelectContinent, selected_continent: "Testcontinent", } as ReducerState); -export const RecoverySelectContinent = createExample( +export const RecoverySelectContinent = tests.createExample( TestedComponent, + {}, reducerStatesExample.recoverySelectContinent, ); -export const RecoverySelectCountry = createExample(TestedComponent, { +export const RecoverySelectCountry = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.recoverySelectContinent, selected_continent: "Testcontinent", } as ReducerState); diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx index fc9c0f097..3231e61e4 100644 --- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx @@ -46,8 +46,9 @@ export function ContinentSelectionScreen(): VNode { // const cc = reducer.currentReducerState.selected_country || ""; const theCountry = countryList.find((c) => c.code === countryCode); const selectCountryAction = async () => { - //selection should be when the select box changes it value + // selection should be when the select box changes it value if (!theCountry) return; + // FIXME: Why is there no await? reducer.transition("select_country", { country_code: countryCode, }); @@ -56,6 +57,7 @@ export function ContinentSelectionScreen(): VNode { // const step1 = reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting || // reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting; + // FIXME: i18n const errors = !theCountry ? "Select a country" : undefined; const handleBack = async () => { diff --git a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx index 1e3650300..3c9fd7f50 100644 --- a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx @@ -20,7 +20,8 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../utils/index.js"; import { EditPoliciesScreen as TestedComponent } from "./EditPoliciesScreen.js"; export default { @@ -35,8 +36,9 @@ export default { }, }; -export const EditingAPolicy = createExample( +export const EditingAPolicy = tests.createExample( TestedComponent, + { index: 0 }, { ...reducerStatesExample.policyReview, policies: [ @@ -84,11 +86,11 @@ export const EditingAPolicy = createExample( }, ], } as ReducerState, - { index: 0 }, ); -export const CreatingAPolicy = createExample( +export const CreatingAPolicy = tests.createExample( TestedComponent, + { index: 3 }, { ...reducerStatesExample.policyReview, policies: [ @@ -136,5 +138,4 @@ export const CreatingAPolicy = createExample( }, ], } as ReducerState, - { index: 3 }, ); diff --git a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx index 56c224d34..ea88b74a0 100644 --- a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { PoliciesPayingScreen as TestedComponent } from "./PoliciesPayingScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Policies paying", @@ -35,11 +36,12 @@ export default { }, }; -export const Example = createExample( +export const Example = tests.createExample( TestedComponent, + {}, reducerStatesExample.policyPay, ); -export const WithSomePaymentRequest = createExample(TestedComponent, { +export const WithSomePaymentRequest = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.policyPay, policy_payment_requests: [ { diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx index 1eb2ae50c..97e0821fd 100644 --- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx @@ -21,8 +21,9 @@ import { ReducerState } from "@gnu-taler/anastasis-core"; import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { RecoveryFinishedScreen as TestedComponent } from "./RecoveryFinishedScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Recovery Finished", @@ -36,7 +37,7 @@ export default { }, }; -export const GoodEnding = createExample(TestedComponent, { +export const GoodEnding = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.recoveryFinished, recovery_document: { secret_name: "the_name_of_the_secret", @@ -49,7 +50,8 @@ export const GoodEnding = createExample(TestedComponent, { }, } as ReducerState); -export const BadEnding = createExample( +export const BadEnding = tests.createExample( TestedComponent, + {}, reducerStatesExample.recoveryFinished, ); diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx index 62ac410a2..f528bc207 100644 --- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx @@ -58,9 +58,14 @@ export function RecoveryFinishedScreen(): VNode { const secret = bytesToString(decodeCrock(encodedSecret.value)); const plainText = encodedSecret.value.length < 1000 && encodedSecret.mime === "text/plain"; - const contentURI = !plainText - ? secret - : `data:${encodedSecret.mime},${secret}`; + + let [uri, setUri] = useState(`data:${encodedSecret.mime},${secret}`); + fetch(`data:${encodedSecret.mime},${secret}`) // TODO: look into using new Blob + .then((v) => v.blob()) + .then((blob) => URL.createObjectURL(blob)) + .then((newUri) => { + setUri(newUri); + }); return ( <AnastasisClientFrame title="Recovery Success" hideNav> <h2 class="subtitle">Your secret was recovered</h2> @@ -87,7 +92,7 @@ export function RecoveryFinishedScreen(): VNode { download={ encodedSecret.filename ? encodedSecret.filename : "secret.file" } - href={contentURI} + href={uri} > <div class="icon is-small "> <i class="mdi mdi-download" /> diff --git a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx index c5003d6a0..71144917a 100644 --- a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { ReviewPoliciesScreen as TestedComponent } from "./ReviewPoliciesScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Reviewing Policies", @@ -35,227 +36,235 @@ export default { }, }; -export const HasPoliciesButMethodListIsEmpty = createExample(TestedComponent, { - ...reducerStatesExample.policyReview, - policies: [ - { - methods: [ - { - authentication_method: 0, - provider: "asd", - }, - { - authentication_method: 1, - provider: "asd", - }, - ], - }, - { - methods: [ - { - authentication_method: 1, - provider: "asd", - }, - ], - }, - ], - authentication_methods: [], -} as ReducerState); +export const HasPoliciesButMethodListIsEmpty = tests.createExample( + TestedComponent, + {}, + { + ...reducerStatesExample.policyReview, + policies: [ + { + methods: [ + { + authentication_method: 0, + provider: "asd", + }, + { + authentication_method: 1, + provider: "asd", + }, + ], + }, + { + methods: [ + { + authentication_method: 1, + provider: "asd", + }, + ], + }, + ], + authentication_methods: [], + } as ReducerState, +); -export const SomePoliciesWithMethods = createExample(TestedComponent, { - ...reducerStatesExample.policyReview, - policies: [ - { - methods: [ - { - authentication_method: 0, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 1, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 2, - provider: "https://kudos.demo.anastasis.lu/", - }, - ], - }, - { - methods: [ - { - authentication_method: 0, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 1, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 3, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 0, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 1, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 4, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 0, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 2, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 3, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 0, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 2, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 4, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 0, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 3, - provider: "https://anastasis.demo.taler.net/", - }, - { - authentication_method: 4, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 1, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 2, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 3, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 1, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 2, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 4, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 1, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 3, - provider: "https://anastasis.demo.taler.net/", - }, - { - authentication_method: 4, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - { - methods: [ - { - authentication_method: 2, - provider: "https://kudos.demo.anastasis.lu/", - }, - { - authentication_method: 3, - provider: "https://anastasis.demo.taler.net/", - }, - { - authentication_method: 4, - provider: "https://anastasis.demo.taler.net/", - }, - ], - }, - ], - authentication_methods: [ - { - type: "email", - instructions: "Email to qwe@asd.com", - challenge: "E5VPA", - }, - { - type: "sms", - instructions: "SMS to 555-555", - challenge: "", - }, - { - type: "question", - instructions: "Does P equal NP?", - challenge: "C5SP8", - }, - { - type: "totp", - instructions: "Response code for 'Anastasis'", - challenge: "E5VPA", - }, - { - type: "sms", - instructions: "SMS to 6666-6666", - challenge: "", - }, - { - type: "question", - instructions: "How did the chicken cross the road?", - challenge: "C5SP8", - }, - ], -} as ReducerState); +export const SomePoliciesWithMethods = tests.createExample( + TestedComponent, + {}, + { + ...reducerStatesExample.policyReview, + policies: [ + { + methods: [ + { + authentication_method: 0, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 1, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 2, + provider: "https://kudos.demo.anastasis.lu/", + }, + ], + }, + { + methods: [ + { + authentication_method: 0, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 1, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 3, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 0, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 1, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 4, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 0, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 2, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 3, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 0, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 2, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 4, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 0, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 3, + provider: "https://anastasis.demo.taler.net/", + }, + { + authentication_method: 4, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 1, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 2, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 3, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 1, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 2, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 4, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 1, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 3, + provider: "https://anastasis.demo.taler.net/", + }, + { + authentication_method: 4, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + { + methods: [ + { + authentication_method: 2, + provider: "https://kudos.demo.anastasis.lu/", + }, + { + authentication_method: 3, + provider: "https://anastasis.demo.taler.net/", + }, + { + authentication_method: 4, + provider: "https://anastasis.demo.taler.net/", + }, + ], + }, + ], + authentication_methods: [ + { + type: "email", + instructions: "Email to qwe@asd.com", + challenge: "E5VPA", + }, + { + type: "sms", + instructions: "SMS to 555-555", + challenge: "", + }, + { + type: "question", + instructions: "Does P equal NP?", + challenge: "C5SP8", + }, + { + type: "totp", + instructions: "Response code for 'Anastasis'", + challenge: "E5VPA", + }, + { + type: "sms", + instructions: "SMS to 6666-6666", + challenge: "", + }, + { + type: "question", + instructions: "How did the chicken cross the road?", + challenge: "C5SP8", + }, + ], + } as ReducerState, +); diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx index dbf8bf128..24bbb2927 100644 --- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { SecretEditorScreen as TestedComponent } from "./SecretEditorScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Secret editor", @@ -35,11 +36,15 @@ export default { }, }; -export const WithSecretNamePreselected = createExample(TestedComponent, { - ...reducerStatesExample.secretEdition, - secret_name: "someSecretName", -} as ReducerState); +export const WithSecretNamePreselected = tests.createExample( + TestedComponent, + {}, + { + ...reducerStatesExample.secretEdition, + secret_name: "someSecretName", + } as ReducerState, +); -export const WithoutName = createExample(TestedComponent, { +export const WithoutName = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.secretEdition, } as ReducerState); diff --git a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx index 7669668ee..fb3b26e15 100644 --- a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx @@ -20,7 +20,8 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../utils/index.js"; import { SecretSelectionScreen, SecretSelectionScreenFound, @@ -34,17 +35,9 @@ export default { }, }; -export const Example = createExample( +export const Example = tests.createExample( SecretSelectionScreenFound, { - ...reducerStatesExample.secretSelection, - recovery_document: { - provider_url: "https://kudos.demo.anastasis.lu/", - secret_name: "secretName", - version: 1, - }, - } as ReducerState, - { policies: [ { secret_name: "The secret name 1", @@ -70,9 +63,21 @@ export const Example = createExample( }, ], }, + { + ...reducerStatesExample.secretSelection, + recovery_document: { + provider_url: "https://kudos.demo.anastasis.lu/", + secret_name: "secretName", + version: 1, + }, + } as ReducerState, ); -export const NoRecoveryDocumentFound = createExample(SecretSelectionScreen, { - ...reducerStatesExample.secretSelection, - recovery_document: undefined, -} as ReducerState); +export const NoRecoveryDocumentFound = tests.createExample( + SecretSelectionScreen, + {}, + { + ...reducerStatesExample.secretSelection, + recovery_document: undefined, + } as ReducerState, +); diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx index 1058ae126..dc707a052 100644 --- a/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { SolveScreen as TestedComponent } from "./SolveScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Solve Screen", @@ -35,12 +36,12 @@ export default { }, }; -export const NoInformation = createExample( +export const NoInformation = tests.createExample( TestedComponent, reducerStatesExample.challengeSolving, ); -export const NotSupportedChallenge = createExample(TestedComponent, { +export const NotSupportedChallenge = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -55,7 +56,7 @@ export const NotSupportedChallenge = createExample(TestedComponent, { selected_challenge_uuid: "ASDASDSAD!1", } as ReducerState); -export const MismatchedChallengeId = createExample(TestedComponent, { +export const MismatchedChallengeId = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ diff --git a/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx index 960426098..1f6145345 100644 --- a/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../utils/index.js"; import { StartScreen as TestedComponent } from "./StartScreen.js"; export default { @@ -34,7 +35,8 @@ export default { }, }; -export const InitialState = createExample( +export const InitialState = tests.createExample( TestedComponent, + {}, reducerStatesExample.initial, ); diff --git a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx index 40ed5117c..424c4884a 100644 --- a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../utils/index.js"; +import { reducerStatesExample } from "../../utils/index.js"; import { TruthsPayingScreen as TestedComponent } from "./TruthsPayingScreen.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Truths Paying", @@ -35,11 +36,12 @@ export default { }, }; -export const Example = createExample( +export const Example = tests.createExample( TestedComponent, + {}, reducerStatesExample.truthsPaying, ); -export const WithPaytoList = createExample(TestedComponent, { +export const WithPaytoList = tests.createExample(TestedComponent, {}, { ...reducerStatesExample.truthsPaying, payments: ["payto://x-taler-bank/bank/account"], } as ReducerState); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx index 4a2d76ca3..aee7829ff 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; export default { @@ -36,17 +37,16 @@ export default { const type: KnownAuthMethods = "email"; -export const Empty = createExample( +export const Empty = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [], }, + reducerStatesExample.authEditing, ); -export const WithOneExample = createExample( +export const WithOneExample = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -57,11 +57,11 @@ export const WithOneExample = createExample( }, ], }, + reducerStatesExample.authEditing, ); -export const WithMoreExamples = createExample( +export const WithMoreExamples = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -78,4 +78,5 @@ export const WithMoreExamples = createExample( }, ], }, + reducerStatesExample.authEditing, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx index cc378d8f6..075bab2a7 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx @@ -23,8 +23,9 @@ import { ChallengeFeedbackStatus, ReducerState, } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Auth method: Email solve", @@ -40,9 +41,12 @@ export default { const type: KnownAuthMethods = "email"; -export const WithoutFeedback = createExample( +export const WithoutFeedback = tests.createExample( TestedComponent[type].solve, { + id: "uuid-1", + }, + { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -56,14 +60,14 @@ export const WithoutFeedback = createExample( }, selected_challenge_uuid: "uuid-1", } as ReducerState, - { - id: "uuid-1", - }, ); -export const PaymentFeedback = createExample( +export const PaymentFeedback = tests.createExample( TestedComponent[type].solve, { + id: "uuid-1", + }, + { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -85,7 +89,4 @@ export const PaymentFeedback = createExample( }, }, } as ReducerState, - { - id: "uuid-1", - }, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx index dfe3850f1..d571093f7 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; export default { @@ -36,17 +37,16 @@ export default { const type: KnownAuthMethods = "iban"; -export const Empty = createExample( +export const Empty = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [], }, + reducerStatesExample.authEditing, ); -export const WithOneExample = createExample( +export const WithOneExample = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -57,10 +57,10 @@ export const WithOneExample = createExample( }, ], }, + reducerStatesExample.authEditing, ); -export const WithMoreExamples = createExample( +export const WithMoreExamples = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -77,4 +77,5 @@ export const WithMoreExamples = createExample( }, ], }, + reducerStatesExample.authEditing, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx index 8a9a3f7a0..2a16c8456 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../../utils/index.js"; -import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; +import { KnownAuthMethods, authMethods as TestedComponent } from "./index.js"; export default { title: "Auth method: IBAN Solve", @@ -37,9 +38,12 @@ export default { const type: KnownAuthMethods = "iban"; -export const WithoutFeedback = createExample( +export const WithoutFeedback = tests.createExample( TestedComponent[type].solve, { + id: "uuid-1", + }, + { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -53,7 +57,4 @@ export const WithoutFeedback = createExample( }, selected_challenge_uuid: "uuid-1", } as ReducerState, - { - id: "uuid-1", - }, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx index 8a32c45c1..a893c923e 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; export default { @@ -36,17 +37,16 @@ export default { const type: KnownAuthMethods = "post"; -export const Empty = createExample( +export const Empty = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [], }, + reducerStatesExample.authEditing, ); -export const WithOneExample = createExample( +export const WithOneExample = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -57,11 +57,11 @@ export const WithOneExample = createExample( }, ], }, + reducerStatesExample.authEditing, ); -export const WithMoreExamples = createExample( +export const WithMoreExamples = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -78,4 +78,5 @@ export const WithMoreExamples = createExample( }, ], }, + reducerStatesExample.authEditing, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx index 702ba2810..3495f7f63 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Auth method: Post solve", @@ -37,9 +38,12 @@ export default { const type: KnownAuthMethods = "post"; -export const WithoutFeedback = createExample( +export const WithoutFeedback = tests.createExample( TestedComponent[type].solve, { + id: "uuid-1", + }, + { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -53,7 +57,4 @@ export const WithoutFeedback = createExample( }, selected_challenge_uuid: "uuid-1", } as ReducerState, - { - id: "uuid-1", - }, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx index 2e108b4e6..c9bc127f7 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; export default { @@ -36,17 +37,16 @@ export default { const type: KnownAuthMethods = "question"; -export const Empty = createExample( +export const Empty = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [], }, + reducerStatesExample.authEditing, ); -export const WithOneExample = createExample( +export const WithOneExample = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -58,11 +58,11 @@ export const WithOneExample = createExample( }, ], }, + reducerStatesExample.authEditing, ); -export const WithMoreExamples = createExample( +export const WithMoreExamples = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -80,4 +80,5 @@ export const WithMoreExamples = createExample( }, ], }, + reducerStatesExample.authEditing, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx index f7116bf6f..dbb17ddab 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx @@ -23,8 +23,10 @@ import { ChallengeFeedbackStatus, ReducerState, } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { AmountString } from "@gnu-taler/taler-util"; export default { title: "Auth method: Question solve", @@ -40,9 +42,12 @@ export default { const type: KnownAuthMethods = "question"; -export const WithoutFeedback = createExample( +export const WithoutFeedback = tests.createExample( TestedComponent[type].solve, { + id: "uuid-1", + }, + { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -56,9 +61,6 @@ export const WithoutFeedback = createExample( }, selected_challenge_uuid: "uuid-1", } as ReducerState, - { - id: "uuid-1", - }, ); const recovery_information = { @@ -72,45 +74,58 @@ const recovery_information = { policies: [], }; -export const CodeInFileFeedback = createExample(TestedComponent[type].solve, { - ...reducerStatesExample.challengeSolving, - recovery_information, - selected_challenge_uuid: "ASDASDSAD!1", - challenge_feedback: { - "ASDASDSAD!1": { - state: ChallengeFeedbackStatus.CodeInFile, - filename: "asd", - display_hint: "hint", +export const CodeInFileFeedback = tests.createExample( + TestedComponent[type].solve, + {}, + { + ...reducerStatesExample.challengeSolving, + recovery_information, + selected_challenge_uuid: "ASDASDSAD!1", + challenge_feedback: { + "ASDASDSAD!1": { + state: ChallengeFeedbackStatus.CodeInFile, + filename: "asd", + display_hint: "hint", + }, }, - }, -} as ReducerState); - -export const CodeSentFeedback = createExample(TestedComponent[type].solve, { - ...reducerStatesExample.challengeSolving, - recovery_information, - selected_challenge_uuid: "ASDASDSAD!1", - challenge_feedback: { - "ASDASDSAD!1": { - state: ChallengeFeedbackStatus.CodeSent, - address_hint: "asdasd", - display_hint: "qweqweqw", + } as ReducerState, +); + +export const CodeSentFeedback = tests.createExample( + TestedComponent[type].solve, + {}, + { + ...reducerStatesExample.challengeSolving, + recovery_information, + selected_challenge_uuid: "ASDASDSAD!1", + challenge_feedback: { + "ASDASDSAD!1": { + state: ChallengeFeedbackStatus.CodeSent, + address_hint: "asdasd", + display_hint: "qweqweqw", + }, }, - }, -} as ReducerState); - -export const SolvedFeedback = createExample(TestedComponent[type].solve, { - ...reducerStatesExample.challengeSolving, - recovery_information, - selected_challenge_uuid: "ASDASDSAD!1", - challenge_feedback: { - "ASDASDSAD!1": { - state: ChallengeFeedbackStatus.Solved, + } as ReducerState, +); + +export const SolvedFeedback = tests.createExample( + TestedComponent[type].solve, + {}, + { + ...reducerStatesExample.challengeSolving, + recovery_information, + selected_challenge_uuid: "ASDASDSAD!1", + challenge_feedback: { + "ASDASDSAD!1": { + state: ChallengeFeedbackStatus.Solved, + }, }, - }, -} as ReducerState); + } as ReducerState, +); -export const ServerFailureFeedback = createExample( +export const ServerFailureFeedback = tests.createExample( TestedComponent[type].solve, + {}, { ...reducerStatesExample.challengeSolving, recovery_information, @@ -124,45 +139,58 @@ export const ServerFailureFeedback = createExample( } as ReducerState, ); -export const TruthUnknownFeedback = createExample(TestedComponent[type].solve, { - ...reducerStatesExample.challengeSolving, - recovery_information, - selected_challenge_uuid: "ASDASDSAD!1", - challenge_feedback: { - "ASDASDSAD!1": { - state: ChallengeFeedbackStatus.TruthUnknown, +export const TruthUnknownFeedback = tests.createExample( + TestedComponent[type].solve, + {}, + { + ...reducerStatesExample.challengeSolving, + recovery_information, + selected_challenge_uuid: "ASDASDSAD!1", + challenge_feedback: { + "ASDASDSAD!1": { + state: ChallengeFeedbackStatus.TruthUnknown, + }, }, - }, -} as ReducerState); - -export const TalerPaymentFeedback = createExample(TestedComponent[type].solve, { - ...reducerStatesExample.challengeSolving, - recovery_information, - selected_challenge_uuid: "ASDASDSAD!1", - challenge_feedback: { - "ASDASDSAD!1": { - state: ChallengeFeedbackStatus.TalerPayment, - payment_secret: "secret", - provider: "asdasdas", - taler_pay_uri: "taler://pay/...", + } as ReducerState, +); + +export const TalerPaymentFeedback = tests.createExample( + TestedComponent[type].solve, + {}, + { + ...reducerStatesExample.challengeSolving, + recovery_information, + selected_challenge_uuid: "ASDASDSAD!1", + challenge_feedback: { + "ASDASDSAD!1": { + state: ChallengeFeedbackStatus.TalerPayment, + payment_secret: "secret", + provider: "asdasdas", + taler_pay_uri: "taler://pay/...", + }, }, - }, -} as ReducerState); - -export const UnsupportedFeedback = createExample(TestedComponent[type].solve, { - ...reducerStatesExample.challengeSolving, - recovery_information, - selected_challenge_uuid: "ASDASDSAD!1", - challenge_feedback: { - "ASDASDSAD!1": { - state: ChallengeFeedbackStatus.Unsupported, - unsupported_method: "method", + } as ReducerState, +); + +export const UnsupportedFeedback = tests.createExample( + TestedComponent[type].solve, + {}, + { + ...reducerStatesExample.challengeSolving, + recovery_information, + selected_challenge_uuid: "ASDASDSAD!1", + challenge_feedback: { + "ASDASDSAD!1": { + state: ChallengeFeedbackStatus.Unsupported, + unsupported_method: "method", + }, }, - }, -} as ReducerState); + } as ReducerState, +); -export const RateLimitExceededFeedback = createExample( +export const RateLimitExceededFeedback = tests.createExample( TestedComponent[type].solve, + {}, { ...reducerStatesExample.challengeSolving, recovery_information, @@ -175,8 +203,9 @@ export const RateLimitExceededFeedback = createExample( } as ReducerState, ); -export const IbanInstructionsFeedback = createExample( +export const IbanInstructionsFeedback = tests.createExample( TestedComponent[type].solve, + {}, { ...reducerStatesExample.challengeSolving, recovery_information, @@ -184,7 +213,7 @@ export const IbanInstructionsFeedback = createExample( challenge_feedback: { "ASDASDSAD!1": { state: ChallengeFeedbackStatus.IbanInstructions, - challenge_amount: "EUR:1", + challenge_amount: "EUR:1" as AmountString, target_iban: "DE12345789000", target_business_name: "Data Loss Incorporated", wire_transfer_subject: "Anastasis 987654321", @@ -194,8 +223,9 @@ export const IbanInstructionsFeedback = createExample( } as ReducerState, ); -export const IncorrectAnswerFeedback = createExample( +export const IncorrectAnswerFeedback = tests.createExample( TestedComponent[type].solve, + {}, { ...reducerStatesExample.challengeSolving, recovery_information, @@ -207,44 +237,3 @@ export const IncorrectAnswerFeedback = createExample( }, } as ReducerState, ); - -// export const AuthIbanFeedback = createExample(TestedComponent[type].solve, { -// ...reducerStatesExample.challengeSolving, -// recovery_information: { -// challenges: [ -// { -// instructions: "does P equals NP?", -// type: "question", -// uuid: "ASDASDSAD!1", -// }, -// ], -// policies: [], -// }, -// selected_challenge_uuid: "ASDASDSAD!1", -// challenge_feedback: { -// "ASDASDSAD!1": ibanFeedback, -// }, -// } as ReducerState); - -// export const PaymentFeedback = createExample(TestedComponent[type].solve, { -// ...reducerStatesExample.challengeSolving, -// recovery_information: { -// challenges: [ -// { -// instructions: "does P equals NP?", -// type: "question", -// uuid: "ASDASDSAD!1", -// }, -// ], -// policies: [], -// }, -// selected_challenge_uuid: "ASDASDSAD!1", -// challenge_feedback: { -// "ASDASDSAD!1": { -// state: ChallengeFeedbackStatus.TalerPayment, -// taler_pay_uri: "taler://pay/...", -// provider: "https://localhost:8080/", -// payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG", -// }, -// }, -// } as ReducerState); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx index b2c6cb61d..fbf345779 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; export default { @@ -36,17 +37,16 @@ export default { const type: KnownAuthMethods = "sms"; -export const Empty = createExample( +export const Empty = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [], }, + reducerStatesExample.authEditing, ); -export const WithOneExample = createExample( +export const WithOneExample = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -57,11 +57,11 @@ export const WithOneExample = createExample( }, ], }, + reducerStatesExample.authEditing, ); -export const WithMoreExamples = createExample( +export const WithMoreExamples = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -78,4 +78,5 @@ export const WithMoreExamples = createExample( }, ], }, + reducerStatesExample.authEditing, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx index 2064f12ff..8e3fb1a16 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; +import * as tests from "@gnu-taler/web-util/testing"; export default { title: "Auth method: SMS solve", @@ -37,9 +38,12 @@ export default { const type: KnownAuthMethods = "sms"; -export const WithoutFeedback = createExample( +export const WithoutFeedback = tests.createExample( TestedComponent[type].solve, { + id: "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0", + }, + { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -54,7 +58,4 @@ export const WithoutFeedback = createExample( selected_challenge_uuid: "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0", } as ReducerState, - { - id: "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0", - }, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx index 5582590f7..ee66fcee1 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx @@ -19,7 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createExample, reducerStatesExample } from "../../../utils/index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; export default { @@ -36,16 +37,15 @@ export default { const type: KnownAuthMethods = "totp"; -export const Empty = createExample( +export const Empty = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [], }, + reducerStatesExample.authEditing, ); -export const WithOneExample = createExample( +export const WithOneExample = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -56,10 +56,10 @@ export const WithOneExample = createExample( }, ], }, + reducerStatesExample.authEditing, ); -export const WithMoreExample = createExample( +export const WithMoreExample = tests.createExample( TestedComponent[type].setup, - reducerStatesExample.authEditing, { configured: [ { @@ -76,4 +76,5 @@ export const WithMoreExample = createExample( }, ], }, + reducerStatesExample.authEditing, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx index 20cd7e3c9..c120aaadc 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx @@ -20,8 +20,9 @@ */ import { ReducerState } from "@gnu-taler/anastasis-core"; -import { createExample, reducerStatesExample } from "../../../utils/index.js"; -import { authMethods as TestedComponent, KnownAuthMethods } from "./index.js"; +import * as tests from "@gnu-taler/web-util/testing"; +import { reducerStatesExample } from "../../../utils/index.js"; +import { KnownAuthMethods, authMethods as TestedComponent } from "./index.js"; export default { title: "Auth method: Totp solve", @@ -37,9 +38,12 @@ export default { const type: KnownAuthMethods = "totp"; -export const WithoutFeedback = createExample( +export const WithoutFeedback = tests.createExample( TestedComponent[type].solve, { + id: "uuid-1", + }, + { ...reducerStatesExample.challengeSolving, recovery_information: { challenges: [ @@ -53,7 +57,4 @@ export const WithoutFeedback = createExample( }, selected_challenge_uuid: "uuid-1", } as ReducerState, - { - id: "uuid-1", - }, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/totp.ts b/packages/anastasis-webui/src/pages/home/authMethod/totp.ts index 434dd92fc..ff8027ced 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/totp.ts +++ b/packages/anastasis-webui/src/pages/home/authMethod/totp.ts @@ -13,6 +13,8 @@ You should have received a copy of the GNU Affero General Public License along with GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ + +//@ts-ignore import jssha from "jssha"; const SEARCH_RANGE = 16; diff --git a/packages/anastasis-webui/src/pages/home/index.storiesNo.tsx b/packages/anastasis-webui/src/pages/home/index.stories.tsx index 0dad73724..b4525b423 100644 --- a/packages/anastasis-webui/src/pages/home/index.storiesNo.tsx +++ b/packages/anastasis-webui/src/pages/home/index.stories.tsx @@ -35,6 +35,7 @@ export * as authMethod_AuthMethodSmsSetup from "./authMethod/AuthMethodSmsSetup. export * as authMethod_AuthMethodSmsSolve from "./authMethod/AuthMethodSmsSolve.stories.js"; export * as authMethod_AuthMethodTotpSetup from "./authMethod/AuthMethodTotpSetup.stories.js"; export * as authMethod_AuthMethodTotpSolve from "./authMethod/AuthMethodTotpSolve.stories.js"; + export * as BackupFinishedScreen from "./BackupFinishedScreen.stories.js"; export * as ChallengeOverviewScreen from "./ChallengeOverviewScreen.stories.js"; export * as ChallengePayingScreen from "./ChallengePayingScreen.stories.js"; @@ -42,6 +43,7 @@ export * as ContinentSelectionScreen from "./ContinentSelectionScreen.stories.js export * as EditPoliciesScreen from "./EditPoliciesScreen.stories.js"; export * as PoliciesPayingScreen from "./PoliciesPayingScreen.stories.js"; export * as RecoveryFinishedScreen from "./RecoveryFinishedScreen.stories.js"; + export * as ReviewPoliciesScreen from "./ReviewPoliciesScreen.stories.js"; export * as SecretEditorScreen from "./SecretEditorScreen.stories.js"; export * as SecretSelectionScreen from "./SecretSelectionScreen.stories.js"; diff --git a/packages/anastasis-webui/src/pages/home/index.tsx b/packages/anastasis-webui/src/pages/home/index.tsx index 44e065807..c665144a4 100644 --- a/packages/anastasis-webui/src/pages/home/index.tsx +++ b/packages/anastasis-webui/src/pages/home/index.tsx @@ -228,6 +228,8 @@ function AnastasisClientImpl(): VNode { return <StartScreen />; } + // FIXME: Use switch statements here! + if ( (state.reducer_type === "backup" && state.backup_state === BackupStates.ContinentSelecting) || diff --git a/packages/anastasis-webui/src/stories.tsx b/packages/anastasis-webui/src/stories.tsx index f345f082d..cdaa4022f 100644 --- a/packages/anastasis-webui/src/stories.tsx +++ b/packages/anastasis-webui/src/stories.tsx @@ -20,9 +20,9 @@ */ import { strings } from "./i18n/strings.js"; -import * as pages from "./pages/home/index.storiesNo.js"; +import * as pages from "./pages/home/index.stories.js"; -import { renderStories } from "@gnu-taler/web-util/lib/index.browser"; +import { renderStories } from "@gnu-taler/web-util/browser"; import "./scss/main.scss"; diff --git a/packages/anastasis-webui/src/test-utils.ts b/packages/anastasis-webui/src/test-utils.ts deleted file mode 100644 index f220540f1..000000000 --- a/packages/anastasis-webui/src/test-utils.ts +++ /dev/null @@ -1,205 +0,0 @@ -/* - This file is part of GNU Anastasis - (C) 2021-2022 Anastasis SARL - - GNU Anastasis is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -import { - ComponentChildren, - Fragment, - FunctionalComponent, - h as create, - options, - render as renderIntoDom, - VNode, -} from "preact"; -import { render as renderToString } from "preact-render-to-string"; - -// When doing tests we want the requestAnimationFrame to be as fast as possible. -// without this option the RAF will timeout after 100ms making the tests slower -options.requestAnimationFrame = (fn: () => void) => { - // console.log("RAF called") - return fn(); -}; - -export function createExample<Props>( - Component: FunctionalComponent<Props>, - props: Partial<Props> | (() => Partial<Props>), -): ComponentChildren { - //FIXME: props are evaluated on build time - // in some cases we want to evaluated the props on render time so we can get some relative timestamp - // check how we can build evaluatedProps in render time - const evaluatedProps = typeof props === "function" ? props() : props; - const Render = (args: any): VNode => create(Component, args); - return { - component: Render, - props: evaluatedProps - }; -} - -export function createExampleWithCustomContext<Props, ContextProps>( - Component: FunctionalComponent<Props>, - props: Partial<Props> | (() => Partial<Props>), - ContextProvider: FunctionalComponent<ContextProps>, - contextProps: Partial<ContextProps>, -): ComponentChildren { - const evaluatedProps = typeof props === "function" ? props() : props; - const Render = (args: any): VNode => create(Component, args); - const WithContext = (args: any): VNode => - create(ContextProvider, { - ...contextProps, - children: [Render(args)], - } as any); - return { - component: WithContext, - props: evaluatedProps - }; -} - -export function NullLink({ - children, -}: { - children?: ComponentChildren; -}): VNode { - return create("a", { children, href: "javascript:void(0);" }); -} - -export function renderNodeOrBrowser(Component: any, args: any): void { - const vdom = create(Component, args); - if (typeof window === "undefined") { - renderToString(vdom); - } else { - const div = document.createElement("div"); - document.body.appendChild(div); - renderIntoDom(vdom, div); - renderIntoDom(null, div); - document.body.removeChild(div); - } -} - -interface Mounted<T> { - unmount: () => void; - getLastResultOrThrow: () => T; - assertNoPendingUpdate: () => void; - waitNextUpdate: (s?: string) => Promise<void>; -} - -const isNode = typeof window === "undefined"; - -export function mountHook<T>( - callback: () => T, - Context?: ({ children }: { children: any }) => VNode, -): Mounted<T> { - // const result: { current: T | null } = { - // current: null - // } - let lastResult: T | Error | null = null; - - const listener: Array<() => void> = []; - - // component that's going to hold the hook - function Component(): VNode { - try { - lastResult = callback(); - } catch (e) { - if (e instanceof Error) { - lastResult = e; - } else { - lastResult = new Error(`mounting the hook throw an exception: ${e}`); - } - } - - // notify to everyone waiting for an update and clean the queue - listener.splice(0, listener.length).forEach((cb) => cb()); - return create(Fragment, {}); - } - - // create the vdom with context if required - const vdom = !Context - ? create(Component, {}) - : create(Context, { children: [create(Component, {})] }); - - // waiter callback - async function waitNextUpdate(_label = ""): Promise<void> { - if (_label) _label = `. label: "${_label}"`; - await new Promise((res, rej) => { - const tid = setTimeout(() => { - rej( - Error(`waiting for an update but the hook didn't make one${_label}`), - ); - }, 100); - - listener.push(() => { - clearTimeout(tid); - res(undefined); - }); - }); - } - - const customElement = {} as Element; - const parentElement = isNode ? customElement : document.createElement("div"); - if (!isNode) { - document.body.appendChild(parentElement); - } - - renderIntoDom(vdom, parentElement); - - // clean up callback - function unmount(): void { - if (!isNode) { - document.body.removeChild(parentElement); - } - } - - function getLastResult(): T | Error | null { - const copy = lastResult; - lastResult = null; - return copy; - } - - function getLastResultOrThrow(): T { - const r = getLastResult(); - if (r instanceof Error) throw r; - if (!r) throw Error("there was no last result"); - return r; - } - - async function assertNoPendingUpdate(): Promise<void> { - await new Promise((res, rej) => { - const tid = setTimeout(() => { - res(undefined); - }, 10); - - listener.push(() => { - clearTimeout(tid); - rej( - Error(`Expecting no pending result but the hook got updated. - If the update was not intended you need to check the hook dependencies - (or dependencies of the internal state) but otherwise make - sure to consume the result before ending the test.`), - ); - }); - }); - - const r = getLastResult(); - if (r) - throw Error(`There are still pending results. - This may happen because the hook did a new update but the test didn't consume the result using getLastResult`); - } - return { - unmount, - getLastResultOrThrow, - waitNextUpdate, - assertNoPendingUpdate, - }; -} diff --git a/packages/anastasis-webui/src/utils/index.tsx b/packages/anastasis-webui/src/utils/index.tsx index 4cf839473..88bcac551 100644 --- a/packages/anastasis-webui/src/utils/index.tsx +++ b/packages/anastasis-webui/src/utils/index.tsx @@ -21,67 +21,12 @@ import { ReducerState, ReducerStateRecovery, } from "@gnu-taler/anastasis-core"; -import { ComponentChildren, FunctionalComponent, h, VNode } from "preact"; -import { AnastasisProvider } from "../context/anastasis.js"; +import { VNode } from "preact"; const noop = async (): Promise<void> => { return; }; -export function createExampleWithoutAnastasis<Props>( - Component: FunctionalComponent<Props>, - props: Partial<Props> | (() => Partial<Props>), -): ComponentChildren { - //FIXME: props are evaluated on build time - // in some cases we want to evaluated the props on render time so we can get some relative timestamp - // check how we can build evaluatedProps in render time - const evaluatedProps = typeof props === "function" ? props() : props; - const Render = (args: any): VNode => h(Component, args); - return { - component: Render, - props: evaluatedProps, - }; -} - -export function createExample<Props>( - Component: FunctionalComponent<Props>, - currentReducerState?: ReducerState, - props?: Partial<Props>, -): ComponentChildren { - const Render = (args: Props): VNode => { - return ( - <AnastasisProvider - value={{ - currentReducerState, - discoverMore: noop, - discoverStart: noop, - discoveryState: { - state: "finished", - }, - currentError: undefined, - back: noop, - dismissError: noop, - reset: noop, - runTransaction: noop, - startBackup: noop, - startRecover: noop, - transition: noop, - exportState: () => { - return "{}"; - }, - importState: noop, - }} - > - <Component {...(args as any)} /> - </AnastasisProvider> - ); - }; - return { - component: Render, - props: props, - }; -} - const base = { continents: [ { |