Skip to content

Testing & Deployment

Comprehensive guide to testing strategies, deployment processes, and maintaining plugins across the Motanamy platform.

Testing Strategies

Testing Pyramid

Follow a balanced testing approach:

End-to-End Tests (10-20%)

Integration Tests (20-30%)

Unit Tests (40-60%)

Static Analysis (10-20%)

Unit Testing

Test individual functions and modules in isolation.

Setting Up Testing Framework

javascript
// test/setup.js
import { expect } from 'chai';
import sinon from 'sinon';
import { PluginTestHarness } from '@motanamy/testing';

global.expect = expect;
global.sinon = sinon;

// Test harness for plugin testing
global.harness = new PluginTestHarness();

Writing Unit Tests

javascript
// test/my-plugin.test.js
import MyPlugin from '../src/MyPlugin.js';

describe('MyPlugin', () => {
  let plugin;
  let mockAPI;

  beforeEach(() => {
    plugin = new MyPlugin();
    mockAPI = sinon.mock(plugin.api);
  });

  afterEach(() => {
    mockAPI.restore();
  });

  describe('onLoad()', () => {
    it('should register hooks successfully', async () => {
      const registerHookSpy = sinon.spy(plugin, 'registerHook');

      await plugin.onLoad();

      expect(registerHookSpy.calledWith('onUserLogin')).to.be.true;
      expect(registerHookSpy.calledWith('onDataUpdate')).to.be.true;
    });

    it('should initialize plugin state', async () => {
      await plugin.onLoad();

      expect(plugin.initialized).to.be.true;
      expect(plugin.version).to.equal('1.0.0');
    });
  });

  describe('handleUserLogin()', () => {
    it('should process user login event', () => {
      const user = { id: 1, name: 'Test User', role: 'admin' };
      const logSpy = sinon.spy(plugin.logger, 'info');

      plugin.handleUserLogin(user);

      expect(logSpy.calledWith('User logged in: Test User')).to.be.true;
    });

    it('should handle login errors gracefully', () => {
      const invalidUser = null;

      expect(() => plugin.handleUserLogin(invalidUser)).to.not.throw();
    });
  });
});

Running Unit Tests

bash
# Run all tests
npm test

# Run specific test file
npm test -- test/my-plugin.test.js

# Run with coverage
npm run test:coverage

# Watch mode for development
npm run test:watch

Integration Testing

Test how your plugin interacts with the Motanamy platform.

Platform Simulation

javascript
// test/integration/platform.test.js
import { PlatformSimulator } from '@motanamy/testing';
import MyPlugin from '../src/MyPlugin.js';

describe('Platform Integration', () => {
  let simulator;
  let plugin;

  beforeEach(async () => {
    simulator = new PlatformSimulator({
      platform: 'ea',
      version: '1.0.0'
    });

    plugin = new MyPlugin();
    await simulator.loadPlugin(plugin);
  });

  afterEach(async () => {
    await simulator.cleanup();
  });

  it('should handle user login workflow', async () => {
    const user = { id: 1, name: 'John Doe', email: 'john@example.com' };

    // Simulate user login
    await simulator.triggerEvent('onUserLogin', user);

    // Verify plugin response
    const notifications = simulator.getNotifications();
    expect(notifications).to.have.lengthOf(1);
    expect(notifications[0].message).to.include('Welcome John Doe');
  });

  it('should integrate with API', async () => {
    // Mock API response
    simulator.mockAPI('/users', { users: [{ id: 1, name: 'User' }] });

    // Trigger API call
    await simulator.triggerEvent('onDataSync');

    // Verify API was called
    const apiCalls = simulator.getAPICalls();
    expect(apiCalls).to.have.lengthOf(1);
    expect(apiCalls[0].endpoint).to.equal('/users');
  });
});

Cross-Platform Testing

javascript
// test/integration/cross-platform.test.js
import { CrossPlatformTester } from '@motanamy/testing';

describe('Cross-Platform Compatibility', () => {
  const platforms = ['ea', 'sa', 'os'];
  const versions = ['1.0.0', '1.1.0', '2.0.0'];

  platforms.forEach(platform => {
    versions.forEach(version => {
      describe(`${platform} ${version}`, () => {
        let tester;

        beforeEach(() => {
          tester = new CrossPlatformTester(platform, version);
        });

        it('should load plugin successfully', async () => {
          const result = await tester.loadPlugin('./dist/my-plugin.motapkg');
          expect(result.success).to.be.true;
        });

        it('should execute basic functionality', async () => {
          await tester.loadPlugin('./dist/my-plugin.motapkg');
          const result = await tester.executeTest('basic-functionality');
          expect(result.passed).to.be.true;
        });
      });
    });
  });
});

