技能 编程开发 PostHog本地开发与测试工作流

PostHog本地开发与测试工作流

v20260423
posthog-local-dev-loop
本指南提供了一个完整的PostHog本地开发工作流。它指导用户如何设置一个健壮的本地开发环境,包括启用开发模式进行实时事件调试、使用Mocking技术进行单元测试,以及配置集成测试。这有助于开发人员在不影响生产数据的情况下,安全、高效地测试和迭代分析追踪功能。
获取技能
243 次下载
概览

PostHog Local Dev Loop

Overview

Set up a fast local development workflow for PostHog integrations. Covers debug mode for event inspection, mocking posthog-node for unit tests, and a dev/test PostHog project to avoid polluting production data.

Prerequisites

  • Completed posthog-install-auth setup
  • Node.js 20+ with npm/pnpm
  • Vitest or Jest for testing
  • Separate PostHog project for development (recommended)

Instructions

Step 1: Project Structure

my-posthog-app/
├── src/
│   ├── analytics/
│   │   ├── posthog.ts         # Singleton client
│   │   ├── events.ts          # Event taxonomy (typed constants)
│   │   └── flags.ts           # Feature flag keys
│   └── index.ts
├── tests/
│   ├── analytics.test.ts      # Unit tests with mocked PostHog
│   └── integration.test.ts    # Integration tests (real PostHog dev project)
├── .env.local                 # Dev keys (git-ignored)
├── .env.example               # Template: NEXT_PUBLIC_POSTHOG_KEY=phc_...
└── package.json

Step 2: PostHog Client with Dev Mode

// src/analytics/posthog.ts
import { PostHog } from 'posthog-node';

let client: PostHog | null = null;

export function getPostHog(): PostHog {
  if (!client) {
    client = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
      host: process.env.POSTHOG_HOST || 'https://us.i.posthog.com',
      flushAt: process.env.NODE_ENV === 'development' ? 1 : 20,
      flushInterval: process.env.NODE_ENV === 'development' ? 0 : 10000,
      // In dev, flush immediately so events appear instantly in dashboard
    });
  }
  return client;
}

export async function shutdown() {
  if (client) {
    await client.shutdown();
    client = null;
  }
}

Step 3: Browser Debug Mode

// Enable PostHog debug mode in development
import posthog from 'posthog-js';

posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  api_host: 'https://us.i.posthog.com',
  loaded: (ph) => {
    if (process.env.NODE_ENV === 'development') {
      ph.debug();
      // All events logged to browser console:
      // [PostHog.js] Sending event: {"event":"$pageview","properties":{...}}
    }
  },
});

// Disable capture entirely in test environments
if (process.env.NODE_ENV === 'test') {
  posthog.opt_out_capturing();
}

Step 4: Mock PostHog for Unit Tests

// tests/analytics.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock posthog-node
vi.mock('posthog-node', () => {
  const mockCapture = vi.fn();
  const mockIdentify = vi.fn();
  const mockGetFeatureFlag = vi.fn().mockResolvedValue(true);
  const mockShutdown = vi.fn().mockResolvedValue(undefined);
  const mockFlush = vi.fn().mockResolvedValue(undefined);

  return {
    PostHog: vi.fn().mockImplementation(() => ({
      capture: mockCapture,
      identify: mockIdentify,
      getFeatureFlag: mockGetFeatureFlag,
      getAllFlags: vi.fn().mockResolvedValue({ 'new-feature': true }),
      shutdown: mockShutdown,
      flush: mockFlush,
    })),
  };
});

import { PostHog } from 'posthog-node';

describe('Analytics', () => {
  let ph: InstanceType<typeof PostHog>;

  beforeEach(() => {
    vi.clearAllMocks();
    ph = new PostHog('phc_test_key');
  });

  it('captures events with correct properties', () => {
    ph.capture({
      distinctId: 'user-1',
      event: 'button_clicked',
      properties: { button: 'signup' },
    });

    expect(ph.capture).toHaveBeenCalledWith({
      distinctId: 'user-1',
      event: 'button_clicked',
      properties: { button: 'signup' },
    });
  });

  it('evaluates feature flags', async () => {
    const result = await ph.getFeatureFlag('new-feature', 'user-1');
    expect(result).toBe(true);
  });
});

Step 5: Integration Test with Real Dev Project

// tests/integration.test.ts
import { describe, it, expect, afterAll } from 'vitest';
import { PostHog } from 'posthog-node';

const POSTHOG_KEY = process.env.POSTHOG_TEST_KEY;

describe.skipIf(!POSTHOG_KEY)('PostHog Integration', () => {
  const ph = new PostHog(POSTHOG_KEY!, {
    host: 'https://us.i.posthog.com',
    flushAt: 1,
    flushInterval: 0,
  });

  afterAll(async () => {
    await ph.shutdown();
  });

  it('should capture and flush an event', async () => {
    ph.capture({
      distinctId: `test-${Date.now()}`,
      event: 'integration_test',
      properties: { test: true },
    });
    // Flush returns successfully if network is reachable
    await expect(ph.flush()).resolves.not.toThrow();
  });

  it('should evaluate feature flags', async () => {
    const flags = await ph.getAllFlags(`test-${Date.now()}`);
    expect(typeof flags).toBe('object');
  });
});

Step 6: Package Scripts

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "test": "vitest run",
    "test:watch": "vitest --watch",
    "test:integration": "POSTHOG_TEST_KEY=$NEXT_PUBLIC_POSTHOG_KEY vitest run tests/integration"
  }
}

Error Handling

Error Cause Solution
Events not in dev dashboard Wrong project key Verify .env.local has dev project phc_ key
Mock not intercepting Wrong import path Ensure vi.mock path matches actual import
Integration test timeout PostHog unreachable Check network, increase vitest timeout
Debug mode too noisy ph.debug() in prod Guard with NODE_ENV === 'development'

Output

  • Development PostHog client with instant flush
  • Browser debug mode for event inspection
  • Mocked posthog-node for unit tests
  • Integration test suite for real PostHog connectivity

Resources

Next Steps

See posthog-sdk-patterns for production-ready code patterns.

信息
Category 编程开发
Name posthog-local-dev-loop
版本 v20260423
大小 6.47KB
更新时间 2026-04-28
语言