Add connect diaglog tests convert storage to js to avoid ts issues with testing
This commit is contained in:
parent
f10cdf491d
commit
69924aa0b3
154
libs/react-helpers/src/lib/vega-wallet/connect-dialog.test.tsx
Normal file
154
libs/react-helpers/src/lib/vega-wallet/connect-dialog.test.tsx
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import {
|
||||||
|
act,
|
||||||
|
fireEvent,
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
waitFor,
|
||||||
|
} from '@testing-library/react';
|
||||||
|
import { VegaWalletContext, VegaWalletContextShape } from './context';
|
||||||
|
import { VegaConnectDialog } from './connect-dialog';
|
||||||
|
import { VegaConnectDialogProps } from '.';
|
||||||
|
import { RestConnector } from './connectors';
|
||||||
|
|
||||||
|
let defaultProps: VegaConnectDialogProps;
|
||||||
|
let defaultContextValue: VegaWalletContextShape;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
defaultProps = {
|
||||||
|
connectors: {
|
||||||
|
rest: new RestConnector(),
|
||||||
|
},
|
||||||
|
dialogOpen: false,
|
||||||
|
setDialogOpen: jest.fn(),
|
||||||
|
};
|
||||||
|
defaultContextValue = {
|
||||||
|
keypair: null,
|
||||||
|
keypairs: null,
|
||||||
|
connect: jest.fn(),
|
||||||
|
disconnect: jest.fn(),
|
||||||
|
selectPublicKey: jest.fn(),
|
||||||
|
connector: null,
|
||||||
|
sendTx: jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function generateJSX(
|
||||||
|
props?: Partial<VegaConnectDialogProps>,
|
||||||
|
contextValue?: Partial<VegaWalletContextShape>
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<VegaWalletContext.Provider
|
||||||
|
value={{ ...defaultContextValue, ...contextValue }}
|
||||||
|
>
|
||||||
|
<VegaConnectDialog {...defaultProps} {...props} />
|
||||||
|
</VegaWalletContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('Renders list of connectors', () => {
|
||||||
|
const { container, rerender } = render(generateJSX());
|
||||||
|
expect(container).toBeEmptyDOMElement();
|
||||||
|
rerender(generateJSX({ dialogOpen: true }));
|
||||||
|
const list = screen.getByTestId('connectors-list');
|
||||||
|
expect(list).toBeInTheDocument();
|
||||||
|
expect(list.children).toHaveLength(
|
||||||
|
Object.keys(defaultProps.connectors).length
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const fillInForm = () => {
|
||||||
|
const walletValue = 'test-wallet';
|
||||||
|
fireEvent.change(screen.getByLabelText('Wallet'), {
|
||||||
|
target: { value: walletValue },
|
||||||
|
});
|
||||||
|
const passphraseValue = 'test-passphrase';
|
||||||
|
fireEvent.change(screen.getByLabelText('Passphrase'), {
|
||||||
|
target: { value: passphraseValue },
|
||||||
|
});
|
||||||
|
return { wallet: walletValue, passphrase: passphraseValue };
|
||||||
|
};
|
||||||
|
|
||||||
|
test('Successful connection using rest auth form', async () => {
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(defaultProps.connectors['rest'] as RestConnector, 'authenticate')
|
||||||
|
.mockImplementation(() => Promise.resolve({ success: true, error: null }));
|
||||||
|
|
||||||
|
render(generateJSX({ dialogOpen: true }));
|
||||||
|
// Switches to rest form
|
||||||
|
fireEvent.click(screen.getByText('rest provider'));
|
||||||
|
|
||||||
|
// Client side validation
|
||||||
|
fireEvent.submit(screen.getByTestId('rest-connector-form'));
|
||||||
|
expect(spy).not.toHaveBeenCalled();
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getAllByText('Required')).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
const fields = fillInForm();
|
||||||
|
|
||||||
|
// Wait for auth method to be called
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.submit(screen.getByTestId('rest-connector-form'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith(fields);
|
||||||
|
|
||||||
|
expect(defaultProps.setDialogOpen).toHaveBeenCalledWith(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Unsuccessful connection using rest auth form', async () => {
|
||||||
|
// Error from service
|
||||||
|
let spy = jest
|
||||||
|
.spyOn(defaultProps.connectors['rest'] as RestConnector, 'authenticate')
|
||||||
|
.mockImplementation(() =>
|
||||||
|
Promise.resolve({ success: false, error: 'Error message' })
|
||||||
|
);
|
||||||
|
|
||||||
|
render(generateJSX({ dialogOpen: true }));
|
||||||
|
// Switches to rest form
|
||||||
|
fireEvent.click(screen.getByText('rest provider'));
|
||||||
|
|
||||||
|
const fields = fillInForm();
|
||||||
|
fireEvent.submit(screen.getByTestId('rest-connector-form'));
|
||||||
|
|
||||||
|
// Wait for auth method to be called
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.submit(screen.getByTestId('rest-connector-form'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith(fields);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form-error')).toHaveTextContent(
|
||||||
|
'Something went wrong'
|
||||||
|
);
|
||||||
|
expect(defaultProps.setDialogOpen).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
// Fetch failed due to wallet not running
|
||||||
|
spy = jest
|
||||||
|
.spyOn(defaultProps.connectors['rest'] as RestConnector, 'authenticate')
|
||||||
|
// @ts-ignore test fetch failed with typeerror
|
||||||
|
.mockImplementation(() => Promise.reject(new TypeError('fetch failed')));
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.submit(screen.getByTestId('rest-connector-form'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form-error')).toHaveTextContent(
|
||||||
|
'Wallet not running at http://localhost:1789'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Reject eg non 200 results
|
||||||
|
spy = jest
|
||||||
|
.spyOn(defaultProps.connectors['rest'] as RestConnector, 'authenticate')
|
||||||
|
// @ts-ignore test fetch failed with typeerror
|
||||||
|
.mockImplementation(() => Promise.reject(new Error('Error!')));
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.submit(screen.getByTestId('rest-connector-form'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form-error')).toHaveTextContent(
|
||||||
|
'Authentication failed'
|
||||||
|
);
|
||||||
|
});
|
@ -3,7 +3,8 @@ import { Dialog } from '@vegaprotocol/ui-toolkit';
|
|||||||
import { VegaConnector } from './connectors';
|
import { VegaConnector } from './connectors';
|
||||||
import { RestConnectorForm } from './rest-connector-form';
|
import { RestConnectorForm } from './rest-connector-form';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { RestConnector, useVegaWallet } from '.';
|
import { RestConnector } from './connectors/rest-connector';
|
||||||
|
import { useVegaWallet } from './hooks';
|
||||||
|
|
||||||
export interface VegaConnectDialogProps {
|
export interface VegaConnectDialogProps {
|
||||||
connectors: { [name: string]: VegaConnector };
|
connectors: { [name: string]: VegaConnector };
|
||||||
@ -57,17 +58,20 @@ export function VegaConnectDialog({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ul className="flex flex-col justify-center gap-4 items-start">
|
<ul
|
||||||
|
className="flex flex-col justify-center gap-4 items-start"
|
||||||
|
data-testid="connectors-list"
|
||||||
|
>
|
||||||
{Object.entries(connectors).map(([key, connector]) => (
|
{Object.entries(connectors).map(([key, connector]) => (
|
||||||
<li key={key} className="mb-12 last:mb-0">
|
<li key={key} className="mb-12 last:mb-0">
|
||||||
<button
|
<button
|
||||||
key={key}
|
key={key}
|
||||||
onClick={() => setSelectedConnector(connector)}
|
onClick={() => setSelectedConnector(connector)}
|
||||||
className="capitalize hover:text-vega-pink"
|
className="capitalize hover:text-vega-pink dark:hover:text-vega-yellow"
|
||||||
>
|
>
|
||||||
{key} provider
|
{key} provider
|
||||||
</button>
|
</button>
|
||||||
<p className="text-neutral-500">{connector.description}</p>
|
<p>{connector.description}</p>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -50,7 +50,7 @@ export function RestConnectorForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)} data-testid="rest-connector-form">
|
||||||
<FormGroup label="Wallet" labelFor="wallet">
|
<FormGroup label="Wallet" labelFor="wallet">
|
||||||
<Input
|
<Input
|
||||||
{...register('wallet', { required: 'Required' })}
|
{...register('wallet', { required: 'Required' })}
|
||||||
@ -59,7 +59,9 @@ export function RestConnectorForm({
|
|||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
{errors.wallet?.message && (
|
{errors.wallet?.message && (
|
||||||
<InputError intent="danger">{errors.wallet.message}</InputError>
|
<InputError intent="danger" className="mt-4">
|
||||||
|
{errors.wallet.message}
|
||||||
|
</InputError>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup label="Passphrase" labelFor="passphrase">
|
<FormGroup label="Passphrase" labelFor="passphrase">
|
||||||
@ -69,10 +71,16 @@ export function RestConnectorForm({
|
|||||||
type="password"
|
type="password"
|
||||||
/>
|
/>
|
||||||
{errors.passphrase?.message && (
|
{errors.passphrase?.message && (
|
||||||
<InputError intent="danger">{errors.passphrase.message}</InputError>
|
<InputError intent="danger" className="mt-4">
|
||||||
|
{errors.passphrase.message}
|
||||||
|
</InputError>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
{error && <p className="text-intent-danger mb-12">{error}</p>}
|
{error && (
|
||||||
|
<p className="text-intent-danger mb-12" data-testid="form-error">
|
||||||
|
{error}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
<Button variant="primary" type="submit">
|
<Button variant="primary" type="submit">
|
||||||
Connect
|
Connect
|
||||||
</Button>
|
</Button>
|
||||||
|
12
libs/storage/.babelrc
Normal file
12
libs/storage/.babelrc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@nrwl/react/babel",
|
||||||
|
{
|
||||||
|
"runtime": "automatic",
|
||||||
|
"useBuiltIns": "usage"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"plugins": []
|
||||||
|
}
|
@ -9,9 +9,8 @@
|
|||||||
"outputs": ["{options.outputPath}"],
|
"outputs": ["{options.outputPath}"],
|
||||||
"options": {
|
"options": {
|
||||||
"outputPath": "dist/libs/storage",
|
"outputPath": "dist/libs/storage",
|
||||||
"tsConfig": "libs/storage/tsconfig.lib.json",
|
|
||||||
"project": "libs/storage/package.json",
|
"project": "libs/storage/package.json",
|
||||||
"entryFile": "libs/storage/src/index.ts",
|
"entryFile": "libs/storage/src/index.js",
|
||||||
"rollupConfig": "@nrwl/react/plugins/bundle-rollup",
|
"rollupConfig": "@nrwl/react/plugins/bundle-rollup",
|
||||||
"compiler": "babel",
|
"compiler": "babel",
|
||||||
"assets": [
|
"assets": [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// TODO: fine for now however will leak state between tests (we don't really have) in future. Ideally should use a provider
|
// TODO: fine for now however will leak state between tests (we don't really have) in future. Ideally should use a provider
|
||||||
export const LocalStorage = {
|
export const LocalStorage = {
|
||||||
getItem: (key: string) => {
|
getItem: (key) => {
|
||||||
if (typeof window === 'undefined') return;
|
if (typeof window === 'undefined') return;
|
||||||
try {
|
try {
|
||||||
const item = window.localStorage.getItem(key);
|
const item = window.localStorage.getItem(key);
|
||||||
@ -10,7 +10,7 @@ export const LocalStorage = {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setItem: (key: string, value: string) => {
|
setItem: (key, value) => {
|
||||||
if (typeof window === 'undefined') return;
|
if (typeof window === 'undefined') return;
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem(key, value);
|
window.localStorage.setItem(key, value);
|
||||||
@ -18,7 +18,7 @@ export const LocalStorage = {
|
|||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeItem: (key: string) => {
|
removeItem: (key) => {
|
||||||
if (typeof window === 'undefined') return;
|
if (typeof window === 'undefined') return;
|
||||||
try {
|
try {
|
||||||
window.localStorage.removeItem(key);
|
window.localStorage.removeItem(key);
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.base.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"allowJs": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitOverride": true,
|
|
||||||
"noPropertyAccessFromIndexSignature": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noFallthroughCasesInSwitch": true
|
|
||||||
},
|
|
||||||
"files": [],
|
|
||||||
"include": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.lib.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.spec.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../../dist/out-tsc",
|
|
||||||
"types": ["node"]
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
|
||||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"**/*.spec.ts",
|
|
||||||
"**/*.test.ts",
|
|
||||||
"**/*.spec.tsx",
|
|
||||||
"**/*.test.tsx",
|
|
||||||
"**/*.spec.js",
|
|
||||||
"**/*.test.js",
|
|
||||||
"**/*.spec.jsx",
|
|
||||||
"**/*.test.jsx"
|
|
||||||
],
|
|
||||||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
|
||||||
}
|
|
@ -16,7 +16,7 @@
|
|||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@vegaprotocol/react-helpers": ["libs/react-helpers/src/index.ts"],
|
"@vegaprotocol/react-helpers": ["libs/react-helpers/src/index.ts"],
|
||||||
"@vegaprotocol/storage": ["libs/storage/src/index.ts"],
|
"@vegaprotocol/storage": ["libs/storage/src/index.js"],
|
||||||
"@vegaprotocol/tailwindcss-config": [
|
"@vegaprotocol/tailwindcss-config": [
|
||||||
"libs/tailwindcss-config/src/index.js"
|
"libs/tailwindcss-config/src/index.js"
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user