Skip to content

Commit

Permalink
feat: separate pic server management from instance management
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanosdev committed Apr 20, 2024
1 parent dcd690a commit 15b4dc4
Show file tree
Hide file tree
Showing 53 changed files with 1,460 additions and 117 deletions.
2 changes: 0 additions & 2 deletions .github/actions/setup-bun/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ runs:
steps:
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: '1.0.26'

- name: Install Dependencies
shell: bash
Expand Down
6 changes: 1 addition & 5 deletions .github/actions/setup-dfx/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ description: Setup DFX
runs:
using: 'composite'
steps:
- name: Get DFX version
shell: bash
run: echo "dfx_version=$(cat dfx.json | jq -r .dfx)" >> "$GITHUB_ENV"

- name: Setup DFX
uses: dfinity/setup-dfx@main
with:
dfx-version: ${{ env.dfx_version }}
dfx-version: 'auto'
4 changes: 2 additions & 2 deletions .github/actions/setup-nodejs/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ runs:
using: 'composite'
steps:
- name: Install NodeJS
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 20
node-version-file: '.node-version'
registry-url: 'https://registry.npmjs.org'
12 changes: 5 additions & 7 deletions .github/actions/setup-pnpm/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,23 @@ runs:
steps:
- uses: ./.github/actions/setup-nodejs

- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v3
name: Install pnpm
id: pnpm-install
with:
run_install: false

- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- uses: actions/cache@v3
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store
${{ runner.os }}-pnpm-store-
- name: Install dependencies
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
url: https://www.npmjs.com/package/@hadronous/pic
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
needs: release_latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4

- uses: ./.github/actions/setup-pnpm

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-bun.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4

- uses: ./.github/actions/setup-bun

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4

- uses: ./.github/actions/setup-pnpm

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
contents: write
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

Expand Down
Binary file modified bun.lockb
Binary file not shown.
45 changes: 38 additions & 7 deletions docs/docs/guides/01-getting-started.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
# Getting started

