iitc-kuku-plugin-tester
v1.1.0
Published
Test environment for IITC plugins
Readme
IITC Plugin Tester
A test harness for IITC (Ingress Intel Total Conversion) plugins. It boots IITC in a real headless Chromium browser and lets you assert plugin behaviour and take screenshots without needing a Niantic account or internet access.

How it works
IITC normally runs as a userscript injected into intel.ingress.com. It requires:
- A logged-in Niantic session (
window.PLAYER) - Specific minified globals for tile parameters (
extractFromStock()) - Map tile images from CartoDB / Google Maps
- Ingress API endpoints (
POST /r/*)
This project provides all of that as local mocks:
| Component | What it does |
|---|---|
| server/index.ts | Express server on localhost:3000 |
| server/routes/intel-page.ts | Serves a fake intel.ingress.com HTML page with mock globals and inline plugin code |
| server/routes/api.ts | Handles POST /r/* Ingress API calls with fixture data |
| server/routes/tiles.ts | Serves pre-fetched OSM map tiles from server/fixtures/tiles/; returns a blank tile for any uncached request |
| server/fixtures/ | JSON responses for game score, entities, and player data; pre-fetched PNG tiles |
| iitc/total-conversion-build.js | The IITC built script (downloaded from the official release, not included) |
| plugins/ | Drop plugin .js files here for standalone development -- auto-embedded at boot |
| tests/test-plugin.js | Built-in boot-signal plugin (sets data-iitc-fully-loaded, always loaded last) |
| tests/helpers/iitc-page.ts | Playwright route interceptions for tiles and fonts |
| tests/iitc-loads.spec.ts | Built-in boot verification test with visual screenshot comparison |
| tests/entities.spec.ts | Built-in test verifying fake portals, links, and fields for all factions |
| tests/screenshots/iitc-loaded.png | Baseline screenshot for visual regression |
| scripts/fetch-tiles.js | One-time script to download and cache OSM tiles for the screenshot area |
Non-obvious detail: plugin injection
IITC replaces document.body during boot. Any <script src> tags placed after the IITC script in the HTML end up inserted into the now-detached old body node, which browsers refuse to execute. To work around this, the server reads every .js file from the plugins directory and embeds the code inline in a <script> block that runs before the IITC script. Each plugin pushes its setup() function onto window.bootPlugins, and IITC's boot() calls them once it is fully initialised.
Map tiles
Map tiles are served from server/fixtures/tiles/{z}/{x}/{y}.png. These are real OSM tiles pre-fetched for the default screenshot area (zoom 15, centre 51.5068/-0.1278). Any tile request outside the cached set receives a blank transparent PNG so tests never make real network requests.
To refresh the tile cache after changing the map centre or zoom level:
node scripts/fetch-tiles.jsQuick start (local plugin development)
1. Install
npm install --save-dev iitc-kuku-plugin-tester @playwright/test
npx playwright install chromium2. Download the IITC script
IITC_VERSION=0.42.2
mkdir -p iitc
curl -sSLo /tmp/iitc.zip \
"https://github.com/IITC-CE/ingress-intel-total-conversion/releases/download/${IITC_VERSION}/release-${IITC_VERSION}.zip"
unzip -p /tmp/iitc.zip total-conversion-build.user.js > iitc/total-conversion-build.jsOr let the CLI download it for you (see --iitc-version below).
3. Run against your plugin
# Headless
npx iitc-plugin-tester --plugin dist/my-plugin.js
# With a visible browser window
npx iitc-plugin-tester --plugin dist/my-plugin.js -- --headed
# Auto-download a specific IITC version
npx iitc-plugin-tester --plugin dist/my-plugin.js --iitc-version 0.42.2The command prints a Playwright summary. A Playwright HTML report is written to playwright-report/ and can be opened with:
npx playwright show-report4. Update the screenshot baseline
On the first run (or after an intentional visual change) the baseline screenshot does not exist yet and the visual test will fail. Regenerate it with:
npx iitc-plugin-tester --plugin dist/my-plugin.js -- --update-snapshotsCommit the resulting tests/screenshots/iitc-loaded.png alongside your plugin.
Usage as an installable package (recommended for CI)
1. Install
npm install --save-dev iitc-kuku-plugin-tester @playwright/test
npx playwright install chromium2. Provide the IITC built script
The IITC script is not bundled. See Downloading the IITC script below for how to get it in CI or locally.
3. Run
npx iitc-plugin-tester --plugin dist/my-plugin.jsThe CLI:
- Stages the plugin (and any declared dependencies) into a temporary directory in the correct load order
- Starts the mock Express server
- Runs Playwright against it
- Cleans up
CLI options
| Option | Description |
|---|---|
| --plugin <path> | Required. Path to the plugin file under test |
| --dep <path> | A dependency plugin to load before the plugin under test. Repeatable. |
| --iitc-version <ver> | Auto-download this IITC release and test against it. Repeatable. |
| --iitc-dir <path> | Use a pre-downloaded IITC directory. Repeatable. |
| --cache-dir <path> | Where to cache downloaded IITC scripts (default: ~/.cache/iitc-kuku-plugin-tester) |
| --port <number> | Server port (default: 3000) |
| -- | Everything after -- is forwarded to Playwright (e.g. -- --headed) |
When --iitc-version or --iitc-dir are given more than once, the full test suite is run once per version and the process exits non-zero if any version fails.
Examples:
# Basic -- uses ./iitc/total-conversion-build.js
npx iitc-plugin-tester --plugin dist/my-plugin.js
# Auto-download a specific version
npx iitc-plugin-tester --plugin dist/my-plugin.js --iitc-version 0.42.2
# Test against multiple versions (downloaded automatically and cached)
npx iitc-plugin-tester --plugin dist/my-plugin.js \
--iitc-version 0.42.2 \
--iitc-version 0.43.0
# Pre-downloaded directories
npx iitc-plugin-tester --plugin dist/my-plugin.js \
--iitc-dir vendor/iitc-0.42.2 \
--iitc-dir vendor/iitc-0.43.0
# With dependencies
npx iitc-plugin-tester --plugin dist/my-plugin.js \
--dep node_modules/iitc-plugin-lib/dist/lib.js
# Run headed for debugging
npx iitc-plugin-tester --plugin dist/my-plugin.js -- --headedConfig file
Instead of (or in addition to) CLI flags, create iitc-tester.config.json in your project root:
{
"plugin": "./dist/my-plugin.js",
"dependencies": [
"./node_modules/iitc-plugin-lib/dist/lib.js"
],
"iitcVersions": ["0.42.2", "0.43.0"]
}CLI flags take precedence over the config file.
All IITC version fields are mutually exclusive; precedence is iitcVersions > iitcDirs > iitcDir.
Declaring plugin dependencies
If your plugin requires other IITC plugins to be loaded first, list them under dependencies. They are staged and loaded in declaration order, before the plugin under test:
load order: dep[0] -> dep[1] -> ... -> your plugin -> test-plugin.js (boot signal)Downloading the IITC script
IITC releases are published on GitHub: IITC-CE/ingress-intel-total-conversion/releases. Each release ZIP contains total-conversion-build.user.js.
Auto-download (easiest)
Pass --iitc-version and the CLI downloads, extracts, and caches the release automatically:
npx iitc-plugin-tester --plugin dist/my-plugin.js --iitc-version 0.42.2Downloaded scripts are cached in ~/.cache/iitc-kuku-plugin-tester/<version>/ so subsequent runs are instant. Override with --cache-dir or IITC_CACHE_DIR.
The steps below are for cases where you prefer to manage the download yourself (e.g. to pre-warm a CI layer cache keyed to a Docker image).
Pin a specific version (recommended for reproducible builds)
IITC_VERSION=0.42.2
mkdir -p iitc
curl -sSL "https://github.com/IITC-CE/ingress-intel-total-conversion/releases/download/${IITC_VERSION}/release-${IITC_VERSION}.zip" \
| python3 -c "import sys,zipfile,io; z=zipfile.ZipFile(io.BytesIO(sys.stdin.buffer.read())); sys.stdout.buffer.write(z.read('total-conversion-build.user.js'))" \
> iitc/total-conversion-build.jsOr with unzip if you prefer to download first:
IITC_VERSION=0.42.2
curl -sSLo /tmp/iitc.zip \
"https://github.com/IITC-CE/ingress-intel-total-conversion/releases/download/${IITC_VERSION}/release-${IITC_VERSION}.zip"
mkdir -p iitc
unzip -p /tmp/iitc.zip total-conversion-build.user.js > iitc/total-conversion-build.jsAlways use the latest release
mkdir -p iitc
curl -sSL "https://github.com/IITC-CE/ingress-intel-total-conversion/releases/latest/download/total-conversion-build.user.js" \
> iitc/total-conversion-build.jsNote: Check the releases page to confirm the direct-download asset name, as it may vary between releases. If the asset is only available inside a ZIP, use the pinned-version approach above.
Using the gh CLI
IITC_VERSION=0.42.2
mkdir -p iitc
gh release download "${IITC_VERSION}" \
--repo IITC-CE/ingress-intel-total-conversion \
--pattern "release-${IITC_VERSION}.zip" \
--output /tmp/iitc.zip
unzip -p /tmp/iitc.zip total-conversion-build.user.js > iitc/total-conversion-build.jsCache it in CI
Downloading on every run is slow. Cache the result by IITC version:
- name: Cache IITC script
uses: actions/cache@v4
with:
path: iitc/
key: iitc-${{ env.IITC_VERSION }}Typical CI workflow (GitHub Actions)
Single version -- auto-download
The simplest setup. The CLI downloads and caches the IITC script automatically.
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Cache downloaded IITC scripts
uses: actions/cache@v4
with:
path: ~/.cache/iitc-kuku-plugin-tester
key: iitc-0.42.2
- name: Build plugin
run: npm run build
- name: Test plugin
run: npx iitc-plugin-tester --plugin dist/my-plugin.js --iitc-version 0.42.2Matrix -- multiple IITC versions
Run the full suite against every version in parallel. Each job tests one version; the matrix entry is used as both the version string and the cache key.
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
iitc-version: ["0.42.2", "0.43.0"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Cache downloaded IITC scripts
uses: actions/cache@v4
with:
path: ~/.cache/iitc-kuku-plugin-tester
key: iitc-${{ matrix.iitc-version }}
- name: Build plugin
run: npm run build
- name: Test plugin against IITC ${{ matrix.iitc-version }}
run: npx iitc-plugin-tester --plugin dist/my-plugin.js --iitc-version ${{ matrix.iitc-version }}Single version -- manual download (pre-warm image cache)
Use this if you want the IITC script baked into a Docker layer or cached separately from the plugin tester's own cache.
env:
IITC_VERSION: 0.42.2
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Cache IITC script
uses: actions/cache@v4
with:
path: iitc/
key: iitc-${{ env.IITC_VERSION }}
- name: Download IITC script
run: |
mkdir -p iitc
curl -sSLo /tmp/iitc.zip \
"https://github.com/IITC-CE/ingress-intel-total-conversion/releases/download/${{ env.IITC_VERSION }}/release-${{ env.IITC_VERSION }}.zip"
unzip -p /tmp/iitc.zip total-conversion-build.user.js > iitc/total-conversion-build.js
- name: Build plugin
run: npm run build
- name: Test plugin
run: npx iitc-plugin-tester --plugin dist/my-plugin.jsWriting your own tests
The built-in test verifies IITC boots with your plugin loaded. To add plugin-specific assertions, pass extra Playwright arguments pointing to your own test directory:
npx iitc-plugin-tester --plugin dist/my-plugin.js -- --test-dir tests/Your tests use the standard Playwright API. Wait for [data-iitc-fully-loaded="true"] before asserting anything -- it is the reliable signal that IITC and all plugins have finished booting:
import { test, expect } from '@playwright/test';
import { setupIITCRoutes, suppressIITCDialogs } from 'iitc-kuku-plugin-tester/tests/helpers/iitc-page';
test('my plugin renders a button', async ({ page }) => {
await page.addInitScript(suppressIITCDialogs);
await setupIITCRoutes(page);
await page.goto('/');
await page.waitForSelector('[data-iitc-fully-loaded="true"]', { timeout: 20000 });
await expect(page.locator('#my-plugin-button')).toBeVisible();
// Visual regression: compare against a stored baseline.
// First run (or --update-snapshots) creates the baseline; subsequent runs
// fail if the page differs beyond the allowed pixel tolerance.
await expect(page).toHaveScreenshot('my-plugin.png', {
mask: [page.locator('#chatinput time')], // mask the clock to avoid flakiness
maxDiffPixelRatio: 0.02,
});
});Visual regression baseline
The built-in test stores its baseline at tests/screenshots/iitc-loaded.png. Commit this file so CI can compare against it.
To create or refresh a baseline after an intentional UI change:
npx playwright test --update-snapshotsLocal development (working on this package)
Prerequisites: Node.js 18+
npm install
npx playwright install chromiumPlace the IITC built script at iitc/total-conversion-build.js.
npm test # headless
npm run test:headed # with a visible browser window
npm run server # start the mock server standalone on port 3000
npx tsc --noEmit # type-check
npx playwright test --update-snapshots # refresh the baseline screenshot
node scripts/fetch-tiles.js # re-download OSM tiles for the screenshot areaDrop additional plugin .js files into plugins/ and they are automatically embedded into the page at boot alongside the built-in tests/test-plugin.js.
Plugin file format
Plugins must be IIFEs that push a setup function onto window.bootPlugins. The userscript self-injection wrapper (document.createElement('script')) is not needed -- files already run in page context.
(function () {
if (typeof window.plugin !== 'function') window.plugin = function () {};
window.plugin.myPlugin = {};
function setup() {
// All IITC globals available: window.map, window.addHook, window.dialog, etc.
}
setup.info = { pluginId: 'my-plugin' };
if (!window.bootPlugins) window.bootPlugins = [];
window.bootPlugins.push(setup);
if (window.iitcLoaded && typeof setup === 'function') setup();
})();Customising mock data
| File | What to change |
|---|---|
| server/fixtures/player.json | Player nickname, team (RESISTANCE / ENLIGHTENED), level, AP |
| server/fixtures/entities.json | Portal/link/field data to populate the map |
| server/fixtures/gameScore.json | Enlightened / Resistance MindUnit scores |
| server/fixtures/tiles/ | Pre-fetched OSM tiles; run node scripts/fetch-tiles.js to repopulate |
| server/routes/api.ts | Add handlers for any other POST /r/* endpoints your plugin calls |
Mocking additional network requests
tests/helpers/iitc-page.ts contains the Playwright route interceptions. Add more page.route() calls there for external URLs your plugin fetches:
await page.route(/my-external-api\.com/, (route) =>
route.fulfill({ status: 200, contentType: 'application/json', body: '{"ok":true}' })
);Project structure
iitc-kuku-plugin-tester/
├── bin/
│ └── iitc-plugin-tester.js # CLI entry point
├── scripts/
│ └── fetch-tiles.js # Downloads OSM tiles for the screenshot area
├── src/
│ ├── config.ts # Config loading (file + CLI args)
│ ├── setup.ts # Plugin staging (temp dir)
│ ├── cli.ts # CLI logic
│ └── download.ts # IITC release downloader + cache
├── iitc/ # IITC built script (not included -- provide your own)
│ └── total-conversion-build.js
├── plugins/ # Drop .js files here for standalone dev use
├── server/
│ ├── index.ts # Express entry point
│ ├── start.js # Plain-JS launcher (used by playwright webServer)
│ ├── fixtures/
│ │ ├── player.json
│ │ ├── gameScore.json
│ │ ├── entities.json
│ │ └── tiles/ # Pre-fetched OSM tiles ({z}/{x}/{y}.png)
│ └── routes/
│ ├── intel-page.ts # Mock intel.ingress.com HTML
│ ├── api.ts # Mock POST /r/* endpoints
│ └── tiles.ts # Local tile server (fixtures or blank PNG)
├── tests/
│ ├── helpers/
│ │ └── iitc-page.ts # Shared route interceptors + dialog suppressor
│ ├── screenshots/
│ │ └── iitc-loaded.png # Baseline screenshot for visual regression
│ ├── test-plugin.js # Boot-signal plugin (always loaded last by the harness)
│ ├── iitc-loads.spec.ts # Built-in boot + visual regression test
│ └── entities.spec.ts # Verifies portals, links, and fields for all factions
├── iitc-tester.config.json # (create in your project, not here)
├── playwright.config.ts
└── tsconfig.json