Skip to content

07. Test Debug

Vitaly Kozyura edited this page Jul 7, 2025 · 11 revisions

Test and Debug Extensions

In this section, we will debug extension handlers running locally.
To do this, we'll run the extension project in the same Node.js environment, instead of executing it within the Oyster Framework.

Running the Extension Project in Debug Mode

Modify the runtime parameter in the extension's package.json file from "oyster" to "debug":

"cds": {
  "requires": {
    "code-extensibility": {
      "runtime": "debug",
      "maxTime": 1000,
      "maxMemory": 4
    }
  }
}

Start the extension project using cds watch with a debugger attached. For example, you can use the JavaScript Debug Terminal in Visual Studio Code.

Set a breakpoint, for instance, at line 3 in the on-promoteCustomer.js file.

In the Incidents preview, click the promote Customer button and select a customer. Execution should stop at the breakpoint.

Investigating the API

In the debugger, you can observe the provided API exactly as it will be accessible later within the Oyster Framework.
If you compare this API with the one available in a standard custom handler, you'll notice that it is reduced to a minimal subset — just enough to support writing a code extension handler.

The following objects are available and worth inspecting in the debugger:

  • this: A service object that exposes allowed service operations such as read and update (for CRUD operations), emit (for sending events), and entities (for accessing entity definitions visible to the service).
  • req: The request object that contains the input passed to the handler. It includes the event name, request data, request subject, and results. It also provides methods to create errors or reject the request.
  • Query Language (QL) API: For example, SELECT. As with standard custom handlers, the extension handler can also use the QL API. However, the functionality is limited compared to the full query language feature set.

Debugger Steps

You can optionally step into the debugger while executing line 3 of the __on-promoteCustomer.js__ file to examine the simplified Query Language (QL) that will later be used within the Oyster Framework.

To make this more interesting, modify line 3 to assign the result of the update statement to a variable:

const updRes = await this.update('CustomersProjection').with({ status: 'Gold' }).where({ ID: req.data.Customer_ID })

If you now step over this statement, you'll see that the value of updRes is undefined.
This is the expected behavior.

It highlights a special property of the reduced QL: only SELECT statements return a result set. Other operations like update do not return a value.

Playing Around

You can start the Incidents app (or any other CAP Node.js app of your choice).
If you set a breakpoint in a custom handler and pause execution during runtime,
you can compare the API objects we inspected earlier in code extension handlers with those available in standard custom handlers.

For example, take a look at the custom handlers defined in the processor-service.js file of the Incidents app.

You'll notice that the API scope provided to the Oyster framework is significantly reduced compared to the generic case.

Clone this wiki locally