@nicodoggie/node-kiwi-tcms-api
TypeScript icon, indicating that this package has built-in type declarations

1.1.1 • Public • Published

Node.js Kiwi TCMS API Wrapper

THIS WAS VIBE-CODED! I just needed something fast. USE AT YOUR OWN RISK!

A comprehensive Node.js/TypeScript wrapper for the Kiwi TCMS XML-RPC API. This library provides a modern, type-safe interface for interacting with Kiwi TCMS test management system.

⚠️ Version Compatibility

Important: This library supports different Kiwi TCMS versions, but older installations have significantly fewer API methods available. The API has evolved considerably over time.

Version-Specific Support

Kiwi TCMS 8.x (Legacy - circa 2020):

  • Basic CRUD: TestCase, TestExecution, TestRun create/filter/update
  • Comments: addComment, removeComment for TestCase and TestExecution
  • Tags: addTag, removeTag for TestCase and TestRun
  • Components: addComponent, removeComponent for TestCase
  • Attachments: addAttachment, listAttachments for TestCase
  • Links: addLink, getLinks, removeLink for TestExecution
  • Test Run Management: addCase, removeCase, getCases
  • Missing: properties, history, comments (read), notification CC, many other methods

Kiwi TCMS 10.x+ (Modern):

  • ✅ All legacy methods plus additional methods like properties, history, etc.

Kiwi TCMS 14.x+ (Latest):

  • ✅ Full API coverage with all documented methods

How to Check Your Version

// Check available methods on your system
const methods = await kiwi.getClient().call('system.listMethods');
console.log('Available methods:', methods);

// The length can give you a rough idea:
// ~50-60 methods = Kiwi TCMS 8.x
// ~70-80 methods = Kiwi TCMS 10.x  
// ~90+ methods = Kiwi TCMS 12.x+

If you're on Kiwi TCMS 8.7 or older, stick to the basic methods listed above. This library will gracefully handle missing methods, but you should test your specific use case first.

Features

  • 🚀 Full API Coverage: Complete implementation of all Kiwi TCMS RPC methods
  • 🔒 Type Safety: Comprehensive TypeScript types for all API entities
  • 🔄 Auto-Authentication: Automatic session management and re-authentication
  • 🎯 Modern Async/Await: Promise-based API with async/await support
  • 📚 Well Documented: Extensive JSDoc comments and usage examples
  • 🛡️ Error Handling: Robust error handling with descriptive messages
  • 🔧 Configurable: Flexible configuration options for different environments

Installation

npm install node-kiwi-tcms-api
# or
yarn add node-kiwi-tcms-api

Quick Start

import { KiwiTCMS } from 'node-kiwi-tcms-api';

// Initialize the client
const kiwi = new KiwiTCMS({
  baseUrl: 'https://your-kiwi-instance.com',
  username: 'your-username',
  password: 'your-password'
});

// Authenticate (optional - done automatically on first API call)
await kiwi.login();

// Get all test cases
const testCases = await kiwi.testCase.filter();

// Create a new test plan
const testPlan = await kiwi.testPlan.create({
  name: 'My Test Plan',
  text: 'Description of the test plan',
  product_version_id: 1,
  author_id: 1,
  type_id: 1
});

// Add test cases to the plan
await kiwi.testPlan.addCase(testPlan.id, testCases[0].id);

// Create a test run
const testRun = await kiwi.testRun.create({
  summary: 'My Test Run',
  plan_id: testPlan.id,
  build_id: 1,
  manager_id: 1,
  default_tester_id: 1
});

console.log('Test run created:', testRun);

Configuration

interface KiwiConfig {
  baseUrl: string;                    // Kiwi TCMS instance URL
  username?: string;                  // Username for authentication
  password?: string;                  // Password for authentication
  token?: string;                     // API token (alternative to username/password)
  timeout?: number;                   // Request timeout in milliseconds (default: 30000)
  headers?: { [key: string]: string }; // Custom HTTP headers
  cloudflareClientId?: string;        // Cloudflare Access Client ID
  cloudflareClientSecret?: string;    // Cloudflare Access Client Secret
}

Cloudflare Access Support

If your Kiwi TCMS instance is protected by Cloudflare Access, you can use service tokens to bypass the authentication. You'll need both the Client ID and Client Secret from your Cloudflare Access service token:

const kiwi = new KiwiTCMS({
  baseUrl: 'https://kiwi.protected-by-cloudflare.com',
  username: 'your-username',
  password: 'your-password',
  cloudflareClientId: 'your-client-id.access',
  cloudflareClientSecret: 'your-client-secret'
});

Custom Headers

You can add custom HTTP headers to all requests:

