Skip to main content

Local Testing

This guide explains how to test uiMatch packages locally before publishing to npm. Two methods are available: Pack (recommended for pre-publish verification) and Link (for rapid development iteration).

The pack method simulates actual npm distribution and catches dependency issues that might not appear during development.

Why Pack?

  • Accurate simulation: Mimics real npm package installation
  • Dependency validation: Catches missing runtime dependencies
  • Module resolution testing: Verifies ESM/CJS compatibility
  • Pre-publish verification: Ensures packages work as distributed

Steps

1. Build All Packages

pnpm build

2. Create Tarballs

pnpm automatically resolves workspace:* dependencies to actual versions during pack:

mkdir -p dist-packages
pnpm -C packages/shared-logging pack --pack-destination ../../dist-packages
pnpm -C packages/uimatch-selector-spi pack --pack-destination ../../dist-packages
pnpm -C packages/uimatch-core pack --pack-destination ../../dist-packages
pnpm -C packages/uimatch-scoring pack --pack-destination ../../dist-packages
pnpm -C packages/uimatch-selector-anchors pack --pack-destination ../../dist-packages
pnpm -C packages/uimatch-cli pack --pack-destination ../../dist-packages

Result: Tarballs are created in dist-packages/:

  • uimatch-shared-logging-0.1.0.tgz
  • uimatch-selector-spi-0.1.0.tgz
  • uimatch-core-0.1.0.tgz
  • uimatch-scoring-0.1.0.tgz
  • uimatch-selector-anchors-0.1.0.tgz
  • uimatch-cli-0.1.0.tgz

3. Test in Isolated Environment

# Create clean test environment
mkdir -p /tmp/uimatch-test && cd /tmp/uimatch-test
npm init -y

# Install from tarballs
npm install \
/path/to/uimatch/dist-packages/uimatch-shared-logging-*.tgz \
/path/to/uimatch/dist-packages/uimatch-selector-spi-*.tgz \
/path/to/uimatch/dist-packages/uimatch-core-*.tgz \
/path/to/uimatch/dist-packages/uimatch-scoring-*.tgz \
/path/to/uimatch/dist-packages/uimatch-selector-anchors-*.tgz \
/path/to/uimatch/dist-packages/uimatch-cli-*.tgz \
playwright

# Install browser
npx playwright install chromium

4. Verify with Smoke Test

# Set bypass mode environment variable (10x10 red square PNG)
export UIMATCH_FIGMA_PNG_B64="iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mP8z8BQz0AEYBxVSF+FABJADveWkH6oAAAAAElFTkSuQmCC"

# Run smoke test
npx uimatch compare \
figma=bypass:test \
story="data:text/html,<div id='t' style='width:10px;height:10px;background:red'></div>" \
selector="#t" \
dpr=1 \
size=pad

Expected output:

✅ DFS: XX.XX

What to Verify

  • ✅ CLI executable runs without errors
  • ✅ All dependencies resolve correctly
  • ✅ ESM module imports work
  • ✅ Playwright integration functions
  • ✅ Comparison engine produces expected output
  • ✅ No runtime dependency errors

Common Issues Detected

IssueSymptomFix
Missing runtime dependencyCannot find module '@uimatch/core'Move dep from devDependencies to dependencies
ESM resolution failureERR_MODULE_NOT_FOUNDCheck package.json type: "module" and exports
CLI not executablecommand not found: uimatchVerify bin field in package.json
Peer dependency missingPlaywright errorsDocument peer deps in README

The link method is faster for development but doesn't catch distribution issues.

  • Rapid prototyping: Quick iteration during feature development
  • Local debugging: Testing changes without full build cycle
  • Cross-package development: Working on multiple packages simultaneously

⚠️ Limitations:

  • Doesn't catch dependency packaging issues
  • Links persist across restarts but break if paths move
  • Requires manual unlinking cleanup

Steps

1. Build Packages

pnpm build

2. Register Packages Globally