[PocketIC](https://github.com/dfinity/pocketic) is a deterministic, lightweight and versatile testing solution for [Internet Computer canisters](https://internetcomputer.org/how-it-works/canister-lifecycle/).

PicJS provides bindings to interact with [PocketIC](https://github.com/dfinity/pocketic) from Typescript and JavaScript.

## JavaScript runtime environment

Tests written with PicJS are executed in a JavaScript runtime environment, such as [NodeJS](https://nodejs.org/en). To get started with PicJS, you will need to have a JavaScript runtime environment installed on your system.
Tests written with PicJS are executed in a JavaScript runtime environment, such as [NodeJS](https://nodejs.org/en).

[Bun](https://bun.sh/) is an alternative JavaScript runtime environment that is compatible with PicJS. Bun has several features that make it a great choice for running PicJS tests, such as a built-in test runner and assertion library in addition to being much more performant than NodeJS.
To get started with PicJS, you will need to have a JavaScript runtime environment installed on your system. If you're new to JavaScript, then [NodeJS](https://nodejs.org/en) is the recommended choice.

[Deno](https://deno.com/) in theory should also work, but it is not officially supported and compatibility is not actively tested. If you choose Deno and run into issues, please open an issue on the [GitHub repository](https://github.com/hadronous/pic-js/issues).
[Bun](https://bun.sh/) is an alternative JavaScript runtime environment that is compatible with PicJS. Bun has several features that make it a great choice for running PicJS tests, such as a built-in test runner and assertion library in addition to being much more performant than [NodeJS](https://nodejs.org/en). Bun is not very widely used yet, so it is not recommended for beginners.

[Deno](https://deno.com/) in theory should also work, but it is not officially supported and compatibility is not actively tested. If you choose Deno and run into issues, please open an issue on the [GitHub repository](https://github.com/hadronous/pic-js/issues). Deno is also not widely used, so it is not recommended for developers that are unfamiliar with it.

## Package manager

PicJS is a JavaScript/TypeScript package distributed on [NPM](https://www.npmjs.com/package/@hadronous/pic). To install and manage NPM packages, you will need to have an NPM-compatible package manager.

- [npm](https://nodejs.org/en/learn/getting-started/an-introduction-to-the-npm-package-manager) is the official package manager for NodeJS and comes pre-installed with NodeJS.
- [pnpm](https://pnpm.io/) is a fast, disk space-efficient package manager.
- [Yarn](https://yarnpkg.com/) is a package manager that doubles down as a project manager.
- [Bun](https://bun.sh/) also includes a built-in package manager.
- [npm](https://nodejs.org/en/learn/getting-started/an-introduction-to-the-npm-package-manager)
- This is the official package manager for [NodeJS](https://nodejs.org/en) and comes pre-installed.
- Beginners should stick with this option.
- [pnpm](https://pnpm.io/)
- A fast, disk space-efficient package manager.
- A great alternative to [npm](https://nodejs.org/en/learn/getting-started/an-introduction-to-the-npm-package-manager) for more experienced developers.
- [Yarn](https://yarnpkg.com/)
- A package manager that doubles down as a project manager.
- Another great alternative to [npm](https://nodejs.org/en/learn/getting-started/an-introduction-to-the-npm-package-manager) for more experienced developers.
- [Bun](https://bun.sh/)
- Bun also includes a built-in package manager.
- This is convenient if you are already using Bun as your runtime environment or test runner.

## DFX

Expand All @@ -30,3 +44,20 @@ sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
You can also check out the official [DFX installation documentation](https://internetcomputer.org/docs/current/developer-docs/getting-started/install) for more information.

DFX version 0.16.0 or later is recommended when writing PicJS tests. If you are on an earlier version then make sure to check out the [Canister declarations guide](./canister-declarations) to see how declarations should be used with older versions with DFX.

## Test runner

PicJS tests can be run with any test runner that runs on [NodeJS](https://nodejs.org/en) or [Bun](https://bun.sh/) (in theory the same should be true for [Deno](https://deno.com/), but that is not actively tested).

The following test runners are actively tested and officially supported:

- [Jest](https://jestjs.io/)
- Recommended if you're new to JavaScript testing because it has the largest community and is the most widely used.
- See the [Jest guide](./using-jest) for details on getting started with Jest and PicJS.
- [Vitest](https://vitest.dev/)
- If you're already using [Vite](https://vitejs.dev/) and Vitest for your frontend, then this is a good choice to reduce your dev dependencies.
- See the [Vitest guide](./using-vitest) for details on getting started with Vitest and PicJS.
- [Bun](https://bun.sh/)
- If you're already using Bun, or want to try it out, then this is a good choice.
- This is not recommended for beginners because it is less widely used and still immature compared to the other options.
- See the [Bun guide](./using-bun) for details on getting started with Bun and PicJS.
208 changes: 208 additions & 0 deletions docs/docs/guides/02-using-jest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Using Jest

[Jest](https://jestjs.io) is a JavaScript testing framework that is widely used in the JavaScript community. It is recommended for beginners because it has the largest community and is the most widely used. Jest is also the officially supported test runner for PicJS.

## Setup

To get started with [Jest](https://jestjs.io), install the relevant packages using your preferred package manager:

<Tabs>
<TabItem value="npm" label="npm" default>
```shell
npm i -D jest @types/jest @types/node ts-jest
```
</TabItem>

<TabItem value="pnpm" label="pnpm">
```shell
pnpm i -D jest @types/jest @types/node ts-jest
```
</TabItem>

<TabItem value="yarn" label="yarn">
```shell
yarn add -D jest @types/jest @types/node ts-jest
```
</TabItem>

<TabItem value="bun" label="bun">
```shell
bun add -d jest @types/jest @types/node ts-jest
```
</TabItem>
</Tabs>

Create a `tsconfig.json` file:

```json title="tsconfig.json"
{
"compilerOptions": {
// enable latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"allowJs": true, // allow importing `.js` from `.ts`
"types": ["jest", "node"],

// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,

// Best practices
"strict": true,
"skipLibCheck": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,

// Some stricter flags
"useUnknownInCatchVariables": true,
"noPropertyAccessFromIndexSignature": true
},
"include": [
"./src/**/*.ts",
"./global-setup.ts",
"./global-teardown.ts",
"./types.d.ts"
]
}
```

Create a `jest.config.ts` file:

```ts title="jest.config.ts"
import type { Config } from 'jest';

const config: Config = {
watch: false,
preset: 'ts-jest/presets/js-with-ts',
testEnvironment: 'node',
globalSetup: '<rootDir>/global-setup.ts',
globalTeardown: '<rootDir>/global-teardown.ts',
};

export default config;
```

You can also check out the official the [`ts-jest` documentation](https://kulshekhar.github.io/ts-jest/docs/) for more information on configuring this file.

Then, add a `test` script to your `package.json`:

```json title="package.json"
{
"scripts": {
"test": "jest"
}
}
```

The PocketIC server needs to be started before running tests and stopped once they're finished running. This can be done by creating `global-setup.ts` and `global-teardown.ts` files in your project's root directory:

```ts title="global-setup.ts"
import { PocketIcServer } from '@hadronous/pic';

module.exports = async function (): Promise<void> {
const pic = await PocketIcServer.start();
const url = pic.getUrl();

process.env.PIC_URL = url;
global.__PIC__ = pic;
};
```

```ts title="global-teardown.ts"
module.exports = async function () {
await global.__PIC__.stop();
};
```

To improve type-safety for `process.env.PIC_URL` and `global.__PIC__`, create a `types.d.ts` file:

```ts title="types.d.ts"
import { PocketIcServer } from '@hadronous/pic';

declare global {
declare var __PIC__: PocketIcServer;

namespace NodeJS {
interface ProcessEnv {
PIC_URL: string;
}
}
}
```

## Writing tests

[Jest](https://jestjs.io) tests are very similar to tests written with [Jasmine](https://jasmine.github.io), or [Vitest](https://vitest.dev) so they will feel very familiar to developers who have used these frameworks before.

The basic skeleton of all PicJS tests written with [Jest](https://jestjs.io) will look something like this:

```ts title="tests/example.spec.ts"
// Import generated types for your canister
import { type _SERVICE } from '../../declarations/backend/backend.did';

// Define the path to your canister's WASM file
export const WASM_PATH = resolve(
import.meta.dir,
'..',
'..',
'target',
'wasm32-unknown-unknown',
'release',
'backend.wasm',
);

// The `describe` function is used to group tests together
// and is completely optional.
describe('Test suite name', () => {
// Define variables to hold our PocketIC instance, canister ID,
// and an actor to interact with our canister.
let pic: PocketIc;
let canisterId: Principal;
let actor: Actor<_SERVICE>;

// The `beforeEach` hook runs before each test.
//
// This can be replaced with a `beforeAll` hook to persist canister
// state between tests.
beforeEach(async () => {
// create a new PocketIC instance
pic = await PocketIc.create(process.env.PIC_URL);

// Setup the canister and actor
const fixture = await pic.setupCanister<_SERVICE>({
idlFactory,
wasm: WASM_PATH,
});

// Save the actor and canister ID for use in tests
actor = fixture.actor;
canisterId = fixture.canisterId;
});

// The `afterEach` hook runs after each test.
//
// This should be replaced with an `afterAll` hook if you use
// a `beforeAll` hook instead of a `beforeEach` hook.
afterEach(async () => {
// tear down the PocketIC instance
await pic.tearDown();
});

// The `it` function is used to define individual tests
it('should do something cool', async () => {
const response = await actor.do_something_cool();

expect(response).toEqual('cool');
});
});
```

You can also check out the official [Jest getting started documentation](https://jestjs.io/docs/getting-started) for more information on writing tests.
Loading

0 comments on commit 15b4dc4

Please sign in to comment.