342 lines
7.2 KiB
Markdown
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/
|