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.