replace jest with mocha
This commit is contained in:
parent
2e71117f59
commit
9f8139e09b
@ -45,7 +45,6 @@
|
||||
"@storybook/preact": "^6.3.12",
|
||||
"@storybook/preset-scss": "^1.0.3",
|
||||
"@types/enzyme": "^3.10.10",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
||||
"@typescript-eslint/parser": "^5.3.0",
|
||||
"bulma": "^0.9.3",
|
||||
@ -55,20 +54,11 @@
|
||||
"enzyme-adapter-preact-pure": "^3.2.0",
|
||||
"eslint": "^8.1.0",
|
||||
"eslint-config-preact": "^1.2.0",
|
||||
"jest": "^27.3.1",
|
||||
"jest-preset-preact": "^4.0.5",
|
||||
"jssha": "^3.2.0",
|
||||
"preact-cli": "^3.3.1",
|
||||
"sass": "1.32.13",
|
||||
"sass-loader": "^10",
|
||||
"sirv-cli": "^1.0.14",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-preset-preact",
|
||||
"setupFiles": [
|
||||
"<rootDir>/tests/__mocks__/browserMocks.ts",
|
||||
"<rootDir>/tests/__mocks__/setupTests.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -52,10 +52,10 @@ module.exports = {
|
||||
// https://github.com/storybookjs/storybook/issues/16623
|
||||
// https://github.com/nodejs/node/issues/33460
|
||||
// FIXME: remove this comments in 2022 if no problem arise
|
||||
// config.resolve.alias = {
|
||||
// react: "preact/compat",
|
||||
// "react-dom": "preact/compat",
|
||||
// };
|
||||
// config.resolve.alias = {
|
||||
// react: "preact/compat",
|
||||
// "react-dom": "preact/compat",
|
||||
// };
|
||||
|
||||
// we need to add @linaria loader AFTER the babel-loader
|
||||
// https://github.com/callstack/linaria/blob/master/docs/BUNDLERS_INTEGRATION.md#webpack
|
||||
|
@ -21,7 +21,6 @@ import { TranslationProvider } from '../src/context/translation'
|
||||
import { PopupBox, WalletBox } from '../src/components/styled'
|
||||
export const parameters = {
|
||||
controls: { expanded: true },
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
}
|
||||
|
||||
export const globalTypes = {
|
||||
|
@ -2,6 +2,7 @@
|
||||
# This file is in the public domain.
|
||||
set -e
|
||||
|
||||
mv node_modules{,_saved}
|
||||
rm -rf dist lib tsconfig.tsbuildinfo
|
||||
(cd ../.. && rm -rf build/web && ./contrib/build-fast-web.sh)
|
||||
rm -rf extension/
|
||||
@ -9,3 +10,4 @@ rm -rf extension/
|
||||
(cd extension/v2 && unzip taler*.zip)
|
||||
(cd extension/v3 && unzip taler*.zip)
|
||||
|
||||
mv node_modules{_saved,}
|
||||
|
@ -9,8 +9,9 @@
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
|
||||
"test": "jest ./tests",
|
||||
"compile": "tsc && rollup -c",
|
||||
"test": "mocha --enable-source-maps 'dist/**/*.test.js'",
|
||||
"test:coverage": "nyc pnpm test",
|
||||
"compile": "rollup -c -m",
|
||||
"build-storybook": "build-storybook",
|
||||
"storybook": "start-storybook -s . -p 6006",
|
||||
"pretty": "prettier --write src",
|
||||
@ -41,22 +42,21 @@
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.1.0",
|
||||
"@rollup/plugin-replace": "^2.3.4",
|
||||
"@rollup/plugin-typescript": "^8.3.0",
|
||||
"@storybook/addon-a11y": "^6.2.9",
|
||||
"@storybook/addon-essentials": "^6.2.9",
|
||||
"@storybook/preact": "^6.2.9",
|
||||
"@storybook/preact": "6.4.9",
|
||||
"@testing-library/preact": "^2.0.1",
|
||||
"@testing-library/preact-hooks": "^1.1.0",
|
||||
"@types/chrome": "^0.0.128",
|
||||
"@types/enzyme": "^3.10.10",
|
||||
"@types/history": "^4.7.8",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/node": "^14.14.22",
|
||||
"ava": "3.15.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-transform-react-jsx": "^6.24.1",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-preact-pure": "^3.1.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-preset-preact": "^4.0.2",
|
||||
"mocha": "^9.1.3",
|
||||
"nyc": "^15.1.0",
|
||||
"preact-cli": "^3.0.5",
|
||||
"preact-render-to-string": "^5.1.19",
|
||||
"rimraf": "^3.0.2",
|
||||
@ -68,17 +68,10 @@
|
||||
"storybook-dark-mode": "^1.0.8",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-preset-preact",
|
||||
"setupFiles": [
|
||||
"<rootDir>/tests/__mocks__/setupTests.ts"
|
||||
"nyc": {
|
||||
"include": [
|
||||
"**"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"\\.(css|less)$": "identity-obj-proxy",
|
||||
"@linaria/react": "<rootDir>/tests/__mocks__/linaria.ts"
|
||||
},
|
||||
"transform": {
|
||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|po)$": "<rootDir>/tests/__mocks__/fileTransformer.js"
|
||||
}
|
||||
"exclude": []
|
||||
}
|
||||
}
|
@ -8,8 +8,36 @@ import nodeResolve from "@rollup/plugin-node-resolve";
|
||||
import replace from "@rollup/plugin-replace";
|
||||
import css from 'rollup-plugin-css-only';
|
||||
import ignore from "rollup-plugin-ignore";
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
function fromDir(startPath, regex) {
|
||||
if (!fs.existsSync(startPath)) {
|
||||
return;
|
||||
}
|
||||
const files = fs.readdirSync(startPath);
|
||||
const result = files.flatMap(file => {
|
||||
const filename = path.join(startPath, file);
|
||||
|
||||
const stat = fs.lstatSync(filename);
|
||||
if (stat.isDirectory()) {
|
||||
return fromDir(filename, regex);
|
||||
}
|
||||
else if (regex.test(filename)) {
|
||||
return filename
|
||||
}
|
||||
}).filter(x => !!x)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
const makePlugins = () => [
|
||||
typescript({
|
||||
outputToFilesystem: false,
|
||||
}),
|
||||
|
||||
alias({
|
||||
entries: [
|
||||
{ find: 'react', replacement: 'preact/compat' },
|
||||
@ -28,7 +56,8 @@ const makePlugins = () => [
|
||||
|
||||
replace({
|
||||
"process.env.NODE_ENV": JSON.stringify("production"),
|
||||
"__filename": "'__webextension__'",
|
||||
// "__filename": "'__webextension__'",
|
||||
preventAssignment: true
|
||||
}),
|
||||
|
||||
commonjs({
|
||||
@ -49,7 +78,7 @@ const makePlugins = () => [
|
||||
|
||||
|
||||
const webExtensionWalletEntryPoint = {
|
||||
input: "lib/walletEntryPoint.js",
|
||||
input: "src/walletEntryPoint.tsx",
|
||||
output: {
|
||||
file: "dist/walletEntryPoint.js",
|
||||
format: "iife",
|
||||
@ -65,7 +94,7 @@ const webExtensionWalletEntryPoint = {
|
||||
};
|
||||
|
||||
const webExtensionPopupEntryPoint = {
|
||||
input: "lib/popupEntryPoint.js",
|
||||
input: "src/popupEntryPoint.tsx",
|
||||
output: {
|
||||
file: "dist/popupEntryPoint.js",
|
||||
format: "iife",
|
||||
@ -81,7 +110,7 @@ const webExtensionPopupEntryPoint = {
|
||||
};
|
||||
|
||||
const webExtensionBackgroundPageScript = {
|
||||
input: "lib/background.js",
|
||||
input: "src/background.ts",
|
||||
output: {
|
||||
file: "dist/background.js",
|
||||
format: "iife",
|
||||
@ -92,7 +121,7 @@ const webExtensionBackgroundPageScript = {
|
||||
};
|
||||
|
||||
const webExtensionCryptoWorker = {
|
||||
input: "lib/browserWorkerEntry.js",
|
||||
input: "src/browserWorkerEntry.ts",
|
||||
output: {
|
||||
file: "dist/browserWorkerEntry.js",
|
||||
format: "iife",
|
||||
@ -102,9 +131,26 @@ const webExtensionCryptoWorker = {
|
||||
plugins: makePlugins(),
|
||||
};
|
||||
|
||||
const tests = fromDir('./src', /.test.ts$/).map(test => ({
|
||||
input: test,
|
||||
output: {
|
||||
file: test.replace(/^src/, 'dist').replace(/\.ts$/, '.js'),
|
||||
format: "iife",
|
||||
exports: "none",
|
||||
name: test,
|
||||
},
|
||||
plugins: [
|
||||
...makePlugins(),
|
||||
css({
|
||||
output: 'walletEntryPoint.css',
|
||||
}),
|
||||
],
|
||||
}))
|
||||
|
||||
export default [
|
||||
webExtensionPopupEntryPoint,
|
||||
webExtensionWalletEntryPoint,
|
||||
webExtensionBackgroundPageScript,
|
||||
webExtensionCryptoWorker,
|
||||
...tests,
|
||||
];
|
||||
|
23
packages/taler-wallet-webextension/run-test-in-browser.html
Normal file
23
packages/taler-wallet-webextension/run-test-in-browser.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mocha Tests</title>
|
||||
<link rel="stylesheet" href="node_modules/mocha/mocha.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="node_modules/mocha/mocha.js"></script>
|
||||
<script>mocha.setup('bdd')</script>
|
||||
|
||||
<!-- load code you want to test here -->
|
||||
|
||||
<!-- script src="dist/stories.test.js"></script -->
|
||||
<script src="dist/hooks/useTalerActionURL.test.js"></script>
|
||||
<!-- load your test files here -->
|
||||
|
||||
<script>
|
||||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -37,7 +37,7 @@ export enum Pages {
|
||||
deposit = "/deposit/:currency",
|
||||
settings = "/settings",
|
||||
dev = "/dev",
|
||||
cta = "/cta",
|
||||
cta = "/cta/:action",
|
||||
backup = "/backup",
|
||||
history = "/history",
|
||||
transaction = "/transaction/:tid",
|
||||
|
24
packages/taler-wallet-webextension/src/api/browser.ts
Normal file
24
packages/taler-wallet-webextension/src/api/browser.ts
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
export async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.tabs.executeScript(
|
||||
{
|
||||
code: `
|
||||
(() => {
|
||||
let x = document.querySelector("a[href^='taler://'") || document.querySelector("a[href^='taler+http://'");
|
||||
return x ? x.href.toString() : null;
|
||||
})();
|
||||
`,
|
||||
allFrames: false,
|
||||
},
|
||||
(result) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error(chrome.runtime.lastError);
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
resolve(result[0]);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
"use strict";
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2017 INRIA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getPermissionsApi = exports.isNode = exports.isFirefox = void 0;
|
||||
/**
|
||||
* Compatibility helpers needed for browsers that don't implement
|
||||
* WebExtension APIs consistently.
|
||||
*/
|
||||
function isFirefox() {
|
||||
const rt = chrome.runtime;
|
||||
if (typeof rt.getBrowserInfo === "function") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
exports.isFirefox = isFirefox;
|
||||
/**
|
||||
* Check if we are running under nodejs.
|
||||
*/
|
||||
function isNode() {
|
||||
return typeof process !== "undefined" && process.release.name === "node";
|
||||
}
|
||||
exports.isNode = isNode;
|
||||
function getPermissionsApi() {
|
||||
const myBrowser = globalThis.browser;
|
||||
if (
|
||||
typeof myBrowser === "object" &&
|
||||
typeof myBrowser.permissions === "object"
|
||||
) {
|
||||
return {
|
||||
addPermissionsListener: () => {
|
||||
// Not supported yet.
|
||||
},
|
||||
contains: myBrowser.permissions.contains,
|
||||
request: myBrowser.permissions.request,
|
||||
remove: myBrowser.permissions.remove,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
addPermissionsListener: chrome.permissions.onAdded.addListener.bind(
|
||||
chrome.permissions.onAdded,
|
||||
),
|
||||
contains: chrome.permissions.contains,
|
||||
request: chrome.permissions.request,
|
||||
remove: chrome.permissions.remove,
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.getPermissionsApi = getPermissionsApi;
|
||||
//# sourceMappingURL=compat.js.map
|
@ -19,7 +19,7 @@ import { h, VNode } from "preact";
|
||||
import {
|
||||
ButtonPrimary,
|
||||
TableWithRoundRows as TableWithRoundedRows,
|
||||
} from "./styled/index";
|
||||
} from "./styled";
|
||||
|
||||
export function BalanceTable({
|
||||
balances,
|
||||
|
@ -14,7 +14,7 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { Outlined, StyledCheckboxLabel } from "./styled/index";
|
||||
import { Outlined, StyledCheckboxLabel } from "./styled";
|
||||
import { h, VNode } from "preact";
|
||||
|
||||
interface Props {
|
||||
|
@ -32,7 +32,8 @@ export function ErrorTalerOperation({
|
||||
|
||||
if (!title || !error) return null;
|
||||
// const errorCode: number | undefined = (error.details as any)?.errorResponse?.code
|
||||
const errorHint: string | undefined = (error.details as any)?.errorResponse?.hint
|
||||
const errorHint: string | undefined = (error.details as any)?.errorResponse
|
||||
?.hint;
|
||||
|
||||
return (
|
||||
<ErrorBox style={{ paddingTop: 0, paddingBottom: 0 }}>
|
||||
@ -53,11 +54,11 @@ export function ErrorTalerOperation({
|
||||
<div style={{ padding: 5, textAlign: "left" }}>
|
||||
<div>{error.message}</div>
|
||||
</div>
|
||||
{errorHint &&
|
||||
{errorHint && (
|
||||
<div style={{ padding: 5, textAlign: "left" }}>
|
||||
<div>{errorHint}</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
{devMode && (
|
||||
<div style={{ textAlign: "left", overflowX: "auto" }}>
|
||||
<pre>{JSON.stringify(error, undefined, 2)}</pre>
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { NiceSelect } from "./styled/index";
|
||||
import { NiceSelect } from "./styled";
|
||||
|
||||
interface Props {
|
||||
value?: string;
|
||||
|
@ -34,7 +34,7 @@ import {
|
||||
SmallLightText,
|
||||
LargeText,
|
||||
LightText,
|
||||
} from "./styled/index";
|
||||
} from "./styled";
|
||||
import { Time } from "./Time";
|
||||
|
||||
export function TransactionItem(props: {
|
||||
|
49
packages/taler-wallet-webextension/src/context/iocContext.ts
Normal file
49
packages/taler-wallet-webextension/src/context/iocContext.ts
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createContext, h, VNode } from "preact";
|
||||
import { useContext } from "preact/hooks";
|
||||
import { findTalerUriInActiveTab } from "../api/browser";
|
||||
|
||||
interface Type {
|
||||
findTalerUriInActiveTab: () => Promise<string | undefined>;
|
||||
}
|
||||
const Context = createContext<Type>({
|
||||
findTalerUriInActiveTab: async () => undefined,
|
||||
});
|
||||
|
||||
/**
|
||||
* Inversion of control Context
|
||||
*
|
||||
* This context act as a proxy between API that need to be replaced in
|
||||
* different environments
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export const useIocContext = (): Type => useContext(Context);
|
||||
|
||||
export const IoCProviderForTesting = ({ value, children }: { value: Type, children: any }): VNode => {
|
||||
return h(Context.Provider, { value, children });
|
||||
};
|
||||
|
||||
export const IoCProviderForRuntime = ({ children }: { children: any }): VNode => {
|
||||
return h(Context.Provider, { value: { findTalerUriInActiveTab }, children });
|
||||
};
|
@ -34,13 +34,13 @@ export const NoBalance = createExample(TestedComponent, {
|
||||
status: PreparePayResultType.InsufficientBalance,
|
||||
noncePriv: "",
|
||||
proposalId: "proposal1234",
|
||||
contractTerms: ({
|
||||
contractTerms: {
|
||||
merchant: {
|
||||
name: "someone",
|
||||
},
|
||||
summary: "some beers",
|
||||
amount: "USD:10",
|
||||
} as Partial<ContractTerms>) as any,
|
||||
} as Partial<ContractTerms> as any,
|
||||
amountRaw: "USD:10",
|
||||
},
|
||||
});
|
||||
@ -50,13 +50,13 @@ export const NoEnoughBalance = createExample(TestedComponent, {
|
||||
status: PreparePayResultType.InsufficientBalance,
|
||||
noncePriv: "",
|
||||
proposalId: "proposal1234",
|
||||
contractTerms: ({
|
||||
contractTerms: {
|
||||
merchant: {
|
||||
name: "someone",
|
||||
},
|
||||
summary: "some beers",
|
||||
amount: "USD:10",
|
||||
} as Partial<ContractTerms>) as any,
|
||||
} as Partial<ContractTerms> as any,
|
||||
amountRaw: "USD:10",
|
||||
},
|
||||
balance: {
|
||||
@ -67,42 +67,40 @@ export const NoEnoughBalance = createExample(TestedComponent, {
|
||||
});
|
||||
|
||||
export const PaymentPossible = createExample(TestedComponent, {
|
||||
uri:
|
||||
"taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
|
||||
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
|
||||
payStatus: {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountEffective: "USD:10",
|
||||
amountRaw: "USD:10",
|
||||
noncePriv: "",
|
||||
contractTerms: ({
|
||||
contractTerms: {
|
||||
nonce: "123213123",
|
||||
merchant: {
|
||||
name: "someone",
|
||||
},
|
||||
amount: "USD:10",
|
||||
summary: "some beers",
|
||||
} as Partial<ContractTerms>) as any,
|
||||
} as Partial<ContractTerms> as any,
|
||||
contractTermsHash: "123456",
|
||||
proposalId: "proposal1234",
|
||||
},
|
||||
});
|
||||
|
||||
export const PaymentPossibleWithFee = createExample(TestedComponent, {
|
||||
uri:
|
||||
"taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
|
||||
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
|
||||
payStatus: {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountEffective: "USD:10.20",
|
||||
amountRaw: "USD:10",
|
||||
noncePriv: "",
|
||||
contractTerms: ({
|
||||
contractTerms: {
|
||||
nonce: "123213123",
|
||||
merchant: {
|
||||
name: "someone",
|
||||
},
|
||||
amount: "USD:10",
|
||||
summary: "some beers",
|
||||
} as Partial<ContractTerms>) as any,
|
||||
} as Partial<ContractTerms> as any,
|
||||
contractTermsHash: "123456",
|
||||
proposalId: "proposal1234",
|
||||
},
|
||||
@ -113,7 +111,7 @@ export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, {
|
||||
status: PreparePayResultType.AlreadyConfirmed,
|
||||
amountEffective: "USD:10",
|
||||
amountRaw: "USD:10",
|
||||
contractTerms: ({
|
||||
contractTerms: {
|
||||
merchant: {
|
||||
name: "someone",
|
||||
},
|
||||
@ -121,7 +119,7 @@ export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, {
|
||||
"congratulations! you are looking at the fulfillment message! ",
|
||||
summary: "some beers",
|
||||
amount: "USD:10",
|
||||
} as Partial<ContractTerms>) as any,
|
||||
} as Partial<ContractTerms> as any,
|
||||
contractTermsHash: "123456",
|
||||
proposalId: "proposal1234",
|
||||
paid: false,
|
||||
@ -135,13 +133,13 @@ export const AlreadyConfirmedWithoutFullfilment = createExample(
|
||||
status: PreparePayResultType.AlreadyConfirmed,
|
||||
amountEffective: "USD:10",
|
||||
amountRaw: "USD:10",
|
||||
contractTerms: ({
|
||||
contractTerms: {
|
||||
merchant: {
|
||||
name: "someone",
|
||||
},
|
||||
summary: "some beers",
|
||||
amount: "USD:10",
|
||||
} as Partial<ContractTerms>) as any,
|
||||
} as Partial<ContractTerms> as any,
|
||||
contractTermsHash: "123456",
|
||||
proposalId: "proposal1234",
|
||||
paid: false,
|
||||
@ -154,7 +152,7 @@ export const AlreadyPaid = createExample(TestedComponent, {
|
||||
status: PreparePayResultType.AlreadyConfirmed,
|
||||
amountEffective: "USD:10",
|
||||
amountRaw: "USD:10",
|
||||
contractTerms: ({
|
||||
contractTerms: {
|
||||
merchant: {
|
||||
name: "someone",
|
||||
},
|
||||
@ -162,7 +160,7 @@ export const AlreadyPaid = createExample(TestedComponent, {
|
||||
"congratulations! you are looking at the fulfillment message! ",
|
||||
summary: "some beers",
|
||||
amount: "USD:10",
|
||||
} as Partial<ContractTerms>) as any,
|
||||
} as Partial<ContractTerms> as any,
|
||||
contractTermsHash: "123456",
|
||||
proposalId: "proposal1234",
|
||||
paid: true,
|
||||
|
@ -135,7 +135,9 @@ export function PayPage({
|
||||
? Amounts.parseOrThrow(foundBalance.available)
|
||||
: undefined;
|
||||
// We use a string here so that dependency tracking for useEffect works properly
|
||||
const foundAmountStr = foundAmount ? Amounts.stringify(foundAmount) : undefined;
|
||||
const foundAmountStr = foundAmount
|
||||
? Amounts.stringify(foundAmount)
|
||||
: undefined;
|
||||
|
||||
useEffect(() => {
|
||||
if (!talerPayUri) return;
|
||||
|
@ -35,10 +35,10 @@ export const Complete = createExample(TestedComponent, {
|
||||
amountRefundGone: "USD:0",
|
||||
amountRefundGranted: "USD:2",
|
||||
contractTermsHash: "QWEASDZXC",
|
||||
info: ({
|
||||
info: {
|
||||
summary: "tasty cold beer",
|
||||
contractTermsHash: "QWEASDZXC",
|
||||
} as Partial<OrderShortInfo>) as any,
|
||||
} as Partial<OrderShortInfo> as any,
|
||||
pendingAtExchange: false,
|
||||
proposalId: "proposal123",
|
||||
},
|
||||
@ -50,10 +50,10 @@ export const Partial = createExample(TestedComponent, {
|
||||
amountRefundGone: "USD:1",
|
||||
amountRefundGranted: "USD:2",
|
||||
contractTermsHash: "QWEASDZXC",
|
||||
info: ({
|
||||
info: {
|
||||
summary: "tasty cold beer",
|
||||
contractTermsHash: "QWEASDZXC",
|
||||
} as Partial<OrderShortInfo>) as any,
|
||||
} as Partial<OrderShortInfo> as any,
|
||||
pendingAtExchange: false,
|
||||
proposalId: "proposal123",
|
||||
},
|
||||
@ -65,10 +65,10 @@ export const InProgress = createExample(TestedComponent, {
|
||||
amountRefundGone: "USD:1",
|
||||
amountRefundGranted: "USD:2",
|
||||
contractTermsHash: "QWEASDZXC",
|
||||
info: ({
|
||||
info: {
|
||||
summary: "tasty cold beer",
|
||||
contractTermsHash: "QWEASDZXC",
|
||||
} as Partial<OrderShortInfo>) as any,
|
||||
} as Partial<OrderShortInfo> as any,
|
||||
pendingAtExchange: true,
|
||||
proposalId: "proposal123",
|
||||
},
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
WarningBox,
|
||||
WarningText,
|
||||
} from "../components/styled";
|
||||
import { TermsState } from "../utils";
|
||||
import { TermsState } from "../utils/index";
|
||||
|
||||
interface Props {
|
||||
reviewing: boolean;
|
||||
|
@ -24,12 +24,16 @@ import { createExample } from "../test-utils";
|
||||
import { termsHtml, termsPdf, termsPlain, termsXml } from "./termsExample";
|
||||
import { View as TestedComponent } from "./Withdraw";
|
||||
|
||||
function parseFromString(s: string): Document {
|
||||
if (typeof window === "undefined") {
|
||||
return {} as Document;
|
||||
}
|
||||
return new window.DOMParser().parseFromString(s, "text/xml");
|
||||
}
|
||||
|
||||
export default {
|
||||
title: "cta/withdraw",
|
||||
component: TestedComponent,
|
||||
argTypes: {
|
||||
onSwitchExchange: { action: "onRetry" },
|
||||
},
|
||||
};
|
||||
|
||||
const exchangeList: ExchangeListItem[] = [
|
||||
@ -77,7 +81,7 @@ export const NewTerms = createExample(TestedComponent, {
|
||||
terms: {
|
||||
content: {
|
||||
type: "xml",
|
||||
document: new DOMParser().parseFromString(termsXml, "text/xml"),
|
||||
document: parseFromString(termsXml),
|
||||
},
|
||||
status: "new",
|
||||
version: "",
|
||||
@ -192,7 +196,7 @@ export const TermsReviewingXML = createExample(TestedComponent, {
|
||||
terms: {
|
||||
content: {
|
||||
type: "xml",
|
||||
document: new DOMParser().parseFromString(termsXml, "text/xml"),
|
||||
document: parseFromString(termsXml),
|
||||
},
|
||||
status: "new",
|
||||
version: "",
|
||||
@ -219,7 +223,7 @@ export const NewTermsAccepted = createExample(TestedComponent, {
|
||||
terms: {
|
||||
content: {
|
||||
type: "xml",
|
||||
document: new DOMParser().parseFromString(termsXml, "text/xml"),
|
||||
document: parseFromString(termsXml),
|
||||
},
|
||||
status: "new",
|
||||
version: "",
|
||||
@ -247,7 +251,7 @@ export const TermsShowAgainXML = createExample(TestedComponent, {
|
||||
terms: {
|
||||
content: {
|
||||
type: "xml",
|
||||
document: new DOMParser().parseFromString(termsXml, "text/xml"),
|
||||
document: parseFromString(termsXml),
|
||||
},
|
||||
version: "",
|
||||
status: "new",
|
||||
@ -276,7 +280,7 @@ export const TermsChanged = createExample(TestedComponent, {
|
||||
terms: {
|
||||
content: {
|
||||
type: "xml",
|
||||
document: new DOMParser().parseFromString(termsXml, "text/xml"),
|
||||
document: parseFromString(termsXml),
|
||||
},
|
||||
version: "",
|
||||
status: "changed",
|
||||
@ -351,7 +355,7 @@ export const WithoutFee = createExample(TestedComponent, {
|
||||
terms: {
|
||||
content: {
|
||||
type: "xml",
|
||||
document: new DOMParser().parseFromString(termsXml, "text/xml"),
|
||||
document: parseFromString(termsXml),
|
||||
},
|
||||
status: "accepted",
|
||||
version: "",
|
||||
|
@ -40,7 +40,11 @@ import {
|
||||
WalletAction,
|
||||
} from "../components/styled";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { amountToString, buildTermsOfServiceState, TermsState } from "../utils";
|
||||
import {
|
||||
amountToString,
|
||||
buildTermsOfServiceState,
|
||||
TermsState,
|
||||
} from "../utils/index";
|
||||
import * as wxApi from "../wxApi";
|
||||
import { TermsOfServiceSection } from "./TermsOfServiceSection";
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { useTalerActionURL } from "./useTalerActionURL"
|
||||
import { justBrowser_it, mountBrowser } from "../test-utils";
|
||||
import { IoCProviderForTesting } from "../context/iocContext";
|
||||
import { h, VNode } from "preact";
|
||||
import { act } from "preact/test-utils";
|
||||
|
||||
describe('useTalerActionURL hook', () => {
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
justBrowser_it('should be set url to undefined when dismiss', async () => {
|
||||
|
||||
const ctx = ({ children }: { children: any }): VNode => {
|
||||
return h(IoCProviderForTesting, {
|
||||
value: {
|
||||
findTalerUriInActiveTab: async () => "asd",
|
||||
}, children
|
||||
})
|
||||
}
|
||||
|
||||
const { result, waitNextUpdate } = mountBrowser(useTalerActionURL, ctx)
|
||||
|
||||
{
|
||||
const [url] = result.current!
|
||||
if (url !== undefined) throw Error('invalid')
|
||||
}
|
||||
|
||||
await waitNextUpdate()
|
||||
|
||||
{
|
||||
const [url] = result.current!
|
||||
if (url !== "asd") throw Error(`invalid: ${url}`)
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
const [, setDismissed] = result.current!
|
||||
setDismissed(true)
|
||||
})
|
||||
|
||||
{
|
||||
const [url] = result.current!
|
||||
if (url !== undefined) throw Error('invalid')
|
||||
}
|
||||
|
||||
})
|
||||
})
|
@ -14,8 +14,8 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useIocContext } from "../context/iocContext";
|
||||
|
||||
export function useTalerActionURL(): [
|
||||
string | undefined,
|
||||
@ -25,6 +25,8 @@ export function useTalerActionURL(): [
|
||||
undefined,
|
||||
);
|
||||
const [dismissed, setDismissed] = useState(false);
|
||||
const { findTalerUriInActiveTab } = useIocContext()
|
||||
|
||||
useEffect(() => {
|
||||
async function check(): Promise<void> {
|
||||
const talerUri = await findTalerUriInActiveTab();
|
||||
@ -35,28 +37,3 @@ export function useTalerActionURL(): [
|
||||
const url = dismissed ? undefined : talerActionUrl;
|
||||
return [url, setDismissed];
|
||||
}
|
||||
|
||||
async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.tabs.executeScript(
|
||||
{
|
||||
code: `
|
||||
(() => {
|
||||
let x = document.querySelector("a[href^='taler://'") || document.querySelector("a[href^='taler+http://'");
|
||||
return x ? x.href.toString() : null;
|
||||
})();
|
||||
`,
|
||||
allFrames: false,
|
||||
},
|
||||
(result) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error(chrome.runtime.lastError);
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
console.log("got result", result);
|
||||
resolve(result[0]);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -1,11 +1,7 @@
|
||||
import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import {
|
||||
Button,
|
||||
ButtonSuccess,
|
||||
InputWithLabel,
|
||||
} from "../components/styled/index";
|
||||
import { Button, ButtonSuccess, InputWithLabel } from "../components/styled";
|
||||
import { actionForTalerUri } from "../utils/index";
|
||||
|
||||
export interface Props {
|
||||
|
@ -17,7 +17,7 @@
|
||||
import { BalancesResponse, i18n } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { BalanceTable } from "../components/BalanceTable";
|
||||
import { ButtonPrimary, ErrorBox } from "../components/styled/index";
|
||||
import { ButtonPrimary, ErrorBox } from "../components/styled";
|
||||
import { HookResponse, useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { PageLink } from "../renderHtml";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
@ -20,7 +20,7 @@ import { format } from "date-fns";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { Diagnostics } from "../components/Diagnostics";
|
||||
import { NotifyUpdateFadeOut } from "../components/styled/index";
|
||||
import { NotifyUpdateFadeOut } from "../components/styled";
|
||||
import { Time } from "../components/Time";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { useDiagnostics } from "../hooks/useDiagnostics";
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { ButtonPrimary } from "../components/styled/index";
|
||||
import { ButtonPrimary } from "../components/styled";
|
||||
import { TransactionItem } from "../components/TransactionItem";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import * as wxApi from "../wxApi";
|
||||
@ -133,7 +133,7 @@ export function HistoryView({
|
||||
style={{ color: "darkgreen", textDecoration: "none" }}
|
||||
href={
|
||||
// eslint-disable-next-line no-undef
|
||||
chrome.extension
|
||||
typeof chrome !== "undefined" && chrome.extension
|
||||
? // eslint-disable-next-line no-undef
|
||||
chrome.extension.getURL(`/static/wallet.html#/history`)
|
||||
: "#"
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h } from "preact";
|
||||
import { ButtonPrimary, ButtonSuccess } from "../components/styled/index";
|
||||
import { ButtonPrimary, ButtonSuccess } from "../components/styled";
|
||||
import { actionForTalerUri } from "../utils/index";
|
||||
|
||||
export interface Props {
|
||||
|
@ -14,11 +14,16 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
// This fixed an error related to the CSS and loading gif breaking my Jest test
|
||||
// See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets
|
||||
export default 'test-file-stub';
|
||||
import * as a1 from "./AddNewActionView.stories";
|
||||
import * as a2 from "./Balance.stories";
|
||||
import * as a3 from "./DeveloperPage.stories";
|
||||
import * as a4 from "./History.stories";
|
||||
import * as a5 from "./Popup.stories";
|
||||
import * as a6 from "./TalerActionFound.stories";
|
||||
|
||||
export default [a1, a2, a3, a4, a5, a6];
|
@ -22,7 +22,7 @@
|
||||
|
||||
import { setupI18n } from "@gnu-taler/taler-util";
|
||||
import { createHashHistory } from "history";
|
||||
import { render, h } from "preact";
|
||||
import { render, h, VNode, Fragment } from "preact";
|
||||
import Router, { route, Route } from "preact-router";
|
||||
import { useEffect } from "preact/hooks";
|
||||
import { PopupBox } from "./components/styled";
|
||||
@ -39,6 +39,7 @@ import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
|
||||
import { SettingsPage } from "./popup/Settings";
|
||||
import { TalerActionFound } from "./popup/TalerActionFound";
|
||||
import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
|
||||
import { IoCProviderForRuntime } from "./context/iocContext";
|
||||
|
||||
function main(): void {
|
||||
try {
|
||||
@ -63,17 +64,24 @@ if (document.readyState === "loading") {
|
||||
main();
|
||||
}
|
||||
|
||||
function Application() {
|
||||
const [talerActionUrl, setDismissed] = useTalerActionURL();
|
||||
function CheckTalerActionComponent(): VNode {
|
||||
const [talerActionUrl] = useTalerActionURL();
|
||||
|
||||
useEffect(() => {
|
||||
if (talerActionUrl) route(Pages.cta);
|
||||
if (talerActionUrl)
|
||||
route(Pages.cta.replace(":action", encodeURIComponent(talerActionUrl)));
|
||||
}, [talerActionUrl]);
|
||||
|
||||
return <Fragment />;
|
||||
}
|
||||
|
||||
function Application() {
|
||||
return (
|
||||
<div>
|
||||
<DevContextProvider>
|
||||
<IoCProviderForRuntime>
|
||||
<WalletNavBar />
|
||||
<CheckTalerActionComponent />
|
||||
<PopupBox>
|
||||
<Router history={createHashHistory()}>
|
||||
<Route path={Pages.dev} component={DeveloperPage} />
|
||||
@ -91,15 +99,19 @@ function Application() {
|
||||
<Route path={Pages.settings} component={SettingsPage} />
|
||||
<Route
|
||||
path={Pages.cta}
|
||||
component={() => (
|
||||
component={function Action({ action }: { action: string }) {
|
||||
const [, setDismissed] = useTalerActionURL();
|
||||
|
||||
return (
|
||||
<TalerActionFound
|
||||
url={talerActionUrl!}
|
||||
url={decodeURIComponent(action)}
|
||||
onDismiss={() => {
|
||||
setDismissed(true);
|
||||
route(Pages.balance);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<Route
|
||||
@ -144,6 +156,7 @@ function Application() {
|
||||
<Route default component={Redirect} to={Pages.balance} />
|
||||
</Router>
|
||||
</PopupBox>
|
||||
</IoCProviderForRuntime>
|
||||
</DevContextProvider>
|
||||
</div>
|
||||
);
|
||||
|
51
packages/taler-wallet-webextension/src/stories.test.ts
Normal file
51
packages/taler-wallet-webextension/src/stories.test.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
import * as popup from "./popup/index.stories";
|
||||
import * as wallet from "./wallet/index.stories";
|
||||
|
||||
import { setupI18n } from "@gnu-taler/taler-util";
|
||||
import { renderNodeOrBrowser } from "./test-utils";
|
||||
setupI18n("en", { en: {} });
|
||||
|
||||
function testThisStory(st: any): any {
|
||||
describe(`render examples for ${(st as any).default.title}`, () => {
|
||||
Object.keys(st).forEach((k) => {
|
||||
const Component = (st as any)[k];
|
||||
if (k === "default" || !Component) return;
|
||||
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it(`example: ${k}`, () => {
|
||||
renderNodeOrBrowser(Component, Component.args);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("render every storybook example", () => {
|
||||
[popup, wallet].forEach(function testAll(st: any) {
|
||||
if (Array.isArray(st.default)) {
|
||||
st.default.forEach(testAll)
|
||||
} else {
|
||||
testThisStory(st)
|
||||
}
|
||||
});
|
||||
});
|
@ -14,13 +14,15 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { ComponentChildren, FunctionalComponent, h as render, VNode } from "preact";
|
||||
import { PendingTestFunction, TestFunction } from "mocha";
|
||||
import { ComponentChildren, Fragment, FunctionalComponent, h as create, render as renderIntoDom, VNode } from "preact";
|
||||
import { render as renderToString } from "preact-render-to-string";
|
||||
|
||||
export function createExample<Props>(
|
||||
Component: FunctionalComponent<Props>,
|
||||
props: Partial<Props>,
|
||||
): ComponentChildren {
|
||||
const Render = (args: any) => render(Component, args);
|
||||
const Render = (args: any): VNode => create(Component, args);
|
||||
Render.args = props;
|
||||
return Render;
|
||||
}
|
||||
@ -31,12 +33,89 @@ export function createExampleWithCustomContext<Props, ContextProps>(
|
||||
ContextProvider: FunctionalComponent<ContextProps>,
|
||||
contextProps: Partial<ContextProps>,
|
||||
): ComponentChildren {
|
||||
const Render = (args: any): VNode => render(Component, args);
|
||||
const WithContext = (args: any): VNode => render(ContextProvider, { ...contextProps, children: [Render(args)] } as any);
|
||||
const Render = (args: any): VNode => create(Component, args);
|
||||
const WithContext = (args: any): VNode => create(ContextProvider, { ...contextProps, children: [Render(args)] } as any);
|
||||
WithContext.args = props
|
||||
return WithContext
|
||||
}
|
||||
|
||||
export function NullLink({ children }: { children?: ComponentChildren }) {
|
||||
return render("a", { children, href: "javascript:void(0);" });
|
||||
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;
|
||||
result: { current: T | null };
|
||||
waitNextUpdate: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function mountBrowser<T>(callback: () => T, Context?: ({ children }: { children: any }) => VNode): Mounted<T> {
|
||||
const result: { current: T | null } = {
|
||||
current: null
|
||||
}
|
||||
const listener: Array<() => void> = []
|
||||
|
||||
// component that's going to hold the hook
|
||||
function Component(): VNode {
|
||||
const hookResult = callback()
|
||||
// save the hook result
|
||||
result.current = hookResult
|
||||
// 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, {})] },);
|
||||
|
||||
// in non-browser environment (server side rendering) just serialize to
|
||||
// string and exit
|
||||
if (typeof window === "undefined") {
|
||||
renderToString(vdom);
|
||||
return { unmount: () => null, result } as any
|
||||
}
|
||||
|
||||
// do the render into the DOM
|
||||
const div = document.createElement("div");
|
||||
document.body.appendChild(div);
|
||||
renderIntoDom(vdom, div);
|
||||
|
||||
// clean up callback
|
||||
function unmount(): any {
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
|
||||
// waiter callback
|
||||
async function waitNextUpdate(): Promise<void> {
|
||||
await new Promise((res, rej) => {
|
||||
const tid = setTimeout(() => {
|
||||
rej(Error("waiting for an update but the hook didn't make one"))
|
||||
}, 100)
|
||||
|
||||
listener.push(() => {
|
||||
clearTimeout(tid)
|
||||
res(undefined)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
unmount, result, waitNextUpdate
|
||||
}
|
||||
}
|
||||
|
||||
export const justBrowser_it: PendingTestFunction | TestFunction =
|
||||
typeof window === 'undefined' ? it.skip : it
|
@ -17,7 +17,7 @@
|
||||
import { BalancesResponse, i18n } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { BalanceTable } from "../components/BalanceTable";
|
||||
import { ButtonPrimary, Centered, ErrorBox } from "../components/styled/index";
|
||||
import { ButtonPrimary, Centered, ErrorBox } from "../components/styled";
|
||||
import { HookResponse, useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { PageLink } from "../renderHtml";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
@ -19,7 +19,7 @@
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { AmountJson, Amounts, parsePaytoUri } from "@gnu-taler/taler-util";
|
||||
import { Amounts, parsePaytoUri } from "@gnu-taler/taler-util";
|
||||
import { DepositFee } from "@gnu-taler/taler-wallet-core/src/operations/deposits";
|
||||
import { createExample } from "../test-utils";
|
||||
import { View as TestedComponent } from "./DepositPage";
|
||||
|
@ -108,8 +108,13 @@ export function View({
|
||||
const currency = balance.currency;
|
||||
const amountStr: AmountString = `${currency}:${amount}`;
|
||||
|
||||
const account = knownBankAccounts[accountIdx];
|
||||
const accountURI = `payto://${account.targetType}/${account.targetPath}`;
|
||||
const account = knownBankAccounts.length
|
||||
? knownBankAccounts[accountIdx]
|
||||
: undefined;
|
||||
const accountURI = !account
|
||||
? ""
|
||||
: `payto://${account.targetType}/${account.targetPath}`;
|
||||
|
||||
useEffect(() => {
|
||||
if (amount === undefined) return;
|
||||
onCalculateFee(accountURI, amountStr).then((result) => {
|
||||
|
@ -23,6 +23,17 @@ import { termsXml } from "../cta/termsExample";
|
||||
import { createExample } from "../test-utils";
|
||||
import { View as TestedComponent } from "./ExchangeAddConfirm";
|
||||
|
||||
function parseFromString(s: string): Document {
|
||||
if (typeof window === "undefined") {
|
||||
return {
|
||||
querySelector: () => ({
|
||||
children: [],
|
||||
}),
|
||||
} as any;
|
||||
}
|
||||
return new window.DOMParser().parseFromString(s, "text/xml");
|
||||
}
|
||||
|
||||
export default {
|
||||
title: "wallet/exchange add/confirm",
|
||||
component: TestedComponent,
|
||||
@ -60,7 +71,7 @@ export const TermsChanged = createExample(TestedComponent, {
|
||||
version: "1",
|
||||
content: {
|
||||
type: "xml",
|
||||
document: new DOMParser().parseFromString(termsXml, "text/xml"),
|
||||
document: parseFromString(termsXml),
|
||||
},
|
||||
},
|
||||
onAccept: async () => undefined,
|
||||
|
@ -1,14 +1,10 @@
|
||||
import { i18n } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import {
|
||||
Button,
|
||||
ButtonSuccess,
|
||||
ButtonWarning,
|
||||
} from "../components/styled/index";
|
||||
import { Button, ButtonSuccess, ButtonWarning } from "../components/styled";
|
||||
import { TermsOfServiceSection } from "../cta/TermsOfServiceSection";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { buildTermsOfServiceState, TermsState } from "../utils";
|
||||
import { buildTermsOfServiceState, TermsState } from "../utils/index";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
||||
export interface Props {
|
||||
|
@ -21,7 +21,7 @@ import {
|
||||
import { h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { queryToSlashKeys } from "../utils";
|
||||
import { queryToSlashKeys } from "../utils/index";
|
||||
import * as wxApi from "../wxApi";
|
||||
import { ExchangeAddConfirmPage } from "./ExchangeAddConfirm";
|
||||
import { ExchangeSetUrlPage } from "./ExchangeSetUrl";
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
import { createExample } from "../test-utils";
|
||||
import { queryToSlashKeys } from "../utils";
|
||||
import { queryToSlashKeys } from "../utils/index";
|
||||
import { ExchangeSetUrlPage as TestedComponent } from "./ExchangeSetUrl";
|
||||
|
||||
export default {
|
||||
|
@ -7,12 +7,7 @@ import {
|
||||
import { Fragment, h } from "preact";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { ErrorMessage } from "../components/ErrorMessage";
|
||||
import {
|
||||
Button,
|
||||
ButtonPrimary,
|
||||
Input,
|
||||
WarningBox,
|
||||
} from "../components/styled/index";
|
||||
import { Button, ButtonPrimary, Input, WarningBox } from "../components/styled";
|
||||
|
||||
export interface Props {
|
||||
initialValue?: string;
|
||||
|
@ -30,8 +30,8 @@ import {
|
||||
Input,
|
||||
LightText,
|
||||
SmallLightText,
|
||||
} from "../components/styled/index";
|
||||
import { queryToSlashConfig } from "../utils";
|
||||
} from "../components/styled";
|
||||
import { queryToSlashConfig } from "../utils/index";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
||||
interface Props {
|
||||
|
@ -3,7 +3,7 @@ import { Fragment, h, VNode } from "preact";
|
||||
import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType";
|
||||
import { QR } from "../components/QR";
|
||||
import { ButtonDestructive, WarningBox } from "../components/styled";
|
||||
import { amountToString } from "../utils";
|
||||
import { amountToString } from "../utils/index";
|
||||
export interface Props {
|
||||
reservePub: string;
|
||||
payto: string;
|
||||
|
@ -29,7 +29,7 @@ import { useBackupDeviceName } from "../hooks/useBackupDeviceName";
|
||||
import { useExtendedPermissions } from "../hooks/useExtendedPermissions";
|
||||
import { useLang } from "../hooks/useLang";
|
||||
import { Pages } from "../NavigationBar";
|
||||
import { buildTermsOfServiceStatus } from "../utils";
|
||||
import { buildTermsOfServiceStatus } from "../utils/index";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
||||
export function SettingsPage(): VNode {
|
||||
|
@ -125,12 +125,13 @@ const exampleData = {
|
||||
const transactionError = {
|
||||
code: 7005,
|
||||
details: {
|
||||
requestUrl: "http://merchant-backend.taler:9966/orders/2021.340-02AD5XCC97MQM/pay",
|
||||
requestUrl:
|
||||
"http://merchant-backend.taler:9966/orders/2021.340-02AD5XCC97MQM/pay",
|
||||
httpStatusCode: 410,
|
||||
errorResponse: {
|
||||
code: 2161,
|
||||
hint: "The payment is too late, the offer has expired."
|
||||
}
|
||||
hint: "The payment is too late, the offer has expired.",
|
||||
},
|
||||
},
|
||||
hint: "Error: WALLET_UNEXPECTED_REQUEST_ERROR",
|
||||
message: "Unexpected error code in response",
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import * as a1 from "./Backup.stories";
|
||||
import * as a2 from "./Balance.stories";
|
||||
import * as a3 from "./CreateManualWithdraw.stories";
|
||||
import * as a4 from "./DepositPage.stories";
|
||||
import * as a5 from "./ExchangeAddConfirm.stories";
|
||||
import * as a6 from "./ExchangeAddSetUrl.stories";
|
||||
import * as a7 from "./History.stories";
|
||||
import * as a8 from "./ProviderAddConfirmProvider.stories";
|
||||
import * as a9 from "./ProviderAddSetUrl.stories";
|
||||
import * as a10 from "./ProviderDetail.stories";
|
||||
import * as a11 from "./ReserveCreated.stories";
|
||||
import * as a12 from "./Settings.stories";
|
||||
import * as a13 from "./Transaction.stories";
|
||||
import * as a14 from "./Welcome.stories";
|
||||
|
||||
export default [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14];
|
@ -46,6 +46,7 @@ import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
|
||||
import { ProviderAddPage } from "./wallet/ProviderAddPage";
|
||||
import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
|
||||
import { DepositPage } from "./wallet/DepositPage";
|
||||
import { IoCProviderForRuntime } from "./context/iocContext";
|
||||
|
||||
function main(): void {
|
||||
try {
|
||||
@ -88,6 +89,7 @@ function Application(): VNode {
|
||||
return (
|
||||
<div>
|
||||
<DevContextProvider>
|
||||
<IoCProviderForRuntime>
|
||||
<Router history={createHashHistory()}>
|
||||
<Route
|
||||
path={Pages.welcome}
|
||||
@ -185,6 +187,7 @@ function Application(): VNode {
|
||||
|
||||
<Route default component={Redirect} to={Pages.history} />
|
||||
</Router>
|
||||
</IoCProviderForRuntime>
|
||||
</DevContextProvider>
|
||||
</div>
|
||||
);
|
||||
|
@ -39,7 +39,7 @@ import {
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import { DepositFee } from "@gnu-taler/taler-wallet-core/src/operations/deposits";
|
||||
import { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core/src/operations/withdraw";
|
||||
import { MessageFromBackend } from "./wxBackend.js";
|
||||
import { MessageFromBackend } from "./wxBackend";
|
||||
|
||||
export interface ExtendedPermissionsResponse {
|
||||
newValue: boolean;
|
||||
@ -75,7 +75,7 @@ async function callBackend(operation: string, payload: any): Promise<any> {
|
||||
console.log("Error calling backend");
|
||||
reject(
|
||||
new Error(
|
||||
`Error contacting backend: chrome.runtime.lastError.message`,
|
||||
`Error contacting backend: ${chrome.runtime.lastError.message}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
// fileTransformer.js
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
process(src, filename, config, options) {
|
||||
return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
|
||||
},
|
||||
};
|
||||
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Here we are mocking the linaria runtime since it should not be used in
|
||||
* runtime.
|
||||
*/
|
||||
export const styled = new Proxy(function (tag: any) {
|
||||
return jest.fn(() => `mock-styled.${tag}`);
|
||||
}, {
|
||||
get(o, prop) {
|
||||
return o(prop);
|
||||
},
|
||||
})
|
||||
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import 'regenerator-runtime/runtime'
|
||||
import { configure } from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-preact-pure';
|
||||
|
||||
configure({
|
||||
adapter: new Adapter()
|
||||
});
|
||||
|
||||
// Polyfill for encoding which isn't present globally in jsdom
|
||||
import { TextEncoder, TextDecoder } from 'util'
|
||||
global.TextEncoder = TextEncoder;
|
||||
global.TextDecoder = TextDecoder;
|
||||
(global as any).chrome = {};
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2020 Taler Systems SA
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
// import * as test from "ava";
|
||||
import { internalSetStrings, i18n, Translate } from "@gnu-taler/taler-util";
|
||||
import { render, configure } from "enzyme";
|
||||
import { h } from 'preact';
|
||||
import Adapter from 'enzyme-adapter-preact-pure';
|
||||
|
||||
configure({ adapter: new Adapter() });
|
||||
|
||||
const testStrings = {
|
||||
domain: "messages",
|
||||
locale_data: {
|
||||
messages: {
|
||||
str1: ["foo1"],
|
||||
str2: [""],
|
||||
"str3 %1$s / %2$s": ["foo3 %2$s ; %1$s"],
|
||||
"": {
|
||||
domain: "messages",
|
||||
plural_forms: "nplurals=2; plural=(n != 1);",
|
||||
lang: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test("str translation", (done) => {
|
||||
|
||||
// Alias, so we nly use the function for lookups, not for string extranction.
|
||||
const strAlias = i18n.str;
|
||||
const TranslateAlias = Translate;
|
||||
internalSetStrings(testStrings);
|
||||
expect(strAlias`str1`).toEqual("foo1");
|
||||
expect(strAlias`str2`).toEqual("str2");
|
||||
const a = "a";
|
||||
const b = "b";
|
||||
expect(strAlias`str3 ${a} / ${b}`).toEqual("foo3 b ; a");
|
||||
const r = render(<Translate>str1</Translate>);
|
||||
expect(r.text()).toEqual("foo1");
|
||||
|
||||
const r2 = render(
|
||||
<TranslateAlias>
|
||||
str3 <span>{a}</span> / <span>{b}</span>
|
||||
</TranslateAlias>,
|
||||
);
|
||||
expect(r2.text()).toEqual("foo3 b ; a");
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
// test.default("existing str translation", (t) => {
|
||||
// internalSetStrings(strings);
|
||||
// t.pass();
|
||||
// });
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
import { mount } from 'enzyme';
|
||||
import { h } from 'preact';
|
||||
|
||||
import fs from 'fs';
|
||||
|
||||
function getFiles(dir: string, files_: string[] = []) {
|
||||
const files = fs.readdirSync(dir);
|
||||
for (const i in files) {
|
||||
const name = dir + '/' + files[i];
|
||||
if (fs.statSync(name).isDirectory()) {
|
||||
getFiles(name, files_);
|
||||
} else {
|
||||
files_.push(name);
|
||||
}
|
||||
}
|
||||
return files_;
|
||||
}
|
||||
|
||||
const re = RegExp('.*\.stories.tsx')
|
||||
|
||||
import { setupI18n } from '@gnu-taler/taler-util';
|
||||
setupI18n('en',{'en':{}})
|
||||
|
||||
it('render every story', () => {
|
||||
// jest.spyOn(i18n, 'useTranslationContext').mockImplementation(() => ({ changeLanguage: () => null, lang: 'en' }));
|
||||
|
||||
getFiles('./src').filter(f => re.test(f)).map(f => {
|
||||
// const f = "./src/paths/instance/transfers/list/List.stories.tsx";
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const s = require(`../${f}`)
|
||||
|
||||
delete s.default
|
||||
|
||||
Object.keys(s).forEach(k => {
|
||||
const Component = s[k];
|
||||
expect(() => {
|
||||
try {
|
||||
let p = mount(<Component {...Component.args} /> as any)
|
||||
p.mount()
|
||||
p.unmount()
|
||||
p.mount();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
throw e
|
||||
}
|
||||
}).not.toThrow() //`problem rendering ${f} example ${k}`
|
||||
|
||||
})
|
||||
})
|
||||
});
|
4659
pnpm-lock.yaml
4659
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user