Rationale

Testing, easily manipulating a Ledger application is hard. Although Speculos strongly eases it, it cannot always replace IRL tests on physical devices.

There are libraries allowing to communicate with a physical device. However, it would be very convenient to be able to develop code which would be compatible wherever the application runs, either on an emulator or on a physical device.

On top of this, all these libraries provides low-level functions like pressing a button or sending APDUs. Applications can be complex pieces of software and testing one require higher-level code.

Abstracting the backends

The original goal of Ragger is to make the manipulation of an application oblivious of the underlying device. Most applications are tested against Speculos, the Ledger device emulator, but it is not always enough, and testing on real physical devices is often required.

Ragger provides an interface which wraps several libraries:

  • one emulator-only library: Speculos (which uses itself as an emulator),

  • two agnostic libraries, which can communicate with either a physical device, or an emulated one:

In Ragger, the classes embedding these libraries are called backends. Any other backend can be added, given it respects the BackendInterface interface.

Software / communication layers between an application and its client

Application clients using Ragger must comply with this interface to communicate with the application. Once it’s done, the client can communicate with an application running either on top of an emulator or on a real, physical device with very little cost.

Why not no cost? That’s because the backend actually needs to talk to something. Speculos is conveniently able to start its emulator itself, however the other backends will need the application to be already started. Typically, the application will have to be installed on a physical device, started, and the device connected to the computer launching the client.

How to exploit these capabilities to write test running on both emulated or physical device is documented in the tutorial section.

Easing the development of application clients

On top of abstracting the backend, Ragger provides tools and mechanisms allowing to ease the development of application clients and write more thorough tests.

Touch screen management

Dealing with UI and user interaction is never simple. Nano devices has only two user physical inputs, through the two buttons, which already allows some elaborate combinations that could be challenging to test automatically.

With the touchable screens of Stax or Flex devices, the number of possibilities drastically increases.

Ragger embeds tools allowing to ease the development and the maintenance of UI clients. this tools mainly consist of 3 components:

  • the layout classes, representing the layouts proposed in the NBGL section of the C SDK,

  • the use cases classes, representing the use cases proposed in the NBGL section of the C SDK,

  • the screen module, allowing to nest the previous components in a single, centralized object.

Note

If you are familiar with the NBGL library, you will notice that Ragger does not implement a Page representation. It will be integrated eventually.

These components bring multiple benefits:

  • these abstractions prevent to directly use (X, Y) coordinates to interact with the screen and propose higher-level methods (for instance, when using the UseCaseHome use case, going to the settings is triggered with the method UseCaseHome.settings() instead of touching the screen at (342, 55)). The client’s code is meaningful.

  • Ragger internally keeps track of these positions on every SDK version. If a new SDK version moves a button to other coordinates, the code written with the Ragger components will stay valid and functional.

  • the layouts and use cases mimic the NBGL capabilities, so that the Ragger client screen architecture is close to the application one.

  • the FullScreen class embeds every existing layout and use case in a single class, providing a fast way of testing an interface without any other configuration.

  • the MetaScreen metaclass allows to build custom screen classes nesting the layouts and the use cases of your choosing, creating a convenient and meaningful screen object where all UI interactions are centralized.

You can find example of these components in this tutorial.