Files
2026-07-13 12:20:06 +08:00

342 lines
7.2 KiB
Markdown

# Testing & Development Environment
Set up development and testing environments for Zoom integrations.
## Overview
Zoom provides several options for development and testing:
- Development app credentials (separate from production)
- Test accounts
- Local webhook testing tools
- SDK sandbox modes
## Skills Needed
- **general** - App configuration
- **webhooks** - Webhook testing
---
## Development vs Production Apps
### Create Separate Apps
**Always create separate apps for development and production:**
| Environment | Purpose | Credentials |
|-------------|---------|-------------|
| Development | Testing, debugging | Dev Client ID/Secret |
| Production | Live users | Prod Client ID/Secret |
1. Go to [Zoom Marketplace](https://marketplace.zoom.us/)
2. Create "MyApp - Development" for testing
3. Create "MyApp - Production" for live deployment
4. Use environment variables to switch between them
```javascript
// .env.development
ZOOM_CLIENT_ID=dev_client_id_here
ZOOM_CLIENT_SECRET=dev_secret_here
ZOOM_ACCOUNT_ID=dev_account_id
// .env.production
ZOOM_CLIENT_ID=prod_client_id_here
ZOOM_CLIENT_SECRET=prod_secret_here
ZOOM_ACCOUNT_ID=prod_account_id
```
---
## Test Accounts
### Option 1: Developer Account
Use your own Zoom account for initial development:
- Free tier works for basic API testing
- Pro account needed for SDK testing
- Create test meetings manually
### Option 2: Zoom Developer Sandbox (ISV Partners)
ISV partners can request sandbox accounts:
- Contact Zoom partnership team
- Isolated test environment
- Multiple test users
### Option 3: Programmatic Test Users
Create test users via API (requires admin account):
```javascript
// Create a test user
const response = await axios.post(
'https://api.zoom.us/v2/users',
{
action: 'create',
user_info: {
email: 'testuser+1@yourcompany.com', // Use + alias
type: 1, // Basic user
first_name: 'Test',
last_name: 'User'
}
},
{ headers: { 'Authorization': `Bearer ${accessToken}` }}
);
```
**Tip**: Use email aliases (`testuser+1@company.com`, `testuser+2@company.com`) that all route to one inbox.
---
## Local Webhook Testing
### Option 1: ngrok (Recommended)
Expose your local development webhook server to the internet for testing:
```bash
# Install ngrok
npm install -g ngrok
# Start your local server
node server.js # Running on port 3000
# In another terminal, create tunnel
ngrok http 3000
```
Output:
```
Forwarding https://abc123.ngrok.io -> http://YOUR_DEV_HOST:3000
```
Use `https://abc123.ngrok.io/webhook` as your webhook URL in Zoom Marketplace.
### Option 2: Cloudflare Tunnel
```bash
# Install cloudflared
brew install cloudflare/cloudflare/cloudflared
# Create tunnel
LOCAL_WEBHOOK_BASE_URL="http://YOUR_DEV_HOST:3000"
cloudflared tunnel --url "$LOCAL_WEBHOOK_BASE_URL"
```
### Option 3: localtunnel
```bash
npm install -g localtunnel
lt --port 3000
```
### Webhook URL Validation
Zoom requires validating your webhook endpoint. Your server must respond to the challenge:
```javascript
app.post('/webhook', (req, res) => {
// Handle Zoom's endpoint validation
if (req.body.event === 'endpoint.url_validation') {
const hashForValidate = crypto
.createHmac('sha256', ZOOM_WEBHOOK_SECRET)
.update(req.body.payload.plainToken)
.digest('hex');
return res.json({
plainToken: req.body.payload.plainToken,
encryptedToken: hashForValidate
});
}
// Handle actual events
// ...
});
```
---
## SDK Development Mode
### Meeting SDK Web
Enable debug logging:
```javascript
const client = ZoomMtgEmbedded.createClient();
client.init({
debug: true, // Enable debug logs
zoomAppRoot: document.getElementById('meetingSDKElement'),
language: 'en-US',
});
```
### Video SDK Web
```javascript
const client = ZoomVideo.createClient();
await client.init('en-US', 'CDN', {
enforceMultipleVideos: true,
stayAwake: true,
patchJsMedia: true,
leaveOnPageUnload: true,
});
// Enable debug mode
ZoomVideo.setLogLevel('debug');
```
### Native SDKs (iOS/Android/Desktop)
Enable verbose logging:
```swift
// iOS
let initParams = ZoomVideoSDKInitParams()
initParams.enableLog = true
initParams.logFilePrefix = "videosdk_debug"
```
```kotlin
// Android
val initParams = ZoomVideoSDKInitParams().apply {
enableLog = true
logFilePrefix = "videosdk_debug"
}
```
---
## Mock Webhook Events
### Manual Testing with curl
Test your webhook handler locally:
```bash
LOCAL_WEBHOOK_BASE_URL="http://YOUR_DEV_HOST:3000"
# Simulate meeting.started event
curl -X POST "$LOCAL_WEBHOOK_BASE_URL/webhook" \
-H "Content-Type: application/json" \
-H "x-zm-signature: v0=test" \
-H "x-zm-request-timestamp: $(date +%s)" \
-d '{
"event": "meeting.started",
"payload": {
"account_id": "abc123",
"object": {
"id": "123456789",
"uuid": "abcd-1234-efgh",
"topic": "Test Meeting",
"host_id": "xyz789"
}
}
}'
```
### Webhook Replay Tool
Build a simple replay tool for testing:
```javascript
const fs = require('fs');
// Save incoming webhooks to file
app.post('/webhook', (req, res) => {
const filename = `webhooks/${Date.now()}_${req.body.event}.json`;
fs.writeFileSync(filename, JSON.stringify(req.body, null, 2));
// Process normally...
});
// Replay saved webhook
async function replayWebhook(filename) {
const payload = JSON.parse(fs.readFileSync(filename));
await processWebhook(payload);
}
```
---
## Testing Checklist
### Before Going Live
- [ ] Test OAuth flow end-to-end
- [ ] Verify webhook signature validation
- [ ] Test with multiple user types (host, participant, admin)
- [ ] Handle rate limiting gracefully
- [ ] Test error scenarios (invalid tokens, network failures)
- [ ] Verify recording download permissions
- [ ] Test SDK on all target platforms
- [ ] Load test with expected user volume
### API Testing
```javascript
// Test helper for API calls
async function testAPICall(name, fn) {
console.log(`Testing: ${name}`);
try {
const result = await fn();
console.log(`Pass: ${name}`);
return result;
} catch (error) {
console.error(`Fail: ${name}:`, error.message);
throw error;
}
}
// Run tests
await testAPICall('Create meeting', () =>
createMeeting({ topic: 'Test' })
);
await testAPICall('Get meeting', () =>
getMeeting(meetingId)
);
await testAPICall('Delete meeting', () =>
deleteMeeting(meetingId)
);
```
---
## Debugging Tips
### Enable Request Logging
```javascript
const axios = require('axios');
// Log all requests
axios.interceptors.request.use(config => {
console.log(`-> ${config.method.toUpperCase()} ${config.url}`);
return config;
});
axios.interceptors.response.use(
response => {
console.log(`<- ${response.status} ${response.config.url}`);
return response;
},
error => {
console.error(`<- ${error.response?.status} ${error.config?.url}`);
console.error('Error:', error.response?.data);
throw error;
}
);
```
### SDK Log Collection
See [SDK Logs & Troubleshooting](../references/sdk-logs-troubleshooting.md) for collecting SDK debug logs.
## Resources
- **ngrok**: https://ngrok.com/
- **Postman Collection**: https://developers.zoom.us/docs/api/rest/postman/
- **Developer Forum**: https://devforum.zoom.us/