Claude-code-plugins klaviyo-ci-integration
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/klaviyo-pack/skills/klaviyo-ci-integration" ~/.claude/skills/jeremylongshore-claude-code-plugins-klaviyo-ci-integration && rm -rf "$T"
manifest:
plugins/saas-packs/klaviyo-pack/skills/klaviyo-ci-integration/SKILL.mdsource content
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)
SDK and vitest configuredklaviyo-api
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 | 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 |
Resources
Next Steps
For deployment patterns, see
klaviyo-deploy-integration.