End-to-End Testing

Test complete user workflows from start to finish.

E2E Test Setup

javascript
// test/e2e/user-workflow.test.js
import { E2ETester, UserSimulator } from '@motanamy/testing';

describe('User Workflow E2E', () => {
  let tester;
  let user;

  beforeEach(async () => {
    tester = new E2ETester({
      platform: 'ea',
      headless: true
    });

    user = new UserSimulator({
      name: 'Test User',
      email: 'test@example.com'
    });

    await tester.start();
    await tester.loadPlugin('./dist/my-plugin.motapkg');
  });

  afterEach(async () => {
    await tester.stop();
  });

  it('should complete full user registration workflow', async () => {
    // Navigate to registration page
    await tester.navigate('/register');

    // Fill registration form
    await tester.fillForm({
      name: user.name,
      email: user.email,
      password: 'testpass123'
    });

    // Submit form
    await tester.click('register-button');

    // Verify success
    await tester.waitForText('Registration successful');

    // Check database
    const dbUser = await tester.queryDatabase('SELECT * FROM users WHERE email = ?', [user.email]);
    expect(dbUser).to.have.lengthOf(1);
  });

  it('should handle plugin-enhanced workflow', async () => {
    // Login user
    await user.login(tester);

    // Navigate to plugin feature
    await tester.click('plugin-menu-item');

    // Interact with plugin UI
    await tester.fillForm({ input: 'test data' });
    await tester.click('process-button');

    // Verify plugin functionality
    await tester.waitForText('Data processed successfully');

    // Check plugin logs
    const logs = await tester.getPluginLogs();
    expect(logs).to.include('Processing completed');
  });
});

Performance Testing

Ensure your plugin performs well under various conditions.

Load Testing

javascript
// test/performance/load.test.js
import { LoadTester } from '@motanamy/testing';

describe('Performance Testing', () => {
  let loadTester;

  beforeEach(() => {
    loadTester = new LoadTester({
      duration: '30s',
      concurrency: 10,
      rampUp: '10s'
    });
  });

  it('should handle concurrent user load', async () => {
    const results = await loadTester.runScenario({
      name: 'concurrent-users',
      setup: async () => {
        await loadTester.loadPlugin('./dist/my-plugin.motapkg');
      },
      scenario: async (user) => {
        // Simulate user actions
        await user.login();
        await user.performAction('heavy-computation');
        await user.logout();
      }
    });

    // Assert performance metrics
    expect(results.avgResponseTime).to.be.below(1000); // < 1 second
    expect(results.errorRate).to.be.below(0.05); // < 5% errors
    expect(results.throughput).to.be.above(50); // > 50 requests/second
  });

  it('should maintain performance under memory pressure', async () => {
    const results = await loadTester.runMemoryTest({
      duration: '5m',
      memoryLimit: '512MB',
      scenario: async () => {
        // Memory-intensive operations
        for (let i = 0; i < 1000; i++) {
          await loadTester.performMemoryOperation();
        }
      }
    });

    expect(results.memoryLeak).to.be.false;
    expect(results.gcPressure).to.be.below(0.8);
  });
});

Security Testing

Verify your plugin doesn't introduce security vulnerabilities.

Security Test Suite

javascript
// test/security/security.test.js
import { SecurityTester } from '@motanamy/testing';

describe('Security Testing', () => {
  let securityTester;

  beforeEach(async () => {
    securityTester = new SecurityTester();
    await securityTester.loadPlugin('./dist/my-plugin.motapkg');
  });

  it('should prevent SQL injection', async () => {
    const maliciousInput = "'; DROP TABLE users; --";

    const result = await securityTester.testSQLInjection({
      endpoint: '/api/search',
      payload: { query: maliciousInput }
    });

    expect(result.vulnerable).to.be.false;
  });

  it('should validate input properly', async () => {
    const testCases = [
      { input: '<script>alert("xss")</script>', shouldBlock: true },
      { input: 'normal text', shouldBlock: false },
      { input: '../../../etc/passwd', shouldBlock: true }
    ];

    for (const testCase of testCases) {
      const result = await securityTester.testInputValidation(testCase.input);
      expect(result.blocked).to.equal(testCase.shouldBlock);
    }
  });

  it('should handle authentication correctly', async () => {
    // Test unauthorized access
    const unauthorized = await securityTester.testUnauthorizedAccess('/admin');
    expect(unauthorized.blocked).to.be.true;

    // Test authorized access
    await securityTester.authenticate('admin');
    const authorized = await securityTester.testAuthorizedAccess('/admin');
    expect(authorized.allowed).to.be.true;
  });
});

