Hello Test Tutorial

Time & Level

Time: ~1 hours | Level: Beginner

Welcome to the Hello Test tutorial. Today you will be learning how to test your Holochain apps. This tutorial will add to the previous Hello Holo tutorial, so make sure you do that one first.

What will you learn

You will learn how to use the try-o-rama testing library to test you app.

Why it matters

Testing is a really important part of building higher quality apps but it's also a an excellent way to think through how your app will be used.

Understand the tests

When you ran hc init in the previous tutorial Holochain already generated some tests for you.

The tests are written in JavaScript and use the Holochain testing framework try-o-rama, along with a popular test harness called Tape. You can run them with Node.JS, a runtime that lets you execute JavaScript in the terminal.

Open up the cc_tuts/test/index.js in your favourite text editor. Have a look through the code.

Imports required to do testing:

const path = require('path');
const tape = require('tape');

const {
  Config,
  Orchestrator,
  tapeExecutor,
  singleConductor,
  combine,
} = require('@holochain/try-o-rama');

This is a catch-all error logger that will let you know if a Promise fails and there's no error handler to hear it. Promises are a way of simplifying complex asynchronous code, and try-o-rama uses a lot of them.

process.on('unhandledRejection', error => {
  console.error('got unhandledRejection:', error);
});

The path to your compiled DNA.

const dnaPath = path.join(__dirname, "../dist/cc_tuts.dna.json")

Setup a testing scenario. This creates two agents: Alice and Bob.

const orchestrator = new Orchestrator({
  middleware: combine(singleConductor, tapeExecutor(tape)),
  globalConfig: {
Disable logging:
-    logger: true,
+    logger: false,
Change the network to sim2h:
-    network: 'memory',  
+    network: {
+      type: 'sim2h',
+      sim2h_url: 'wss://sim2h.holochain.org:9000',
+    },
  },
});

const config = {
  instances: {
-    myInstanceName: Config.dna(dnaPath, 'scaffold-test')
+    cc_tuts: Config.dna(dnaPath, 'cc_tuts'),
  },
};
This is the test that Holochain generated based on the my_entry struct and the zome functions that work with it. We removed them in our Hello Holo tutorial, so let's remove the test.

Remove the following section:

!!! note "Remove this:

orchestrator.registerScenario("description of example test", async (s, t) => {

  const {alice, bob} = await s.players({alice: conductorConfig, bob: conductorConfig})

  // Make a call to a Zome function
  // indicating the function, and passing it an input
  const addr = await alice.call("myInstanceName", "my_zome", "create_my_entry", {"entry" : {"content":"sample content"}})

  // Wait for all network activity to
  await s.consistency()

  const result = await alice.call("myInstanceName", "my_zome", "get_my_entry", {"address": addr.Ok})

  // check for equality of the actual and expected results
  t.deepEqual(result, { Ok: { App: [ 'my_entry', '{"content":"sample content"}' ] } })
})

This line will run the tests that you have set up.

orchestrator.run()

Create a test scenario

Tests are organized by creating scenarios. Think of them as a series of actions that the user or group of users take when interacting with your app.

For this test you simply want to get the Alice user to call the hello_holo zome function. Then check that you get the result Hello Holo.

Tip

The following lines go right before orchestrator.run()

Register a test scenario that checks hello_holo() returns the correct value:

orchestrator.registerScenario('Test hello holo', async (s, t) => {
Create the Alice and Bob agents (you will use Bob later):
  const {alice, bob} = await s.players({alice: config, bob: config}, true);
Make a call to the hello_holo Zome function, passing no arguments:
  const result = await alice.call('cc_tuts', 'hello', 'hello_holo', {});

Make sure the result is okay:

  t.ok(result.Ok);

Check that the result matches what you expected:

  t.deepEqual(result, { Ok: 'Hello Holo' })
})

Run the test

Check your code
const path = require('path');
const tape = require('tape');

const {
  Config,
  Orchestrator,
  tapeExecutor,
  singleConductor,
  combine,
} = require('@holochain/try-o-rama');

process.on('unhandledRejection', error => {
  console.error('got unhandledRejection:', error);
});

const dnaPath = path.join(__dirname, "../dist/cc_tuts.dna.json")
const orchestrator = new Orchestrator({
  middleware: combine(singleConductor, tapeExecutor(tape)),
  globalConfig: {
    logger: false,
    network: {
      type: 'sim2h',
      sim2h_url: 'wss://sim2h.holochain.org:9000',
    },
  },
});
const config = {
  instances: {
    cc_tuts: Config.dna(dnaPath, 'cc_tuts'),
  },
};

orchestrator.registerScenario('Test hello holo', async (s, t) => {
  const {alice, bob} = await s.players({alice: config, bob: config}, true);
  const result = await alice.call('cc_tuts', 'hello', 'hello_holo', {});
  t.ok(result.Ok);
  t.deepEqual(result, { Ok: 'Hello Holo' })
})
orchestrator.run();

Now in the hello_helo directory, run the test like this:

Run in nix-shell https://holochain.love

$ hc test

This will compile and run the test scenario you just wrote. You will see a lot of output.

If everything went okay, then right at the end you will see:

# tests 2
# pass  2

# ok

Congratulations; you have tested your first Holochain app. Look at you go! ✨

Key takeaways

  • Testing is done through the tests folder and uses the try-o-rama testing javascript framework.
  • Tests are arranged into scenarios and run by the conductor.

Learn more

Was this helpful?