Agent Skills: Klaviyo CI Integration

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/klaviyo-ci-integration

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/klaviyo-pack/skills/klaviyo-ci-integration

Skill Files

Browse the full folder contents for klaviyo-ci-integration.

Download Skill

Loading file tree…

plugins/saas-packs/klaviyo-pack/skills/klaviyo-ci-integration/SKILL.md

Skill Metadata

Name
klaviyo-ci-integration
Description
|

Klaviyo CI Integration

Overview

Set up GitHub Actions CI/CD pipelines for Klaviyo integrations with unit tests, integration tests against the real API, and deployment automation.

Prerequisites

  • GitHub repository with Actions enabled
  • Klaviyo test API key (from a test/sandbox account)
  • klaviyo-api SDK and vitest configured

Instructions

Step 1: Configure GitHub Secrets

# Store Klaviyo test credentials as GitHub secrets
gh secret set KLAVIYO_PRIVATE_KEY --body "pk_test_***"
gh secret set KLAVIYO_WEBHOOK_SIGNING_SECRET --body "whsec_test_***"

Step 2: CI Workflow

Create .github/workflows/klaviyo-ci.yml:

name: Klaviyo Integration CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npx tsc --noEmit
      - run: npm test -- --coverage
      - name: Check Klaviyo SDK version
        run: npm list klaviyo-api

  integration-tests:
    runs-on: ubuntu-latest
    needs: unit-tests
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    env:
      KLAVIYO_PRIVATE_KEY: ${{ secrets.KLAVIYO_PRIVATE_KEY }}
      KLAVIYO_TEST: '1'
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - name: Run integration tests
        run: npm run test:integration
        timeout-minutes: 5
      - name: Verify Klaviyo connectivity
        run: |
          curl -s -w "HTTP %{http_code}\n" -o /dev/null \
            -H "Authorization: Klaviyo-API-Key $KLAVIYO_PRIVATE_KEY" \
            -H "revision: 2024-10-15" \
            "https://a.klaviyo.com/api/accounts/"

Step 3: Unit Test Examples

// tests/unit/klaviyo-events.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { ApiKeySession, EventsApi, ProfileEnum } from 'klaviyo-api';

vi.mock('klaviyo-api', () => ({
  ApiKeySession: vi.fn(),
  EventsApi: vi.fn().mockImplementation(() => ({
    createEvent: vi.fn().mockResolvedValue({ body: { data: { id: 'EVT_MOCK' } } }),
    getEvents: vi.fn().mockResolvedValue({
      body: { data: [], links: { next: null } },
    }),
  })),
  ProfileEnum: { Profile: 'profile' },
  EventEnum: { Event: 'event' },
}));

describe('Event Tracking', () => {
  let eventsApi: EventsApi;

  beforeEach(() => {
    eventsApi = new EventsApi(new ApiKeySession('pk_test'));
  });

  it('tracks a purchase event', async () => {
    const result = await eventsApi.createEvent({
      data: {
        type: 'event' as any,
        attributes: {
          metric: { data: { type: 'metric', attributes: { name: 'Placed Order' } } },
          profile: { data: { type: 'profile', attributes: { email: 'test@example.com' } } },
          properties: { orderId: 'ORD-TEST-001', value: 99.99 },
          time: new Date().toISOString(),
        },
      },
    });
    expect(result.body.data.id).toBe('EVT_MOCK');
  });
});

Step 4: Integration Test (Gated)

// tests/integration/klaviyo-live.test.ts
import { describe, it, expect } from 'vitest';
import { ApiKeySession, AccountsApi, ProfilesApi, ProfileEnum } from 'klaviyo-api';

const SKIP = !process.env.KLAVIYO_TEST || !process.env.KLAVIYO_PRIVATE_KEY;

describe.skipIf(SKIP)('Klaviyo Live API', () => {
  const session = new ApiKeySession(process.env.KLAVIYO_PRIVATE_KEY!);

  it('authenticates successfully', async () => {
    const accountsApi = new AccountsApi(session);
    const accounts = await accountsApi.getAccounts();
    expect(accounts.body.data).toHaveLength(1);
  });

  it('creates and cleans up a test profile', async () => {
    const profilesApi = new ProfilesApi(session);
    const testEmail = `ci-test-${Date.now()}@example.com`;

    const created = await profilesApi.createProfile({
      data: {
        type: ProfileEnum.Profile,
        attributes: {
          email: testEmail,
          firstName: 'CI',
          lastName: 'Test',
          properties: { source: 'github-actions', timestamp: new Date().toISOString() },
        },
      },
    });

    expect(created.body.data.id).toBeTruthy();
    expect(created.body.data.attributes.email).toBe(testEmail);
  });
});

Step 5: PR Checks Configuration

# .github/branch-protection.yml (or set via GitHub UI)
# Required checks: unit-tests
# Integration tests: optional (only on main push)

Output

  • Unit tests run on every PR (mocked, no API key needed)
  • Integration tests run on main branch pushes (real API)
  • SDK version verified in CI
  • API connectivity smoke test included

Error Handling

| Issue | Cause | Solution | |-------|-------|----------| | Secret not found in CI | Missing gh secret set | Add secret via repository settings | | Integration test 429 | Rate limited in CI | Add delays between tests, use dedicated test key | | Auth failures in CI | Wrong secret name | Verify secret name matches workflow env var | | Test timeout | Slow Klaviyo response | Increase timeout-minutes |

Resources

Next Steps

For deployment patterns, see klaviyo-deploy-integration.