Custom Resources Development Guide¶
Learn how to create custom resources, patterns, and extensions for TINAA to support your specific testing needs.
Overview¶
Custom resources in TINAA allow you to: - Define domain-specific test patterns - Create reusable test components - Implement custom assertions - Add specialized test generators
Custom Test Patterns¶
Creating a Pattern¶
// patterns/ecommerce-checkout.js
module.exports = {
name: 'ecommerce-checkout',
description: 'E-commerce checkout flow testing pattern',
generate: async (context) => {
return {
steps: [
{ action: 'navigate', target: context.url },
{ action: 'addToCart', products: context.products },
{ action: 'proceedToCheckout' },
{ action: 'fillShipping', data: context.shippingData },
{ action: 'fillPayment', data: context.paymentData },
{ action: 'confirmOrder' },
{ action: 'verifyConfirmation' }
]
};
},
validators: {
cartTotal: (expected, actual) => {
return Math.abs(expected - actual) < 0.01;
},
orderNumber: (orderNum) => {
return /^[A-Z0-9]{8,12}$/.test(orderNum);
}
}
};
Registering Patterns¶
// tinaa.config.js
module.exports = {
patterns: [
'./patterns/ecommerce-checkout.js',
'./patterns/user-authentication.js',
'@tinaa/patterns-banking' // npm package
]
};
Custom Generators¶
AI Prompt Templates¶
// generators/form-validation.js
class FormValidationGenerator {
constructor(ai) {
this.ai = ai;
}
async generate(options) {
const prompt = `
Generate comprehensive form validation tests for ${options.url}.
Include tests for:
- Required fields
- Field formats (email, phone, etc.)
- Field length limits
- Special characters
- XSS prevention
- Boundary values
`;
const response = await this.ai.complete(prompt, {
model: 'gpt-4',
temperature: 0.3
});
return this.parseResponse(response);
}
}
Domain-Specific Languages (DSL)¶
// dsl/banking-dsl.js
class BankingDSL {
constructor(page) {
this.page = page;
}
async transferFunds(from, to, amount) {
await this.page.click('[data-test="transfer-button"]');
await this.page.selectOption('#from-account', from);
await this.page.selectOption('#to-account', to);
await this.page.fill('#amount', amount.toString());
await this.page.click('[data-test="confirm-transfer"]');
}
async verifyBalance(account, expectedBalance) {
const balance = await this.page.textContent(
`[data-account="${account}"] .balance`
);
expect(parseFloat(balance)).toBe(expectedBalance);
}
}
Custom Assertions¶
Creating Custom Matchers¶
// matchers/accessibility.js
expect.extend({
toBeAccessible: async (page, options = {}) => {
const violations = await checkAccessibility(page, options);
return {
pass: violations.length === 0,
message: () => violations.length > 0
? `Found ${violations.length} accessibility violations:\n${formatViolations(violations)}`
: 'Page is accessible'
};
},
toHaveAriaLabel: async (element, expectedLabel) => {
const actualLabel = await element.getAttribute('aria-label');
return {
pass: actualLabel === expectedLabel,
message: () => `Expected aria-label to be "${expectedLabel}", but got "${actualLabel}"`
};
}
});
Using Custom Assertions¶
test('checkout page accessibility', async ({ page }) => {
await page.goto('/checkout');
await expect(page).toBeAccessible({
standards: ['WCAG2AA'],
exclude: ['.third-party-widget']
});
});
Resource Packages¶
Package Structure¶
tinaa-resources-finance/
├── package.json
├── index.js
├── patterns/
│ ├── trading.js
│ ├── banking.js
│ └── insurance.js
├── generators/
│ └── financial-forms.js
├── assertions/
│ └── currency.js
└── helpers/
└── calculations.js
Package Configuration¶
{
"name": "@company/tinaa-resources-finance",
"version": "1.0.0",
"main": "index.js",
"tinaa": {
"type": "resources",
"patterns": ["./patterns/*.js"],
"generators": ["./generators/*.js"],
"assertions": ["./assertions/*.js"]
}
}
Custom Actions¶
Defining Actions¶
// actions/file-upload.js
module.exports = {
name: 'uploadFile',
async execute(page, options) {
const { selector, filePath, waitForUpload = true } = options;
// Handle file input
const fileInput = await page.$(selector);
await fileInput.setInputFiles(filePath);
// Wait for upload completion
if (waitForUpload) {
await page.waitForSelector('.upload-complete', {
timeout: 30000
});
}
return {
success: true,
uploadedFile: filePath
};
}
};
Registering Actions¶
// Register globally
tinaa.registerAction('uploadFile', require('./actions/file-upload'));
// Use in tests
await tinaa.execute('uploadFile', {
selector: '#file-input',
filePath: './test-data/document.pdf'
});
Custom Reporters¶
Creating a Reporter¶
// reporters/confluence-reporter.js
class ConfluenceReporter {
constructor(options) {
this.client = new ConfluenceClient(options);
}
async onTestComplete(test, result) {
const page = await this.client.createPage({
title: `Test Results: ${test.name}`,
parent: this.options.parentPageId,
content: this.formatResults(result)
});
if (result.screenshots) {
await this.uploadScreenshots(page.id, result.screenshots);
}
}
formatResults(result) {
return `
<h2>Test: ${result.name}</h2>
<p>Status: ${result.status}</p>
<p>Duration: ${result.duration}ms</p>
${result.error ? `<pre>${result.error}</pre>` : ''}
`;
}
}
Best Practices¶
1. Modularity¶
Keep resources focused and single-purpose:
// Good: Specific, reusable
const emailValidator = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
// Avoid: Too broad, hard to maintain
const validateEverything = (data) => { /* ... */ };
2. Documentation¶
Document your custom resources:
/**
* Validates credit card numbers using Luhn algorithm
* @param {string} cardNumber - The card number to validate
* @returns {boolean} True if valid
* @example
* validateCard('4111111111111111') // returns true
*/
function validateCard(cardNumber) {
// Implementation
}
3. Testing¶
Test your custom resources:
describe('Custom Banking Patterns', () => {
it('should generate valid transfer tests', async () => {
const pattern = new BankingPattern();
const tests = await pattern.generate({
accounts: ['checking', 'savings']
});
expect(tests).toContainTestStep('transferFunds');
});
});
4. Version Management¶
- Use semantic versioning
- Document breaking changes
- Provide migration guides
Sharing Resources¶
Publishing to NPM¶
Private Registries¶
Community Marketplace¶
Share your resources with the community:
1. Create a GitHub repository
2. Add topic: tinaa-resources
3. Submit to TINAA Marketplace