Continuous Integration

CI/CD Pipeline Setup

GitHub Actions Example

yaml
# .github/workflows/ci.yml
name: CI/CD Pipeline

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

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x, 18.x, 20.x]

    steps:
    - uses: actions/checkout@v3

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run linting
      run: npm run lint

    - name: Run unit tests
      run: npm run test:unit

    - name: Run integration tests
      run: npm run test:integration

    - name: Run security scan
      run: npm run security-scan

    - name: Build plugin
      run: npm run build

    - name: Run E2E tests
      run: npm run test:e2e

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
    - name: Deploy to staging
      run: npm run deploy:staging

    - name: Run smoke tests
      run: npm run test:smoke

    - name: Deploy to production
      run: npm run deploy:production

Automated Testing Scripts

bash
# package.json
{
  "scripts": {
    "test": "npm run test:unit && npm run test:integration",
    "test:unit": "mocha test/unit/**/*.test.js",
    "test:integration": "mocha test/integration/**/*.test.js",
    "test:e2e": "cypress run",
    "test:security": "npm audit && motanamy security-scan",
    "test:performance": "artillery run test/performance/load.yml",
    "test:smoke": "mocha test/smoke/**/*.test.js",
    "lint": "eslint src/**/*.js",
    "build": "webpack --mode production",
    "deploy:staging": "motanamy deploy --env staging",
    "deploy:production": "motanamy deploy --env production"
  }
}

Deployment Strategies

Staging Environment

Test your plugin in a staging environment before production deployment.

bash
# Deploy to staging
motanamy deploy my-plugin.motapkg --env staging --version 1.0.0-beta.1

# Run staging tests
npm run test:staging

# Promote to production
motanamy promote my-plugin --from staging --to production

Blue-Green Deployment

Minimize downtime with blue-green deployment strategy.

bash
# Deploy to blue environment
motanamy deploy my-plugin.motapkg --env blue --version 1.1.0

# Test blue environment
npm run test:blue

# Switch traffic to blue
motanamy switch-traffic --to blue

# Keep green as rollback option
# If issues found, switch back
motanamy switch-traffic --to green

Canary Deployment

Gradually roll out new versions to subsets of users.

bash
# Deploy to 10% of users
motanamy canary-deploy my-plugin.motapkg --percentage 10

# Monitor metrics
motanamy monitor my-plugin --metrics error-rate,performance

# Gradually increase rollout
motanamy canary-deploy my-plugin.motapkg --percentage 25
motanamy canary-deploy my-plugin.motapkg --percentage 50
motanamy canary-deploy my-plugin.motapkg --percentage 100

Rollback Procedures

bash
# Quick rollback to previous version
motanamy rollback my-plugin --to-version 1.0.0

# Rollback with data migration
motanamy rollback my-plugin --to-version 1.0.0 --migrate-data

# Emergency rollback (immediate)
motanamy emergency-rollback my-plugin

Monitoring and Maintenance

Health Checks

Implement health checks for your plugin.

javascript
// health.js
export async function healthCheck() {
  const checks = {
    database: await checkDatabaseConnection(),
    api: await checkAPIConnectivity(),
    memory: await checkMemoryUsage(),
    disk: await checkDiskSpace()
  };

  const healthy = Object.values(checks).every(check => check.status === 'healthy');

  return {
    status: healthy ? 'healthy' : 'unhealthy',
    timestamp: new Date().toISOString(),
    checks
  };
}

async function checkDatabaseConnection() {
  try {
    await db.query('SELECT 1');
    return { status: 'healthy' };
  } catch (error) {
    return { status: 'unhealthy', error: error.message };
  }
}

Logging and Monitoring

javascript
// monitoring.js
import { Logger, Metrics } from '@motanamy/sdk';

export class PluginMonitor {
  constructor() {
    this.metrics = new Metrics('my-plugin');
    this.logger = new Logger('monitor');
  }

  async recordMetric(name, value, tags = {}) {
    await this.metrics.record(name, value, tags);
  }

  async logEvent(level, message, context = {}) {
    this.logger[level](message, context);
  }

  async monitorPerformance(operation, fn) {
    const startTime = Date.now();
    try {
      const result = await fn();
      const duration = Date.now() - startTime;

      await this.recordMetric('operation_duration', duration, {
        operation,
        status: 'success'
      });

      return result;
    } catch (error) {
      const duration = Date.now() - startTime;

      await this.recordMetric('operation_duration', duration, {
        operation,
        status: 'error'
      });

      await this.logEvent('error', `Operation ${operation} failed`, {
        error: error.message,
        duration
      });

      throw error;
    }
  }
}