const kiwi = new KiwiTCMS({
  baseUrl: 'https://your-kiwi-instance.com',
  username: 'your-username',
  password: 'your-password',
  headers: {
    'X-Custom-Header': 'custom-value',
    'Authorization': 'Bearer your-api-token'
  }
});

// Or set headers after creation (requires new client instance)
kiwi.getClient().setHeader('X-New-Header', 'new-value');

Advanced Authentication

For advanced authentication scenarios, you can use custom headers:

// Service token authentication
const kiwi = new KiwiTCMS({
  baseUrl: 'https://your-kiwi-instance.com',
  headers: {
    'Authorization': 'Token your-service-token',
    'X-API-Key': 'your-api-key'
  }
});

// Skip username/password login if using service tokens
kiwi.getClient().setSessionId('your-service-token');

// Cloudflare Access with service token and API authentication
const kiwiWithBoth = new KiwiTCMS({
  baseUrl: 'https://protected-kiwi.example.com',
  cloudflareClientId: 'your-cf-client-id.access',
  cloudflareClientSecret: 'your-cf-client-secret',
  headers: {
    'Authorization': 'Token your-kiwi-api-token'
  }
});

API Reference

Core Test Management

Test Cases

// Create test case  
const testCase = await kiwi.testCase.create({
  summary: 'Test user login functionality',
  category_id: 1,
  priority_id: 1,
  case_status_id: 2,
  author_id: 1,
  default_tester_id: 1
});

// Filter and search  
const cases = await kiwi.testCase.filter({
  category_id: 1,
  is_automated: false
});

// Update test case
await kiwi.testCase.update(testCase.id, {
  summary: 'Updated test case summary',
  notes: 'Additional notes'
});

// Manage comments
await kiwi.testCase.addComment(testCase.id, 'This test needs review');
await kiwi.testCase.removeComment(testCase.id, commentId);

// Manage tags
await kiwi.testCase.addTag(testCase.id, 'regression');
await kiwi.testCase.removeTag(testCase.id, 'obsolete');

// Manage components
await kiwi.testCase.addComponent(testCase.id, componentId);
await kiwi.testCase.removeComponent(testCase.id, componentId);

// File attachments
await kiwi.testCase.addAttachment(testCase.id, 'screenshot.png', base64Content);
const attachments = await kiwi.testCase.listAttachments(testCase.id);
// Or use alias
const attachments2 = await kiwi.testCase.getAttachments(testCase.id);

Test Plans

// Create test plan
const plan = await kiwi.testPlan.create({
  name: 'Release Test Plan',
  text: 'Test plan for version 1.0',
  product_version_id: 1,
  author_id: 1,
  type_id: 1
});

// Add/remove test cases
await kiwi.testPlan.addCase(plan.id, testCase.id);
await kiwi.testPlan.removeCase(plan.id, testCase.id);

// Manage tags and attachments
await kiwi.testPlan.addTag(plan.id, 'release-1.0');
await kiwi.testPlan.addAttachment(plan.id, 'spec.pdf', base64Content);

Test Runs

// Create test run
const run = await kiwi.testRun.create({
  summary: 'Smoke Test Run',
  plan_id: plan.id,
  build_id: 1,
  manager_id: 1,
  default_tester_id: 1
});

// Add test cases and manage execution
await kiwi.testRun.addCase(run.id, testCase.id);
const executions = await kiwi.testRun.getCases(run.id);

Test Executions

// Filter test executions
const executions = await kiwi.testExecution.filter({
  case_id: testCase.id,
  status_id: 1
});

// Update test execution status
await kiwi.testExecution.update(execution.id, {
  status_id: 2, // Pass
  tested_by_id: 1,
  stop_date: new Date().toISOString()
});

// Manage comments
await kiwi.testExecution.addComment(execution.id, 'Test passed successfully');
await kiwi.testExecution.removeComment(execution.id, commentId);

// Manage links and references
await kiwi.testExecution.addLink(execution.id, {
  url: 'https://bug-tracker.com/bug/123',
  name: 'Related Bug',
  is_defect: true
});

const links = await kiwi.testExecution.getLinks({ execution_id: execution.id });
await kiwi.testExecution.removeLink(execution.id, linkId);

Management Entities

// Products and builds
const products = await kiwi.product.filter();
const builds = await kiwi.build.filter({ version_id: 1 });

// Components and categories
const components = await kiwi.component.filter({ product_id: 1 });
const categories = await kiwi.category.filter({ product_id: 1 });

// Users and environments
const users = await kiwi.user.filter({ is_active: true });
const environments = await kiwi.environment.filter();

// Priorities and statuses
const priorities = await kiwi.priority.filter();
const statuses = await kiwi.testCaseStatus.filter();

Advanced Features

