remove old testing function, use web-utils
This commit is contained in:
parent
7fe5f3767e
commit
dbb3529b49
@ -10,7 +10,7 @@
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
|
||||
"test": "pnpm compile && mocha --require source-map-support/register 'dist/**/*.test.js' 'dist/**/test.js'",
|
||||
"test": "mocha --require source-map-support/register 'dist/**/*.test.js' 'dist/**/test.js'",
|
||||
"test:coverage": "nyc pnpm test",
|
||||
"compile": "tsc && ./build-fast-with-linaria.mjs",
|
||||
"prepare": "tsc",
|
||||
@ -82,4 +82,4 @@
|
||||
"pogen": {
|
||||
"domain": "taler-wallet-webex"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
import { setupI18n } from "@gnu-taler/taler-util";
|
||||
import { parseGroupImport } from "@gnu-taler/web-util/lib/index.browser";
|
||||
import { parseGroupImport, tests } from "@gnu-taler/web-util/lib/index.browser";
|
||||
import chromeAPI from "./platform/chrome.js";
|
||||
import { setupPlatform } from "./platform/foreground.js";
|
||||
|
||||
@ -28,8 +28,8 @@ import * as cta from "./cta/index.stories.js";
|
||||
import * as mui from "./mui/index.stories.js";
|
||||
import * as popup from "./popup/index.stories.js";
|
||||
import * as wallet from "./wallet/index.stories.js";
|
||||
import { renderNodeOrBrowser } from "./test-utils.js";
|
||||
import { h, VNode } from "preact";
|
||||
// import { renderNodeOrBrowser } from "./test-utils.js";
|
||||
import { h, VNode, ComponentChildren } from "preact";
|
||||
import { AlertProvider } from "./context/alert.js";
|
||||
|
||||
setupI18n("en", { en: {} });
|
||||
@ -43,15 +43,7 @@ describe("All the examples:", () => {
|
||||
describe(`Component ${component.name}:`, () => {
|
||||
component.examples.forEach((example) => {
|
||||
it(`should render example: ${example.name}`, () => {
|
||||
function C(): VNode {
|
||||
const B = h(example.render.component, example.render.props);
|
||||
//FIXME:
|
||||
//some components push the alter in the UI function
|
||||
//that's not correct, should be moved into the state function
|
||||
// until then, we ran the tests with the alert provider
|
||||
return h(AlertProvider, { children: B }, B);
|
||||
}
|
||||
renderNodeOrBrowser(C, {});
|
||||
tests.renderUI(example.render, DefaultTestingContext);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -59,3 +51,14 @@ describe("All the examples:", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
function DefaultTestingContext({
|
||||
children,
|
||||
}: {
|
||||
children: ComponentChildren;
|
||||
}): VNode {
|
||||
//FIXME:
|
||||
//some components push the alter in the UI function
|
||||
//that's not correct, should be moved into the state function
|
||||
// until then, we ran the tests with the alert provider
|
||||
return h(AlertProvider, { children });
|
||||
}
|
||||
|
@ -21,204 +21,18 @@ import {
|
||||
WalletCoreRequestType,
|
||||
WalletCoreResponseType,
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import { TranslationProvider } from "@gnu-taler/web-util/lib/index.browser";
|
||||
import {
|
||||
ComponentChildren,
|
||||
Fragment,
|
||||
FunctionalComponent,
|
||||
VNode,
|
||||
h as create,
|
||||
options,
|
||||
render as renderIntoDom,
|
||||
} from "preact";
|
||||
import { render as renderToString } from "preact-render-to-string";
|
||||
import { AlertProvider } from "./context/alert.js";
|
||||
import { BackendProvider } from "./context/backend.js";
|
||||
import { strings } from "./i18n/strings.js";
|
||||
import { nullFunction } from "./mui/handlers.js";
|
||||
import { BackgroundApiClient, wxApi } from "./wxApi.js";
|
||||
import { TranslationProvider } from "@gnu-taler/web-util/lib/index.browser";
|
||||
import { strings } from "./i18n/strings.js";
|
||||
|
||||
// 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) => {
|
||||
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);
|
||||
// Render.args = evaluatedProps;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
type RecursiveState<S> = S | (() => RecursiveState<S>);
|
||||
|
||||
interface Mounted<T> {
|
||||
unmount: () => void;
|
||||
pullLastResultOrThrow: () => Exclude<T, VoidFunction>;
|
||||
assertNoPendingUpdate: () => void;
|
||||
// waitNextUpdate: (s?: string) => Promise<void>;
|
||||
waitForStateUpdate: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
const isNode = typeof window === "undefined";
|
||||
|
||||
export function mountHook<T extends object>(
|
||||
callback: () => RecursiveState<T>,
|
||||
Context?: ({ children }: { children: any }) => VNode,
|
||||
): Mounted<T> {
|
||||
let lastResult: Exclude<T, VoidFunction> | Error | null = null;
|
||||
|
||||
const listener: Array<() => void> = [];
|
||||
|
||||
// component that's going to hold the hook
|
||||
function Component(): VNode {
|
||||
try {
|
||||
let componentOrResult = callback();
|
||||
while (typeof componentOrResult === "function") {
|
||||
componentOrResult = componentOrResult();
|
||||
}
|
||||
//typecheck fails here
|
||||
const l: Exclude<T, () => void> = componentOrResult as any;
|
||||
lastResult = l;
|
||||
} 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, {})] });
|
||||
|
||||
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 pullLastResult(): Exclude<T | Error | null, VoidFunction> {
|
||||
const copy: Exclude<T | Error | null, VoidFunction> = lastResult;
|
||||
lastResult = null;
|
||||
return copy;
|
||||
}
|
||||
|
||||
function pullLastResultOrThrow(): Exclude<T, VoidFunction> {
|
||||
const r = pullLastResult();
|
||||
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 = pullLastResult();
|
||||
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 pullLastResult`);
|
||||
}
|
||||
async function waitForStateUpdate(): Promise<boolean> {
|
||||
return await new Promise((res, rej) => {
|
||||
const tid = setTimeout(() => {
|
||||
res(false);
|
||||
}, 10);
|
||||
|
||||
listener.push(() => {
|
||||
clearTimeout(tid);
|
||||
res(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
unmount,
|
||||
pullLastResultOrThrow,
|
||||
waitForStateUpdate,
|
||||
assertNoPendingUpdate,
|
||||
};
|
||||
}
|
||||
|
||||
// export const nullFunction: any = () => null;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user