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 { RestConnectorForm } from './rest-connector-form';
|
||||
import { useEffect } from 'react';
|
||||
import { RestConnector, useVegaWallet } from '.';
|
||||
import { RestConnector } from './connectors/rest-connector';
|
||||
import { useVegaWallet } from './hooks';
|
||||
|
||||
export interface VegaConnectDialogProps {
|
||||
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]) => (
|
||||
<li key={key} className="mb-12 last:mb-0">
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => setSelectedConnector(connector)}
|
||||
className="capitalize hover:text-vega-pink"
|
||||
className="capitalize hover:text-vega-pink dark:hover:text-vega-yellow"
|
||||
>
|
||||
{key} provider
|
||||
</button>
|
||||
<p className="text-neutral-500">{connector.description}</p>
|
||||
<p>{connector.description}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -50,7 +50,7 @@ export function RestConnectorForm({
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<form onSubmit={handleSubmit(onSubmit)} data-testid="rest-connector-form">
|
||||
<FormGroup label="Wallet" labelFor="wallet">
|
||||
<Input
|
||||
{...register('wallet', { required: 'Required' })}
|
||||
@ -59,7 +59,9 @@ export function RestConnectorForm({
|
||||
autoFocus={true}
|
||||
/>
|
||||
{errors.wallet?.message && (
|
||||
<InputError intent="danger">{errors.wallet.message}</InputError>
|
||||
<InputError intent="danger" className="mt-4">
|
||||
{errors.wallet.message}
|
||||
</InputError>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup label="Passphrase" labelFor="passphrase">
|
||||
@ -69,10 +71,16 @@ export function RestConnectorForm({
|
||||
type="password"
|
||||
/>
|
||||
{errors.passphrase?.message && (
|
||||
<InputError intent="danger">{errors.passphrase.message}</InputError>
|
||||
<InputError intent="danger" className="mt-4">
|
||||
{errors.passphrase.message}
|
||||
</InputError>
|
||||
)}
|
||||
</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">
|
||||
Connect
|
||||
</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}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/storage",
|
||||
"tsConfig": "libs/storage/tsconfig.lib.json",
|
||||
"project": "libs/storage/package.json",
|
||||
"entryFile": "libs/storage/src/index.ts",
|
||||
"entryFile": "libs/storage/src/index.js",
|
||||
"rollupConfig": "@nrwl/react/plugins/bundle-rollup",
|
||||
"compiler": "babel",
|
||||
"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
|
||||
export const LocalStorage = {
|
||||
getItem: (key: string) => {
|
||||
getItem: (key) => {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
const item = window.localStorage.getItem(key);
|
||||
@ -10,7 +10,7 @@ export const LocalStorage = {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
setItem: (key: string, value: string) => {
|
||||
setItem: (key, value) => {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
window.localStorage.setItem(key, value);
|
||||
@ -18,7 +18,7 @@ export const LocalStorage = {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
removeItem: (key: string) => {
|
||||
removeItem: (key) => {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
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": ".",
|
||||
"paths": {
|
||||
"@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": [
|
||||
"libs/tailwindcss-config/src/index.js"
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user