Testing Strategies
Effective testing ensures your SuiteScript applications work correctly and reliably.
Testing Levels
┌─────────────────────────────────────────────────────────────────────────────┐
│ TESTING PYRAMID │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────┐
│ E2E │ ← Fewer, slower, more coverage
│ Tests │
├─────────────┤
│ Integration │
│ Tests │
├─────────────┤
│ Unit │ ← More, faster, specific
│ Tests │
└─────────────┘
UNIT TESTS:
• Test individual functions
• Mock NetSuite APIs
• Fast execution
• Run locally
INTEGRATION TESTS:
• Test script interactions
• Use sandbox environment
• Test with real records
E2E TESTS:
• Full workflow testing
• User scenario simulation
• Complete business processes
Manual Testing Checklist
Script Type Testing
| Script Type | What to Test |
|---|---|
| Suitelet | GET/POST handling, form display, data processing |
| User Event | beforeLoad, beforeSubmit, afterSubmit triggers |
| Client Script | Field changes, validation, save behavior |
| Scheduled | Execution, governance, rescheduling |
| Map/Reduce | All stages, error handling, summarize |
| RESTlet | All HTTP methods, authentication, responses |
| Workflow Action | Trigger conditions, return values |
Testing User Event Scripts
/**
* Manual Test Plan for User Event Script
*/
// TEST: beforeLoad
// 1. Navigate to record in View mode
// 2. Verify custom fields appear
// 3. Verify buttons added correctly
// 4. Check page layout changes
// TEST: beforeSubmit
// 1. Create new record with valid data → Should save
// 2. Create record with invalid data → Should show error
// 3. Edit record and modify key fields → Should validate
// 4. Try to violate business rules → Should block
// TEST: afterSubmit
// 1. Create record → Check if related records created
// 2. Update record → Verify external systems notified
// 3. Check execution logs for errors
Testing Script
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
* @description Include test logging
*/
define(['N/log'], (log) => {
const beforeSubmit = (context) => {
log.debug('TEST', '=== beforeSubmit START ===');
log.debug('Context Type', context.type);
log.debug('Record ID', context.newRecord.id);
log.debug('Record Type', context.newRecord.type);
// Log field values for debugging
const fields = ['entity', 'total', 'custbody_status'];
fields.forEach(field => {
log.debug(`Field: ${field}`, context.newRecord.getValue({ fieldId: field }));
});
// Your logic here
log.debug('TEST', '=== beforeSubmit END ===');
};
return { beforeSubmit };
});
Testing Client Scripts
/**
* Client Script Testing Checklist
*/
// TEST: pageInit
// 1. Load record in CREATE mode → Check defaults set
// 2. Load record in EDIT mode → Check existing values
// 3. Load record in COPY mode → Check copied values
// TEST: fieldChanged
// 1. Change field A → Verify field B updates
// 2. Change field to invalid value → Check validation
// 3. Change field on sublist → Verify line updates
// TEST: validateLine
// 1. Enter valid line data → Should commit
// 2. Enter invalid line data → Should block with message
// TEST: saveRecord
// 1. Save valid record → Should succeed
// 2. Save with missing required data → Should block
// 3. Save with business rule violation → Should block
// BROWSER CONSOLE TESTING
// Open browser console (F12)
// Look for console.log messages
// Check for JavaScript errors
Debug in Browser
// Add to client script for browser debugging
const pageInit = (context) => {
console.log('=== pageInit ===');
console.log('Mode:', context.mode);
console.log('Record:', context.currentRecord);
// Expose for browser console
window.testRecord = context.currentRecord;
};
// In browser console:
// > testRecord.getValue({ fieldId: 'entity' })
// > testRecord.setText({ fieldId: 'salesrep', text: 'John Smith' })
Testing Scheduled Scripts
┌─────────────────────────────────────────────────────────────────────────────┐
│ SCHEDULED SCRIPT TESTING │
└─────────────────────────────────────────────────────────────────────────────┘
1. SET DEPLOYMENT TO "TESTING"
├── Go to: Customization → Scripting → Script Deployments
└── Set Status: Testing (only you can run)
2. RUN MANUALLY
├── Click "Save & Execute" button
└── Monitor execution in real-time
3. CHECK LOGS
├── Customization → Scripting → Script Execution Logs
└── Filter by your script
4. VERIFY RESULTS
├── Check records were updated
├── Verify emails sent
└── Confirm expected behavior
5. TEST GOVERNANCE
├── Run with small dataset first
├── Check getRemainingUsage() logs
└── Verify rescheduling works
Governance Testing
const execute = (context) => {
const script = runtime.getCurrentScript();
// Log governance throughout
log.debug('Initial Units', script.getRemainingUsage());
mySearch.run().each((result, index) => {
if (index % 100 === 0) {
log.debug('Governance Check', {
processed: index,
remaining: script.getRemainingUsage()
});
}
processRecord(result);
return true;
});
log.debug('Final Units', script.getRemainingUsage());
};
Testing RESTlets
Using Postman
-
Create Request
- Set URL:
https://{accountid}.restlets.api.netsuite.com/... - Add OAuth 1.0 authentication
- Set Content-Type: application/json
- Set URL:
-
GET Request Test
GET ?script=customscript_api&deploy=1&id=123
- POST Request Test
{
"action": "create",
"data": {
"name": "Test Customer",
"email": "test@example.com"
}
}
Using cURL
# GET request
curl -X GET \
'https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=customscript_api&deploy=1&id=123' \
-H 'Authorization: OAuth oauth_consumer_key="...",oauth_token="...",oauth_signature="..."' \
-H 'Content-Type: application/json'
# POST request
curl -X POST \
'https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=customscript_api&deploy=1' \
-H 'Authorization: OAuth ...' \
-H 'Content-Type: application/json' \
-d '{"action":"create","data":{"name":"Test"}}'
Testing Map/Reduce Scripts
┌─────────────────────────────────────────────────────────────────────────────┐
│ MAP/REDUCE TESTING STRATEGY │
└─────────────────────────────────────────────────────────────────────────────┘
1. TEST getInputData FIRST
├── Return small dataset (5-10 records)
├── Verify data format
└── Check filters working
2. TEST map FUNCTION
├── Check context.value parsing
├── Verify context.write() calls
└── Check error handling
3. TEST reduce FUNCTION
├── Verify key grouping
├── Check context.values iteration
└── Test record creation/updates
4. TEST summarize
├── Check error iteration
├── Verify output processing
└── Test notification sending
5. FULL TEST
├── Run with full dataset
├── Monitor M/R status page
└── Check all stages complete
Monitor Map/Reduce Status
Customization → Scripting → Script Execution → Map/Reduce Script Status
Shows:
- Current stage
- Records processed
- Errors per stage
- Time elapsed
Test Data Management
Create Test Data
/**
* Suitelet to create test data
*/
const createTestData = () => {
const testCustomer = record.create({
type: record.Type.CUSTOMER
});
testCustomer.setValue({ fieldId: 'companyname', value: 'TEST - Automation Customer' });
testCustomer.setValue({ fieldId: 'email', value: 'test@automation.local' });
const customerId = testCustomer.save();
log.debug('Test Data', `Created customer: ${customerId}`);
return customerId;
};
Clean Test Data
/**
* Clean up test records
*/
const cleanTestData = () => {
const testRecords = search.create({
type: search.Type.CUSTOMER,
filters: [
['companyname', 'startswith', 'TEST -']
]
});
testRecords.run().each((result) => {
record.delete({
type: record.Type.CUSTOMER,
id: result.id
});
return true;
});
};
Logging Best Practices
// Use appropriate log levels
log.debug('Debug', 'Detailed debugging info'); // Development only
log.audit('Audit', 'Important milestones'); // Always log
log.error('Error', 'Error information'); // Always log
// Log structured data
log.debug('Record Data', JSON.stringify({
id: record.id,
type: record.type,
status: record.getValue({ fieldId: 'status' })
}, null, 2));
// Log timing
const startTime = Date.now();
// ... processing ...
log.audit('Performance', `Completed in ${Date.now() - startTime}ms`);
// Mark test entries clearly
log.debug('=== TEST START ===');
// ... test code ...
log.debug('=== TEST END ===');
Test Documentation Template
# Test Plan: Invoice Approval Script
## Test Environment
- Account: TSTDRV1234567
- Date: 2024-01-15
- Tester: John Smith
## Test Cases
### TC001: Invoice Under Threshold
- **Input**: Create invoice for $500
- **Expected**: No approval required
- **Result**: ✓ PASS
### TC002: Invoice Over Threshold
- **Input**: Create invoice for $5,000
- **Expected**: Routes to manager for approval
- **Result**: ✓ PASS
### TC003: Approval Action
- **Input**: Manager clicks Approve button
- **Expected**: Status updates, notification sent
- **Result**: ✗ FAIL - Email not sent
## Issues Found
1. Issue #1: Email notification fails when...
Next Steps
- Deploy to Production - Production deployment
- Rollback - Handling deployment issues
- Error Handling - Error management