After we have developed the unit tests for the AppRun applications, there is one more thing to do. We must make sure the events and states in the AppRun applications work as expected. AppRun comes with handy tools for developers to fine-tune the events and states.

In this chapter, we will use the AppRun RealWorld example application to demonstrate the AppRun DevTools. You will learn how to verify the registered components and events and how to monitor the events and state changes of the running application.

Use AppRun DevTools

AppRun exposes the app instance globally to the window object. AppRun event publication and subscription allows us to attach the DevTools to examine and monitor the components, states, and events of the AppRun applications. There is no need to set any debug flag or compile the code into debug mode. The application code remains the same.

The AppRun DevTools script is distributed with the AppRun package. To use the AppRun DevTools, we include the script in the HTML file, as shown here:

<script src="https://unpkg.com/apprun@latest/dist/apprun-dev-tools.js"></script>

Once we finish using the AppRun DevTools, we remove the AppRun DevTools script from the HTML file.

Command Line in the Console

The AppRun DevTools script adds a command-line interface (CLI) to the JavaScript console. The CLI provides a few commands that we can type in the JavaScript console. To run the commands, type the following:

_apprun `<command> [options]`

The help command lists the available commands (see Figure 12-1).

Figure 12-1
figure 1

AppRun CLI in the console

The AppRun DevTools CLI has the following commands:

  • components: Lists registered components

  • events: Lists registered events

  • log: Configures the logging of the AppRun debug events

We can use the CLI commands to verify the components, events, and debug events of the AppRun RealWorld example application.

Components

When we developed the AppRun RealWorld example application in Chapter 10, we planned the components and their events, as shown in Table 12-1.

Table 12-1 Components and Events

In Table 12-1 the events that have names starting with #/ are the routing events. The events that have names starting with / are global events. The other events are local events.

We can use the AppRun DevTools CLI to verify whether the components are registered as planned. To do so, we can run the components command in the console (see Figure 12-2).

Figure 12-2
figure 2

The components command

You can see that the running components and the events match the design. There is one component mounted to the header #element. There are seven components mounted to the #my-app elements.

The benefit of using the browser’s JavaScript console is that it prints the objects nicely and allows us to drill down to the properties. We can further drill down to see the events subscribed to by each component (see Figure 12-3).

Figure 12-3
figure 3

Elements, components, and events

The components command has a print option.

_apprun `components print`

The print option makes the AppRun DevTools CLI print the elements, components, and events in a new window (see Figure 12-4).

Figure 12-4
figure 4

Printing the elements, components, and events

We can print to a printer to get a hard copy of the elements, components, and events of our applications.

Events

Besides verifying the components, we want to verify the events subscribed to by the components globally and locally. It is important to use the events only when they are necessary. Unnecessary events could cause memory leak and performance issues.

We run the events command in the console. The events command lists all event subscriptions grouped by global and local events in the console (see Figure 12-5).

Figure 12-5
figure 5

The events command

We can also use the print option with the events command.

_apprun `events print`

The print option prints the events and the components in a new window (see Figure 12-6).

Figure 12-6
figure 6

Printing events

By verifying the components and events, we have confirmed the AppRun RealWorld example application has been developed as per the design (see Table 12-1). Next, we will see whether the events are published and handled as expected.

Debug Events

AppRun publishes the debug events at the two AppRun event lifecycle checkpoints: when AppRun components complete handling the events and when AppRun components complete the view function. Using the AppRun DevTools CLI, we can turn on and off the logging of the debug events.

  • log on: Starts logging the event handling and view function

  • log off: Stops logging the event handling and view function

  • log event on: Starts logging the event handling

  • log event off: Stops logging the event handling

  • log view on: Starts logging the view function

  • log view off: Stops logging the view function

We can turn on logging the event handlers and view functions of the AppRun RealWorld example application (see Figure 12-7).

Figure 12-7
figure 7

Debugging events

We can also drill down to examine the details of the events, the state, the new state, and the virtual DOM (see Figure 12-8).

Figure 12-8
figure 8

Debug event, state, and virtual DOM

Extend the Command Line

The AppRun DevTools CLI in the console is extensible. You can create your commands to enhance the CLI by registering your command function in the window object.

Register the Command

The AppRun DevTools CLI uses the following naming convention:

window['_apprun-<command>'] = [     'command brief description]',     (p) => { /* command implementation*/}, `[command long description]` ]

