UNPKG

@dfinity/pic

Version:

An Internet Computer Protocol canister testing library for TypeScript and JavaScript.

1,248 lines 45.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PocketIc = void 0; const principal_1 = require("@dfinity/principal"); const util_1 = require("./util"); const pocket_ic_client_1 = require("./pocket-ic-client"); const pocket_ic_actor_1 = require("./pocket-ic-actor"); const pocket_ic_types_1 = require("./pocket-ic-types"); const management_canister_1 = require("./management-canister"); const pocket_ic_deferred_actor_1 = require("./pocket-ic-deferred-actor"); /** * This class represents the main PocketIC client. * It is responsible for interacting with the PocketIC server via the REST API. * See {@link PocketIcServer} for details on the server to use with this client. * * @category API * * @example * The easist way to use PocketIC is to use {@link setupCanister} convenience method: * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { _SERVICE, idlFactory } from '../declarations'; * * const wasmPath = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const fixture = await pic.setupCanister<_SERVICE>({ idlFactory, wasmPath }); * const { actor } = fixture; * * // perform tests... * * await pic.tearDown(); * await picServer.stop(); * ``` * * If more control is needed, then the {@link createCanister}, {@link installCode} and * {@link createActor} methods can be used directly: * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { _SERVICE, idlFactory } from '../declarations'; * * const wasm = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const canisterId = await pic.createCanister(); * await pic.installCode({ canisterId, wasm }); * const actor = pic.createActor<_SERVICE>({ idlFactory, canisterId }); * * // perform tests... * * await pic.tearDown(); * await picServer.stop(); * ``` */ class PocketIc { client; constructor(client) { this.client = client; } /** * Creates a PocketIC instance. * * @param url The URL of an existing PocketIC server to connect to. * @param options Options for creating the PocketIC instance see {@link CreateInstanceOptions}. * @returns A new PocketIC instance. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const fixture = await pic.setupCanister<_SERVICE>({ idlFactory, wasmPath }); * const { actor } = fixture; * * await pic.tearDown(); * await picServer.stop(); * ``` */ static async create(url, options) { const client = await pocket_ic_client_1.PocketIcClient.create(url, options); return new PocketIc(client); } /** * A convenience method that creates a new canister, * installs the given WASM module to it and returns a typesafe {@link Actor} * that implements the Candid interface of the canister. * To just create a canister, see {@link createCanister}. * To just install code to an existing canister, see {@link installCode}. * To just create an Actor for an existing canister, see {@link createActor}. * * @param options Options for setting up the canister, see {@link SetupCanisterOptions}. * @returns The {@link Actor} instance. * * @see [Candid](https://internetcomputer.org/docs/current/references/candid-ref) * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { _SERVICE, idlFactory } from '../declarations'; * * const wasmPath = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const fixture = await pic.setupCanister<_SERVICE>({ idlFactory, wasmPath }); * const { actor } = fixture; * * await pic.tearDown(); * await picServer.stop(); * ``` */ async setupCanister({ sender, arg, wasm, idlFactory, computeAllocation, controllers, cycles, freezingThreshold, memoryAllocation, targetCanisterId, targetSubnetId, reservedCyclesLimit, }) { const canisterId = await this.createCanister({ computeAllocation, controllers, cycles, freezingThreshold, memoryAllocation, reservedCyclesLimit, targetCanisterId, targetSubnetId, sender, }); await this.installCode({ canisterId, wasm, arg, sender, targetSubnetId }); const actor = this.createActor(idlFactory, canisterId); return { actor, canisterId }; } /** * Creates a new canister. * For a more convenient way of creating a PocketIC instance, * creating a canister and installing code, see {@link setupCanister}. * * @param options Options for creating the canister, see {@link CreateCanisterOptions}. * @returns The Principal of the newly created canister. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const canisterId = await pic.createCanister(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async createCanister({ sender = principal_1.Principal.anonymous(), cycles = 1000000000000000000n, controllers, computeAllocation, freezingThreshold, memoryAllocation, reservedCyclesLimit, targetCanisterId, targetSubnetId, } = {}) { const payload = (0, management_canister_1.encodeCreateCanisterRequest)({ settings: [ { controllers: (0, util_1.optional)(controllers), compute_allocation: (0, util_1.optional)(computeAllocation), memory_allocation: (0, util_1.optional)(memoryAllocation), freezing_threshold: (0, util_1.optional)(freezingThreshold), reserved_cycles_limit: (0, util_1.optional)(reservedCyclesLimit), }, ], amount: [cycles], specified_id: (0, util_1.optional)(targetCanisterId), }); const res = await this.client.updateCall({ canisterId: management_canister_1.MANAGEMENT_CANISTER_ID, sender, method: 'provisional_create_canister_with_cycles', payload, effectivePrincipal: targetSubnetId ? { subnetId: targetSubnetId, } : undefined, }); return (0, management_canister_1.decodeCreateCanisterResponse)(res.body).canister_id; } /** * Starts the given canister. * * @param options Options for starting the canister, see {@link StartCanisterOptions}. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.startCanister({ canisterId }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async startCanister({ canisterId, sender = principal_1.Principal.anonymous(), targetSubnetId, }) { const payload = (0, management_canister_1.encodeStartCanisterRequest)({ canister_id: canisterId, }); await this.client.updateCall({ canisterId: management_canister_1.MANAGEMENT_CANISTER_ID, sender, method: 'start_canister', payload, effectivePrincipal: targetSubnetId ? { subnetId: targetSubnetId, } : undefined, }); } /** * Stops the given canister. * * @param options Options for stopping the canister, see {@link StopCanisterOptions}. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.stopCanister({ canisterId }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async stopCanister({ canisterId, sender = principal_1.Principal.anonymous(), targetSubnetId, }) { const payload = (0, management_canister_1.encodeStartCanisterRequest)({ canister_id: canisterId, }); await this.client.updateCall({ canisterId: management_canister_1.MANAGEMENT_CANISTER_ID, sender, method: 'stop_canister', payload, effectivePrincipal: targetSubnetId ? { subnetId: targetSubnetId, } : undefined, }); } /** * Installs the given WASM module to the provided canister. * To create a canister to install code to, see {@link createCanister}. * For a more convenient way of creating a PocketIC instance, * creating a canister and installing code, see {@link setupCanister}. * * @param options Options for installing the code, see {@link InstallCodeOptions}. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { resolve } from 'node:path'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * const wasm = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.installCode({ canisterId, wasm }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async installCode({ arg = new Uint8Array(), sender = principal_1.Principal.anonymous(), canisterId, wasm, targetSubnetId, }) { if (typeof wasm === 'string') { wasm = await (0, util_1.readFileAsBytes)(wasm); } const payload = (0, management_canister_1.encodeInstallCodeRequest)({ arg: new Uint8Array(arg), canister_id: canisterId, mode: { install: null, }, wasm_module: new Uint8Array(wasm), }); await this.client.updateCall({ canisterId: management_canister_1.MANAGEMENT_CANISTER_ID, sender, method: 'install_code', payload, effectivePrincipal: targetSubnetId ? { subnetId: targetSubnetId, } : undefined, }); } /** * Reinstalls the given WASM module to the provided canister. * This will reset both the canister's heap and its stable memory. * To create a canister to upgrade, see {@link createCanister}. * To install the initial WASM module to a new canister, see {@link installCode}. * * @param options Options for reinstalling the code, see {@link ReinstallCodeOptions}. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { resolve } from 'node:path'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * const wasm = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.reinstallCode({ canisterId, wasm }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async reinstallCode({ sender = principal_1.Principal.anonymous(), arg = new Uint8Array(), canisterId, wasm, }) { if (typeof wasm === 'string') { wasm = await (0, util_1.readFileAsBytes)(wasm); } const payload = (0, management_canister_1.encodeInstallCodeRequest)({ arg: new Uint8Array(arg), canister_id: canisterId, mode: { reinstall: null, }, wasm_module: new Uint8Array(wasm), }); await this.client.updateCall({ canisterId: management_canister_1.MANAGEMENT_CANISTER_ID, sender, method: 'install_code', payload, }); } /** * Upgrades the given canister with the given WASM module. * This will reset the canister's heap, but preserve stable memory. * To create a canister to upgrade to, see {@link createCanister}. * To install the initial WASM module to a new canister, see {@link installCode}. * * @param options Options for upgrading the canister, see {@link UpgradeCanisterOptions}. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { resolve } from 'node:path'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * const wasm = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.upgradeCanister({ canisterId, wasm }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async upgradeCanister({ sender = principal_1.Principal.anonymous(), arg = new Uint8Array(), canisterId, wasm, }) { if (typeof wasm === 'string') { wasm = await (0, util_1.readFileAsBytes)(wasm); } const payload = (0, management_canister_1.encodeInstallCodeRequest)({ arg: new Uint8Array(arg), canister_id: canisterId, mode: { upgrade: null, }, wasm_module: new Uint8Array(wasm), }); await this.client.updateCall({ canisterId: management_canister_1.MANAGEMENT_CANISTER_ID, sender, method: 'install_code', payload, }); } /** * Updates the settings of the given canister. * * @param options Options for updating the canister settings, see {@link UpdateCanisterSettingsOptions}. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.updateCanisterSettings({ * canisterId, * controllers: [Principal.fromUint8Array(new Uint8Array([1]))], * }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async updateCanisterSettings({ canisterId, computeAllocation, controllers, freezingThreshold, memoryAllocation, reservedCyclesLimit, sender = principal_1.Principal.anonymous(), }) { const payload = (0, management_canister_1.encodeUpdateCanisterSettingsRequest)({ canister_id: canisterId, settings: { controllers: (0, util_1.optional)(controllers), compute_allocation: (0, util_1.optional)(computeAllocation), memory_allocation: (0, util_1.optional)(memoryAllocation), freezing_threshold: (0, util_1.optional)(freezingThreshold), reserved_cycles_limit: (0, util_1.optional)(reservedCyclesLimit), }, }); await this.client.updateCall({ canisterId: management_canister_1.MANAGEMENT_CANISTER_ID, sender, method: 'update_settings', payload, }); } /** * Creates an {@link Actor} for the given canister. * An {@link Actor} is a typesafe class that implements the Candid interface of a canister. * To create a canister for the {@link Actor}, see {@link createCanister}. * For a more convenient way of creating a PocketIC instance, * creating a canister and installing code, see {@link setupCanister}. * * @param interfaceFactory The InterfaceFactory to use for the {@link Actor}. * @param canisterId The Principal of the canister to create the {@link Actor} for. * @typeparam T The type of the {@link Actor}. Must implement {@link ActorInterface}. * @returns The {@link Actor} instance. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * @see [InterfaceFactory](https://agent-js.icp.xyz/candid/modules/IDL.html#InterfaceFactory) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { _SERVICE, idlFactory } from '../declarations'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * const wasm = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const canisterId = await pic.createCanister(); * await pic.installCode({ canisterId, wasm }); * const actor = pic.createActor<_SERVICE>({ idlFactory, canisterId }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ createActor(interfaceFactory, canisterId) { const Actor = (0, pocket_ic_actor_1.createActorClass)(interfaceFactory, canisterId, this.client); return new Actor(); } /** * Creates a {@link DeferredActor} for the given canister. * A {@link DeferredActor} is a typesafe class that implements the Candid interface of a canister. * * A {@link DeferredActor} in contrast to a normal {@link Actor} will submit the call to the PocketIc replica, * but the call will not be executed immediately. Instead, the calls are queued and a `Promise` is returned * by the {@link DeferredActor} that can be awaited to process the pending canister call. * * To create a canister for the {@link DeferredActor}, see {@link createCanister}. * For a more convenient way of creating a PocketIC instance, * creating a canister and installing code, see {@link setupCanister}. * * @param interfaceFactory The InterfaceFactory to use for the {@link DeferredActor}. * @param canisterId The Principal of the canister to create the {@link DeferredActor} for. * @typeparam T The type of the {@link DeferredActor}. Must implement {@link ActorInterface}. * @returns The {@link DeferredActor} instance. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * @see [InterfaceFactory](https://agent-js.icp.xyz/candid/modules/IDL.html#InterfaceFactory) * * @example */ createDeferredActor(interfaceFactory, canisterId) { const DeferredActor = (0, pocket_ic_deferred_actor_1.createDeferredActorClass)(interfaceFactory, canisterId, this.client); return new DeferredActor(); } /** * Makes a query call to the given canister. * * @param options Options for making the query call, see {@link QueryCallOptions}. * @returns The Candid-encoded response of the query call. * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { _SERVICE, idlFactory } from '../declarations'; * * const wasm = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * canisterId = await pic.createCanister({ * sender: controllerIdentity.getPrincipal(), * }); * await pic.installCode({ canisterId, wasm }); * * const res = await pic.queryCall({ * canisterId, * method: 'greet', * }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async queryCall({ canisterId, method, arg = new Uint8Array(), sender = principal_1.Principal.anonymous(), targetSubnetId, }) { const res = await this.client.queryCall({ canisterId, method, payload: new Uint8Array(arg), sender, effectivePrincipal: targetSubnetId ? { subnetId: targetSubnetId, } : undefined, }); return res.body; } /** * Makes an update call to the given canister. * * @param options Options for making the update call, see {@link UpdateCallOptions}. * @returns The Candid-encoded response of the update call. * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * import { _SERVICE, idlFactory } from '../declarations'; * * const wasm = resolve('..', '..', 'canister.wasm'); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * canisterId = await pic.createCanister({ * sender: controllerIdentity.getPrincipal(), * }); * await pic.installCode({ canisterId, wasm }); * * const res = await pic.updateCall({ * canisterId, * method: 'greet', * }); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async updateCall({ canisterId, method, arg = new Uint8Array(), sender = principal_1.Principal.anonymous(), targetSubnetId, }) { const res = await this.client.updateCall({ canisterId, method, payload: new Uint8Array(arg), sender, effectivePrincipal: targetSubnetId ? { subnetId: targetSubnetId, } : undefined, }); return res.body; } /** * Deletes the PocketIC instance. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async tearDown() { await this.client.deleteInstance(); } /** * Make the IC produce and progress by one block. Accepts a parameter `times` to tick multiple times, * the default is `1`. * * @param times The number of new blocks to produce and progress by. Defaults to `1`. * * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.tick(); * * // or to tick multiple times * await pic.tick(3); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async tick(times = 1) { for (let i = 0; i < times; i++) { await this.client.tick(); } } /** * Get the controllers of the specified canister. * * @param canisterId The Principal of the canister to get the controllers of. * @returns The controllers of the specified canister. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const controllers = await pic.getControllers(canisterId); * * await pic.tearDown(); * await picServer.stop(); */ async getControllers(canisterId) { return await this.client.getControllers({ canisterId }); } /** * Get the current time of the IC in milliseconds since the Unix epoch. * * @returns The current time in milliseconds since the UNIX epoch. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const time = await pic.getTime(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async getTime() { const { millisSinceEpoch } = await this.client.getTime(); return millisSinceEpoch; } /** * Reset the time of the IC to the current time. * {@link tick} should be called after calling this method in order for query calls * and read state request to reflect the new time. * * Use {@link resetCertifiedTime} to set time and immediately have query calls and * read state requests reflect the new time. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.resetTime(); * await pic.tick(); * * const time = await pic.getTime(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async resetTime() { await this.setTime(Date.now()); } /** * Reset the time of the IC to the current time and immediately have query calls and * read state requests reflect the new time. * * Use {@link resetTime} to reset time without immediately reflecting the new time. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.resetCertifiedTime(); * * const time = await pic.getTime(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async resetCertifiedTime() { await this.setCertifiedTime(Date.now()); } /** * Set the current time of the IC. * {@link tick} should be called after calling this method in order for query calls * and read state request to reflect the new time. * * Use {@link setCertifiedTime} to set time and immediately have query calls and * read state requests reflect the new time. * * @param time The time to set in milliseconds since the Unix epoch. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const pic = await PocketIc.create(); * * const date = new Date(); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.setTime(date); * // or * await pic.setTime(date.getTime()); * * await pic.tick(); * * const time = await pic.getTime(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async setTime(time) { if (time instanceof Date) { time = time.getTime(); } await this.client.setTime({ millisSinceEpoch: time }); } /** * Set the current time of the IC and immediately have query calls and * read state requests reflect the new time. * * Use {@link setTime} to set time without immediately reflecting the new time. * * @param time The time to set in milliseconds since the Unix epoch. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const pic = await PocketIc.create(); * * const date = new Date(); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.setCertifiedTime(date); * // or * await pic.setCertifiedTime(date.getTime()); * * const time = await pic.getTime(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async setCertifiedTime(time) { if (time instanceof Date) { time = time.getTime(); } await this.client.setCertifiedTime({ millisSinceEpoch: time }); } /** * Advance the time of the IC by the given duration in milliseconds. * {@link tick} should be called after calling this method in order for query calls * and read state requests to reflect the new time. * * Use {@link advanceCertifiedTime} to advance time and immediately have query calls and * read state requests reflect the new time. * * @param duration The duration to advance the time by. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const initialTime = await pic.getTime(); * await pic.advanceTime(1_000); * await pic.tick(); * * const newTime = await pic.getTime(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async advanceTime(duration) { const currentTime = await this.getTime(); const newTime = currentTime + duration; await this.setTime(newTime); } /** * Advance the time of the IC by the given duration in milliseconds and * immediately have query calls and read state requests reflect the new time. * * Use {@link advanceTime} to advance time without immediately reflecting the new time. * * @param duration The duration to advance the time by. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const initialTime = await pic.getTime(); * await pic.advanceCertifiedTime(1_000); * * const newTime = await pic.getTime(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async advanceCertifiedTime(duration) { const currentTime = await this.getTime(); const newTime = currentTime + duration; await this.setCertifiedTime(newTime); } /** * Fetch the public key of the specified subnet. * * @param subnetId The Principal of the subnet to fetch the public key of. * @returns The public key of the specified subnet. * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const subnets = pic.getApplicationSubnets(); * const pubKey = await pic.getPubKey(subnets[0].id); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async getPubKey(subnetId) { return await this.client.getPubKey({ subnetId }); } /** * Gets the subnet Id of the provided canister Id. * * @param canisterId The Principal of the canister to get the subnet Id of. * @returns The canister's subnet Id if the canister exists, `null` otherwise. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const subnetId = await pic.getCanisterSubnetId(canisterId); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async getCanisterSubnetId(canisterId) { const { subnetId } = await this.client.getSubnetId({ canisterId }); return subnetId; } /** * Get the topology of this instance's network. * The topology is a list of subnets, each with a type and a list of canister ID ranges * that can be deployed to that subnet. * The instance network topology is configured via the {@link create} method. * * @returns An array of subnet topologies, see {@link SubnetTopology}. */ async getTopology() { const topology = await this.client.getTopology(); return Object.values(topology); } /** * Get the Bitcoin subnet topology for this instance's network. * The instance network topology is configured via the {@link create} method. * * @returns The subnet topology for the Bitcoin subnet, * if it exists on this instance's network. */ async getBitcoinSubnet() { const topology = await this.getTopology(); return topology.find(subnet => subnet.type === pocket_ic_types_1.SubnetType.Bitcoin); } /** * Get the Fiduciary subnet topology for this instance's network. * The instance network topology is configured via the {@link create} method. * * @returns The subnet topology for the Fiduciary subnet, * if it exists on this instance's network. */ async getFiduciarySubnet() { const topology = await this.getTopology(); return topology.find(subnet => subnet.type === pocket_ic_types_1.SubnetType.Fiduciary); } /** * Get the Internet Identity subnet topology for this instance's network. * The instance network topology is configured via the {@link create} method. * * @returns The subnet topology for the Internet Identity subnet, * if it exists on this instance's network. */ async getInternetIdentitySubnet() { const topology = await this.getTopology(); return topology.find(subnet => subnet.type === pocket_ic_types_1.SubnetType.InternetIdentity); } /** * Get the NNS subnet topology for this instance's network. * The instance network topology is configured via the {@link create} method. * * @returns The subnet topology for the NNS subnet, * if it exists on this instance's network. */ async getNnsSubnet() { const topology = await this.getTopology(); return topology.find(subnet => subnet.type === pocket_ic_types_1.SubnetType.NNS); } /** * Get the SNS subnet topology for this instance's network. * The instance network topology is configured via the {@link create} method. * * @returns The subnet topology for the SNS subnet, * if it exists on this instance's network. */ async getSnsSubnet() { const topology = await this.getTopology(); return topology.find(subnet => subnet.type === pocket_ic_types_1.SubnetType.SNS); } /** * Get all application subnet topologies for this instance's network. * The instance network topology is configured via the {@link create} method. * * @returns An array of subnet topologies for each application subnet * that exists on this instance's network. */ async getApplicationSubnets() { const topology = await this.getTopology(); return topology.filter(subnet => subnet.type === pocket_ic_types_1.SubnetType.Application); } /** * Get all system subnet topologies for this instance's network. * The instance network topology is configured via the {@link create} method. * * @returns An array of subnet topologies for each system subnet * that exists on this instance's network. */ async getSystemSubnets() { const topology = await this.getTopology(); return topology.filter(subnet => subnet.type === pocket_ic_types_1.SubnetType.System); } /** * Gets the current cycle balance of the specified canister. * * @param canisterId The Principal of the canister to check. * @returns The current cycles balance of the canister. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const cyclesBalance = await pic.getCyclesBalance(canisterId); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async getCyclesBalance(canisterId) { const { cycles } = await this.client.getCyclesBalance({ canisterId }); return cycles; } /** * Add cycles to the specified canister. * * @param canisterId The Principal of the canister to add cycles to. * @param amount The amount of cycles to add. * @returns The new cycle balance of the canister. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const newCyclesBalance = await pic.addCycles(canisterId, 10_000_000); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async addCycles(canisterId, amount) { const { cycles } = await this.client.addCycles({ canisterId, amount }); return cycles; } /** * Set the stable memory of a given canister. * * @param canisterId The Principal of the canister to set the stable memory of. * @param stableMemory A blob containing the stable memory to set. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * const stableMemory = new Uint8Array([0, 1, 2, 3, 4]); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * await pic.setStableMemory(canisterId, stableMemory); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async setStableMemory(canisterId, stableMemory) { const { blobId } = await this.client.uploadBlob({ blob: new Uint8Array(stableMemory), }); await this.client.setStableMemory({ canisterId, blobId }); } /** * Get the stable memory of a given canister. * * @param canisterId The Principal of the canister to get the stable memory of. * @returns A blob containing the canister's stable memory. * * @see [Principal](https://agent-js.icp.xyz/principal/classes/Principal.html) * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * const stableMemory = await pic.getStableMemory(canisterId); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async getStableMemory(canisterId) { const { blob } = await this.client.getStableMemory({ canisterId }); return blob; } /** * Get all pending HTTPS Outcalls across all subnets on this * PocketIC instance. * * @returns An array of pending HTTPS Outcalls. * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * // queue the canister message that will send the HTTPS Outcall * const executeGoogleSearch = await deferredActor.google_search(); * * // tick for two rounds to allow the canister message to be processed * // and for the HTTPS Outcall to be queued * await pic.tick(2); * * // get all queued HTTPS Outcalls * const pendingHttpsOutcalls = await pic.getPendingHttpsOutcalls(); * * // get the first pending HTTPS Outcall * const pendingGoogleSearchOutcall = pendingHttpsOutcalls[0]; * * // mock the HTTPS Outcall * await pic.mockPendingHttpsOutcall({ * requestId: pendingGoogleSearchOutcall.requestId, * subnetId: pendingGoogleSearchOutcall.subnetId, * response: { * type: 'success', * body: new TextEncoder().encode('Google search result'), * statusCode: 200, * headers: [], * }, * }); * * // finish executing the message, including the HTTPS Outcall * const result = await executeGoogleSearch(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async getPendingHttpsOutcalls() { return await this.client.getPendingHttpsOutcalls(); } /** * Mock a pending HTTPS Outcall. * * @param options Options for mocking the pending HTTPS Outcall, see {@link MockPendingHttpsOutcallOptions}. * * @example * ```ts * import { Principal } from '@dfinity/principal'; * import { PocketIc, PocketIcServer } from '@dfinity/pic'; * * const canisterId = Principal.fromUint8Array(new Uint8Array([0])); * * const picServer = await PocketIcServer.create(); * const pic = await PocketIc.create(picServer.getUrl()); * * // queue the canister message that will send the HTTPS Outcall * const executeGoogleSearch = await deferredActor.google_search(); * * // tick for two rounds to allow the canister message to be processed * // and for the HTTPS Outcall to be queued * await pic.tick(2); * * // get all queued HTTPS Outcalls * const pendingHttpsOutcalls = await pic.getPendingHttpsOutcalls(); * * // get the first pending HTTPS Outcall * const pendingGoogleSearchOutcall = pendingHttpsOutcalls[0]; * * // mock the HTTPS Outcall * await pic.mockPendingHttpsOutcall({ * requestId: pendingGoogleSearchOutcall.requestId, * subnetId: pendingGoogleSearchOutcall.subnetId, * response: { * type: 'success', * body: new TextEncoder().encode('Google search result'), * statusCode: 200, * headers: [], * }, * }); * * // finish executing the message, including the HTTPS Outcall * const result = await executeGoogleSearch(); * * await pic.tearDown(); * await picServer.stop(); * ``` */ async mockPendingHttpsOutcall({ requestId, response, subnetId, additionalResponses = [], }) { return await this.client.mockPendingHttpsOutcall({ requestId, response, subnetId, additionalResponses, }); } } exports.PocketIc = PocketIc; //# sourceMappingURL=pocket-ic.js.map