Alerting

Set up alerts for critical issues.

javascript
// alerts.js
import { AlertManager } from '@motanamy/sdk';

export class PluginAlerts {
  constructor() {
    this.alertManager = new AlertManager();
  }

  async setupAlerts() {
    // Error rate alert
    await this.alertManager.createAlert({
      name: 'high-error-rate',
      condition: 'error_rate > 0.05',
      duration: '5m',
      severity: 'critical',
      channels: ['email', 'slack']
    });

    // Performance degradation alert
    await this.alertManager.createAlert({
      name: 'slow-response-time',
      condition: 'avg_response_time > 2000',
      duration: '10m',
      severity: 'warning',
      channels: ['email']
    });

    // Memory usage alert
    await this.alertManager.createAlert({
      name: 'high-memory-usage',
      condition: 'memory_usage > 80',
      duration: '5m',
      severity: 'warning',
      channels: ['email']
    });
  }

  async sendAlert(alertName, details) {
    await this.alertManager.trigger(alertName, details);
  }
}

Version Management

Semantic Versioning Strategy

javascript
// version.js
export class VersionManager {
  constructor(currentVersion) {
    this.current = this.parseVersion(currentVersion);
  }

  parseVersion(version) {
    const [major, minor, patch] = version.split('.').map(Number);
    return { major, minor, patch };
  }

  bump(type) {
    const newVersion = { ...this.current };

    switch (type) {
      case 'major':
        newVersion.major++;
        newVersion.minor = 0;
        newVersion.patch = 0;
        break;
      case 'minor':
        newVersion.minor++;
        newVersion.patch = 0;
        break;
      case 'patch':
        newVersion.patch++;
        break;
    }

    return `${newVersion.major}.${newVersion.minor}.${newVersion.patch}`;
  }

  isCompatible(version) {
    const other = this.parseVersion(version);
    return other.major === this.current.major;
  }
}

Update Mechanisms

javascript
// updates.js
export class UpdateManager {
  constructor() {
    this.checkInterval = 24 * 60 * 60 * 1000; // 24 hours
  }

  async checkForUpdates() {
    try {
      const latestVersion = await this.fetchLatestVersion();
      const currentVersion = await this.getCurrentVersion();

      if (this.isNewerVersion(latestVersion, currentVersion)) {
        await this.notifyUserOfUpdate(latestVersion);
      }
    } catch (error) {
      console.error('Failed to check for updates:', error);
    }
  }

  async applyUpdate(newVersion) {
    // Download update
    await this.downloadUpdate(newVersion);

    // Backup current version
    await this.createBackup();

    // Apply update
    await this.installUpdate(newVersion);

    // Verify installation
    await this.verifyUpdate(newVersion);

    // Restart if necessary
    await this.restartPlugin();
  }
}

Troubleshooting Deployment Issues

Common Deployment Problems

Plugin Won't Install

  • Check platform compatibility
  • Verify dependencies are available
  • Ensure sufficient permissions

Runtime Errors

  • Check error logs
  • Verify configuration
  • Test in isolation

Performance Issues

  • Profile resource usage
  • Check for memory leaks
  • Optimize database queries

Debugging Tools

bash
# Enable debug logging
motanamy debug my-plugin --level verbose

# Profile performance
motanamy profile my-plugin --duration 60s

# Inspect plugin state
motanamy inspect my-plugin

# Simulate platform events
motanamy simulate my-plugin --event onUserLogin --data '{"userId": 123}'

Best Practices

Testing Best Practices

  • Test Early and Often: Integrate testing into development workflow
  • Automate Everything: Use CI/CD for automated testing
  • Test Realistic Scenarios: Use production-like data and environments
  • Monitor Test Coverage: Aim for >80% code coverage
  • Test Failure Scenarios: Don't just test happy paths

Deployment Best Practices

  • Zero-Downtime Deployments: Use blue-green or canary strategies
  • Automated Rollbacks: Have rollback procedures ready
  • Gradual Rollouts: Start with small user groups
  • Monitoring: Monitor key metrics post-deployment
  • Documentation: Document deployment procedures

Maintenance Best Practices

  • Regular Updates: Keep dependencies and platform SDK updated
  • Security Patches: Address vulnerabilities promptly
  • Performance Monitoring: Monitor and optimize performance
  • User Feedback: Listen to user reports and feedback
  • Version Planning: Plan version releases and deprecation schedules

Resources


Thorough testing and reliable deployment are crucial for plugin success. Following these practices ensures your plugins are robust, secure, and provide excellent user experiences across the Motanamy platform.