Skip to content

Latest commit

 

History

History
375 lines (264 loc) · 12 KB

File metadata and controls

375 lines (264 loc) · 12 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Component-Specific Documentation

Each component has its own CLAUDE.md with detailed guidance. These are automatically loaded when working in that directory.

Core: client, hosted-fields, three-d-secure, data-collector, lib/frame-service

Digital Wallets: apple-pay, google-payment

Alternative Payment Methods: paypal-checkout, paypal-checkout-v6, venmo, us-bank-account, sepa, local-payment

Card Networks: american-express, unionpay

Services: instant-verification, payment-ready, payment-request, vault-manager, fastlane

Deprecated (Do Not Use): paypal (use paypal-checkout), masterpass, visa-checkout, preferred-payment-methods

Development Tools

Storybook: See /.storybook/CLAUDE.md for interactive component development, visual testing, integration testing, SDK version management, and writing stories.

Commands

Development

  • npm run build - Build all components
  • npm run build <component> - Build a single component (e.g., npm run build client)

Local Build Testing

  • npm run build:integration - Build SDK, copy to Storybook static dir, build Storybook, and start HTTPS server at https://127.0.0.1:8080
  • npm run storybook:dev-local - Start Storybook with your local builds (copies build files automatically)
  • npm run storybook:copy-local-build - Copy local builds to Storybook static directory

Testing

  • npm test - Run all tests
  • npm test <component> - Run tests for a single component (e.g., npm test client)
  • npm test lib - Run tests for the lib directory
  • jest <path-to-file> - Run a single test file (requires jest installed globally)

Linting and Formatting

  • npm run lint - Lint all code
  • npm run lint <component> - Lint a single component
  • npm run prettier - Format all code with Prettier

Documentation and Development Tools

  • npm run jsdoc - Generate JSDoc documentation
  • npm run storybook:dev - Start Storybook development server on port 6006
  • npm run storybook:build - Build Storybook static files
  • npm run test:integration - Run BrowserStack integration tests with CDN versions
  • npm run test:integration:local - Run tests with your local build (LOCAL_BUILD=true)
  • npm run test:integration -- --spec .storybook/tests/your-test.test.ts - Run single test file

Architecture

Project Structure

  • src/ - Source code organized by payment method components
  • src/lib/ - Shared utilities and core functionality
  • src/index.js - Main entry point that exports all payment method modules
  • tasks/ - Gulp build tasks, one per component
  • test/ - Test files mirroring the src/ structure
  • components.json - List of all payment method components

Build System

  • Uses Gulp with component-specific tasks in tasks/ directory
  • Each component defined in components.json gets its own build task
  • Browserify for bundling with environment variable transforms
  • Outputs to dist/ with separate npm and hosted (CDN) builds

Testing

  • Jest for unit testing with component-specific configurations
  • Tests mirror src/ structure in test/ directory
  • Integration tests using WebDriver with Browserstack
  • Storybook for component development and testing

Component Implementation Patterns

Standard Component Creation

All components follow this lifecycle pattern:

  1. Basic Verification - Using basicComponentVerification.verify()
  2. Client Creation - Either use provided client or create deferred client
  3. Configuration Check - Verify component is enabled in gateway config
  4. Component Initialization - Create and return component instance

Component Structure

// src/<component>/index.js
function create(options) {
  return basicComponentVerification
    .verify({
      name: "ComponentName",
      client: options.client,
      authorization: options.authorization,
    })
    .then(function () {
      return createDeferredClient.create({
        authorization: options.authorization,
        client: options.client,
        assetsUrl: createAssetsUrl.create(options.authorization),
        name: "ComponentName",
      });
    })
    .then(function (client) {
      // Check gateway configuration
      // Initialize component
      // Return component instance
    });
}

Error Handling

Use BraintreeError for all error conditions:

var BraintreeError = require("../lib/braintree-error");

// Create error with proper type classification
new BraintreeError({
  type: BraintreeError.types.MERCHANT, // CUSTOMER, MERCHANT, NETWORK, INTERNAL, UNKNOWN
  code: "COMPONENT_SPECIFIC_ERROR_CODE",
  message: "User-friendly error message",
  details: { originalError: err }, // Optional additional info
});

Build Process Details

Browserify Pipeline

  1. Environment Transform - envify replaces process.env variables
  2. Code Removal - removeIf(production) blocks stripped in production
  3. Derequire - Prevents global require conflicts
  4. Minification - UglifyJS for production builds

Build Outputs

  • dist/npm/ - CommonJS modules for npm package
  • dist/hosted/ - CDN-ready files with versioned paths

Component Build Tasks

Each component in components.json gets:

  • build:<component> - Build single component
  • lint:<component> - Lint single component
  • Individual gulp task in tasks/<component>.js

Testing Patterns

Test Structure

  • Tests mirror src/ structure in test/ directory
  • Each component has its own Jest configuration
  • Global test timeout: 4 seconds

Test Helpers

  • test/helpers/promise-helper.js - Promise testing utilities
  • test/helpers/components.js - Component-specific helpers
  • rejectIfResolves() - Helper for testing promise rejections
  • wait(time) - Helper for async testing delays

Running Tests

# All tests for a component
npm test client

# Single test file
jest test/client/unit/client.js

# With coverage
BRAINTREE_JS_ENV=development jest --coverage

Debugging and Troubleshooting

Environment Setup

Create .env file with development settings:

BRAINTREE_JS_API_HOST=development.gateway.hostname
BRAINTREE_JS_API_PORT=443
BRAINTREE_JS_API_PROTOCOL=https
STORYBOOK_BRAINTREE_TOKENIZATION_KEY=your_sandbox_key

Analytics and Logging

Components send analytics events for debugging:

var analytics = require("../lib/analytics");

