Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve web test #415

Merged
merged 4 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/core/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import { defaultLogger } from './logger'
import { openDb } from './db'

type Options = {
export type SetupOptions = {
endpoint?: string
block?: string | number | null
genesis?: string | Genesis
Expand All @@ -35,7 +35,7 @@ type Options = {
maxMemoryBlockCount?: number
}

export const setup = async (options: Options) => {
export const setup = async (options: SetupOptions) => {
let provider: ProviderInterface
if (options.genesis) {
if (typeof options.genesis === 'string') {
Expand Down
22 changes: 7 additions & 15 deletions packages/web-test/index.html
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
</head>
<body>
<div style="position: absolute; top: 10px; right: 10px">
<a href="/chopsticks/docs">
<button>Go to docs</button>
</a>
</div>

<pre>Open console to access <u>chain</u></pre>
<div id="app" style="font: 16px monospace">Loading...</div>
<div style="display: flex; flex-direction: column; align-items: start">
<pre>Caller 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY</pre>
<textarea placeholder="Call" id="extrinsic" style="font: 16px monospace"></textarea>
<input type="button" id="submit" value="Dry Run Call" />
<pre id="result" style="font: 16px monospace"></pre>
</div>
<script type="module">
import { Buffer } from 'buffer'
window.Buffer = Buffer
</script>
<script type="module" src="src/index.ts"></script>

<div id="root"></div>
<script type="module" src="src/index.tsx"></script>
</body>
</html>
16 changes: 13 additions & 3 deletions packages/web-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,25 @@
"build": "npx vite build",
"vite:serve": "npx vite --port 3000 --host",
"vite:preview": "npx vite preview --port 3000",
"parcel:serve": "npx parcel serve index.html --port 3000",
"test": "npx playwright test"
"parcel:serve": "parcel serve index.html --port 3000",
"test": "playwright test"
},
"dependencies": {
"@acala-network/chopsticks-core": "workspace:*"
"@acala-network/chopsticks-core": "workspace:*",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.14.10",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@playwright/test": "^1.37.1",
"@types/react": "^18",
"@types/react-dom": "^18",
"@vitejs/plugin-react": "^4.1.0",
"crypto-browserify": "^3.12.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"path-browserify": "^1.0.1",
"stream-browserify": "^3.0.0",
"typescript": "^5.1.6"
Expand Down
255 changes: 255 additions & 0 deletions packages/web-test/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
import {
Alert,
Box,
CircularProgress,
Container,
FormControl,
Input,
InputLabel,
Button as MuiBtn,
TextField,
Typography,
} from '@mui/material'
import { HexString } from '@polkadot/util/types'
import { setStorage, setup } from '@acala-network/chopsticks-core'
import { styled } from '@mui/system'
import { useEffect, useState } from 'react'
import type { SetupOptions } from '@acala-network/chopsticks-core'

const DocsLink = styled('a')`
position: absolute;
top: 16px;
right: 10px;
`

const Button = styled(MuiBtn)`
border-radius: 8px;
padding: 0.4em 0.8em;
font-weight: 500;
font-family: inherit;
cursor: pointer;
transition: border-color 0.25s;
`

const BlocksContainer = styled('div')`
width: 100%;
display: flex;
flex-direction: column;
justify-content: start;
font: 16px monospace;
overflow-x: scroll;
padding: 5px;
`

const DryRunTextArea = styled(TextField)({
width: '100%',
})

const Pre = styled('pre')`
max-width: 100%;
overflow: auto;
font-size: 14px;
margin: 4px 0;
padding: 4px 6px;
border-radius: 4px;
background-color: #ffe4efb7;
`

const Section = styled('section')`
min-height: 180px;
margin-top: 24px;
display: flex;
flex-direction: column;
align-items: start;
justify-content: start;
max-width: 100%;
`

const Code = styled('code')`
font-size: 14px;
margin: 0 2px;
padding: 4px 5px;
border-radius: 4px;
background-color: #ffe4efb7;
`

function App() {
const [dryRunLoading, setDryRunLoading] = useState(false)
const [chainLoading, setChainLoading] = useState(false)
const [extrinsic, setExtrinsic] = useState('')
const [dryRunResult, setDryRunResult] = useState('')
const [config, setConfig] = useState<SetupOptions>({
endpoint: 'wss://acala-rpc-0.aca-api.network',
block: 4_000_000,
})
const [blocks, setBlocks] = useState<{ number: number; hash: HexString }[]>([])

const resetState = () => {
setBlocks([])
setDryRunLoading(false)
setExtrinsic('0x0a000088dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee0f0090c04bb6db2b')
setDryRunResult('')
}

const setupChain = async () => {
setChainLoading(true)
const chain = await setup({
endpoint: config.endpoint,
block: config.block,
mockSignatureHost: true,
db: 'cache',
})
globalThis.chain = chain

await setStorage(chain, {
System: {
Account: [
[
['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
{
providers: 1,
data: {
free: '1000000000000000000',
},
},
],
],
},
})

setChainLoading(false)
setBlocks([{ number: chain.head.number, hash: chain.head.hash }])

// build a block
await chain.newBlock().catch(console.error)
setBlocks([...blocks, { number: chain.head.number, hash: chain.head.hash }])
}

useEffect(() => {
resetState()
setupChain()

return () => {
globalThis.chain?.api.disconnect()
globalThis.chain?.close()
}
}, [])

const handleDryRun = async () => {
setDryRunResult('')
setDryRunLoading(true)
const call = extrinsic.trim() as HexString
try {
const { outcome, storageDiff } = await globalThis.chain.dryRunExtrinsic({
call,
address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
})
setDryRunResult(JSON.stringify({ outcome: outcome.toHuman(), storageDiff }, null, 2))
} catch (e) {
setDryRunResult((e as Error).toString())
}
setDryRunLoading(false)
}

const handleSaveConfig = async () => {
await chain.api.disconnect()
await chain.close()
resetState()
setupChain()
}

return (
<Container sx={{ mt: 2, width: 700, maxWidth: '70vw' }}>
<DocsLink href="/chopsticks/docs">
<Button variant="outlined">Go to docs</Button>
</DocsLink>

<Alert severity="info" sx={{ borderRadius: 2 }}>
Open console to access <Code>chain</Code>
</Alert>

<Section sx={{ minHeight: 100 }}>
<Typography variant="h5" component="h2">
Configuration
</Typography>
<FormControl variant="standard" sx={{ width: '100%', mt: 1 }}>
<InputLabel shrink htmlFor="block-input">
Block Number or Hash
</InputLabel>
<Input
id="block-input"
placeholder="4000000"
value={config.block}
onChange={(e) => setConfig({ ...config, block: e.target.value })}
/>
</FormControl>
<FormControl variant="standard" sx={{ width: '100%', mt: 1 }}>
<InputLabel shrink htmlFor="endpoint-input">
API Url
</InputLabel>
<Input
id="endpoint-input"
placeholder="wss://acala-rpc-0.aca-api.network"
value={config.endpoint}
onChange={(e) => setConfig({ ...config, endpoint: e.target.value })}
/>
</FormControl>
<Button
variant="outlined"
disabled={chainLoading || !globalThis.chain}
onClick={handleSaveConfig}
sx={{ mt: 1 }}
>
Save
{chainLoading && (
<Box sx={{ display: 'flex', ml: 1 }}>
<CircularProgress size={13} />
</Box>
)}
</Button>
</Section>

<Section id="blocks-section">
<Typography variant="h5" component="h2">
Blocks
</Typography>
<BlocksContainer>
{blocks.map((block) => (
<Pre key={block.number}>
{block.number} {block.hash}
</Pre>
))}
</BlocksContainer>
</Section>

<Section id="extrinsic-section">
<Typography variant="h5" component="h2">
Dry Run
</Typography>
<Pre>Caller 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY</Pre>
<DryRunTextArea
label="Extrinsic"
value={extrinsic}
multiline
minRows={4}
sx={{ mt: 1 }}
onChange={(e) => {
setExtrinsic(e.target.value)
}}
/>
<Button
variant="outlined"
onClick={handleDryRun}
disabled={dryRunLoading || chainLoading || !globalThis.chain}
sx={{ mt: 1, mb: 1 }}
>
Dry Run Call
</Button>
{dryRunResult && <Pre sx={{ fontSize: 13 }}>{dryRunResult}</Pre>}
{dryRunLoading && <Pre>Loading dry run result...</Pre>}
</Section>
</Container>
)
}

export default App
11 changes: 11 additions & 0 deletions packages/web-test/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
}

body {
margin: 0;
display: flex;
min-height: 100vh;
}
Loading