Running tests
Configuring the server binary
Section titled “Configuring the server binary”By default, the PocketIC server binary downloaded by the @dfinity/pic install script is used, which requires allowing the install script. A different binary can be provided using the binPath option, for example:
const picServer = await PocketIcServer.start({ binPath: '/path/to/pocket-ic',});Alternatively, the POCKET_IC_BIN environment variable can be set to the path of the binary, for example:
POCKET_IC_BIN=/path/to/pocket-ic npm testThe binPath option takes precedence over the POCKET_IC_BIN environment variable.
Configuring logging
Section titled “Configuring logging”Canister logs
Section titled “Canister logs”Logs for canisters can be configured when running the PocketIC server using the showCanisterLogs option, for example:
const picServer = await PocketIcServer.start({ showCanisterLogs: true,});To assert on a canister’s logs in a test, fetch its log records with fetchCanisterLogs. By default, only the canister’s controllers can read its logs; other principals need the canister’s log visibility to allow them:
const pic = await PocketIc.create(picServer.getUrl());// set up a canister controlled by `controller`...
const logs = await pic.fetchCanisterLogs({ canisterId, sender: controller.getPrincipal(),});const messages = logs.map(log => new TextDecoder().decode(log.content));Records can be narrowed to an index or timestamp range with filter, for example filter: { type: 'byIdx', start: 0n, end: 10n }.
Server logs
Section titled “Server logs”Logs for the PocketIC server can be configured by setting the POCKET_IC_LOG_DIR and POCKET_IC_LOG_DIR_LEVELS environment variables.
The POCKET_IC_LOG_DIR variable specifies the directory where the logs will be stored. It accepts any valid relative, or absolute directory path.
The POCKET_IC_LOG_DIR_LEVELS variable specifies the log levels. It accepts any of the following string values: trace, debug, info, warn, or error.
For example:
POCKET_IC_LOG_DIR=./logs POCKET_IC_LOG_DIR_LEVELS=trace npm testIt’s also possible to set individual log levels for different modules, for examples:
POCKET_IC_LOG_DIR=./logs POCKET_IC_LOG_DIR_LEVELS=pocket_ic_server=trace,tower_http=info,axum::rejection=info npm testRuntime logs
Section titled “Runtime logs”Logs for the IC runtime can be configured when running the PocketIC server using the showRuntimeLogs option, for example:
const picServer = await PocketIcServer.start({ showRuntimeLogs: true,});These include the logs of each instance’s replica, which only logs warnings and errors by default. To see more, set its log level with the logLevel option when creating the instance, one of critical, error, warn, info, debug or trace:
const pic = await PocketIc.create(picServer.getUrl(), { logLevel: 'debug',});Testing interleaved calls
Section titled “Testing interleaved calls”While a call waits at an await, for example for an inter-canister call, the canister can execute other calls. If the first call checked some state before the await and updates it after, another call can act on the same state in between, which can cause reentrancy bugs.
To reproduce this, submit the calls with a deferred actor before executing any of them. Calling a method of a deferred actor submits the call and returns a function that executes it. Calls submitted together are executed together, so they interleave at their awaits. The Reentrancy example uses this to show a withdrawal that pays out twice, and how to fix it. For calls without generated declarations, pic.submitCall and pic.awaitCall do the same with a Candid-encoded argument.
Live mode
Section titled “Live mode”makeLive makes the instance execute rounds on its own, in real time, and starts an HTTP gateway, so agents can call canisters as they would on a real network:
const gatewayPort = await pic.makeLive();const agent = await HttpAgent.create({ host: `http://localhost:${gatewayPort}`, shouldFetchRootKey: true,});
// make calls with the agent...
await pic.stopLive();The gateway can be configured with the httpGateway option, for example pic.makeLive({ httpGateway: { port: 8080 } }).
To create an instance that is live from the start, set the autoProgress option, for example PocketIc.create(url, { autoProgress: {} }). Its time follows the real time right away, and makeLive starts the HTTP gateway for it.
To test how a client handles slower calls, for example its loading states or timeouts, set a minimum delay between rounds with artificialDelayMs, for example pic.makeLive({ artificialDelayMs: 500 }). This delays calls that wait for live mode to execute them: calls made through the HTTP gateway, and calls submitted with pic.submitCall whose result is checked with pic.ingressStatus. Calls made with an actor, a deferred actor, pic.updateCall or pic.awaitCall execute their rounds themselves and are not delayed.