// Send event for debugging
analytics.sendEvent(client, "component.action.started");

Common Error Codes

  • CLIENT_AUTHORIZATION_INVALID - Invalid/expired authorization
  • INCOMPATIBLE_VERSIONS - Version mismatch between components
  • COMPONENT_NOT_ENABLED - Component disabled in gateway config
  • CLIENT_SCRIPT_FAILED_TO_LOAD - Network/CDN loading issues

Frame Communication Issues

For components using Frame Service (PayPal, Venmo, SEPA, Local Payment), see /src/lib/frame-service/CLAUDE.md for detailed debugging guidance.

For Hosted Fields iframe issues, see /src/hosted-fields/CLAUDE.md.

General debugging:

  1. Check browser console for framebus errors
  2. Verify iframe URLs are loading correctly
  3. Ensure proper domain configuration for cross-origin
  4. Test with BRAINTREE_JS_ENV=development for detailed logging

Integration Testing with BrowserStack

Test Structure

Integration tests use WebDriverIO with BrowserStack across multiple browsers:

  • Chrome (Windows 10)
  • Safari (macOS Monterey)
  • Firefox (macOS Monterey)
  • Edge (Windows 10)

Custom Browser Commands

Commands are registered via loadHelpers() in .storybook/tests/helpers/browser-commands/index.ts:

Common Commands:

  • browser.getResult() - Extract success/failure from result div

Hosted Fields Commands:

  • browser.waitForHostedFieldsReady() - Wait for SDK and all hosted field iframes
  • browser.hostedFieldSendInput(key, value) - Type into hosted field iframe
  • browser.submitPay() - Submit form and wait for result

PayPal Commands:

  • completePayPalCheckoutFlow() - Full PayPal login and approval flow
  • switchToPayPalPopup() - Switch to PayPal popup window

Network Interception:

  • Uses wdio-intercept-service for network request verification
  • browser.setupInterceptor() - Setup network interception
  • browser.getRequests() - Get intercepted HTTP requests

Writing Integration Tests

import { browser } from "@wdio/globals";
import { expect } from "chai";
import { getWorkflowUrl } from "./helpers/url-utils";
import { loadHelpers } from "./helpers/browser-commands";

describe("Component Integration", () => {
  before(() => loadHelpers());

  it("should complete flow", async () => {
    const url = getWorkflowUrl("/iframe.html?id=story-id");
    await browser.url(url);
    await browser.setupInterceptor();

    // Test implementation
    const requests = await browser.getRequests();
    expect(requests).to.have.length.greaterThan(0);
  });
});

Running Integration Tests

# All tests
npm run test:integration

# With local build
npm run test:integration:local

# Single test file
npm run test:integration -- --spec .storybook/tests/your-test.test.ts

Important Notes

Environment Variables

Required in .env file:

# Local development(not committed to git)
BRAINTREE_JS_API_HOST=development.gateway.hostname
BRAINTREE_JS_API_PORT=443
BRAINTREE_JS_API_PROTOCOL=https
STORYBOOK_BRAINTREE_TOKENIZATION_KEY=sandbox_xxxxx_yyyyyy

# For integration tests only
BROWSERSTACK_USERNAME=your_username
BROWSERSTACK_ACCESS_KEY=your_access_key
PAYPAL_SANDBOX_BUYER_EMAIL=buyer@example.com
PAYPAL_SANDBOX_OTP_CODE=111111

Code Style

  • 2-space indentation, semicolons at end of statements, single quotes for strings
  • ES5 syntax (for browser compatibility) - use function not arrow functions, var not const/let
  • ES5 Promises for functional code; async/await allowed only in tests
  • Use === and !== for equality checks (never ==/!=)
  • Trailing commas in multi-line objects and arrays
  • JSDoc comments for public APIs
  • Prettier for consistent formatting; ESLint with Braintree configuration
  • Never use emojis in code or comments

Naming Conventions

  • camelCase for variables and functions
  • PascalCase for classes
  • UPPER_SNAKE_CASE for constants
  • Boolean variables: prefix with is, has, can, or should
  • Event handlers: prefix with on (e.g., onClick)
  • CRUD functions: prefix with create, update, delete, or fetch
  • Initialization functions: use init or initialize

Dependencies

  • Core dependencies are minimal browser-compatible libraries
  • Custom Braintree packages prefixed with @braintree/
  • Uses framebus for iframe communication (see Frame Service and Hosted Fields docs)
  • Cardinal Commerce Songbird.js for 3D Secure (loaded dynamically)
  • SJCL crypto library (custom build) for data-collector component

Branch Naming Convention

Branch names are validated by pre-push hooks and CI. Valid formats:

  • Standard: lowercase-kebab-case (e.g., fix-payment-bug)
  • Jira: TICKET-123-lowercase-kebab-case (e.g., DTBTWEB-123-fix-bug)
  • Versioned: feature-name.1 or TICKET-123-feature.1

Jira prefix must be uppercase (DTBTWEB-123, not dtbtweb-123). Validate manually with: node scripts/validate-branch-name.js "your-branch-name"

Development Workflow

  1. Run npm test after making changes (includes linting)
  2. Use npm run build <component> to build specific components during development
  3. Test integration scenarios in Storybook
  4. Follow existing patterns when adding new components or features
  5. Use scripts/npm-to-gulp wrapper for component-specific commands
  6. Check version compatibility with basicComponentVerification
  7. Verify environment variables are set correctly for local development
  8. For components requiring secure UI (popups/modals), use Frame Service (see /src/lib/frame-service/CLAUDE.md)
  9. For components requiring card input, use Hosted Fields (see /src/hosted-fields/CLAUDE.md)
  10. For transactions requiring 3DS authentication, integrate with 3D Secure component (see /src/three-d-secure/CLAUDE.md)