<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Davide Scalzo</title>
    <description>The latest articles on Forem by Davide Scalzo (@davodesign84).</description>
    <link>https://forem.com/davodesign84</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F138463%2F43bdb102-20da-4efa-866c-dbadb64b8c20.jpeg</url>
      <title>Forem: Davide Scalzo</title>
      <link>https://forem.com/davodesign84</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/davodesign84"/>
    <language>en</language>
    <item>
      <title>A quick intro to end-to-end testing Solana dApps</title>
      <dc:creator>Davide Scalzo</dc:creator>
      <pubDate>Wed, 27 Jul 2022 15:24:45 +0000</pubDate>
      <link>https://forem.com/davodesign84/a-quick-intro-to-end-to-end-testing-solana-dapps-2b3l</link>
      <guid>https://forem.com/davodesign84/a-quick-intro-to-end-to-end-testing-solana-dapps-2b3l</guid>
      <description>&lt;h2&gt;
  
  
  The challenges of testing decentralised applications
&lt;/h2&gt;

&lt;p&gt;While working on one of the new projects at &lt;a href="https://www.jetprotocol.io/"&gt;Jet Protocol&lt;/a&gt; it became &lt;em&gt;very&lt;/em&gt; apparent that the ecosystem lacked some basic tools needed to run end-to-end tests on Solana dApps. Solana is not alone in providing this challenges, as most decentralised application environments require the user to approve or sign transactions by interacting with a wallet.&lt;/p&gt;

&lt;p&gt;If a transaction is not signed with the user private key, the network can not accept the transaction.&lt;/p&gt;

&lt;p&gt;This puts the conscientious web3 developer in a bit of a pickle.&lt;/p&gt;

&lt;p&gt;On one hand existing automation systems (e.g. Cypress, Puppetteer, Selenium) do not handle interaction browser extensions particularly well, and to make them work you need complicated setups with multiple instances of a test runner (one for the app and one for the extension) and sync them somehow. Messy. Unreliable.&lt;/p&gt;

&lt;p&gt;On the other hand, decentralised applications more often than not deal with transactions of a certain value, being tokens, NFT or whatnot, so you want to make sure your application is bullet-proof.&lt;/p&gt;

&lt;p&gt;So what do you (we) do?&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not reinvent the wheel. I repeat. Do not reinvent the wheel.
&lt;/h2&gt;

&lt;p&gt;Pablo Piccasso once said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Good artists copy, great artists steal 🧑‍🎨&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well it turns out that there is always someone smarter than you in a room. It's hundred of orders of magnitude truer if that room is as big as the web.&lt;/p&gt;

&lt;p&gt;That excellent chap named &lt;a href="https://github.com/austintgriffith"&gt;Austin Griffith&lt;/a&gt; already solved this problem for the Ethereum blockchain. He developed a &lt;a href="https://github.com/austintgriffith/burner-provider"&gt;burner provider&lt;/a&gt; that generated a private key in the browser and allowed the developer to not need to interact with an extension if needed (as is the case for E2E testing, but there are also other uses).&lt;/p&gt;

&lt;p&gt;So we've done the same for the Solana blockchain (thanks Austin!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing &lt;code&gt;@jet-lab/e2e-react-adapter&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;At this point I could just link you to the &lt;a href="https://github.com/jet-lab/e2e-react-adapter"&gt;&lt;code&gt;@jet-lab/e2e-react-adapter&lt;/code&gt;&lt;/a&gt; repo and be done as I'm not really used to write blog posts. But I'll try to give you a run down if you bear with me.&lt;/p&gt;

&lt;p&gt;This package is designed to work with the solana react provider, but you should be able to get it to work with other implementations (with some tweaks).&lt;/p&gt;

&lt;p&gt;This is how a generic Solana react dApp looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;WalletProvider&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;PhantomWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;MathWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SolflareWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SolongWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SolletWalletAdapter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-wallets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;YourMainApplication&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt;  &lt;span class="kd"&gt;function&lt;/span&gt;  &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PhantomWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MathWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SolflareWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SolongWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SolletWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SlopeWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;]},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WalletProvider&lt;/span&gt;  &lt;span class="nx"&gt;wallets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;wallets&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="nx"&gt;autoConnect&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YourMainApplication&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/WalletProvier&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To enable e2e testing all you have to do is installing the &lt;a href="https://www.npmjs.com/package/@jet-lab/e2e-react-adapter"&gt;package&lt;/a&gt; and add it to your array of adapters (possibly on your staging / devnet deployments only).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Other imports&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;E2EWalletAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;e2e-react-adapter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt;  &lt;span class="kd"&gt;function&lt;/span&gt;  &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// set your devnet logic here&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// other adapters&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;E2EWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isDev&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WalletProvider&lt;/span&gt;  &lt;span class="nx"&gt;wallets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;wallets&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="nx"&gt;autoConnect&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YourMainApplication&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/WalletProvier&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you'll be able to write end-to-end tests for your Solana dApps!&lt;/p&gt;

&lt;h2&gt;
  
  
  I lied, you're not done yet. But almost!
&lt;/h2&gt;

&lt;p&gt;As the package is intended for devnet / localnet end-to-end testing, you do want to have the transactions actually go through the network and not just interaction with the rpc node. But that needs some SOL to power the transactions.&lt;/p&gt;

&lt;p&gt;You have two options here.&lt;br&gt;
One is to have somewhere in your devnet dApp where you can airdrop some SOL to your shiny new burner adapter. It would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useWallet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RequestAirdrop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useWallet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestAirdrop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; 
   &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestAirdrop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;LAMPORTS_PER_SOL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;confirmTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;requestAirdrop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Airdrop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your test can target this button as soon as the adapter is connected.&lt;/p&gt;

&lt;p&gt;The other option is to initialise the adapter with a keypair which you've preloaded with devnet SOL. So something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;E2EWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;keypair&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;your_keypair_object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This comes in handy also if you want to run a set of tests in a specific order but your automation program refreshes the browser after each test for instance. Just make sure that you handle any and all private keys safely 🕵️‍♀️&lt;/p&gt;

&lt;p&gt;After that you're free to pick whatever E2E framework you prefer, some of the most used ones are Cypress, Puppetteer, TestCafe or Selenium, each with their own traits so pick the one that most suits your needs.&lt;/p&gt;

&lt;p&gt;And of course, make sure you don't run tests in production as they would use real SOL, though if you stuck reading till now, you wouldn't do that anyway. Right? Right!&lt;/p&gt;

&lt;p&gt;As in most articles around the web thesea are my own personal opinions and not those of Jet.&lt;/p&gt;

&lt;p&gt;On that note, about Jet Procol, Jet is an open source, non-custodial liquidity protocol pushing the envelope on decentralized finance and debt capital markets efficiency. Check it out if it piques your interest!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get In Touch&lt;/strong&gt;&lt;br&gt;
🌐 Visit us at JetProtocol.io 🌐&lt;br&gt;
📩 Email us at hello[at]JetProtocol[dot]io 📩&lt;br&gt;
💬 Chat with us on Telegram or Discord 💬&lt;br&gt;
🐦 Find us on Twitter — @JetProtocol 🐦&lt;br&gt;
Subscribe to our newsletter: &lt;a href="https://jetprotocol.substack.com"&gt;https://jetprotocol.substack.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solana</category>
      <category>web3</category>
      <category>testing</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