The AppRun CLI command is like a tuple that has three fields: the brief description, the function implementation, and the optional long description of the command.

When users type _apprun `command` in the browser’s DevTools console, the AppRun CLI searches the window object for _apprun-command. If it finds the command tuple, it executes the command function.

In the command function , we use the two AppRun built-in events to retrieve the components and monitor the checkpoints of the AppRun event lifecycle. To demonstrate the AppRun DevTools CLI’s extensibility, we will develop two commands to generate unit tests and to generate snapshot tests.

Generate Unit Tests

The built-in AppRun event get-components returns the mounted components grouped by the elements that the components mount to. We can iterate through the components to do many interesting things. For example, we can develop a command to generate unit tests of the components and events (Listing 12-1).

Listing 12-1 Generating Unit Tests

1.   let win; 2.   function openWin(name) { 3.       win = window.open(", name); 4.       win.document.write(`<html> 5.           <title>AppRun Analyzer | ${document.location.href}</title> 6.           <style> 7.               body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI" } 8.           </style> 9.       <body><pre>`); 10.  } 11.  function write(text) { 12.    win.document.write(text + '\n'); 13.  } 14.  function closeWin() { 15.    win.document.write(`</pre> 16.    </body> 17.    </html>`); 18.    win.document.close(); 19.  } 20.  const _createEventTests = () => { 21.      const o = { components: {} }; 22.      app.run('get-components', o); 23.      const { components } = o; 24.      openWin("); 25.      Object.keys(components).forEach(el => { 26.          components[el].forEach(component => { 27.              write(`const component = ${component.constructor.name};`); 28.              write(`describe('${component.constructor.name}', ()=>{`); 29.              component._actions.forEach(action => { 30.                  write(`  it ('should handle event: ${action.name}', ()=>{`); 31.                  write(`component.run('${action.name}');`); 32.                  write(`expect(component.state).toBeTruthy();`); 33.                  write(`})`); 34.              }); 35.              write(`});`); 36.          }); 37.      }); 38.      closeWin(); 39.  } 40.  window['_apprun-create-event-tests'] = ['create-event-tests', 41.    () => _createEventTests() 42.  ]

If we print the generated result in the console, it would be difficult to copy from the console. We want to print the results into a new window instead. The three functions—openWin , write , and closeWin —are the helper functions that let us write text to a new window (lines 2–19).

The _createEventTests function generates the unit tests (lines 20–39). It is registered as an AppRun DevTools command (lines 40–42).

The _createEventTests function uses the get-component event to retrieve the mounted components from AppRun (lines 20–23). It then iterates through the results and prints the unit tests.

Include the script (Listing 12-1) into the HTML and run the command _apprun `create-event-tests` in the console (see Figure 12-9). This generates the unit tests for components and events in a new window (see Figure 12-10).

Figure 12-9
figure 9

Command create-event-tests

Figure 12-10
figure 10

Generated event tests

We can copy the generated unit tests into the project and continue to add mock functions and assertions.

Generate Snapshot Tests

Besides getting components out of AppRun, we can also create an AppRun CLI command to monitor the AppRun events at application runtime using the debug event that AppRun publishes at the two checkpoints of the event lifecycle.

For example, we can develop an AppRun DevTools command, create-state-tests (Listing 12-2) to record the states and generate snapshot tests.

Listing 12-2 create-state-tests

1.   let recording = false; 2.   let events = []; 3.   app.on('debug', p => { 4.       if (recording && p.vdom) { 5.           events.push(p); 6.           console.log(`* ${events.length} state(s) recorded.`); 7.       } 8.   }); 9.   const _createStateTests = (s) => { 10.      const printTests = () => { 11.          if (events.length === 0) { 12.              console.log('* No state recorded.'); 13.              return; 14.          } 15.          openWin("); 16.          events.forEach((event, idx) => { 17.              write(`it ('view snapshot: #${idx+1}', ()=>{`); 18.              write(`const component = ${event.component.constructor.name};`); 19.              write(`const state = ${JSON.stringify(event.state, undefined, 2)};`); 20.              write(`const vdom = component['view'](state);`); 21.              write(`expect(JSON.stringify(vdom)).toMatchSnapshot();`); 22.              write(`})`); 23.          }); 24.          closeWin(); 25.      } 26.      if (s === 'start') { 27.          events = []; 28.          recording = true; 29.          console.log('* State logging started.'); 30.      } else if (s === 'stop') { 31.          printTests(); 32.          recording = false; 33.          events = []; 34.          console.log('* State logging stopped.'); 35.      } else { 36.          console.log('create-state-tests <start|stop>'); 37.      } 38.  } 39.  window['_apprun-create-state-tests'] = ['create-state-tests <start|stop>', 40.       (p?) => _createStateTests(p) 41.  ]

The create-state-tests command accepts a parameter. When we run _apprun `create-state-tests start`, it starts recording the states (see Figure 12-11).

Figure 12-11
figure 11

create-state-tests start

When we run _apprun `create-state-tests stop`, it stops recording the states and generates the snapshot tests (see Figure 12-12).

Figure 12-12
figure 12

create-state-tests stop

Using the create-state-tests command , we can click through pages and let it record the states into the snapshot tests to be copied into the project.

The create-events-tests command and the create-state-tests command are included in a script file and released with the AppRun package. You can reference the script file in the HTML when you need to generate the tests.

<script src="https://unpkg.com/apprun@latest/dist/apprun-dev-tools-tests.js"></script>

You can remove the script reference from the HTML when you no longer need the commands.

Browser DevTools Extension

The AppRun debug event has another great benefit. We can connect AppRun events to the Redux DevTools Extension ( https://github.com/zalmoxisus/redux-devtools-extension ). Redux DevTools Extension is a browser extension for monitoring Redux applications. Ever since the version 2.0 release, it allows other non-Redux applications to communicate with the extension directly.

It is simple and straightforward to connect to the extension (Listing 12-3).

Listing 12-3 Connecting to the Redux DevTools Extension

1.   let devTools_running = false; 2.   const devTools = window['__REDUX_DEVTOOLS_EXTENSION__'].connect(); 3.   devTools.subscribe((message) => { 4.       if (message.type === 'START') devTools_running = true; 5.       else if (message.type === 'STOP') devTools_running = false; 6.   }); 7.   app.on('debug', p => { 8.       if (devTools_running && p.event) { 9.           const state = p.newState; 10.          const type = p.event; 11.          const payload = p.e; 12.          const action = { type, payload }; 13.          if (state instanceof Promise) { 14.              state.then(s => devTools.send(action, s)); 15.          } else { 16.              devTools.send(action, state); 17.          } 18.      } 19.  });

We can turn on and off monitoring the AppRun debug event based on the extensions’ start and stop messages (lines 3–6). In the AppRun debug event handler, we send the AppRun event and state of the AppRun event handler to the extension (lines 7–19).

We can install the Redux DevTools Extension from the Chrome Web Store or the Firefox add-ons. Then we can run the AppRun RealWorld example application and see AppRun events (see Figure 12-13) and application states on the Redux tab inside the browser’s DevTools (see Figure 12-14).

Figure 12-13
figure 13

Events in Redux DevTools Extension

The AppRun events are logged and displayed in the Redux extension in the sequence of the events being published. Each of the events is displayed as an action using the Redux terminology. The AppRun event name becomes the action type. The AppRun event parameters become the action payload.

Figure 12-14
figure 14

States in Redux DevTools Extension

The states of each AppRun component are logged and displayed with the associated AppRun event. If the AppRun events are asynchronous events, the state is a Promise object. The AppRun DevTools wait for the Promise object to resolve and then send the state to the DevTools Redux Extension. The extension can display the state on the Chart tab in a tree view.

The AppRun connection to the Redux DevTools Extension is included in the file that has the AppRun DevTools CLI engine and commands.

<script src="https://unpkg.com/apprun@latest/dist/apprun-dev-tools.js"></script>

Summary

Developing applications involves more than just coding. We need tools to explore, verify, measure, and monitor the applications to confirm the code was developed according to the design specifications. AppRun has provided the DevTools to assist us in achieving that goal.

The AppRun DevTools are nondestructive to the application codebase. We attach the AppRun DevTools when they are needed and detach them when they are not needed. The application does not require recompiling to use DevTools.

The AppRun DevTools introduced in this chapter are part of the AppRun package in two files.

<script src="https://unpkg.com/apprun@latest/dist/apprun-dev-tools.js"></script> <script src="https://unpkg.com/apprun@latest/dist/apprun-dev-tools-tests.js"></script>

You can use the commands and the Redux extension out of the box. You can also use the code in this chapter as a demonstration and reference to extend the AppRun DevTools.