PageSourceSearch

https://q01-platform.github.io/assets/js/6fda5beb.bda2a6d7.js

js q01-platform.github.io collected 2026-10-03 09:49:59 UTC 28,578 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkq_01_docs=self.webpackChunkq_01_docs||[]).push([[8184],{6220:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>r,metadata:()=>o,toc:()=>l});var s=n(7624),i=n(2172);const r={title:"Testing Strategies",sidebar_label:"Testing Strategies",sidebar_position:6,description:"Comprehensive testing approaches for Core API integrations"},a="Testing Strategies",o={id:"products/map.q01.io/core-api-platform-v4/best-practices/testing-strategies",title:"Testing Strategies",description:"Comprehensive testing approaches for Core API integrations",source:"@site/docs/products/map.q01.io/core-api-platform-v4/07-best-practices/testing-strategies.md",sourceDirName:"products/map.q01.io/core-api-platform-v4/07-best-practices",slug:"/products/map.q01.io/core-api-platform-v4/best-practices/testing-strategies",permalink:"/docs/products/map.q01.io/core-api-platform-v4/best-practices/testing-strategies",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{title:"Testing Strategies",sidebar_label:"Testing Strategies",sidebar_position:6,description:"Comprehensive testing approaches for Core API integrations"},sidebar:"mapSidebar",previous:{title:"Security Tips",permalink:"/docs/products/map.q01.io/core-api-platform-v4/best-practices/security-tips"},next:{title:"Migration Guide",permalink:"/docs/products/map.q01.io/core-api-platform-v4/best-practices/migration-guide"}},c={},l=[{value:"Overview",id:"overview",level:2},{value:"Unit Testing",id:"unit-testing",level:2},{value:"Testing API Client Methods",id:"testing-api-client-methods",level:3},{value:"Testing Business Logic",id:"testing-business-logic",level:3},{value:"Integration Testing",id:"integration-testing",level:2},{value:"Testing Against Real API",id:"testing-against-real-api",level:3},{value:"Contract Testing",id:"contract-testing",level:2},{value:"API Contract Verification",id:"api-contract-verification",level:3},{value:"Test Data Management",id:"test-data-management",level:2},{value:"Test Data Setup",id:"test-data-setup",level:3},{value:"E2E Testing",id:"e2e-testing",level:2},{value:"Playwright E2E Tests",id:"playwright-e2e-tests",level:3},{value:"Performance Testing",id:"performance-testing",level:2},{value:"Load Testing with Artillery",id:"load-testing-with-artillery",level:3},{value:"CI/CD Integration",id:"cicd-integration",level:2},{value:"GitHub Actions Workflow",id:"github-actions-workflow",level:3},{value:"Testing Checklist",id:"testing-checklist",level:2},{value:"Before Deployment",id:"before-deployment",level:3},{value:"Test Data",id:"test-data",level:3},{value:"CI/CD",id:"cicd",level:3},{value:"Summary",id:"summary",level:2},{value:"Related Concepts",id:"related-concepts",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",input:"input",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.M)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"testing-strategies",children:"Testing Strategies"}),"\n",(0,s.jsx)(t.h2,{id:"overview",children:"Overview"}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.strong,{children:"Comprehensive testing strategies"})," for Q01 Core API integrations, covering unit tests, integration tests, mocking strategies, test data management, and CI/CD integration."]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Testing Levels:"})}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"Unit Tests - Individual functions"}),"\n",(0,s.jsx)(t.li,{children:"Integration Tests - API interactions"}),"\n",(0,s.jsx)(t.li,{children:"Contract Tests - API contracts"}),"\n",(0,s.jsx)(t.li,{children:"E2E Tests - Complete workflows"}),"\n",(0,s.jsx)(t.li,{children:"Performance Tests - Load and stress"}),"\n",(0,s.jsx)(t.li,{children:"Security Tests - Vulnerability scanning"}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"unit-testing",children:"Unit Testing"}),"\n",(0,s.jsx)(t.h3,{id:"testing-api-client-methods",children:"Testing API Client Methods"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// api-client.js\nclass CoreAPIClient {\n  constructor(baseURL, token) {\n    this.baseURL = baseURL;\n    this.token = token;\n  }\n\n  async get(dimension, id) {\n    const response = await fetch(`${this.baseURL}
1/api/v4/core/${dimension}/${id}`, {\n      headers: {'Authorization': `Bearer ${this.token}`}\n    });\n\n    if (!response.ok) {\n      throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n    }\n\n    return response.json();\n  }\n\n  async create(dimension, data) {\n    const response = await fetch(`${this.baseURL}/api/v4/core/${dimension}`, {\n      method: 'POST',\n      headers: {\n        'Authorization': `Bearer ${this.token}`,\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify(data)\n    });\n\n    if (!response.ok) {\n      throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n    }\n\n    return response.json();\n  }\n}\n\nmodule.exports = CoreAPIClient;\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// api-client.test.js\nconst CoreAPIClient = require('./api-client');\nconst fetchMock = require('jest-fetch-mock');\n\nfetchMock.enableMocks();\n\ndescribe('CoreAPIClient', () => {\n  let client;\n\n  beforeEach(() => {\n    fetch.resetMocks();\n    client = new CoreAPIClient('https://api.q01.io', 'test-token');\n  });\n\n  describe('get', () => {\n    it('should fetch record by ID', async () => {\n      // Arrange\n      const mockProduct = {PRD_ID: 123, XPRD01: 'Widget'};\n      fetch.mockResponseOnce(JSON.stringify(mockProduct));\n\n      // Act\n      const result = await client.get('products', 123);\n\n      // Assert\n      expect(fetch).toHaveBeenCalledWith(\n        'https://api.q01.io/api/v4/core/products/123',\n        expect.objectContaining({\n          headers: {'Authorization': 'Bearer test-token'}\n        })\n      );\n      expect(result).toEqual(mockProduct);\n    });\n\n    it('should throw error on HTTP 404', async () => {\n      // Arrange\n      fetch.mockResponseOnce('Not Found', {status: 404});\n\n      // Act & Assert\n      await expect(client.get('products', 999))\n        .rejects.toThrow('HTTP 404: Not Found');\n    });\n  });\n\n  describe('create', () => {\n    it('should create new record', async () => {\n      // Arrange\n      const newProduct = {XPRD01: 'Widget', XPRD02: 29.99};\n      const createdProduct = {PRD_ID: 123, ...newProduct};\n      fetch.mockResponseOnce(JSON.stringify(createdProduct));\n\n      // Act\n      const result = await client.create('products', newProduct);\n\n      // Assert\n      expect(fetch).toHaveBeenCalledWith(\n        'https://api.q01.io/api/v4/core/products',\n        expect.objectContaining({\n          method: 'POST',\n          headers: {\n            'Authorization': 'Bearer test-token',\n            'Content-Type': 'application/json'\n          },\n          body: JSON.stringify(newProduct)\n        })\n      );\n      expect(result).toEqual(createdProduct);\n    });\n  });\n});\n"})}),"\n",(0,s.jsx)(t.h3,{id:"testing-business-logic",children:"Testing Business Logic"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// product-service.js\nclass ProductService {\n  constructor(apiClient) {\n    this.apiClient = apiClient;\n  }\n\n  async getActiveProducts() {\n    const products = await this.apiClient.list('products', {\n      filters: 'TREC:eq:N,
1XPRD06:eq:Y'\n    });\n\n    return products.data;\n  }\n\n  validateProduct(product) {\n    const errors = [];\n\n    if (!product.XPRD01 || product.XPRD01.trim() === '') {\n      errors.push('Product name is required');\n    }\n\n    if (!product.XPRD02 || product.XPRD02 <= 0) {\n      errors.push('Price must be greater than 0');\n    }\n\n    return errors;\n  }\n}\n\nmodule.exports = ProductService;\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// product-service.test.js\nconst ProductService = require('./product-service');\n\ndescribe('ProductService', () => {\n  let service;\n  let mockAPIClient;\n\n  beforeEach(() => {\n    mockAPIClient = {\n      list: jest.fn()\n    };\n    service = new ProductService(mockAPIClient);\n  });\n\n  describe('getActiveProducts', () => {\n    it('should fetch only active products', async () => {\n      // Arrange\n      const mockProducts = {\n        data: [\n          {PRD_ID: 1, XPRD01: 'Product 1', XPRD06: 'Y'},\n          {PRD_ID: 2, XPRD01: 'Product 2', XPRD06: 'Y'}\n        ]\n      };\n      mockAPIClient.list.mockResolvedValue(mockProducts);\n\n      // Act\n      const result = await service.getActiveProducts();\n\n      // Assert\n      expect(mockAPIClient.list).toHaveBeenCalledWith('products', {\n        filters: 'TREC:eq:N,
1XPRD06:eq:Y'\n      });\n      expect(result).toEqual(mockProducts.data);\n    });\n  });\n\n  describe('validateProduct', () => {\n    it('should return no errors for valid product', () => {\n      const validProduct = {\n        XPRD01: 'Widget',\n        XPRD02: 29.99\n      };\n\n      const errors = service.validateProduct(validProduct);\n\n      expect(errors).toHaveLength(0);\n    });\n\n    it('should return error for missing name', () => {\n      const invalidProduct = {\n        XPRD01: '',\n        XPRD02: 29.99\n      };\n\n      const errors = service.validateProduct(invalidProduct);\n\n      expect(errors).toContain('Product name is required');\n    });\n\n    it('should return error for invalid price', () => {\n      const invalidProduct = {\n        XPRD01: 'Widget',\n        XPRD02: -10\n      };\n\n      const errors = service.validateProduct(invalidProduct);\n\n      expect(errors).toContain('Price must be greater than 0');\n    });\n  });\n});\n"})}),"\n",(0,s.jsx)(t.h2,{id:"integration-testing",children:"Integration Testing"}),"\n",(0,s.jsx)(t.h3,{id:"testing-against-real-api",children:"Testing Against Real API"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// integration.test.js\nconst CoreAPIClient = require('./api-client');\n\n// Use test environment\nconst API_URL = process.env.TEST_API_URL || 'https://api-test.q01.io';\nconst API_TOKEN = process.env.TEST_API_TOKEN;\n\ndescribe('Integration Tests', () => {\n  let client;\n\n  beforeAll(() =>
1 {\n    if (!API_TOKEN) {\n      throw new Error('TEST_API_TOKEN environment variable required');\n    }\n    client = new CoreAPIClient(API_URL, API_TOKEN);\n  });\n\n  describe('Product CRUD', () => {\n    let createdProductId;\n\n    it('should create product', async () => {\n      const newProduct = {\n        XPRD01: `Test Product ${Date.now()}`,\n        XPRD02: 29.99,\n        XPRD03: `TEST-${Date.now()}`,\n        XPRD05: 1,\n        XPRD06: 'Y'\n      };\n\n      const result = await client.create('products', newProduct);\n\n      expect(result).toHaveProperty('PRD_ID');\n      expect(result.XPRD01).toBe(newProduct.XPRD01);\n      expect(result.XPRD02).toBe(newProduct.XPRD02);\n\n      createdProductId = result.PRD_ID;\n    });\n\n    it('should read product', async () => {\n      const result = await client.get('products', createdProductId);\n\n      expect(result.PRD_ID).toBe(createdProductId);\n      expect(result).toHaveProperty('XPRD01');\n      expect(result).toHaveProperty('XPRD02');\n    });\n\n    it('should update product', async () => {\n      const updates = {\n        XPRD02: 39.99\n      };\n\n      const result = await client.update('products', createdProductId, updates);\n\n      expect(result.XPRD02).toBe(39.99);\n    });\n\n    it('should delete product', async () => {\n      await client.delete('products', createdProductId);\n\n      // Verify deleted (should have TREC = 'C')\n      const result = await client.get('products', createdProductId);\n      expect(result.TREC).toBe('C');\n    });\n  });\n\n  describe('Filtering and Pagination', () => {\n    it('should filter by category', async () => {\n      const result = await client.list('products', {\n        filters: 'XPRD05:eq:1,TREC:eq:N',\n        limit: 10\n      });\n\n      expect(result.data).toBeInstanceOf(Array);\n      result.data.forEach(product => {\n        expect(product.XPRD05).toBe(1);\n        expect(product.TREC).toBe('N');\n      });\n    });\n\n    it('should paginate results', async () => {\n      const page1 = await client.list('products', {limit: 10, offset: 0});\n      const page2 = await client.list('products', {limit: 10, offset: 10});\n\n      expect(page1.data).toHaveLength(10);\n      expect(page2.data).toHaveLength(10);\n      expect(page1.data[0].PRD_ID).not.toBe(page2.data[0].PRD_ID);\n    });\n  });\n});\n"})}),"\n",(0,s.jsx)(t.h2,{id:"contract-testing",children:"Contract Testing"}),"\n",(0,s.jsx)(t.h3,{id:"api-contract-verification",children:"API Contract Verification"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// contract.test.js\nconst Pact = require('@pact-foundation/pact');\nconst {like, eachLike} = Pact.Matchers;\nconst CoreAPIClient = require('./api-client');\n\ndescribe('Core API Contract', () => {\n  const provider = new Pact({\n    consumer: 'MyApp',\n    provider: 'CoreAPI',\n    port: 1234,\n    log: './logs/pact.log',\n    logLevel: 'warn'\n  });\n\n  beforeAll(() => provider.setup());\n  afterAll(() => provider.finalize());\n  afterEach(() => provider.verify());\n\n  describe('GET /api/v4/core/products/:id', () => {\n    it('returns product by ID', async () => {\n      // Define expected interaction\n      await provider.addInteraction({\n        state: 'product 123 exists',\n        uponReceiving: 'a request for product 123',\n        withRequest: {\n          method: 'GET',\n          path: '/api/v4/core/products/123',\n          headers: {\n            'Authorization': like('Bearer token123')\n          }\n        },\n        willRespondWith: {\n          status: 200,\n          headers: {'Content-Type': 'application/json'},\n          body: {\n            PRD_ID: 123,\n            XPRD01: like('Product Name'),\n            XPRD02: like(29.99),\n            XPRD03: like('PRD-001'),\n            TREC: 'N'\n          }\n        }\n      });\n\n      // Test\n      const client = new CoreAPIClient('http://localhost:1234', 'token123');\n      const result = await client.get('products', 123);\n\n      expect(result.PRD_ID).toBe(123);\n      expect(result).toHaveProperty('XPRD01');\n    });\n  });\n\n  describe('POST /api/v4/core/products', () => {\n    it('creates new product', async () => {\n      await provider.addInteraction({\n        state: 'user has create permission',\n        uponReceiving: 'a request to create product',\n        withRequest: {\n          method: 'POST',\n          path: '/api/v4/core/products',\n          headers: {\n            'Authorization': like('Bearer token123'),\n            'Content-Type': 'application/json'\n          },\n          body: {\n            XPRD01: 'New Product',\n            XPRD02: 29.99,\n            XPRD05: 1\n          }\n        },\n        willRespondWith: {\n          status: 201,\n          headers: {'Content-Type': 'application/json'},\n          body: {\n            PRD_ID: like(456),\n            XPRD01: 'New Product',\n            XPRD02: 29.99,\n            XPRD05: 1,\n            TREC: 'N'\n          }\n        }\n      });\n\n      const client = new CoreAPIClient('http://localhost:1234', 'token123');\n      const result = await client.create('products', {\n        XPRD01: 'New Product',\n        XPRD02: 29.99,\n        XPRD05: 1\n      });\n\n      expect(result).toHaveProperty('PRD_ID');\n      expect(result.XPRD01).toBe('New Product');\n    });\n  });\n});\n"})}),"\n",(0,s.jsx)(t.h2,{id:"test-data-management",children:"Test Data Management"}),"\n",(0,s.jsx)(t.h3,{id:"test-data-setup",children:"Test Data Setup"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// test-data.js\nclass TestDataManager {\n  
1constructor(apiClient) {\n    this.apiClient = apiClient;\n    this.createdRecords = [];\n  }\n\n  async createTestProduct(overrides = {}) {\n    const product = {\n      XPRD01: `Test Product ${Date.now()}`,\n      XPRD02: 29.99,\n      XPRD03: `TEST-${Date.now()}`,\n      XPRD05: 1,\n      XPRD06: 'Y',\n      ...overrides\n    };\n\n    const result = await this.apiClient.create('products', product);\n    this.createdRecords.push({dimension: 'products', id: result.PRD_ID});\n\n    return result;\n  }\n\n  async createTestCategory(overrides = {}) {\n    const category = {\n      XCAT01: `Test Category ${Date.now()}`,\n      XCAT02: 'Test category description',\n      ...overrides\n    };\n\n    const result = await this.apiClient.create('categories', category);\n    this.createdRecords.push({dimension: 'categories', id: result.CAT_ID});\n\n    return result;\n  }\n\n  async cleanup() {\n    // Delete all created records in reverse order\n    for (const record of this.createdRecords.reverse()) {\n      try {\n        await this.apiClient.delete(record.dimension, record.id);\n      } catch (error) {\n        console.error(`Failed to cleanup ${record.dimension}/${record.id}:`, error);\n      }\n    }\n\n    this.createdRecords = [];\n  }\n}\n\nmodule.exports = TestDataManager;\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// Usage in tests\nconst TestDataManager = require('./test-data');\n\ndescribe('Product Tests with Test Data', () => {\n  let testData;\n\n  beforeEach(() => {\n    testData = new TestDataManager(apiClient);\n  });\n\n  afterEach(async () => {\n    await testData.cleanup();\n  });\n\n  it('should create product with category', async () => {\n    // Setup test data\n    const category = await testData.createTestCategory();\n    const product = await testData.createTestProduct({\n      XPRD05: category.CAT_ID\n    });\n\n    // Test\n    expect(product.XPRD05).toBe(category.CAT_ID);\n\n    // Cleanup handled automatically\n  });\n});\n"})}),"\n",(0,s.jsx)(t.h2,{id:"e2e-testing",children:"E2E Testing"}),"\n",(0,s.jsx)(t.h3,{id:"playwright-e2e-tests",children:"Playwright E2E Tests"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-javascript",children:"// e2e/product-management.spec.js\nconst {test, expect} = require('@playwright/test');\n\ntest.describe('Product Management', () => {\n  test.beforeEach(async ({page}) => {\n    // Login\n    await page.goto('https://app.q01.io/login');\n    await page.fill('[name=\"username\"]', '[email protected]');\n    await page.fill('[name=\"password\"]', 'password123');\n    await page.click('button[type=\"submit\"]');\n    await page.waitForURL('**/dashboard');\n  });\n\n  test('should create new product', async ({page}) => {\n    // Navigate to products\n    await page.goto('https://app.q01.io/products');\n\n    // Click create button\n    await page.click('button:has-text(\"New Product\")');\n\n    // Fill form\n    await page.fill('[name=\"XPRD01\"]', 'E2E Test Product');\n    await page.fill('[name=\"XPRD02\"]', '49.99');\n    await page.selectOption('[name=\"XPRD05\"]', '1');\n\n    // Submit\n    await page.click('button:has-text(\"Save\")');\n\n    // Verify success\n    await expect(page.locator('.success-message')).toContainText('Product created');\n\n    // Verify in list\n    await page.goto('https://app.q01.io/products');\n    await expect(page.locator('table')).toContainText('E2E Test Product');\n  });\n\n  test('should filter products by category', async ({page}) => {\n    await page.goto('https://app.q01.io/products');\n\n    // Select category filter\n    await page.selectOption('[name=\"category\"]', '1');\n    await page.click('button:has-text(\"Filter\")');\n\n    // Verify filtered results\n    const rows = await page.locator('table tbody tr').all();\n    for (const row of rows) {\n      const category = await row.locator('td.category').textContent();\n      expect(category).toBe('Electronics');\n    }\n  });\n});\n"})}),"\n",(0,s.jsx)(t.h2,{id:"performance-testing",children:"Performance Testing"}),"\n",(0,s.jsx)(t.h3,{id:"load-testing-with-artillery",children:"Load Testing with Artillery"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:'# load-test.yml\nconfig:\n  target: \'https://api.q01.io\'\n  phases:\n    - duration: 60\n      arrivalRate: 10\n      name: "Warm up"\n    - duration: 120\n      arrivalRate: 50\n      name: "Sustained load"\n    - duration: 60\n      arrivalRate: 100\n      name: "Spike"\n  variables:\n    token: "{{ $processEnvironment.API_TOKEN }}"\n\nscenarios:\n  - name: "Product operations"\n    flow:\n      - get:\n          url: "/api/v4/core/products"\n          headers:\n            Authorization: "Bearer {{ token }}"\n          expect:\n            - statusCode: 200\n            - contentType: json\n      - post:\n          url: "/api/v4/core/products"\n          headers:\n            Authorization: "Bearer {{ token }}
1"\n            Content-Type: "application/json"\n          json:\n            XPRD01: "Load Test Product {{ $randomNumber() }}"\n            XPRD02: 29.99\n            XPRD05: 1\n          expect:\n            - statusCode: 201\n'})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"# Run load test\nartillery run load-test.yml\n\n# Generate report\nartillery run --output report.json load-test.yml\nartillery report report.json\n"})}),"\n",(0,s.jsx)(t.h2,{id:"cicd-integration",children:"CI/CD Integration"}),"\n",(0,s.jsx)(t.h3,{id:"github-actions-workflow",children:"GitHub Actions Workflow"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"# .github/workflows/test.yml\nname: Test\n\non:\n  push:\n    branches: [main, develop]\n  pull_request:\n    branches: [main]\n\njobs:\n  unit-tests:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: '18'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Run unit tests\n        run: npm test\n\n      - name: Upload coverage\n        uses: codecov/codecov-action@v3\n        with:\n          files: ./coverage/lcov.info\n\n  integration-tests:\n    runs-on: ubuntu-latest\n    needs: unit-tests\n\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: '18'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Run integration tests\n        run: npm run test:integration\n        env:\n          TEST_API_URL: ${{ secrets.TEST_API_URL }}\n          TEST_API_TOKEN: ${{ secrets.TEST_API_TOKEN }}\n\n  e2e-tests:\n    runs-on: ubuntu-latest\n    needs: integration-tests\n\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: '18'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Install Playwright\n        run: npx playwright install --with-deps\n\n      - name: Run E2E tests\n        run: npm run test:e2e\n\n      - name: Upload test results\n        if: always()\n        uses: actions/upload-artifact@v3\n        with:\n          name: playwright-report\n          path: playwright-report/\n"})}),"\n",(0,s.jsx)(t.h2,{id:"testing-checklist",children:"Testing Checklist"}),"\n",(0,s.jsx)(t.h3,{id:"before-deployment",children:"Before Deployment"}),"\n",(0,s.jsxs)(t.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","All unit tests passing"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Integration tests passing"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Contract tests verified"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","E2E tests passing"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Performance tests meet targets"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Security tests passed"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Test coverage > 80%"]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"test-data",children:"Test Data"}),"\n",(0,s.jsxs)(t.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Test data isolated"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Cleanup after tests"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","No hardcoded IDs"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Realistic test data"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Test different scenarios"]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"cicd",children:"CI/CD"}),"\n",(0,s.jsxs)(t.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Tests run on every commit"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Tests run on PR"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Test reports generated"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Coverage tracked"]}),"\n",(0,s.jsxs)(t.li,{className:"task-list-item",children:[(0,s.jsx)(t.input,{type:"checkbox",disabled:!0})," ","Failed tests block deployment"]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Testing Pyramid:"})}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Unit Tests"})," (70%) - Fast, isolated, many"]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Integration Tests"})," (20%) - API interactions"]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"E2E Tests"})," (10%) - Complete workflows"]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Key Takeaways:"})}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Test at multiple levels"}),"\n",(0,s.jsx)(t.li,{children:"Mock external dependencies"}),"\n",(0,s.jsx)(t.li,{children:"Manage test data properly"}),"\n",(0,s.jsx)(t.li,{children:"Integrate with CI/CD"}),"\n",(0,s.jsx)(t.li,{children:"Monitor test coverage"}),"\n",(0,s.jsx)(t.li,{children:"Performance test before production"}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"related-concepts",children:"Related Concepts"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"/docs/products/map.q01.io/core-api-platform-v4/best-practices/use-cases",children:"Use Cases"})," - Implementation patterns"]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"/docs/products/map.q01.io/core-api-platform-v4/best-practices/anti-patterns",children:"Anti-Patterns"})," - What not to do"]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"/docs/products/map.q01.io/core-api-platform-v4/best-practices",children:"Best Practices"})," - Overview"]}),"\n"]})]})}function p(e={}){const{wrapper:t}={...(0,i.M)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}}
1,2172:(e,t,n)=>{n.d(t,{I:()=>o,M:()=>a});var s=n(1504);const i={},r=s.createContext(i);function a(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.