cd packages/shared-logging && pnpm link --global && cd ../..
cd packages/uimatch-selector-spi && pnpm link --global && cd ../..
cd packages/uimatch-core && pnpm link --global && cd ../..
cd packages/uimatch-scoring && pnpm link --global && cd ../..
cd packages/uimatch-selector-anchors && pnpm link --global && cd ../..
cd packages/uimatch-cli && pnpm link --global && cd ../..
cd /path/to/consumer
pnpm link --global @uimatch/shared-logging
pnpm link --global @uimatch/selector-spi
pnpm link --global @uimatch/core
pnpm link --global @uimatch/scoring
pnpm link --global @uimatch/selector-anchors
pnpm link --global @uimatch/cli

4. Test Changes

# Make changes in source packages
cd /path/to/uimatch/packages/uimatch-core
# ... edit files ...
pnpm build

# Changes immediately reflected in linked consumer project
cd /path/to/consumer
npx uimatch compare ...
# In consumer project
cd /path/to/consumer
pnpm unlink --global @uimatch/cli

# In source repository
cd /path/to/uimatch/packages/uimatch-cli
pnpm unlink --global

Repeat for all linked packages.

IssueSolution
Changes not reflectedRebuild package: pnpm build
Link broken after path changeRe-run pnpm link --global from new location
node_modules regeneration breaks linkRe-link in consumer project
Multiple Node versions conflictEnsure same Node version for link and consumer

Pre-Publish Checklist

Before publishing to npm, verify distribution integrity with the Pack method:

# Full verification workflow
pnpm build
# ... run full pack verification from Method 1

# Or quick smoke test
pnpm -C packages/uimatch-cli pack --pack-destination ../../
npm i -g ./uimatch-cli-*.tgz
npx uimatch compare figma=bypass:test story="..." selector="..."

Critical Checks

  • Runtime dependencies: All runtime deps in dependencies (not devDependencies)
  • Module resolution: ESM/CJS imports work with Node.js directly
  • CLI executable: Correct shebang #!/usr/bin/env node
  • No secrets: Run npm pack --dry-run to review package contents
  • Workspace resolution: Publish from root, not subdirectories
  • Peer dependencies: Playwright documented in README

Example Verification Script

#!/bin/bash
# verify-distribution.sh

set -e

echo "🔨 Building packages..."
pnpm build

echo "📦 Creating tarballs..."
mkdir -p dist-packages
for pkg in shared-logging uimatch-selector-spi uimatch-core uimatch-scoring uimatch-selector-anchors uimatch-cli; do
pnpm -C packages/$pkg pack --pack-destination ../../dist-packages
done

echo "🧪 Testing in isolated environment..."
TEST_DIR=$(mktemp -d)
cd "$TEST_DIR"
npm init -y

npm install \
/path/to/uimatch/dist-packages/uimatch-shared-logging-*.tgz \
/path/to/uimatch/dist-packages/uimatch-selector-spi-*.tgz \
/path/to/uimatch/dist-packages/uimatch-core-*.tgz \
/path/to/uimatch/dist-packages/uimatch-scoring-*.tgz \
/path/to/uimatch/dist-packages/uimatch-selector-anchors-*.tgz \
/path/to/uimatch/dist-packages/uimatch-cli-*.tgz \
playwright

npx playwright install chromium

export UIMATCH_FIGMA_PNG_B64="iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mP8z8BQz0AEYBxVSF+FABJADveWkH6oAAAAAElFTkSuQmCC"

npx uimatch compare \
figma=bypass:test \
story="data:text/html,<div id='t' style='width:10px;height:10px;background:red'></div>" \
selector="#t" \
dpr=1 \
size=pad

echo "✅ Distribution verification complete!"

When to Use Each Method

ScenarioMethodWhy
Pre-publish verificationPackCatches distribution issues
Final QA before releasePackSimulates real npm installation
Dependency troubleshootingPackVerifies runtime dependencies
Rapid feature developmentLinkFaster iteration cycle
Multi-package debuggingLinkImmediate change reflection
Cross-package refactoringLinkNo rebuild overhead

Recommendation: Use Link during development, switch to Pack before publishing or when encountering mysterious runtime issues.

See Also