URL Generation and Permalinks

Generate URLs and slugs for Kiwi TCMS entities:

// Generate permalinks for entities
const testCaseUrl = kiwi.url.generateTestCaseUrl(123);
const testPlanUrl = kiwi.url.generateTestPlanUrl(456);
const testRunUrl = kiwi.url.generateTestRunUrl(789);
const bugUrl = kiwi.url.generateBugUrl(42);

// Create URL-friendly slugs
const slug = kiwi.url.createSlug('Test Login with Special Characters!');
// Result: "test-login-with-special-characters"

// Generate short links with slugs
const shortLink = kiwi.url.generateShortLink('case', 123, slug);
// Result: "https://kiwi.example.com/case/123-test-login-with-special-characters"

// Parse existing Kiwi TCMS URLs
const parsed = kiwi.url.parseKiwiUrl('https://kiwi.example.com/case/123/');
// Result: { type: 'case', id: 123 }

Real-world usage example:

// Create a test case and generate shareable URLs
const testCase = await kiwi.testCase.create({
  summary: 'Test user authentication flow',
  // ... other properties
});

// Generate URLs for sharing
const slug = kiwi.url.createSlug(testCase.summary);
const permalink = kiwi.url.generateTestCaseUrl(testCase.id);
const shortLink = kiwi.url.generateShortLink('case', testCase.id, slug);

console.log('Share this test case:', shortLink);
// Share this test case: https://kiwi.example.com/case/456-test-user-authentication-flow

Automatic Permalink Injection

For convenience, you can automatically inject permalinks into objects returned by filter methods using a separate options parameter:

// Basic filter - returns TestCase[]
const basicCases = await kiwi.testCase.filter({ 
  is_automated: true 
});

// Enhanced filter with options - returns TestCaseWithPermalinks[]
const enhancedCases = await kiwi.testCase.filter({ 
  is_automated: true 
}, { 
  includePermalinks: true 
});

// Now each test case includes permalink properties
enhancedCases.forEach(testCase => {
  console.log('Test case:', testCase.summary);
  console.log('Permalink:', testCase.permalink);
  console.log('Short link:', testCase.shortLink);
  console.log('Slug:', testCase.slug);
});

// Works with all filter methods
const testPlans = await kiwi.testPlan.filter({}, { 
  includePermalinks: true 
});

const testRuns = await kiwi.testRun.filter({}, { 
  includePermalinks: true 
});

Real-world example - Generate a test report with shareable links:

// Get failed test cases with permalinks
const failedCases = await kiwi.testCase.filter({
  case_status_id: 3 // Failed status
}, {
  includePermalinks: true
});

// Create a report with shareable links
const report = failedCases.map(testCase => ({
  name: testCase.summary,
  shareableLink: testCase.shortLink,
  detailsUrl: testCase.permalink,
  slug: testCase.slug
}));

// Send report via email, Slack, etc.
console.log('Failed test cases report:', report);

Field Lookups (Django-style)

// Use Django field lookups for complex filtering
const recentCases = await kiwi.testCase.filter({
  'create_date__gte': '2023-01-01',
  'summary__icontains': 'api',
  'author__username__startswith': 'john'
});

Error Handling

try {
  const testCase = await kiwi.testCase.create({
    summary: 'Test case'
    // Missing required fields
  });
} catch (error) {
  console.error('API Error:', error.message);
}

Session Management

// Manual session management
const sessionId = await kiwi.login();
console.log('Session ID:', sessionId);

// Check authentication status
if (kiwi.isAuthenticated()) {
  console.log('Client is authenticated');
}

// Logout
await kiwi.logout();

TypeScript Support

This library is written in TypeScript and provides comprehensive type definitions:

import { 
  KiwiTCMS, 
  TestCase, 
  TestPlan, 
  TestRun,
  TestCaseFilter,
  KiwiConfig 
} from 'node-kiwi-tcms';

// Full type safety
const config: KiwiConfig = {
  baseUrl: 'https://kiwi.example.com',
  username: 'user',
  password: 'pass'
};

const kiwi = new KiwiTCMS(config);

// Typed responses
const testCases: TestCase[] = await kiwi.testCase.filter();
const testPlan: TestPlan = await kiwi.testPlan.create({
  name: 'Typed Test Plan',
  product_version_id: 1,
  author_id: 1,
  type_id: 1
});

Requirements

  • Node.js 18+
  • Kiwi TCMS instance with XML-RPC API enabled

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT

Links

Package Sidebar

Install

npm i @nicodoggie/node-kiwi-tcms-api

Weekly Downloads

7

Version

1.1.1

License

MIT

Unpacked Size

135 kB

Total Files

38

Last publish

Collaborators

  • nicodoggie