mirror of
https://github.com/hanzoai/insights-js.git
synced 2026-10-30 18:34:19 +00:00
One family. Font stacks name Zen and fall back to the native faces, tokens name the role rather than a face, and the packages that used to supply a face now point at @hanzo/font. Self-hosted @font-face blocks are removed rather than renamed: rewriting the family in one would leave a src pointing at a file this repo no longer ships. @hanzo/font carries the binaries and declares the faces, so the local copies go with the declaration that used them. Comments naming a face we no longer use are deleted, not reworded.
4411 lines
204 KiB
HTML
4411 lines
204 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Insights Time-Based Version Detection Test</title>
|
|
<style>
|
|
body {
|
|
font-family: Zen, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #1a1a1a;
|
|
color: #e0e0e0;
|
|
}
|
|
|
|
#log {
|
|
background-color: #2d2d2d;
|
|
border: 1px solid #404040;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
font-family: Zen Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
font-size: 12px;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
button {
|
|
padding: 10px 20px;
|
|
margin: 5px;
|
|
font-size: 16px;
|
|
cursor: pointer;
|
|
background-color: #0066cc;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 5px;
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
button:hover {
|
|
background-color: #0052a3;
|
|
}
|
|
|
|
.scenario-group {
|
|
margin: 20px 0;
|
|
padding: 15px;
|
|
border: 1px solid #404040;
|
|
border-radius: 5px;
|
|
background-color: #2a2a2a;
|
|
}
|
|
|
|
.scenario-title {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
color: #74c0fc;
|
|
}
|
|
|
|
.scenario-description {
|
|
margin-bottom: 10px;
|
|
color: #b0b0b0;
|
|
}
|
|
|
|
.expected-results {
|
|
background-color: #1e3a1e;
|
|
padding: 10px;
|
|
border-radius: 3px;
|
|
margin: 10px 0;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.error {
|
|
color: #ff6b6b;
|
|
}
|
|
|
|
.success {
|
|
color: #51cf66;
|
|
}
|
|
|
|
.info {
|
|
color: #74c0fc;
|
|
}
|
|
|
|
.version-info {
|
|
background-color: #2a2a3a;
|
|
padding: 8px;
|
|
border-radius: 3px;
|
|
margin: 5px 0;
|
|
font-family: Zen Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
font-size: 11px;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<h1>🕒 Time-Based Version Detection Test</h1>
|
|
<p>Tests the dual check logic - versions are "Outdated" if
|
|
<code>releasesBehind >= 3</code> OR <code>(releasesBehind >= 2 && versionAge > 48h)</code>
|
|
</p>
|
|
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">📝 Current Setup</div>
|
|
<div id="apiKeyDisplay"></div>
|
|
</div>
|
|
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">📚 Select SDK to Test</div>
|
|
<select id="sdkSelector" onchange="changeSdk()"
|
|
style="padding: 8px; font-size: 16px; margin: 10px 0; background-color: #2a2a2a; color: #e0e0e0; border: 1px solid #404040;">
|
|
<option value="web">🌐 Web SDK (@hanzo/insights)</option>
|
|
<option value="python">🐍 Python SDK</option>
|
|
<option value="node">📗 Node.js SDK</option>
|
|
<option value="react-native">📱 React Native SDK</option>
|
|
<option value="flutter">🦋 Flutter SDK</option>
|
|
<option value="ios">📱 iOS SDK</option>
|
|
<option value="android">🤖 Android SDK</option>
|
|
<option value="go">🔷 Go SDK</option>
|
|
<option value="php">🐘 PHP SDK</option>
|
|
<option value="ruby">💎 Ruby SDK</option>
|
|
<option value="elixir">⚗️ Elixir SDK</option>
|
|
<option value="dotnet">🔷 .NET SDK</option>
|
|
</select>
|
|
<div id="sdkDescription"></div>
|
|
<div id="versionInfo" class="version-info">Loading version information...</div>
|
|
</div>
|
|
|
|
<div id="testContent">
|
|
<!-- Web SDK Tests (default) -->
|
|
<div id="webTests" class="sdk-tests">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">📱 Real Version Tests (GitHub API Integration)</div>
|
|
<div class="scenario-description">
|
|
Tests with actual Insights-js versions from CDN and real GitHub release dates.
|
|
</div>
|
|
<div id="real-version-info" class="version-info">Loading real version data...</div>
|
|
|
|
<button onclick="testRealCurrentVersion()">✅ Current Version (16 events)</button>
|
|
<button onclick="testRealCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testRealOutdated()">🔴 6+ Releases Behind (16 events)</button>
|
|
<button onclick="testWebSdkEdgeCase1264()">🎯 Web Edge: v1.264.2 (3+ Behind, 5 Days - Should be Close
|
|
Enough)</button>
|
|
<button onclick="testAllRealVersions()">🧪 All Real Version Tests (48 events)</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Python SDK Tests -->
|
|
<div id="pythonTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">🐍 Python SDK Real Version Tests</div>
|
|
<div class="scenario-description">
|
|
Tests with actual Python SDK versions and simulated GitHub release dates.
|
|
</div>
|
|
<div id="python-real-version-info" class="version-info">Loading Python version data...</div>
|
|
|
|
<button onclick="testPythonRealCurrentVersion()">✅ Current Python Version (16 events)</button>
|
|
<button onclick="testPythonRealCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testPythonRealOutdated()">🔴 6+ Releases Behind (16 events)</button>
|
|
<button onclick="testPythonEdgeCase672()">🎯 Python Edge: v6.7.2 (3 Behind, 13 Days - Should be Close
|
|
Enough)</button>
|
|
<button onclick="testAllPythonRealVersions()">🧪 All Python Real Tests (48 events)</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Node.js SDK Tests -->
|
|
<div id="nodeTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">📗 Node.js SDK Real Version Tests</div>
|
|
<div class="scenario-description">
|
|
Tests with actual Node.js SDK versions and simulated GitHub release dates.
|
|
</div>
|
|
<div id="node-real-version-info" class="version-info">Loading Node.js version data...</div>
|
|
|
|
<button onclick="testNodeRealCurrentVersion()">✅ Current Node.js Version (16 events)</button>
|
|
<button onclick="testNodeRealCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testNodeRealOutdated()">🔴 6+ Releases Behind (16 events)</button>
|
|
<button onclick="testNodeEdgeCase581()">🎯 Node.js Edge: v5.8.1 (3 Behind, 20 Days - Should be Close
|
|
Enough)</button>
|
|
<button onclick="testAllNodeRealVersions()">🧪 All Node.js Real Tests (48 events)</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- React Native SDK Tests -->
|
|
<div id="react-nativeTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">📱 React Native SDK Real Version Tests</div>
|
|
<div class="scenario-description">
|
|
Tests with actual React Native SDK versions and GitHub release dates.
|
|
</div>
|
|
<div id="react-native-real-version-info" class="version-info">Loading React Native version data...</div>
|
|
<button onclick="testReactNativeCurrentVersion()">🟢 React Native Current Version</button>
|
|
<button onclick="testReactNativeCloseEnoughVersion()">🟡 React Native Close Enough Version</button>
|
|
<button onclick="testReactNativeOutdatedVersion()">🔴 React Native Outdated Version</button>
|
|
<button onclick="testReactNativeEdgeCase443()">🎯 React Native Edge: v4.4.3 (3 Behind, 20 Days - Should
|
|
be Close Enough)</button>
|
|
<button onclick="testAllReactNativeRealVersions()">🧪 All React Native Real Tests (48 events)</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Flutter SDK Tests -->
|
|
<div id="flutterTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">🦋 Flutter SDK Real Version Tests</div>
|
|
<div class="scenario-description">
|
|
Tests with actual Flutter SDK versions and GitHub release dates.
|
|
</div>
|
|
<div id="flutter-real-version-info" class="version-info">Loading Flutter version data...</div>
|
|
<button onclick="testFlutterCurrentVersion()">🟢 Flutter Current Version</button>
|
|
<button onclick="testFlutterCloseEnoughVersion()">🟡 Flutter Close Enough Version</button>
|
|
<button onclick="testFlutterOutdatedVersion()">🔴 Flutter Outdated Version</button>
|
|
<button onclick="testFlutterEdgeCase542()">🎯 Flutter Edge: v5.4.2 (3 Behind, 9 Days - Should be Close
|
|
Enough)</button>
|
|
<button onclick="testAllFlutterRealVersions()">🧪 All Flutter Real Tests (48 events)</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- iOS SDK Tests -->
|
|
<div id="iosTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">📱 iOS SDK Real Version Tests</div>
|
|
<div class="scenario-description">
|
|
Tests with actual iOS SDK versions and GitHub API release dates.
|
|
</div>
|
|
<div id="ios-real-version-info" class="version-info">Loading iOS version data...</div>
|
|
|
|
<button onclick="testiOSRealCurrentVersion()">✅ Current iOS Version (16 events)</button>
|
|
<button onclick="testiOSRealCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testiOSRealOutdated()">🔴 6+ Releases Behind (16 events)</button>
|
|
<button onclick="testiOSEdgeCase()">🎯 iOS Edge: v3.30.0 (2 Behind, 54 Days - Should be Close Enough
|
|
with 60d threshold)</button>
|
|
<button onclick="testAlliOSRealVersions()">🧪 All iOS Real Tests (48 events)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Android SDK Tests -->
|
|
<div id="androidTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">🤖 Android SDK Real Version Tests</div>
|
|
<div class="scenario-description">
|
|
Tests with actual Android SDK versions and GitHub API release dates.
|
|
</div>
|
|
<div id="android-real-version-info" class="version-info">Loading Android version data...</div>
|
|
|
|
<button onclick="testAndroidRealCurrentVersion()">✅ Current Android Version (16 events)</button>
|
|
<button onclick="testAndroidRealCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testAndroidRealOutdated()">🔴 6+ Releases Behind (16 events)</button>
|
|
<button onclick="testAndroidEdgeCase()">🎯 Android Edge: v3.21.0 (3 Behind, 25 Days - Should be Close
|
|
Enough with 30d threshold)</button>
|
|
<button onclick="testAllAndroidRealVersions()">🧪 All Android Real Tests (48 events)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="goTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">🔷 Go SDK Real Version Tests</div>
|
|
<div class="scenario-description">Tests for Insights Go SDK time-based detection using real release data.
|
|
</div>
|
|
|
|
<p><strong>Expected Badge Results:</strong></p>
|
|
<p>✅ Current: v1.6.3 (matches latest)<br>
|
|
🟡 Close enough: v1.6.2 (1 release behind)<br>
|
|
🔴 Outdated: v1.6.0 (3+ releases behind, >48h old)</p>
|
|
|
|
<button onclick="testGoRealCurrentVersion()">✅ Current Go Version (16 events)</button>
|
|
<button onclick="testGoRealCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testGoRealOutdated()">🔴 3+ Releases Behind (16 events)</button>
|
|
<button onclick="testGoEdgeCaseSimplified()">🎯 Go Edge: v1.6.6 (2 Behind, Should Show Close
|
|
Enough)</button>
|
|
|
|
<button onclick="testAllGoRealVersions()">🧪 All Go Real Tests (48 events)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="phpTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">🐘 PHP SDK Simplified Tests</div>
|
|
<div class="scenario-description">
|
|
PHP SDK uses simplified logic: 1-2 releases behind = "Close enough", 3+ = "Outdated" (no time-based
|
|
detection needed)
|
|
</div>
|
|
<div id="php-version-info" class="version-info">Loading PHP version data...</div>
|
|
<button onclick="testPhpCurrentVersion()">✅ Current PHP Version (16 events)</button>
|
|
<button onclick="testPhpCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testPhpTwoReleasesBehind()">🟡 2 Releases Behind (16 events)</button>
|
|
<button onclick="testPhpOutdated()">🔴 3+ Releases Behind (16 events)</button>
|
|
<button onclick="testAllPhpVersions()">🧪 All PHP Tests (64 events)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="rubyTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">💎 Ruby SDK Real Version Tests</div>
|
|
<div class="scenario-description">
|
|
Tests with actual Ruby SDK versions and GitHub API release dates.
|
|
</div>
|
|
<div id="ruby-real-version-info" class="version-info">Loading Ruby version data...</div>
|
|
<button onclick="testRubyRealCurrentVersion()">✅ Current Ruby Version (16 events)</button>
|
|
<button onclick="testRubyRealCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testRubyRealOutdated()">🔴 3+ Releases Behind (16 events)</button>
|
|
<button onclick="testRubyEdgeCase()">🎯 Ruby Edge: v2.7.0 (3 Behind, Test Days - Should be Close Enough
|
|
with adjusted threshold)</button>
|
|
<button onclick="testAllRubyRealVersions()">🧪 All Ruby Real Tests (48 events)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="elixirTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">⚗️ Elixir SDK Simplified Tests</div>
|
|
<div class="scenario-description">
|
|
Elixir SDK uses simplified logic: 1-2 releases behind = "Close enough", 3+ = "Outdated" (no
|
|
time-based detection needed)
|
|
</div>
|
|
<div id="elixir-version-info" class="version-info">Loading Elixir version data...</div>
|
|
<button onclick="testElixirCurrentVersion()">✅ Current Elixir Version (16 events)</button>
|
|
<button onclick="testElixirCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testElixirTwoReleasesBehind()">🟡 2 Releases Behind (16 events)</button>
|
|
<button onclick="testElixirOutdated()">🔴 3+ Releases Behind (16 events)</button>
|
|
<button onclick="testAllElixirVersions()">🧪 All Elixir Tests (64 events)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="dotnetTests" class="sdk-tests" style="display: none;">
|
|
<div class="scenario-group">
|
|
<div class="scenario-title">🔷 .NET SDK Simplified Tests</div>
|
|
<div class="scenario-description">
|
|
.NET SDK uses simplified logic: 1-2 releases behind = "Close enough", 3+ = "Outdated" (no time-based
|
|
detection needed)
|
|
</div>
|
|
<div id="dotnet-version-info" class="version-info">Loading .NET version data...</div>
|
|
<button onclick="testDotnetCurrentVersion()">✅ Current .NET Version (16 events)</button>
|
|
<button onclick="testDotnetCloseEnough()">🟡 1 Release Behind (16 events)</button>
|
|
<button onclick="testDotnetTwoReleasesBehind()">🟡 2 Releases Behind (16 events)</button>
|
|
<button onclick="testDotnetOutdated()">🔴 3+ Releases Behind (16 events)</button>
|
|
<button onclick="testAllDotnetVersions()">🧪 All .NET Tests (64 events)</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div id="log"></div>
|
|
|
|
<script>
|
|
const API_KEY = 'YOUR_INSIGHTS_PROJECT_API_KEY'; // Replace with your Insights project API key (format: phc_...)
|
|
const HOST = 'http://localhost:8010'; // Replace with your Insights instance URL
|
|
let currentApiKey = API_KEY;
|
|
let distinctId = `test-time-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
let currentTest = null;
|
|
let currentSdk = 'web';
|
|
|
|
// Version tracking - will be populated from CHANGELOG.md
|
|
let latestVersion = null; // Will be populated from CHANGELOG.md
|
|
let versions = []; // Array of versions from newest to oldest
|
|
let versionDates = {}; // Map of version -> release date
|
|
let realVersionData = null; // For real CDN version testing
|
|
let pythonVersionData = null; // For Python SDK testing
|
|
let nodeVersionData = null; // For Node.js SDK testing
|
|
let reactNativeVersionData = null; // For React Native SDK testing
|
|
let flutterVersionData = null; // For Flutter SDK testing
|
|
let iosVersionData = null; // For iOS SDK testing
|
|
let androidVersionData = null; // For Android SDK testing
|
|
|
|
// Fetch latest JS SDK versions and dates from CHANGELOG.md
|
|
async function fetchVersionData() {
|
|
try {
|
|
log('🔍 Fetching JS SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/@hanzo/insights/main/packages/browser/CHANGELOG.md', {
|
|
cache: 'no-cache'
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
|
|
const changelog = await response.text();
|
|
|
|
// Parse versions and dates - looking for "## 1.2.3" format
|
|
const versionMatches = changelog.match(/^## (\d+\.\d+\.\d+)$/gm);
|
|
|
|
if (versionMatches && versionMatches.length >= 5) {
|
|
versions = versionMatches
|
|
.map(match => match.replace(/^## /, ''))
|
|
.slice(0, 10); // Get first 10 versions
|
|
|
|
latestVersion = versions[0];
|
|
|
|
// For release dates, we'll simulate realistic dates
|
|
const now = new Date();
|
|
versionDates[versions[0]] = new Date(now.getTime() - (6 * 60 * 60 * 1000)); // 6 hours ago (recent)
|
|
versionDates[versions[1]] = new Date(now.getTime() - (2 * 24 * 60 * 60 * 1000)); // 2 days ago
|
|
versionDates[versions[2]] = new Date(now.getTime() - (1 * 60 * 60 * 1000)); // 1 hour ago (VERY recent for dual check test)
|
|
versionDates[versions[3]] = new Date(now.getTime() - (5 * 24 * 60 * 60 * 1000)); // 5 days ago (old)
|
|
versionDates[versions[4]] = new Date(now.getTime() - (10 * 24 * 60 * 60 * 1000)); // 10 days ago (very old)
|
|
|
|
log(`✅ Latest JS SDK: ${latestVersion}`, 'success');
|
|
log(`📋 Found ${versions.length} versions for testing`, 'info');
|
|
updateVersionDisplay();
|
|
return true;
|
|
} else {
|
|
throw new Error('Could not parse versions from CHANGELOG');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Failed to fetch Web SDK version data: ${error.message}`, 'error');
|
|
log(`❌ Tests cannot run without real version data - no fallbacks used`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Display current API key and version info
|
|
function updateApiKeyDisplay() {
|
|
document.getElementById('apiKeyDisplay').innerHTML = `<code>API Key: ${currentApiKey}</code>`;
|
|
}
|
|
|
|
function updateVersionDisplay() {
|
|
const formatDate = (date) => {
|
|
const hoursAgo = Math.round((Date.now() - date.getTime()) / (1000 * 60 * 60));
|
|
if (hoursAgo < 48) {
|
|
return `${hoursAgo}h ago (RECENT - <48h)`;
|
|
} else {
|
|
const daysAgo = Math.round(hoursAgo / 24);
|
|
return `${daysAgo}d ago (OLD - >48h)`;
|
|
}
|
|
};
|
|
|
|
const versionDisplay = `
|
|
<strong>Test Versions:</strong><br>
|
|
• Latest (${versions[0]}): Released ${formatDate(versionDates[versions[0]])}<br>
|
|
• 1 behind (${versions[1]}): Released ${formatDate(versionDates[versions[1]])}<br>
|
|
• 2 behind (${versions[2]}): Released ${formatDate(versionDates[versions[2]])} 🎯<br>
|
|
• 3 behind (${versions[3]}): Released ${formatDate(versionDates[versions[3]])}<br>
|
|
• 4 behind (${versions[4]}): Released ${formatDate(versionDates[versions[4]])}
|
|
`;
|
|
document.getElementById('versionInfo').innerHTML = versionDisplay;
|
|
}
|
|
|
|
// SDK switching functionality
|
|
function changeSdk() {
|
|
const selector = document.getElementById('sdkSelector');
|
|
const newSdk = selector.value;
|
|
|
|
// Save selection to localStorage
|
|
localStorage.setItem('selectedSdk', newSdk);
|
|
|
|
// Hide all SDK test sections
|
|
document.querySelectorAll('.sdk-tests').forEach(tests => {
|
|
tests.style.display = 'none';
|
|
});
|
|
|
|
// Show selected SDK tests
|
|
document.getElementById(newSdk + 'Tests').style.display = 'block';
|
|
|
|
// Update SDK description
|
|
const descriptions = {
|
|
web: 'Testing Insights Web SDK (@hanzo/insights) with real CDN versions + GitHub API release dates and mock edge cases.',
|
|
python: 'Testing Insights Python SDK with simulated version events. Python events use the $lib: "insights-python" property.',
|
|
node: 'Testing Insights Node.js SDK with simulated version events. Node.js events use the $lib: "@hanzo/insights-node" property.',
|
|
'react-native': 'Testing Insights React Native SDK with real CHANGELOG.md versions + GitHub API release dates. React Native events use the $lib: "@hanzo/insights-react-native" property.',
|
|
flutter: 'Testing Insights Flutter SDK with real CHANGELOG.md versions + GitHub API release dates. Flutter events use the $lib: "insights-flutter" property.',
|
|
ios: 'Testing Insights iOS SDK with real CHANGELOG.md versions + GitHub API release dates. iOS events use the $lib: "insights-ios" property.',
|
|
android: 'Testing Insights Android SDK with real CHANGELOG.md versions + GitHub API release dates. Android events use the $lib: "insights-android" property.',
|
|
go: 'Testing Insights Go SDK with real CHANGELOG.md versions + GitHub API release dates. Go events use the $lib: "insights-go" property.',
|
|
php: 'Testing Insights PHP SDK with simplified logic (no time-based detection). PHP events use the $lib: "insights-php" property.',
|
|
ruby: 'Testing Insights Ruby SDK with real CHANGELOG.md versions + GitHub API release dates. Ruby events use the $lib: "insights-ruby" property and include framework: "Rails".',
|
|
elixir: 'Testing Insights Elixir SDK with simplified logic (no time-based detection). Elixir events use the $lib: "insights-elixir" property and include framework: "Phoenix".',
|
|
dotnet: 'Testing Insights .NET SDK with simplified logic (no time-based detection). .NET events use the $lib: "insights-dotnet" property.'
|
|
};
|
|
|
|
document.getElementById('sdkDescription').innerHTML = `<p><em>${descriptions[newSdk]}</em></p>`;
|
|
currentSdk = newSdk;
|
|
|
|
// Load version data for the selected SDK
|
|
if (newSdk === 'python' && !pythonVersionData) {
|
|
fetchPythonVersionData();
|
|
} else if (newSdk === 'node' && !nodeVersionData) {
|
|
fetchNodeVersionData();
|
|
} else if (newSdk === 'react-native' && !reactNativeVersionData) {
|
|
fetchReactNativeVersionData();
|
|
} else if (newSdk === 'flutter' && !flutterVersionData) {
|
|
fetchFlutterVersionData();
|
|
} else if (newSdk === 'ios' && !iosVersionData) {
|
|
fetchiOSVersionData();
|
|
} else if (newSdk === 'android' && !androidVersionData) {
|
|
fetchAndroidVersionData();
|
|
} else if (newSdk === 'go' && !goVersionData) {
|
|
fetchGoVersionData();
|
|
}
|
|
|
|
// Update version display based on SDK
|
|
if (newSdk === 'web') {
|
|
updateVersionDisplay();
|
|
} else if (newSdk === 'python' && pythonVersionData) {
|
|
updatePythonVersionDisplay();
|
|
} else if (newSdk === 'node' && nodeVersionData) {
|
|
updateNodeVersionDisplay();
|
|
} else if (newSdk === 'flutter' && flutterVersionData) {
|
|
updateFlutterVersionDisplay();
|
|
} else if (newSdk === 'ios' && iosVersionData) {
|
|
updateiOSVersionDisplay();
|
|
} else if (newSdk === 'android' && androidVersionData) {
|
|
updateAndroidVersionDisplay();
|
|
} else if (newSdk === 'go' && goVersionData) {
|
|
updateGoVersionDisplay();
|
|
}
|
|
}
|
|
|
|
// Restore saved SDK selection
|
|
function restoreSavedSdk() {
|
|
const savedSdk = localStorage.getItem('selectedSdk');
|
|
if (savedSdk) {
|
|
const selector = document.getElementById('sdkSelector');
|
|
selector.value = savedSdk;
|
|
currentSdk = savedSdk;
|
|
changeSdk();
|
|
}
|
|
}
|
|
|
|
// Fetch Python SDK versions
|
|
async function fetchPythonVersionData() {
|
|
try {
|
|
log('🐍 Fetching Python SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-python/master/CHANGELOG.md', {
|
|
cache: 'no-cache'
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
|
|
const changelog = await response.text();
|
|
|
|
// Parse Python SDK versions - looking for "# 6.7.5 - 2025-09-16" format
|
|
const versionMatches = changelog.match(/^# (\d+\.\d+\.\d+) - \d{4}-\d{2}-\d{2}$/gm);
|
|
|
|
if (versionMatches && versionMatches.length >= 5) {
|
|
const pythonVersions = versionMatches
|
|
.map(match => match.replace(/^# /, '').replace(/ - \d{4}-\d{2}-\d{2}$/, ''))
|
|
.slice(0, 10); // Get first 10 versions
|
|
|
|
pythonVersionData = {
|
|
latest: pythonVersions[0],
|
|
closeEnough: pythonVersions[1],
|
|
outdated: pythonVersions[6] || pythonVersions[pythonVersions.length - 1],
|
|
versions: pythonVersions
|
|
};
|
|
|
|
// Simulate realistic release dates for Python SDK
|
|
const now = new Date();
|
|
pythonVersionData.versionDates = {};
|
|
pythonVersionData.versionDates[pythonVersions[0]] = new Date(now.getTime() - (12 * 60 * 60 * 1000)); // 12 hours ago
|
|
pythonVersionData.versionDates[pythonVersions[1]] = new Date(now.getTime() - (3 * 24 * 60 * 60 * 1000)); // 3 days ago
|
|
pythonVersionData.versionDates[pythonVersions[2]] = new Date(now.getTime() - (2 * 60 * 60 * 1000)); // 2 hours ago (recent)
|
|
pythonVersionData.versionDates[pythonVersions[3]] = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); // 7 days ago (old)
|
|
|
|
log(`✅ Latest Python SDK: ${pythonVersionData.latest}`, 'success');
|
|
log(`📋 Found ${pythonVersions.length} Python versions for testing`, 'info');
|
|
updatePythonVersionDisplay();
|
|
return true;
|
|
} else {
|
|
throw new Error('Could not parse Python versions from CHANGELOG');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Failed to fetch Python version data: ${error.message}`, 'error');
|
|
log(`❌ Python tests cannot run without real version data - no fallbacks used`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function updatePythonVersionDisplay() {
|
|
if (!pythonVersionData) return;
|
|
|
|
const formatDate = (date) => {
|
|
const hoursAgo = Math.round((Date.now() - date.getTime()) / (1000 * 60 * 60));
|
|
if (hoursAgo < 48) {
|
|
return `${hoursAgo}h ago (RECENT - <48h)`;
|
|
} else {
|
|
const daysAgo = Math.round(hoursAgo / 24);
|
|
return `${daysAgo}d ago (OLD - >48h)`;
|
|
}
|
|
};
|
|
|
|
const versionDisplay = `
|
|
<strong>Python SDK Test Versions:</strong><br>
|
|
• Latest (${pythonVersionData.versions[0]}): Released ${formatDate(pythonVersionData.versionDates[pythonVersionData.versions[0]])}<br>
|
|
• 1 behind (${pythonVersionData.versions[1]}): Released ${formatDate(pythonVersionData.versionDates[pythonVersionData.versions[1]])}<br>
|
|
• 2 behind (${pythonVersionData.versions[2]}): Released ${formatDate(pythonVersionData.versionDates[pythonVersionData.versions[2]])} 🎯<br>
|
|
• 3 behind (${pythonVersionData.versions[3]}): Released ${formatDate(pythonVersionData.versionDates[pythonVersionData.versions[3]])}
|
|
`;
|
|
document.getElementById('versionInfo').innerHTML = versionDisplay;
|
|
|
|
// Update Python real version info display
|
|
document.getElementById('python-real-version-info').innerHTML = `
|
|
<strong>Python Real Versions:</strong><br>
|
|
• Latest: v${pythonVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${pythonVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${pythonVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
|
|
function updateApiKey() {
|
|
const newKey = prompt('Enter new API key:', currentApiKey);
|
|
if (newKey && newKey.trim()) {
|
|
currentApiKey = newKey.trim();
|
|
updateApiKeyDisplay();
|
|
log('API key updated', 'info');
|
|
}
|
|
}
|
|
|
|
function log(message, type = '') {
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
const logElement = document.getElementById('log');
|
|
const className = type ? ` class="${type}"` : '';
|
|
logElement.innerHTML += `<div${className}>[${timestamp}] ${message}</div>`;
|
|
logElement.scrollTop = logElement.scrollHeight;
|
|
}
|
|
|
|
// Initialize Insights with latest version from CDN
|
|
async function initInsights() {
|
|
if (window.insights) {
|
|
window.insights.reset();
|
|
}
|
|
|
|
// Load Insights from local server for SDK testing
|
|
!function (t, e) { var o, n, p, r; e.__SV || (window.insights = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split("."); 2 == o.length && (t = t[o[0]], e = o[1]); t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = "insights", u.people = u.people || [], u.toString = function (t) { var e = "insights"; return "insights" !== a && (e += "." + a), t || (e += " (stub)"), e }, u.people.toString = function () { return u.toString(1) + ".people (stub)" }, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.insights || []);
|
|
|
|
insights.init(currentApiKey, {
|
|
api_host: 'http://localhost:8010',
|
|
debug: true,
|
|
capture_pageview: false,
|
|
disable_session_recording: true,
|
|
autocapture: false
|
|
});
|
|
|
|
insights.identify(distinctId);
|
|
log(`Insights initialized from local server for Web SDK testing`, 'info');
|
|
}
|
|
|
|
// Send test events with specific version
|
|
async function sendTestEvent(version, scenario, eventIndex) {
|
|
try {
|
|
const releaseAge = versionDates[version] ? Math.round((Date.now() - versionDates[version].getTime()) / (1000 * 60 * 60)) : 'unknown';
|
|
|
|
insights.capture('test_time_based_detection', {
|
|
$lib: 'web',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
test_event_index: eventIndex,
|
|
version_release_age_hours: releaseAge,
|
|
$current_url: window.location.href,
|
|
$session_id: `test-session-${scenario}`,
|
|
$device_type: 'Desktop'
|
|
});
|
|
|
|
log(`📤 Sent: v${version} (${releaseAge}h old) - ${scenario}`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
|
|
async function ensureVersionsLoaded() {
|
|
if (versions.length === 0) {
|
|
await fetchVersionData();
|
|
}
|
|
}
|
|
|
|
function clearEvents() {
|
|
distinctId = `test-time-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
currentTest = null;
|
|
initInsights();
|
|
log('🧹 Events cleared (new distinct ID generated)', 'info');
|
|
}
|
|
|
|
// ========== PYTHON SDK TESTING FUNCTIONS ==========
|
|
function initInsightsForPython() {
|
|
if (window.insights) {
|
|
window.insights.reset();
|
|
}
|
|
|
|
!function (t, e) { var o, n, p, r; e.__SV || (window.insights = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split("."); 2 == o.length && (t = t[o[0]], e = o[1]); t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = "insights", u.people = u.people || [], u.toString = function (t) { var e = "insights"; return "insights" !== a && (e += "." + a), t || (e += " (stub)"), e }, u.people.toString = function () { return u.toString(1) + ".people (stub)" }, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.insights || []);
|
|
|
|
insights.init(currentApiKey, {
|
|
api_host: 'http://localhost:8010',
|
|
debug: true,
|
|
capture_pageview: false,
|
|
disable_session_recording: true,
|
|
autocapture: false
|
|
});
|
|
|
|
insights.identify(distinctId);
|
|
}
|
|
|
|
// Send Python SDK test events
|
|
async function sendPythonTestEvent(version, scenario, eventIndex) {
|
|
try {
|
|
const releaseAge = pythonVersionData.versionDates[version] ?
|
|
Math.round((Date.now() - pythonVersionData.versionDates[version].getTime()) / (1000 * 60 * 60)) : 'unknown';
|
|
|
|
insights.capture('test_python_time_based_detection', {
|
|
$lib: 'insights-python',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
test_event_index: eventIndex,
|
|
version_release_age_hours: releaseAge,
|
|
test_sdk_type: 'python',
|
|
$current_url: window.location.href,
|
|
$session_id: `python-test-session-${scenario}`,
|
|
$device_type: 'Server'
|
|
});
|
|
|
|
log(`📤 Sent: Python v${version} (${releaseAge}h old) - ${scenario}`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending Python event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// Python Real Version Tests
|
|
async function testPythonRealCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!pythonVersionData) {
|
|
alert('Python version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'python_real_current';
|
|
|
|
log('✅ Testing REAL Python Current Version...', 'info');
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.latest;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_real_current_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Python real current test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (Python version matches latest)`, 'info');
|
|
}
|
|
|
|
async function testPythonRealCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!pythonVersionData) {
|
|
alert('Python version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'python_real_close_enough';
|
|
|
|
log('🟡 Testing REAL Python Close Enough Version...', 'info');
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_real_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Python real close enough test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (1 release behind)`, 'info');
|
|
}
|
|
|
|
async function testPythonRealOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!pythonVersionData) {
|
|
alert('Python version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'python_real_outdated';
|
|
|
|
log('🔴 Testing REAL Python Outdated Version...', 'info');
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_real_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Python real outdated test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (6+ releases behind but within 90 day threshold)`, 'info');
|
|
}
|
|
|
|
async function testPythonEdgeCase672() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'python_edge_672';
|
|
|
|
log('🎯 Testing Python Edge Case: v6.7.2 (3 Behind, 13 Days - Should be Close Enough with 15-day threshold)...', 'info');
|
|
log('📡 Using REAL GitHub API data - no mocks!', 'info');
|
|
|
|
await fetchPythonVersionData(); // Ensure we have version data
|
|
initInsightsForPython();
|
|
|
|
const testVersion = '6.7.2'; // Real version 3 releases behind
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(testVersion, 'python_edge_case_672', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Python REAL edge case test complete: 16 events with v${testVersion}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (3 behind but real GitHub date within adjusted 15-day threshold)`, 'info');
|
|
log(`⚠️ Note: This test uses temporarily adjusted threshold (15 days instead of 48h)`, 'warning');
|
|
log(`📊 SDK Doctor will use REAL GitHub API data for time-based detection`, 'info');
|
|
}
|
|
|
|
async function testAllPythonRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_python_real_versions';
|
|
|
|
log('🧪 Testing all REAL Python versions...', 'info');
|
|
|
|
await testPythonRealCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testPythonRealCloseEnoughInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testPythonRealOutdatedInternal();
|
|
|
|
log('🎉 All REAL Python version tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for Python SDK detection results', 'info');
|
|
}
|
|
|
|
// Internal Python real version test functions
|
|
async function testPythonRealCurrentVersionInternal() {
|
|
if (!pythonVersionData) return;
|
|
log('✅ Testing REAL Python Current (internal)...', 'info');
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.latest;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_real_current_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testPythonRealCloseEnoughInternal() {
|
|
if (!pythonVersionData) return;
|
|
log('🟡 Testing REAL Python Close Enough (internal)...', 'info');
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_real_close_enough_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testPythonRealOutdatedInternal() {
|
|
if (!pythonVersionData) return;
|
|
log('🔴 Testing REAL Python Outdated (internal)...', 'info');
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_real_outdated_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// Python Mock Edge Case Tests
|
|
async function testPythonMockDualCheckRecent() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'python_mock_dual_recent';
|
|
|
|
log('🎯 Testing PYTHON Mock Dual Check - Recent 2+ Releases Behind...', 'info');
|
|
await fetchPythonVersionData();
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.versions[2]; // 2 releases behind, but released recently
|
|
const ageHours = Math.round((Date.now() - pythonVersionData.versionDates[version].getTime()) / (1000 * 60 * 60));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_mock_dual_check_recent', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ PYTHON MOCK dual check (recent) test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Python test: v${version} is 2 releases behind but only ${ageHours}h old (<48h)`, 'info');
|
|
log(`🔍 Expected: "Close enough" badge (time override working!)`, 'info');
|
|
}
|
|
|
|
async function testPythonMockDualCheckOld() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'python_mock_dual_old';
|
|
|
|
log('🔴 Testing PYTHON Mock Dual Check - Old 2+ Releases Behind...', 'info');
|
|
await fetchPythonVersionData();
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.versions[3]; // 3 releases behind and old
|
|
const ageHours = Math.round((Date.now() - pythonVersionData.versionDates[version].getTime()) / (1000 * 60 * 60));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_mock_dual_check_old', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ PYTHON MOCK dual check (old) test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Python comparison: v${version} is 3 releases behind and ${ageHours}h old (>48h)`, 'info');
|
|
log(`🔍 Expected: "Outdated" badge (dual check failed)`, 'info');
|
|
}
|
|
|
|
async function testPythonMockExtreme() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'python_mock_extreme';
|
|
|
|
log('⚠️ Testing PYTHON Mock Extreme Edge Case...', 'info');
|
|
initInsightsForPython();
|
|
|
|
// Create an extreme edge case for Python - exactly 2 releases behind and exactly 48h old
|
|
const extremeVersion = '6.999.0';
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
try {
|
|
insights.capture('test_python_mock_extreme_edge_case', {
|
|
$lib: 'insights-python',
|
|
$lib_version: extremeVersion,
|
|
test_scenario: 'python_mock_extreme_edge_case',
|
|
test_event_index: i,
|
|
test_type: 'python_mock_version',
|
|
version_release_age_hours: 48, // Exactly 48 hours
|
|
mock_version_details: 'Python: 2 releases behind, exactly 48h old',
|
|
$current_url: window.location.href,
|
|
$session_id: `python-mock-extreme-session`,
|
|
$device_type: 'Server'
|
|
});
|
|
|
|
log(`📤 Sent: PYTHON MOCK v${extremeVersion} (exactly 48h old) - extreme edge case`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending Python event: ${error.message}`, 'error');
|
|
}
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ PYTHON MOCK extreme edge case test complete: 16 events`, 'success');
|
|
log(`🔍 Python edge case: v${extremeVersion} is exactly 2 releases behind and exactly 48h old`, 'info');
|
|
log(`🔍 Expected: "Outdated" badge (boundary case - 48h is NOT <48h)`, 'info');
|
|
}
|
|
|
|
async function testAllPythonMockScenarios() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_python_mock_scenarios';
|
|
|
|
log('🧪 Testing all PYTHON mock edge case scenarios...', 'info');
|
|
|
|
await testPythonMockDualCheckRecentInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testPythonMockDualCheckOldInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testPythonMockExtremeInternal();
|
|
|
|
log('🎉 All PYTHON mock edge case tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for Python edge case detection results', 'info');
|
|
}
|
|
|
|
// Internal Python mock test functions
|
|
async function testPythonMockDualCheckRecentInternal() {
|
|
log('🎯 PYTHON Mock Dual Check Recent (internal)...', 'info');
|
|
await fetchPythonVersionData();
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.versions[2];
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_mock_dual_recent_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testPythonMockDualCheckOldInternal() {
|
|
log('🔴 PYTHON Mock Dual Check Old (internal)...', 'info');
|
|
await fetchPythonVersionData();
|
|
initInsightsForPython();
|
|
|
|
const version = pythonVersionData.versions[3];
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPythonTestEvent(version, 'python_mock_dual_old_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testPythonMockExtremeInternal() {
|
|
log('⚠️ PYTHON Mock Extreme Edge Case (internal)...', 'info');
|
|
initInsightsForPython();
|
|
|
|
const extremeVersion = '6.999.0';
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('test_python_mock_extreme_internal', {
|
|
$lib: 'insights-python',
|
|
$lib_version: extremeVersion,
|
|
test_scenario: 'python_mock_extreme_internal',
|
|
test_event_index: i,
|
|
test_type: 'python_mock_version',
|
|
version_release_age_hours: 48,
|
|
$session_id: `python-mock-extreme-internal`,
|
|
$device_type: 'Server'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// Test Python SDK with real version 6.7.2 for time-based detection
|
|
async function testPythonRealTimeBasedDetection() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'python_real_time_based';
|
|
|
|
log('⏰ Testing PYTHON Real Time-Based Detection with v6.7.2...', 'info');
|
|
log('📅 Real release date: Sept 3, 2025 (13 days ago)', 'info');
|
|
log('🎯 Expected: Should show "Close enough" with 15-day threshold, "Outdated" with 48h threshold', 'info');
|
|
|
|
initInsightsForPython();
|
|
|
|
// Use real Python version 6.7.2 (released Sept 3, 2025 - 13 days ago)
|
|
// This is 3 releases behind 6.7.5 and 13 days old
|
|
const realTestVersion = '6.7.2';
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
try {
|
|
insights.capture('test_python_real_time_based_detection', {
|
|
$lib: 'insights-python',
|
|
$lib_version: realTestVersion,
|
|
test_scenario: 'python_real_time_based_detection',
|
|
test_event_index: i,
|
|
test_type: 'real_version_time_test',
|
|
real_release_date: '2025-09-03T20:03:06Z',
|
|
releases_behind: 3,
|
|
days_since_release: 13,
|
|
testing_threshold_logic: true,
|
|
$current_url: window.location.href,
|
|
$session_id: `python-real-time-test-session`,
|
|
$device_type: 'Server'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
} catch (error) {
|
|
log(`❌ Error sending Python real time test event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
log(`✅ Python Real Time Test complete! Sent 16 events with v${realTestVersion}`, 'success');
|
|
log('🔍 SDK Doctor will use REAL GitHub API data for this version', 'info');
|
|
log('📊 Check SDK Doctor for time-based detection results', 'info');
|
|
}
|
|
|
|
// ========== REACT NATIVE SDK TESTING FUNCTIONS ==========
|
|
|
|
// Fetch React Native SDK versions
|
|
async function fetchReactNativeVersionData() {
|
|
try {
|
|
log('📱 Fetching React Native SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/@hanzo/insights/main/packages/react-native/CHANGELOG.md');
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const text = await response.text();
|
|
|
|
// Parse React Native SDK versions - format: "## 4.5.1" (no date in header)
|
|
const versionRegex = /^## (\d+\.\d+\.\d+)$/gm;
|
|
const versions = [];
|
|
let match;
|
|
|
|
while ((match = versionRegex.exec(text)) !== null) {
|
|
versions.push(match[1]);
|
|
}
|
|
|
|
if (versions.length >= 3) {
|
|
reactNativeVersionData = {
|
|
latest: versions[0], // Current version
|
|
closeEnough: versions[1], // 1 release behind
|
|
outdated: versions[6] || versions[versions.length - 1], // 6+ releases behind
|
|
versions: versions
|
|
};
|
|
|
|
// Simulate realistic release dates for React Native SDK
|
|
const now = new Date();
|
|
reactNativeVersionData.versionDates = {};
|
|
reactNativeVersionData.versionDates[versions[0]] = new Date(now.getTime() - (1 * 24 * 60 * 60 * 1000)); // 1 day ago
|
|
reactNativeVersionData.versionDates[versions[1]] = new Date(now.getTime() - (20 * 24 * 60 * 60 * 1000)); // 20 days ago
|
|
reactNativeVersionData.versionDates[versions[2]] = new Date(now.getTime() - (2 * 60 * 60 * 1000)); // 2 hours ago (recent)
|
|
reactNativeVersionData.versionDates[versions[3]] = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); // 7 days ago (old)
|
|
|
|
log(`✅ Latest React Native SDK: ${reactNativeVersionData.latest}`, 'success');
|
|
updateReactNativeVersionDisplay();
|
|
} else {
|
|
throw new Error(`Insufficient React Native SDK versions found: ${versions.length}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch React Native versions:', error);
|
|
log(`❌ Failed to load React Native SDK versions: ${error.message}`, 'error');
|
|
|
|
log(`❌ React Native tests cannot run without real version data - no fallbacks used`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function updateReactNativeVersionDisplay() {
|
|
if (!reactNativeVersionData) return;
|
|
|
|
const formatDate = (date) => {
|
|
const hoursAgo = Math.round((Date.now() - date.getTime()) / (1000 * 60 * 60));
|
|
if (hoursAgo < 48) {
|
|
return `${hoursAgo}h ago (RECENT - <48h)`;
|
|
} else {
|
|
const daysAgo = Math.round(hoursAgo / 24);
|
|
return `${daysAgo}d ago (OLD - >48h)`;
|
|
}
|
|
};
|
|
|
|
const versionInfoElement = document.getElementById('version-info');
|
|
if (versionInfoElement) {
|
|
versionInfoElement.innerHTML = `
|
|
<strong>React Native SDK Test Versions:</strong><br>
|
|
• Latest (${reactNativeVersionData.versions[0]}): Released ${formatDate(reactNativeVersionData.versionDates[reactNativeVersionData.versions[0]])}<br>
|
|
• 1 behind (${reactNativeVersionData.versions[1]}): Released ${formatDate(reactNativeVersionData.versionDates[reactNativeVersionData.versions[1]])}<br>
|
|
• 2 behind (${reactNativeVersionData.versions[2]}): Released ${formatDate(reactNativeVersionData.versionDates[reactNativeVersionData.versions[2]])} 🎯<br>
|
|
• 3 behind (${reactNativeVersionData.versions[3]}): Released ${formatDate(reactNativeVersionData.versionDates[reactNativeVersionData.versions[3]])}
|
|
`;
|
|
}
|
|
|
|
// Update React Native real version info display (only if element exists)
|
|
const reactNativeRealVersionInfoElement = document.getElementById('react-native-real-version-info');
|
|
if (reactNativeRealVersionInfoElement) {
|
|
reactNativeRealVersionInfoElement.innerHTML = `
|
|
<strong>React Native Real Versions:</strong><br>
|
|
• Latest: v${reactNativeVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${reactNativeVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${reactNativeVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
}
|
|
|
|
function initInsightsForReactNative() {
|
|
if (window.insights) {
|
|
window.insights.reset();
|
|
}
|
|
|
|
// Initialize Insights normally (we'll simulate React Native events)
|
|
!function (t, e) { var o, n, p, r; e.__SV || (window.insights = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split("."); 2 == o.length && (t = t[o[0]], e = o[1]); t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = "insights", u.people = u.people || [], u.toString = function (t) { var e = "insights"; return "insights" !== a && (e += "." + a), t || (e += " (stub)"), e }, u.people.toString = function () { return u.toString(1) + ".people (stub)" }, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.insights || []);
|
|
|
|
insights.init(currentApiKey, {
|
|
api_host: HOST,
|
|
debug: true,
|
|
capture_pageview: false,
|
|
disable_session_recording: true,
|
|
autocapture: false
|
|
});
|
|
|
|
insights.identify(distinctId);
|
|
}
|
|
|
|
// Send React Native SDK test events
|
|
async function sendReactNativeTestEvent(version, scenario, eventIndex) {
|
|
try {
|
|
const releaseAge = reactNativeVersionData.versionDates[version] ?
|
|
Math.round((Date.now() - reactNativeVersionData.versionDates[version].getTime()) / (1000 * 60 * 60)) : 'unknown';
|
|
|
|
const eventData = {
|
|
$lib: '@hanzo/insights-react-native',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
test_event_index: eventIndex,
|
|
version_release_age_hours: releaseAge,
|
|
test_sdk_type: 'react-native',
|
|
$current_url: window.location.href,
|
|
$session_id: `react-native-test-session-${scenario}`,
|
|
$device_type: 'Mobile'
|
|
};
|
|
|
|
console.log(`[React Native Test] Event ${eventIndex}: $lib_version = "${version}"`, eventData);
|
|
insights.capture('test_react_native_time_based_detection', eventData);
|
|
|
|
log(`📤 Sent: React Native v${version} (${releaseAge}h old) - ${scenario}`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending React Native event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// React Native SDK Test Functions
|
|
async function testReactNativeCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'react_native_current';
|
|
|
|
await fetchReactNativeVersionData();
|
|
initInsightsForReactNative();
|
|
|
|
const version = reactNativeVersionData.latest;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendReactNativeTestEvent(version, 'react_native_current_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testReactNativeCloseEnoughVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'react_native_close_enough';
|
|
|
|
await fetchReactNativeVersionData();
|
|
initInsightsForReactNative();
|
|
|
|
const version = reactNativeVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendReactNativeTestEvent(version, 'react_native_close_enough_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testReactNativeOutdatedVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'react_native_outdated';
|
|
|
|
await fetchReactNativeVersionData();
|
|
initInsightsForReactNative();
|
|
|
|
const version = reactNativeVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendReactNativeTestEvent(version, 'react_native_outdated_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testReactNativeEdgeCase443() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'react_native_edge_443';
|
|
log('🎯 Testing REACT NATIVE Edge Case: v4.4.3 (3 Behind, 20 Days)...', 'info');
|
|
log('⏰ This version should show "Close enough" with adjusted threshold, "Outdated" with 48h threshold', 'info');
|
|
initInsightsForReactNative();
|
|
const version = '4.4.3';
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendReactNativeTestEvent(version, 'react_native_edge_443', i);
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
log(`✅ React Native edge case test complete: 16 events with v${version}`, 'success');
|
|
log(`📊 v4.4.3 released Aug 27 (20 days ago), 3 releases behind v4.5.1`, 'info');
|
|
log(`🔍 Expected: "Close enough" (with wide threshold) or "Outdated" (with 48h threshold)`, 'info');
|
|
}
|
|
|
|
async function testAllReactNativeRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_react_native_real_versions';
|
|
|
|
log('🧪 Testing all REACT NATIVE real version scenarios...', 'info');
|
|
|
|
await testReactNativeCurrentVersion();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testReactNativeCloseEnoughVersion();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testReactNativeOutdatedVersion();
|
|
|
|
log('🎉 All React Native real version tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for React Native detection results', 'info');
|
|
}
|
|
|
|
// React Native Mock Edge Case Tests (placeholders - can be implemented later)
|
|
async function testReactNativeMockDualCheckRecent() {
|
|
alert('React Native mock tests coming soon...');
|
|
}
|
|
|
|
async function testReactNativeMockDualCheckOld() {
|
|
alert('React Native mock tests coming soon...');
|
|
}
|
|
|
|
async function testReactNativeMockExtreme() {
|
|
alert('React Native mock tests coming soon...');
|
|
}
|
|
|
|
async function testAllReactNativeMockScenarios() {
|
|
alert('React Native mock tests coming soon...');
|
|
}
|
|
|
|
// Test React Native SDK with real version 4.5.0 for time-based detection
|
|
async function testReactNativeRealTimeBasedDetection() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'react_native_real_time_based';
|
|
|
|
log('⏰ Testing REACT NATIVE Real Time-Based Detection with v4.5.0...', 'info');
|
|
log('📅 Real release date: Aug 27, 2025 (20 days ago)', 'info');
|
|
log('🎯 Expected: Should show "Close enough" with 25-day threshold, "Outdated" with 48h threshold', 'info');
|
|
|
|
initInsightsForReactNative();
|
|
|
|
// Use real React Native version 4.5.0 (released Aug 27, 2025 - 20 days ago)
|
|
// This is 1 release behind 4.5.1 and 20 days old - good for testing
|
|
const realTestVersion = '4.5.0';
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
try {
|
|
insights.capture('test_react_native_real_time_based_detection', {
|
|
$lib: '@hanzo/insights-react-native',
|
|
$lib_version: realTestVersion,
|
|
test_scenario: 'react_native_real_time_based_detection',
|
|
test_event_index: i,
|
|
test_type: 'real_version_time_test',
|
|
real_release_date: '2025-08-27T09:57:19Z',
|
|
releases_behind: 1,
|
|
days_since_release: 20,
|
|
testing_threshold_logic: true,
|
|
$current_url: window.location.href,
|
|
$session_id: `react-native-real-time-test-session`,
|
|
$device_type: 'Mobile'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
} catch (error) {
|
|
log(`❌ Error sending React Native real time test event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
log(`✅ React Native Real Time Test complete! Sent 16 events with v${realTestVersion}`, 'success');
|
|
log('🔍 SDK Doctor will use REAL GitHub API data for this version', 'info');
|
|
log('📊 Check SDK Doctor for time-based detection results', 'info');
|
|
}
|
|
|
|
// ========== FLUTTER SDK TESTING FUNCTIONS ==========
|
|
|
|
// Fetch Flutter SDK versions
|
|
async function fetchFlutterVersionData() {
|
|
try {
|
|
log('🦋 Fetching Flutter SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-flutter/main/CHANGELOG.md', {
|
|
cache: 'no-cache'
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
|
|
const changelog = await response.text();
|
|
|
|
// Parse Flutter SDK versions - looking for "## 5.5.0" format
|
|
const versionMatches = changelog.match(/^## (\d+\.\d+\.\d+)$/gm);
|
|
|
|
if (versionMatches && versionMatches.length >= 5) {
|
|
const flutterVersions = versionMatches
|
|
.map(match => match.replace('## ', ''))
|
|
.filter(v => /^\d+\.\d+\.\d+$/.test(v));
|
|
|
|
flutterVersionData = {
|
|
latest: flutterVersions[0],
|
|
closeEnough: flutterVersions[1],
|
|
outdated: flutterVersions[4] || flutterVersions[flutterVersions.length - 1],
|
|
versions: flutterVersions
|
|
};
|
|
|
|
// Simulate realistic release dates for Flutter SDK
|
|
const now = new Date();
|
|
flutterVersionData.versionDates = {};
|
|
flutterVersionData.versionDates[flutterVersions[0]] = new Date(now.getTime() - (12 * 60 * 60 * 1000)); // 12 hours ago
|
|
flutterVersionData.versionDates[flutterVersions[1]] = new Date(now.getTime() - (36 * 60 * 60 * 1000)); // 36 hours ago (recent)
|
|
flutterVersionData.versionDates[flutterVersions[2]] = new Date(now.getTime() - (3 * 24 * 60 * 60 * 1000)); // 3 days ago
|
|
flutterVersionData.versionDates[flutterVersions[3]] = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); // 7 days ago (old)
|
|
|
|
log(`✅ Latest Flutter SDK: ${flutterVersionData.latest}`, 'success');
|
|
log(`📋 Found ${flutterVersions.length} Flutter versions for testing`, 'info');
|
|
updateFlutterVersionDisplay();
|
|
return true;
|
|
} else {
|
|
throw new Error('Could not parse Flutter versions from CHANGELOG');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Failed to fetch Flutter version data: ${error.message}`, 'error');
|
|
log(`❌ Flutter tests cannot run without real version data - no fallbacks used`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function updateFlutterVersionDisplay() {
|
|
if (!flutterVersionData) return;
|
|
|
|
const formatDate = (date) => {
|
|
if (!date) return 'Unknown';
|
|
const hoursAgo = Math.round((Date.now() - date.getTime()) / (1000 * 60 * 60));
|
|
if (hoursAgo < 24) return `${hoursAgo}h ago`;
|
|
const daysAgo = Math.round(hoursAgo / 24);
|
|
return `${daysAgo}d ago`;
|
|
};
|
|
|
|
// Flutter Real version info display
|
|
document.getElementById('flutter-real-version-info').innerHTML = `
|
|
<strong>Flutter Real Versions:</strong><br>
|
|
• Latest: v${flutterVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${flutterVersionData.closeEnough} (Close enough)<br>
|
|
• 4+ Behind: v${flutterVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
|
|
// Initialize Insights for Flutter testing
|
|
function initInsightsForFlutter() {
|
|
if (window.insights) {
|
|
window.insights.reset();
|
|
}
|
|
|
|
!function (t, e) { var o, n, p, r; e.__SV || (window.insights = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split("."); 2 == o.length && (t = t[o[0]], e = o[1]); t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = "insights", u.people = u.people || [], u.toString = function (t) { var e = "insights"; return "insights" !== a && (e += "." + a), t || (e += " (stub)"), e }, u.people.toString = function () { return u.toString(1) + ".people (stub)" }, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.insights || []);
|
|
|
|
insights.init(currentApiKey, {
|
|
api_host: 'http://localhost:8010',
|
|
ui_host: 'http://localhost:8010'
|
|
});
|
|
}
|
|
|
|
// Send Flutter SDK test events
|
|
async function sendFlutterTestEvent(version, scenario, eventIndex) {
|
|
try {
|
|
const releaseAge = flutterVersionData.versionDates[version] ?
|
|
Math.round((Date.now() - flutterVersionData.versionDates[version].getTime()) / (1000 * 60 * 60)) : 'unknown';
|
|
|
|
insights.capture('flutter_test_event', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
event_index: eventIndex,
|
|
event_id: `flutter_${scenario}_${eventIndex}_${Date.now()}`,
|
|
test_timestamp: new Date().toISOString(),
|
|
release_age_hours: releaseAge
|
|
});
|
|
|
|
log(`📤 Sent: Flutter v${version} (${releaseAge}h old) - ${scenario}`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending Flutter event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// Flutter Real Version Tests
|
|
async function testFlutterCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_current';
|
|
|
|
if (!realVersionData) {
|
|
alert('Real Insights-js version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
|
|
await fetchFlutterVersionData();
|
|
|
|
// Use current @hanzo/insights version like Web SDK tests
|
|
loadInsightsVersion('latest', async (error) => {
|
|
if (error) {
|
|
log(`❌ Error loading current Insights for Flutter tests: ${error.message}`, 'error');
|
|
return;
|
|
}
|
|
log(`✅ Flutter tests using current Insights-js v${realVersionData.latest}`, 'success');
|
|
|
|
const version = flutterVersionData.latest;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendFlutterTestEvent(version, 'flutter_current_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter current test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (Flutter version matches latest)`, 'info');
|
|
});
|
|
}
|
|
|
|
async function testFlutterCloseEnoughVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_close_enough';
|
|
|
|
if (!realVersionData) {
|
|
alert('Real Insights-js version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
|
|
await fetchFlutterVersionData();
|
|
|
|
// Use current @hanzo/insights version like Web SDK tests
|
|
loadInsightsVersion('latest', async (error) => {
|
|
if (error) {
|
|
log(`❌ Error loading current Insights for Flutter tests: ${error.message}`, 'error');
|
|
return;
|
|
}
|
|
log(`✅ Flutter tests using current Insights-js v${realVersionData.latest}`, 'success');
|
|
|
|
const version = flutterVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendFlutterTestEvent(version, 'flutter_close_enough_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter close enough test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (1 release behind)`, 'info');
|
|
});
|
|
}
|
|
|
|
async function testFlutterOutdatedVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_outdated';
|
|
|
|
if (!realVersionData) {
|
|
alert('Real Insights-js version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
|
|
await fetchFlutterVersionData();
|
|
|
|
// Use current @hanzo/insights version like Web SDK tests
|
|
loadInsightsVersion('latest', async (error) => {
|
|
if (error) {
|
|
log(`❌ Error loading current Insights for Flutter tests: ${error.message}`, 'error');
|
|
return;
|
|
}
|
|
log(`✅ Flutter tests using current Insights-js v${realVersionData.latest}`, 'success');
|
|
|
|
const version = flutterVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendFlutterTestEvent(version, 'flutter_outdated_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter outdated test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (4+ releases behind)`, 'info');
|
|
});
|
|
}
|
|
|
|
async function testAllFlutterRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
|
|
log('🧪 Testing all REAL Flutter versions...', 'info');
|
|
|
|
await testFlutterCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testFlutterCloseEnoughVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testFlutterOutdatedVersionInternal();
|
|
|
|
log('🎉 All REAL Flutter version tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for Flutter SDK detection results', 'info');
|
|
}
|
|
|
|
// Internal Flutter real version test functions
|
|
async function testFlutterCurrentVersionInternal() {
|
|
if (!flutterVersionData) return;
|
|
log('✅ Testing REAL Flutter Current (internal)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const version = flutterVersionData.latest;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendFlutterTestEvent(version, 'flutter_current_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testFlutterCloseEnoughVersionInternal() {
|
|
if (!flutterVersionData) return;
|
|
log('🟡 Testing REAL Flutter Close Enough (internal)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const version = flutterVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendFlutterTestEvent(version, 'flutter_close_enough_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testFlutterOutdatedVersionInternal() {
|
|
if (!flutterVersionData) return;
|
|
log('🔴 Testing REAL Flutter Outdated (internal)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const version = flutterVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendFlutterTestEvent(version, 'flutter_outdated_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// Flutter Mock Edge Case Tests
|
|
async function testFlutterMockDualCheckRecent() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_mock_dual_recent';
|
|
|
|
log('🎯 Testing Flutter Mock: 2 Behind + Recent (should be Close enough)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const mockVersion = '5.3.0'; // 2 releases behind
|
|
const recentDate = new Date(Date.now() - (2 * 60 * 60 * 1000)); // 2 hours ago (recent)
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_mock_dual_recent', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: mockVersion,
|
|
test_scenario: 'flutter_mock_dual_check_recent',
|
|
event_index: i,
|
|
release_age_hours: 2,
|
|
mock_release_date: recentDate.toISOString()
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter mock dual check recent complete: 16 events with v${mockVersion} (2h old)`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (2 behind but recent release)`, 'info');
|
|
}
|
|
|
|
async function testFlutterMockDualCheckOld() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_mock_dual_old';
|
|
|
|
log('🔴 Testing Flutter Mock: 2 Behind + Old (should be Outdated)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const mockVersion = '5.3.0'; // 2 releases behind
|
|
const oldDate = new Date(Date.now() - (4 * 24 * 60 * 60 * 1000)); // 4 days ago (old)
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_mock_dual_old', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: mockVersion,
|
|
test_scenario: 'flutter_mock_dual_check_old',
|
|
event_index: i,
|
|
release_age_hours: 96, // 4 days
|
|
mock_release_date: oldDate.toISOString()
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter mock dual check old complete: 16 events with v${mockVersion} (96h old)`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (2 behind and old release)`, 'info');
|
|
}
|
|
|
|
async function testFlutterMockExtreme() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_mock_extreme';
|
|
|
|
log('⚠️ Testing Flutter Mock: Extreme Edge Case...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const mockVersion = '4.0.0'; // Very old version
|
|
const veryOldDate = new Date(Date.now() - (30 * 24 * 60 * 60 * 1000)); // 30 days ago
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_mock_extreme', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: mockVersion,
|
|
test_scenario: 'flutter_mock_extreme_edge_case',
|
|
event_index: i,
|
|
release_age_hours: 720, // 30 days
|
|
mock_release_date: veryOldDate.toISOString()
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter mock extreme test complete: 16 events with v${mockVersion} (720h old)`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (extremely old version)`, 'info');
|
|
}
|
|
|
|
async function testFlutterRealTimeBasedDetection() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_real_time_based';
|
|
|
|
log('⏰ Testing Flutter Real Time-Based: v5.4.0 (3 Behind, 20 Days Old)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const testVersion = '5.4.0'; // Should be 3+ releases behind current
|
|
const twentyDaysAgo = new Date(Date.now() - (20 * 24 * 60 * 60 * 1000));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_real_time_based', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: testVersion,
|
|
test_scenario: 'flutter_real_time_based_detection',
|
|
event_index: i,
|
|
release_age_hours: 480, // 20 days
|
|
mock_release_date: twentyDaysAgo.toISOString()
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter real time-based test complete: 16 events with v${testVersion} (480h old)`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (3+ behind and >48h old)`, 'info');
|
|
}
|
|
|
|
async function testFlutterEdgeCase542() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'flutter_edge_542';
|
|
|
|
log('🎯 Testing Flutter REAL Edge Case: v5.4.2 (3 Behind, 9 Days - Should be Close Enough with adjusted threshold)...', 'info');
|
|
log('📡 Using REAL GitHub API data - no mocks!', 'info');
|
|
|
|
await fetchFlutterVersionData(); // Ensure we have real version data
|
|
initInsightsForFlutter();
|
|
|
|
const testVersion = '5.4.2'; // Real version from Flutter releases
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_real_edge_case_542', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: testVersion,
|
|
test_scenario: 'flutter_real_edge_case_542',
|
|
event_index: i,
|
|
event_id: `flutter_real_edge_${i}_${Date.now()}`,
|
|
test_timestamp: new Date().toISOString(),
|
|
test_note: 'Real v5.4.2 with adjusted 10-day threshold - SDK Doctor will fetch real GitHub dates'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Flutter REAL edge case test complete: 16 events with v${testVersion}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (3 behind but real GitHub date within adjusted 10-day threshold)`, 'info');
|
|
log(`⚠️ Note: This test uses temporarily adjusted threshold (10 days instead of 48h)`, 'warning');
|
|
log(`📊 SDK Doctor will use REAL GitHub API data for time-based detection`, 'info');
|
|
}
|
|
|
|
async function testAllFlutterMockScenarios() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
|
|
log('🧪 Testing all Flutter Mock scenarios...', 'info');
|
|
|
|
await testFlutterMockDualCheckRecentInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testFlutterMockDualCheckOldInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testFlutterMockExtremeInternal();
|
|
|
|
log('🎉 All Flutter Mock scenario tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for Flutter SDK detection results', 'info');
|
|
}
|
|
|
|
// Internal Flutter mock test functions
|
|
async function testFlutterMockDualCheckRecentInternal() {
|
|
log('🎯 Testing Flutter Mock Dual Recent (internal)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const mockVersion = '5.3.0';
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_mock_dual_recent_internal', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: mockVersion,
|
|
test_scenario: 'flutter_mock_dual_recent_internal',
|
|
event_index: i,
|
|
release_age_hours: 2
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testFlutterMockDualCheckOldInternal() {
|
|
log('🔴 Testing Flutter Mock Dual Old (internal)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const mockVersion = '5.3.0';
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_mock_dual_old_internal', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: mockVersion,
|
|
test_scenario: 'flutter_mock_dual_old_internal',
|
|
event_index: i,
|
|
release_age_hours: 96
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testFlutterMockExtremeInternal() {
|
|
log('⚠️ Testing Flutter Mock Extreme (internal)...', 'info');
|
|
initInsightsForFlutter();
|
|
|
|
const mockVersion = '4.0.0';
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('flutter_mock_extreme_internal', {
|
|
$lib: 'insights-flutter',
|
|
$lib_version: mockVersion,
|
|
test_scenario: 'flutter_mock_extreme_internal',
|
|
event_index: i,
|
|
release_age_hours: 720
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// ========== iOS SDK TESTING FUNCTIONS ==========
|
|
|
|
// Fetch iOS SDK versions
|
|
async function fetchiOSVersionData() {
|
|
try {
|
|
log('📱 Fetching iOS SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-ios/main/CHANGELOG.md');
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch: ${response.status}`);
|
|
}
|
|
|
|
const text = await response.text();
|
|
|
|
// Parse iOS SDK versions - format: "## 3.30.1 - 2025-08-12" (skip "## Next" section)
|
|
const versionMatches = text.match(/^## (\d+\.\d+\.\d+) - \d{4}-\d{2}-\d{2}$/gm);
|
|
|
|
if (versionMatches && versionMatches.length >= 5) {
|
|
const iosVersions = versionMatches
|
|
.map(match => match.replace(/^## /, '').replace(/ - \d{4}-\d{2}-\d{2}$/, ''))
|
|
.slice(0, 10); // Get first 10 versions
|
|
|
|
iosVersionData = {
|
|
latest: iosVersions[0],
|
|
closeEnough: iosVersions[1],
|
|
outdated: iosVersions[6] || iosVersions[iosVersions.length - 1],
|
|
all: iosVersions
|
|
};
|
|
|
|
log(`✅ iOS SDK latest: ${iosVersionData.latest}`, 'success');
|
|
log(`🔍 iOS SDK outdated test: ${iosVersionData.outdated}`, 'info');
|
|
|
|
// Update iOS version info display
|
|
document.getElementById('ios-real-version-info').innerHTML = `
|
|
<strong>iOS Versions:</strong><br>
|
|
• Latest: v${iosVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${iosVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${iosVersionData.outdated} (Outdated)
|
|
`;
|
|
|
|
return true;
|
|
} else {
|
|
throw new Error('Could not parse iOS versions');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Failed to fetch iOS version data: ${error.message}`, 'error');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// iOS test functions
|
|
async function testiOSRealCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ios_current';
|
|
|
|
log('📱 Testing iOS Current Version...', 'info');
|
|
await ensureiOSVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('ios_current_version_test', {
|
|
$lib: 'insights-ios',
|
|
$lib_version: iosVersionData.latest,
|
|
test_scenario: 'ios_current',
|
|
event_index: i,
|
|
$session_id: `ios-current-${Date.now()}`,
|
|
$device_type: 'iPhone'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ iOS current version test complete: 16 events with v${iosVersionData.latest}`, 'success');
|
|
}
|
|
|
|
async function testiOSRealCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ios_close_enough';
|
|
|
|
log('📱 Testing iOS Close Enough Version...', 'info');
|
|
await ensureiOSVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('ios_close_enough_test', {
|
|
$lib: 'insights-ios',
|
|
$lib_version: iosVersionData.closeEnough,
|
|
test_scenario: 'ios_close_enough',
|
|
event_index: i,
|
|
$session_id: `ios-close-${Date.now()}`,
|
|
$device_type: 'iPhone'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ iOS close enough test complete: 16 events with v${iosVersionData.closeEnough}`, 'success');
|
|
}
|
|
|
|
async function testiOSRealOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ios_outdated';
|
|
|
|
log('📱 Testing iOS Outdated Version...', 'info');
|
|
await ensureiOSVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('ios_outdated_test', {
|
|
$lib: 'insights-ios',
|
|
$lib_version: iosVersionData.outdated,
|
|
test_scenario: 'ios_outdated',
|
|
event_index: i,
|
|
$session_id: `ios-outdated-${Date.now()}`,
|
|
$device_type: 'iPhone'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ iOS outdated test complete: 16 events with v${iosVersionData.outdated}`, 'success');
|
|
}
|
|
|
|
async function testiOSEdgeCase() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ios_edge_case';
|
|
|
|
log('📱 Testing iOS Edge Case: v3.30.0 (2 releases behind, ~54 days old)', 'info');
|
|
log('🔧 To test "Close enough": Temporarily change threshold in sidePanelSdkDoctorLogic.tsx:1946 from "< 2" to "< 60" days', 'info');
|
|
await ensureiOSVersionsLoaded();
|
|
initInsights();
|
|
|
|
// Use v3.30.0 specifically (2 releases behind, published Jul 28, 2025 - about 54 days ago)
|
|
const edgeVersion = '3.30.0';
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('ios_edge_case_test', {
|
|
$lib: 'insights-ios',
|
|
$lib_version: edgeVersion,
|
|
test_scenario: 'ios_edge_case',
|
|
event_index: i,
|
|
$session_id: `ios-edge-${Date.now()}`,
|
|
$device_type: 'iPhone'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ iOS edge case test complete: 16 events with v${edgeVersion}`, 'success');
|
|
}
|
|
|
|
async function testAlliOSRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_ios_real';
|
|
|
|
log('📱 Testing All iOS Real Versions...', 'info');
|
|
|
|
await testiOSRealCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testiOSRealCloseEnoughInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testiOSRealOutdatedInternal();
|
|
|
|
log('🎉 All iOS real version tests completed!', 'success');
|
|
}
|
|
|
|
// Internal iOS test functions
|
|
async function testiOSRealCurrentVersionInternal() {
|
|
log('📱 iOS Current (internal)...', 'info');
|
|
await ensureiOSVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('ios_current_internal', {
|
|
$lib: 'insights-ios',
|
|
$lib_version: iosVersionData.latest,
|
|
test_scenario: 'ios_current_internal',
|
|
event_index: i,
|
|
$session_id: `ios-current-internal-${Date.now()}`,
|
|
$device_type: 'iPhone'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testiOSRealCloseEnoughInternal() {
|
|
log('📱 iOS Close Enough (internal)...', 'info');
|
|
await ensureiOSVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('ios_close_enough_internal', {
|
|
$lib: 'insights-ios',
|
|
$lib_version: iosVersionData.closeEnough,
|
|
test_scenario: 'ios_close_enough_internal',
|
|
event_index: i,
|
|
$session_id: `ios-close-internal-${Date.now()}`,
|
|
$device_type: 'iPhone'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testiOSRealOutdatedInternal() {
|
|
log('📱 iOS Outdated (internal)...', 'info');
|
|
await ensureiOSVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('ios_outdated_internal', {
|
|
$lib: 'insights-ios',
|
|
$lib_version: iosVersionData.outdated,
|
|
test_scenario: 'ios_outdated_internal',
|
|
event_index: i,
|
|
$session_id: `ios-outdated-internal-${Date.now()}`,
|
|
$device_type: 'iPhone'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function ensureiOSVersionsLoaded() {
|
|
if (!iosVersionData) {
|
|
log('📱 Loading iOS version data...', 'info');
|
|
await fetchiOSVersionData();
|
|
}
|
|
}
|
|
|
|
// ========== ANDROID SDK TESTING FUNCTIONS ==========
|
|
|
|
// Fetch Android SDK versions
|
|
async function fetchAndroidVersionData() {
|
|
try {
|
|
log('🤖 Fetching Android SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-android/main/insights-android/CHANGELOG.md');
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch: ${response.status}`);
|
|
}
|
|
|
|
const text = await response.text();
|
|
|
|
// Parse Android SDK versions - format: "## 3.20.2 - 2025-08-07"
|
|
const versionMatches = text.match(/^## (\d+\.\d+\.\d+) - \d{4}-\d{2}-\d{2}$/gm);
|
|
|
|
if (versionMatches && versionMatches.length >= 5) {
|
|
const androidVersions = versionMatches
|
|
.map(match => match.replace(/^## /, '').replace(/ - \d{4}-\d{2}-\d{2}$/, ''))
|
|
.slice(0, 10); // Get first 10 versions
|
|
|
|
androidVersionData = {
|
|
latest: androidVersions[0],
|
|
closeEnough: androidVersions[1],
|
|
outdated: androidVersions[6] || androidVersions[androidVersions.length - 1],
|
|
all: androidVersions
|
|
};
|
|
|
|
log(`✅ Android SDK latest: ${androidVersionData.latest}`, 'success');
|
|
log(`🔍 Android SDK outdated test: ${androidVersionData.outdated}`, 'info');
|
|
|
|
// Update Android version info display
|
|
document.getElementById('android-real-version-info').innerHTML = `
|
|
<strong>Android Versions:</strong><br>
|
|
• Latest: v${androidVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${androidVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${androidVersionData.outdated} (Outdated)
|
|
`;
|
|
|
|
return true;
|
|
} else {
|
|
throw new Error('Could not parse Android versions');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Failed to fetch Android version data: ${error.message}`, 'error');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Android test functions
|
|
async function testAndroidRealCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'android_current';
|
|
|
|
log('🤖 Testing Android Current Version...', 'info');
|
|
await ensureAndroidVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('android_current_version_test', {
|
|
$lib: 'insights-android',
|
|
$lib_version: androidVersionData.latest,
|
|
test_scenario: 'android_current',
|
|
event_index: i,
|
|
$session_id: `android-current-${Date.now()}`,
|
|
$device_type: 'Android'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Android current version test complete: 16 events with v${androidVersionData.latest}`, 'success');
|
|
}
|
|
|
|
async function testAndroidRealCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'android_close_enough';
|
|
|
|
log('🤖 Testing Android Close Enough Version...', 'info');
|
|
await ensureAndroidVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('android_close_enough_test', {
|
|
$lib: 'insights-android',
|
|
$lib_version: androidVersionData.closeEnough,
|
|
test_scenario: 'android_close_enough',
|
|
event_index: i,
|
|
$session_id: `android-close-${Date.now()}`,
|
|
$device_type: 'Android'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Android close enough test complete: 16 events with v${androidVersionData.closeEnough}`, 'success');
|
|
}
|
|
|
|
async function testAndroidRealOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'android_outdated';
|
|
|
|
log('🤖 Testing Android Outdated Version...', 'info');
|
|
await ensureAndroidVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('android_outdated_test', {
|
|
$lib: 'insights-android',
|
|
$lib_version: androidVersionData.outdated,
|
|
test_scenario: 'android_outdated',
|
|
event_index: i,
|
|
$session_id: `android-outdated-${Date.now()}`,
|
|
$device_type: 'Android'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Android outdated test complete: 16 events with v${androidVersionData.outdated}`, 'success');
|
|
}
|
|
|
|
async function testAndroidEdgeCase() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'android_edge_case';
|
|
|
|
log('🤖 Testing Android Edge Case: v3.21.0 (3 releases behind, ~25 days old)', 'info');
|
|
log('🔧 To test "Close enough": Temporarily change threshold in sidePanelSdkDoctorLogic.tsx:2046 from "< 2" to "< 30" days', 'info');
|
|
await ensureAndroidVersionsLoaded();
|
|
initInsights();
|
|
|
|
// Use v3.21.0 specifically (3 releases behind: 3.21.3 → 3.21.2 → 3.21.1 → 3.21.0, published Aug 26, 2025 - about 25 days ago)
|
|
const edgeVersion = '3.21.0';
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('android_edge_case_test', {
|
|
$lib: 'insights-android',
|
|
$lib_version: edgeVersion,
|
|
test_scenario: 'android_edge_case',
|
|
event_index: i,
|
|
$session_id: `android-edge-${Date.now()}`,
|
|
$device_type: 'Android'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Android edge case test complete: 16 events with v${edgeVersion}`, 'success');
|
|
}
|
|
|
|
async function testAllAndroidRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_android_real';
|
|
|
|
log('🤖 Testing All Android Real Versions...', 'info');
|
|
|
|
await testAndroidRealCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testAndroidRealCloseEnoughInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testAndroidRealOutdatedInternal();
|
|
|
|
log('🎉 All Android real version tests completed!', 'success');
|
|
}
|
|
|
|
// Internal Android test functions
|
|
async function testAndroidRealCurrentVersionInternal() {
|
|
log('🤖 Android Current (internal)...', 'info');
|
|
await ensureAndroidVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('android_current_internal', {
|
|
$lib: 'insights-android',
|
|
$lib_version: androidVersionData.latest,
|
|
test_scenario: 'android_current_internal',
|
|
event_index: i,
|
|
$session_id: `android-current-internal-${Date.now()}`,
|
|
$device_type: 'Android'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testAndroidRealCloseEnoughInternal() {
|
|
log('🤖 Android Close Enough (internal)...', 'info');
|
|
await ensureAndroidVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('android_close_enough_internal', {
|
|
$lib: 'insights-android',
|
|
$lib_version: androidVersionData.closeEnough,
|
|
test_scenario: 'android_close_enough_internal',
|
|
event_index: i,
|
|
$session_id: `android-close-internal-${Date.now()}`,
|
|
$device_type: 'Android'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testAndroidRealOutdatedInternal() {
|
|
log('🤖 Android Outdated (internal)...', 'info');
|
|
await ensureAndroidVersionsLoaded();
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('android_outdated_internal', {
|
|
$lib: 'insights-android',
|
|
$lib_version: androidVersionData.outdated,
|
|
test_scenario: 'android_outdated_internal',
|
|
event_index: i,
|
|
$session_id: `android-outdated-internal-${Date.now()}`,
|
|
$device_type: 'Android'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function ensureAndroidVersionsLoaded() {
|
|
if (!androidVersionData) {
|
|
log('🤖 Loading Android version data...', 'info');
|
|
await fetchAndroidVersionData();
|
|
}
|
|
}
|
|
|
|
// ========== NODE.JS SDK TESTING FUNCTIONS ==========
|
|
|
|
// Fetch Node.js SDK versions
|
|
async function fetchNodeVersionData() {
|
|
try {
|
|
log('📗 Fetching Node.js SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/@hanzo/insights/main/packages/node/CHANGELOG.md');
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch: ${response.status}`);
|
|
}
|
|
|
|
const text = await response.text();
|
|
|
|
// Parse Node.js SDK versions - format: "## 5.8.4" (no date in header)
|
|
const versionMatches = text.match(/^## (\d+\.\d+\.\d+)$/gm);
|
|
|
|
if (versionMatches && versionMatches.length >= 5) {
|
|
const nodeVersions = versionMatches
|
|
.map(match => match.replace(/^## /, ''))
|
|
.slice(0, 10); // Get first 10 versions
|
|
|
|
nodeVersionData = {
|
|
latest: nodeVersions[0],
|
|
closeEnough: nodeVersions[1],
|
|
outdated: nodeVersions[6] || nodeVersions[nodeVersions.length - 1],
|
|
versions: nodeVersions
|
|
};
|
|
|
|
// Simulate realistic release dates for Node.js SDK
|
|
const now = new Date();
|
|
nodeVersionData.versionDates = {};
|
|
nodeVersionData.versionDates[nodeVersions[0]] = new Date(now.getTime() - (12 * 60 * 60 * 1000)); // 12 hours ago
|
|
nodeVersionData.versionDates[nodeVersions[1]] = new Date(now.getTime() - (3 * 24 * 60 * 60 * 1000)); // 3 days ago
|
|
nodeVersionData.versionDates[nodeVersions[2]] = new Date(now.getTime() - (2 * 60 * 60 * 1000)); // 2 hours ago (recent)
|
|
nodeVersionData.versionDates[nodeVersions[3]] = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); // 7 days ago (old)
|
|
|
|
log(`✅ Latest Node.js SDK: ${nodeVersionData.latest}`, 'success');
|
|
log(`📋 Found ${nodeVersions.length} Node.js versions for testing`, 'info');
|
|
updateNodeVersionDisplay();
|
|
return true;
|
|
} else {
|
|
throw new Error('Could not parse Node.js versions from CHANGELOG');
|
|
}
|
|
} catch (error) {
|
|
console.error('Node.js version fetch error:', error);
|
|
log(`❌ Failed to fetch Node.js version data: ${error.message}`, 'error');
|
|
log(`❌ Node.js tests cannot run without real version data - no fallbacks used`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Update Node.js version display
|
|
function updateNodeVersionDisplay() {
|
|
if (!nodeVersionData) return;
|
|
|
|
function formatDate(date) {
|
|
if (!date) return 'unknown';
|
|
const diffHours = Math.round((Date.now() - date.getTime()) / (1000 * 60 * 60));
|
|
if (diffHours < 1) return 'just now';
|
|
if (diffHours < 24) return `${diffHours}h ago`;
|
|
return `${Math.round(diffHours / 24)}d ago`;
|
|
}
|
|
|
|
// Update edge case version display (only if element exists)
|
|
const versionInfoElement = document.getElementById('version-info');
|
|
if (versionInfoElement) {
|
|
versionInfoElement.innerHTML = `
|
|
<strong>Node.js SDK Test Versions:</strong><br>
|
|
• Latest (${nodeVersionData.versions[0]}): Released ${formatDate(nodeVersionData.versionDates[nodeVersionData.versions[0]])}<br>
|
|
• 1 behind (${nodeVersionData.versions[1]}): Released ${formatDate(nodeVersionData.versionDates[nodeVersionData.versions[1]])}<br>
|
|
• 2 behind (${nodeVersionData.versions[2]}): Released ${formatDate(nodeVersionData.versionDates[nodeVersionData.versions[2]])} 🎯<br>
|
|
• 3 behind (${nodeVersionData.versions[3]}): Released ${formatDate(nodeVersionData.versionDates[nodeVersionData.versions[3]])}
|
|
`;
|
|
}
|
|
|
|
// Update Node.js real version info display (only if element exists)
|
|
const nodeRealVersionInfoElement = document.getElementById('node-real-version-info');
|
|
if (nodeRealVersionInfoElement) {
|
|
nodeRealVersionInfoElement.innerHTML = `
|
|
<strong>Node.js Real Versions:</strong><br>
|
|
• Latest: v${nodeVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${nodeVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${nodeVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
}
|
|
|
|
function initInsightsForNode() {
|
|
if (window.insights) {
|
|
window.insights.reset();
|
|
}
|
|
|
|
// Initialize Insights normally (we'll simulate Node.js events)
|
|
!function (t, e) { var o, n, p, r; e.__SV || (window.insights = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split("."); 2 == o.length && (t = t[o[0]], e = o[1]); t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = "insights", u.people = u.people || [], u.toString = function (t) { var e = "insights"; return "insights" !== a && (e += "." + a), t || (e += " (stub)"), e }, u.people.toString = function () { return u.toString(1) + ".people (stub)" }, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.insights || []);
|
|
|
|
insights.init(currentApiKey, {
|
|
api_host: HOST,
|
|
debug: true,
|
|
capture_pageview: false,
|
|
disable_session_recording: true,
|
|
autocapture: false
|
|
});
|
|
|
|
insights.identify(distinctId);
|
|
}
|
|
|
|
// Send Node.js SDK test events
|
|
async function sendNodeTestEvent(version, scenario, eventIndex) {
|
|
try {
|
|
const releaseAge = nodeVersionData.versionDates[version] ?
|
|
Math.round((Date.now() - nodeVersionData.versionDates[version].getTime()) / (1000 * 60 * 60)) : 'unknown';
|
|
|
|
const eventData = {
|
|
$lib: '@hanzo/insights-node',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
test_event_index: eventIndex,
|
|
version_release_age_hours: releaseAge,
|
|
test_sdk_type: 'node',
|
|
$current_url: window.location.href,
|
|
$session_id: `node-test-session-${scenario}`,
|
|
$device_type: 'Server'
|
|
};
|
|
|
|
console.log(`[Node.js Test] Event ${eventIndex}: $lib_version = "${version}"`, eventData);
|
|
insights.capture('test_node_time_based_detection', eventData);
|
|
|
|
log(`📤 Sent: Node.js v${version} (${releaseAge}h old) - ${scenario}`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending Node.js event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// Node.js Real Version Tests
|
|
async function testNodeRealCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!nodeVersionData) {
|
|
alert('Node.js version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'node_real_current';
|
|
|
|
log('✅ Testing REAL Node.js Current Version...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.latest;
|
|
log(`🎯 Sending Node.js events with version: ${version}`, 'info');
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_real_current_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
|
|
log(`✅ Node.js real current test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (Node.js version matches latest)`, 'info');
|
|
}
|
|
|
|
async function testNodeRealCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!nodeVersionData) {
|
|
alert('Node.js version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'node_real_close_enough';
|
|
|
|
log('🟡 Testing REAL Node.js Close Enough Version...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_real_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
|
|
log(`✅ Node.js real close enough test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (Node.js 1 release behind)`, 'info');
|
|
}
|
|
|
|
async function testNodeRealOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!nodeVersionData) {
|
|
alert('Node.js version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'node_real_outdated';
|
|
|
|
log('🔴 Testing REAL Node.js Outdated Version...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_real_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
|
|
log(`✅ Node.js real outdated test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (Node.js 6+ releases behind)`, 'info');
|
|
}
|
|
|
|
async function testNodeEdgeCase581() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'node_edge_581';
|
|
log('🎯 Testing NODE.JS Edge Case: v5.8.1 (3 Behind, 20 Days)...', 'info');
|
|
log('⏰ This version should show "Close enough" with adjusted threshold, "Outdated" with 48h threshold', 'info');
|
|
initInsightsForNode();
|
|
const version = '5.8.1';
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_edge_581', i);
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
log(`✅ Node.js edge case test complete: 16 events with v${version}`, 'success');
|
|
log(`📊 v5.8.1 released Aug 27 (20 days ago), 3 releases behind v5.8.4`, 'info');
|
|
log(`🔍 Expected: "Close enough" (with wide threshold) or "Outdated" (with 48h threshold)`, 'info');
|
|
}
|
|
|
|
async function testAllNodeRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_node_real_versions';
|
|
|
|
log('🧪 Testing all REAL Node.js versions...', 'info');
|
|
|
|
await testNodeRealCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
await testNodeRealCloseEnoughInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
await testNodeRealOutdatedInternal();
|
|
|
|
log('🎉 All REAL Node.js version tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for Node.js SDK detection results', 'info');
|
|
}
|
|
|
|
// Internal Node.js real version test functions
|
|
async function testNodeRealCurrentVersionInternal() {
|
|
if (!nodeVersionData) return;
|
|
log('✅ Testing REAL Node.js Current (internal)...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.latest;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_real_current_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testNodeRealCloseEnoughInternal() {
|
|
if (!nodeVersionData) return;
|
|
log('🟡 Testing REAL Node.js Close Enough (internal)...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_real_close_enough_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testNodeRealOutdatedInternal() {
|
|
if (!nodeVersionData) return;
|
|
log('🔴 Testing REAL Node.js Outdated (internal)...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_real_outdated_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// Node.js Mock Edge Case Tests
|
|
async function testNodeMockDualCheckRecent() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'node_mock_dual_recent';
|
|
|
|
log('🎯 Testing NODE.JS Mock Dual Check - Recent 2+ Releases Behind...', 'info');
|
|
await fetchNodeVersionData();
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.versions[2]; // 2 releases behind, but released recently
|
|
const ageHours = Math.round((Date.now() - nodeVersionData.versionDates[version].getTime()) / (1000 * 60 * 60));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_mock_dual_check_recent', i);
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
|
|
log(`✅ NODE.JS MOCK dual check (recent) test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Node.js test: v${version} is 2 releases behind but only ${ageHours}h old (<48h)`, 'info');
|
|
log(`🎯 Expected: "Close enough" badge (recent release overrides release count)`, 'info');
|
|
}
|
|
|
|
async function testNodeMockDualCheckOld() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'node_mock_dual_old';
|
|
|
|
log('🔴 Testing NODE.JS Mock Dual Check - Old 2+ Releases Behind...', 'info');
|
|
await fetchNodeVersionData();
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.versions[3]; // 3 releases behind and old
|
|
const ageHours = Math.round((Date.now() - nodeVersionData.versionDates[version].getTime()) / (1000 * 60 * 60));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_mock_dual_check_old', i);
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
|
|
log(`✅ NODE.JS MOCK dual check (old) test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Node.js comparison: v${version} is 3 releases behind and ${ageHours}h old (>48h)`, 'info');
|
|
log(`🎯 Expected: "Outdated" badge (both release count AND age thresholds exceeded)`, 'info');
|
|
}
|
|
|
|
async function testNodeMockExtreme() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'node_mock_extreme';
|
|
|
|
log('⚠️ Testing NODE.JS Mock Extreme Edge Case...', 'info');
|
|
initInsightsForNode();
|
|
|
|
// Create an extreme edge case for Node.js - exactly 2 releases behind and exactly 48h old
|
|
const extremeVersion = '5.3.0';
|
|
for (let i = 0; i < 16; i++) {
|
|
try {
|
|
insights.capture('test_node_mock_extreme_edge_case', {
|
|
$lib: '@hanzo/insights-node',
|
|
$lib_version: extremeVersion,
|
|
test_scenario: 'node_mock_extreme_edge_case',
|
|
test_event_index: i,
|
|
test_type: 'node_mock_version',
|
|
version_release_age_hours: 48, // Exactly 48 hours
|
|
mock_version_details: 'Node.js: 2 releases behind, exactly 48h old',
|
|
test_boundary_condition: true,
|
|
$current_url: window.location.href,
|
|
$session_id: `node-mock-extreme-session`,
|
|
$device_type: 'Server'
|
|
});
|
|
|
|
log(`📤 Sent: NODE.JS MOCK v${extremeVersion} (exactly 48h old) - extreme edge case`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending Node.js event: ${error.message}`, 'error');
|
|
}
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
|
|
log(`✅ NODE.JS MOCK extreme edge case test complete: 16 events`, 'success');
|
|
log(`🔍 Node.js edge case: v${extremeVersion} is exactly 2 releases behind and exactly 48h old`, 'info');
|
|
log(`🎯 Expected: Boundary condition testing for dual-check logic`, 'info');
|
|
}
|
|
|
|
// Test Node.js SDK: Multiple releases in one day scenario
|
|
async function testNodeMockMultipleReleasesOneDay() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'node_mock_multiple_releases_one_day';
|
|
|
|
log('🚀 Testing NODE.JS Mock: Multiple Releases in One Day (4 Behind + 24h)...', 'info');
|
|
initInsightsForNode();
|
|
|
|
// Simulate a realistic Insights scenario:
|
|
// - Current version is 5.8.4 (latest)
|
|
// - We're testing version 5.8.0 (4 releases behind)
|
|
// - But version 5.8.0 was released only 24 hours ago (fast release cycle)
|
|
// - This should show "Close enough" because it's <48h old, despite being 4+ releases behind
|
|
const testVersion = '5.8.0'; // 4 releases behind 5.8.4
|
|
const hoursSinceRelease = 24; // 24 hours ago = recent despite being 4 releases behind
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
try {
|
|
insights.capture('test_node_mock_multiple_releases_one_day', {
|
|
$lib: '@hanzo/insights-node',
|
|
$lib_version: testVersion,
|
|
test_scenario: 'node_mock_multiple_releases_one_day',
|
|
test_event_index: i,
|
|
test_type: 'node_mock_version',
|
|
version_release_age_hours: hoursSinceRelease,
|
|
mock_version_details: 'Node.js: 4 releases behind, 24h old (fast release cycle)',
|
|
test_scenario_description: 'Tests fast release cycle where 4+ releases happen in 48h',
|
|
releases_behind: 4,
|
|
expected_badge: 'Close enough',
|
|
fast_release_cycle: true,
|
|
$current_url: window.location.href,
|
|
$session_id: `node-mock-fast-release-session`,
|
|
$device_type: 'Server'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
} catch (error) {
|
|
log(`❌ Error sending Node.js fast release event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
log(`✅ Node.js Fast Release test complete! Sent 16 events with v${testVersion} (${hoursSinceRelease}h old, 4 releases behind)`, 'success');
|
|
log('🔍 Expected: "Close enough" badge (because <48h despite 4+ releases behind)', 'info');
|
|
log('📊 This tests Insights\'s fast release cycle where multiple releases happen daily', 'info');
|
|
}
|
|
|
|
// Test Node.js SDK with real version 5.8.2 for time-based detection
|
|
async function testNodeRealTimeBasedDetection() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'node_real_time_based';
|
|
|
|
log('⏰ Testing NODE.JS Real Time-Based Detection with v5.8.1...', 'info');
|
|
log('📅 Real release date: Aug 27, 2025 (20 days ago)', 'info');
|
|
log('🎯 This is 3 releases behind - tests the "3+ releases behind" part of dual-check logic', 'info');
|
|
|
|
initInsightsForNode();
|
|
|
|
// Use real Node.js version 5.8.1 (released Aug 27, 2025 - 20 days ago)
|
|
// This is 3 releases behind 5.8.4 and 20 days old
|
|
const realTestVersion = '5.8.1';
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
try {
|
|
insights.capture('test_node_real_time_based_detection', {
|
|
$lib: '@hanzo/insights-node',
|
|
$lib_version: realTestVersion,
|
|
test_scenario: 'node_real_time_based_detection',
|
|
test_event_index: i,
|
|
test_type: 'real_version_time_test',
|
|
real_release_date: '2025-08-27T09:04:49Z',
|
|
releases_behind: 3,
|
|
days_since_release: 20,
|
|
testing_threshold_logic: true,
|
|
$current_url: window.location.href,
|
|
$session_id: `node-real-time-test-session`,
|
|
$device_type: 'Server'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
} catch (error) {
|
|
log(`❌ Error sending Node.js real time test event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
log(`✅ Node.js Real Time Test complete! Sent 16 events with v${realTestVersion}`, 'success');
|
|
log('🔍 SDK Doctor will use REAL GitHub API data for this version', 'info');
|
|
log('📊 Check SDK Doctor for time-based detection results', 'info');
|
|
}
|
|
|
|
async function testAllNodeMockScenarios() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_node_mock_scenarios';
|
|
|
|
log('🧪 Testing all NODE.JS mock edge case scenarios...', 'info');
|
|
|
|
await testNodeMockDualCheckRecentInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
await testNodeMockDualCheckOldInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
await testNodeMockExtremeInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
await testNodeMockMultipleReleasesOneDayInternal();
|
|
|
|
log('🎉 All NODE.JS mock edge case tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for Node.js edge case detection results', 'info');
|
|
}
|
|
|
|
// Internal Node.js mock test functions
|
|
async function testNodeMockDualCheckRecentInternal() {
|
|
log('🎯 NODE.JS Mock Dual Check Recent (internal)...', 'info');
|
|
await fetchNodeVersionData();
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.versions[2];
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_mock_dual_recent_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testNodeMockDualCheckOldInternal() {
|
|
log('🔴 NODE.JS Mock Dual Check Old (internal)...', 'info');
|
|
await fetchNodeVersionData();
|
|
initInsightsForNode();
|
|
|
|
const version = nodeVersionData.versions[3];
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendNodeTestEvent(version, 'node_mock_dual_old_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testNodeMockExtremeInternal() {
|
|
log('⚠️ NODE.JS Mock Extreme (internal)...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const extremeVersion = '5.3.0';
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('test_node_mock_extreme_internal', {
|
|
$lib: '@hanzo/insights-node',
|
|
$lib_version: extremeVersion,
|
|
test_scenario: 'node_mock_extreme_internal',
|
|
test_event_index: i,
|
|
test_type: 'node_mock_version',
|
|
version_release_age_hours: 48,
|
|
mock_version_details: 'Node.js: 2 releases behind, exactly 48h old',
|
|
test_boundary_condition: true,
|
|
$current_url: window.location.href,
|
|
$session_id: `node-mock-extreme-internal`,
|
|
$device_type: 'Server'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testNodeMockMultipleReleasesOneDayInternal() {
|
|
log('🚀 NODE.JS Mock Multiple Releases One Day (internal)...', 'info');
|
|
initInsightsForNode();
|
|
|
|
const testVersion = '5.8.0'; // 4 releases behind 5.8.4
|
|
const hoursSinceRelease = 24; // 24 hours ago
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('test_node_mock_multiple_releases_internal', {
|
|
$lib: '@hanzo/insights-node',
|
|
$lib_version: testVersion,
|
|
test_scenario: 'node_mock_multiple_releases_internal',
|
|
test_event_index: i,
|
|
test_type: 'node_mock_version',
|
|
version_release_age_hours: hoursSinceRelease,
|
|
mock_version_details: 'Node.js: 4 releases behind, 24h old (fast release cycle)',
|
|
releases_behind: 4,
|
|
expected_badge: 'Close enough',
|
|
fast_release_cycle: true,
|
|
$current_url: window.location.href,
|
|
$session_id: `node-mock-fast-release-internal`,
|
|
$device_type: 'Server'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// ========== REAL VERSION TESTING FUNCTIONS ==========
|
|
// Fetch real versions for CDN testing (similar to simple-time-test.html)
|
|
async function fetchRealVersions() {
|
|
try {
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/@hanzo/insights/main/packages/browser/CHANGELOG.md');
|
|
const text = await response.text();
|
|
|
|
const versionRegex = /^## (\d+\.\d+\.\d+)$/gm;
|
|
const realVersions = [];
|
|
let match;
|
|
|
|
while ((match = versionRegex.exec(text)) !== null) {
|
|
realVersions.push(match[1]);
|
|
}
|
|
|
|
if (realVersions.length >= 7) {
|
|
return {
|
|
latest: realVersions[0], // Current version
|
|
closeEnough: realVersions[1], // 1 release behind
|
|
outdated: realVersions[6] || realVersions[realVersions.length - 1] // 6+ releases behind
|
|
};
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch real versions:', error);
|
|
}
|
|
|
|
log(`❌ Real version tests cannot run without CHANGELOG.md data - no fallbacks used`, 'error');
|
|
throw error;
|
|
}
|
|
|
|
function loadInsightsVersion(version, callback) {
|
|
// Clear any existing Insights
|
|
if (window.insights) {
|
|
window.insights = undefined;
|
|
}
|
|
|
|
// Initialize Insights directly with snippet (bypasses CORS)
|
|
!function (t, e) { var o, n, p, r; e.__SV || (window.insights = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split("."); 2 == o.length && (t = t[o[0]], e = o[1]); t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = "insights", u.people = u.people || [], u.toString = function (t) { var e = "insights"; return "insights" !== a && (e += "." + a), t || (e += " (stub)"), e }, u.people.toString = function () { return u.toString(1) + ".people (stub)" }, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.insights || []);
|
|
|
|
// Initialize with local Insights
|
|
insights.init(currentApiKey, {
|
|
api_host: 'http://localhost:8010',
|
|
debug: true,
|
|
capture_pageview: false,
|
|
disable_session_recording: true,
|
|
autocapture: false
|
|
});
|
|
|
|
// Override the version to simulate different versions
|
|
setTimeout(() => {
|
|
if (window.insights && window.insights.config) {
|
|
if (version === 'latest') {
|
|
// Will use whatever version is loaded from your local Insights
|
|
callback();
|
|
} else {
|
|
// Override the library version to simulate older versions
|
|
if (window.insights._) {
|
|
window.insights._.config.lib_version = version;
|
|
}
|
|
// Also override any version reporting
|
|
const originalCapture = window.insights.capture;
|
|
window.insights.capture = function (...args) {
|
|
if (args[1] && typeof args[1] === 'object') {
|
|
args[1].$lib_version = version;
|
|
}
|
|
return originalCapture.apply(this, args);
|
|
};
|
|
callback();
|
|
}
|
|
} else {
|
|
callback(new Error('Insights failed to initialize'));
|
|
}
|
|
}, 2000); // Give more time for init
|
|
}
|
|
|
|
function sendRealTestEvents(version, testName, count = 16) {
|
|
const testDistinctId = `real-test-${testName}-${Date.now()}`;
|
|
insights.identify(testDistinctId);
|
|
|
|
log(`📤 Sending ${count} events with REAL version ${version}...`, 'info');
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
setTimeout(() => {
|
|
insights.capture('test_real_time_based_detection', {
|
|
$lib: 'web',
|
|
$lib_version: version, // Override the version to test specific versions
|
|
test_version: version,
|
|
test_scenario: testName,
|
|
test_event_index: i,
|
|
test_type: 'real_version',
|
|
$session_id: `real-test-session-${testName}`,
|
|
$device_type: 'Desktop'
|
|
});
|
|
|
|
if (i === count - 1) {
|
|
log(`✅ All REAL version events sent! Version: ${version}`, 'success');
|
|
log(`🔍 Now check SDK Doctor for real GitHub API detection results`, 'info');
|
|
}
|
|
}, i * 200); // Spread events over time
|
|
}
|
|
}
|
|
|
|
async function testRealCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!realVersionData) {
|
|
alert('Real version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'real_current';
|
|
|
|
log('✅ Testing REAL Current Version...', 'info');
|
|
loadInsightsVersion('latest', (error) => {
|
|
if (error) {
|
|
log(`❌ Error: ${error.message}`, 'error');
|
|
return;
|
|
}
|
|
log(`✅ REAL Latest Insights loaded (v${realVersionData.latest})`, 'success');
|
|
sendRealTestEvents(realVersionData.latest, 'real_current_version');
|
|
});
|
|
}
|
|
|
|
async function testRealCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!realVersionData) {
|
|
alert('Real version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'real_close_enough';
|
|
|
|
const version = realVersionData.closeEnough;
|
|
log(`🟡 Testing REAL Close Enough Version (v${version})...`, 'info');
|
|
loadInsightsVersion(version, (error) => {
|
|
if (error) {
|
|
log(`❌ Error: ${error.message}`, 'error');
|
|
return;
|
|
}
|
|
log(`✅ REAL v${version} loaded`, 'success');
|
|
sendRealTestEvents(version, 'real_close_enough');
|
|
});
|
|
}
|
|
|
|
async function testRealOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!realVersionData) {
|
|
alert('Real version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'real_outdated';
|
|
|
|
const version = realVersionData.outdated;
|
|
log(`🔴 Testing REAL Outdated Version (v${version})...`, 'info');
|
|
loadInsightsVersion(version, (error) => {
|
|
if (error) {
|
|
log(`❌ Error: ${error.message}`, 'error');
|
|
return;
|
|
}
|
|
log(`✅ REAL v${version} loaded`, 'success');
|
|
sendRealTestEvents(version, 'real_outdated');
|
|
});
|
|
}
|
|
|
|
async function testWebSdkEdgeCase1264() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'web_edge_1264';
|
|
|
|
log('🎯 Testing Web SDK Edge Case: v1.264.2 (3+ Behind, 5 Days - Should be Close Enough with 6-day threshold)...', 'info');
|
|
log('📡 Using REAL GitHub API data - no mocks!', 'info');
|
|
|
|
const testVersion = '1.264.2'; // Real version 3+ releases behind
|
|
|
|
// Load the specific version via Insights CDN
|
|
loadInsightsVersion(testVersion, (error) => {
|
|
if (error) {
|
|
log(`❌ Error loading v${testVersion}: ${error.message}`, 'error');
|
|
return;
|
|
}
|
|
log(`✅ REAL v${testVersion} loaded from CDN`, 'success');
|
|
|
|
// Send 16 test events
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('web_edge_case_1264', {
|
|
test_scenario: 'web_edge_case_1264',
|
|
event_index: i,
|
|
event_id: `web_edge_${i}_${Date.now()}`,
|
|
test_timestamp: new Date().toISOString(),
|
|
test_note: 'Real v1.264.2 with adjusted 6-day threshold - SDK Doctor will fetch real GitHub dates'
|
|
});
|
|
}
|
|
|
|
log(`✅ Web SDK REAL edge case test complete: 16 events with v${testVersion}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (3+ behind but real GitHub date within adjusted 6-day threshold)`, 'info');
|
|
log(`⚠️ Note: This test uses temporarily adjusted threshold (6 days instead of 48h)`, 'warning');
|
|
log(`📊 SDK Doctor will use REAL GitHub API data for time-based detection`, 'info');
|
|
});
|
|
}
|
|
|
|
async function testAllRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_real_versions';
|
|
|
|
log('🧪 Testing all REAL versions with GitHub API integration...', 'info');
|
|
|
|
// Test each real version without triggering reload checks
|
|
await testRealCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testRealCloseEnoughInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
await testRealOutdatedInternal();
|
|
|
|
log('🎉 All REAL version tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for GitHub API-based time detection results', 'info');
|
|
}
|
|
|
|
// Internal real version test functions
|
|
async function testRealCurrentVersionInternal() {
|
|
if (!realVersionData) return;
|
|
const version = realVersionData.latest;
|
|
log(`✅ Testing REAL Current Version (v${version})...`, 'info');
|
|
loadInsightsVersion('latest', (error) => {
|
|
if (!error) {
|
|
sendRealTestEvents(version, 'real_current_internal');
|
|
}
|
|
});
|
|
}
|
|
|
|
async function testRealCloseEnoughInternal() {
|
|
if (!realVersionData) return;
|
|
const version = realVersionData.closeEnough;
|
|
log(`🟡 Testing REAL Close Enough (v${version})...`, 'info');
|
|
loadInsightsVersion(version, (error) => {
|
|
if (!error) {
|
|
sendRealTestEvents(version, 'real_close_enough_internal');
|
|
}
|
|
});
|
|
}
|
|
|
|
async function testRealOutdatedInternal() {
|
|
if (!realVersionData) return;
|
|
const version = realVersionData.outdated;
|
|
log(`🔴 Testing REAL Outdated (v${version})...`, 'info');
|
|
loadInsightsVersion(version, (error) => {
|
|
if (!error) {
|
|
sendRealTestEvents(version, 'real_outdated_internal');
|
|
}
|
|
});
|
|
}
|
|
|
|
// ========== MOCK EDGE CASE TESTING FUNCTIONS ==========
|
|
async function testMockDualCheckRecent() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'mock_dual_recent';
|
|
|
|
log('🎯 Testing MOCK Dual Check - Recent 2+ Releases Behind...', 'info');
|
|
await ensureVersionsLoaded();
|
|
initInsights();
|
|
|
|
const version = versions[2]; // 2 releases behind, but released recently
|
|
const ageHours = Math.round((Date.now() - versionDates[version].getTime()) / (1000 * 60 * 60));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendTestEvent(version, 'mock_dual_check_recent', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ MOCK dual check (recent) test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Key test: v${version} is 2 releases behind but only ${ageHours}h old (<48h)`, 'info');
|
|
log(`🔍 Expected: "Close enough" badge (time override working!)`, 'info');
|
|
}
|
|
|
|
async function testMockDualCheckOld() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'mock_dual_old';
|
|
|
|
log('🔴 Testing MOCK Dual Check - Old 2+ Releases Behind...', 'info');
|
|
await ensureVersionsLoaded();
|
|
initInsights();
|
|
|
|
const version = versions[3]; // 3 releases behind and old
|
|
const ageHours = Math.round((Date.now() - versionDates[version].getTime()) / (1000 * 60 * 60));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendTestEvent(version, 'mock_dual_check_old', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ MOCK dual check (old) test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Comparison: v${version} is 3 releases behind and ${ageHours}h old (>48h)`, 'info');
|
|
log(`🔍 Expected: "Outdated" badge (dual check failed)`, 'info');
|
|
}
|
|
|
|
async function testMockExtreme() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'mock_extreme';
|
|
|
|
log('⚠️ Testing MOCK Extreme Edge Case...', 'info');
|
|
initInsights();
|
|
|
|
// Create an extreme edge case - exactly 2 releases behind and exactly 48h old
|
|
const extremeVersion = '1.999.0';
|
|
const exactly48hAgo = new Date(Date.now() - (48 * 60 * 60 * 1000));
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
try {
|
|
insights.capture('test_mock_extreme_edge_case', {
|
|
$lib: 'web',
|
|
$lib_version: extremeVersion,
|
|
test_scenario: 'mock_extreme_edge_case',
|
|
test_event_index: i,
|
|
test_type: 'mock_version',
|
|
version_release_age_hours: 48, // Exactly 48 hours
|
|
mock_version_details: '2 releases behind, exactly 48h old',
|
|
$current_url: window.location.href,
|
|
$session_id: `mock-extreme-session`,
|
|
$device_type: 'Desktop'
|
|
});
|
|
|
|
log(`📤 Sent: MOCK v${extremeVersion} (exactly 48h old) - extreme edge case`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending event: ${error.message}`, 'error');
|
|
}
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ MOCK extreme edge case test complete: 16 events`, 'success');
|
|
log(`🔍 Edge case: v${extremeVersion} is exactly 2 releases behind and exactly 48h old`, 'info');
|
|
log(`🔍 Expected: "Outdated" badge (boundary case - 48h is NOT <48h)`, 'info');
|
|
}
|
|
|
|
async function testAllMockScenarios() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_mock_scenarios';
|
|
|
|
log('🧪 Testing all MOCK edge case scenarios...', 'info');
|
|
|
|
await testMockDualCheckRecentInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testMockDualCheckOldInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
await testMockExtremeInternal();
|
|
|
|
log('🎉 All MOCK edge case tests completed!', 'success');
|
|
log('🔍 Check SDK Doctor for edge case detection results', 'info');
|
|
}
|
|
|
|
// Internal mock test functions
|
|
async function testMockDualCheckRecentInternal() {
|
|
log('🎯 MOCK Dual Check Recent (internal)...', 'info');
|
|
await ensureVersionsLoaded();
|
|
initInsights();
|
|
|
|
const version = versions[2];
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendTestEvent(version, 'mock_dual_recent_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testMockDualCheckOldInternal() {
|
|
log('🔴 MOCK Dual Check Old (internal)...', 'info');
|
|
await ensureVersionsLoaded();
|
|
initInsights();
|
|
|
|
const version = versions[3];
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendTestEvent(version, 'mock_dual_old_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testMockExtremeInternal() {
|
|
log('⚠️ MOCK Extreme Edge Case (internal)...', 'info');
|
|
initInsights();
|
|
|
|
const extremeVersion = '1.999.0';
|
|
for (let i = 0; i < 16; i++) {
|
|
insights.capture('test_mock_extreme_internal', {
|
|
$lib: 'web',
|
|
$lib_version: extremeVersion,
|
|
test_scenario: 'mock_extreme_internal',
|
|
test_event_index: i,
|
|
test_type: 'mock_version',
|
|
version_release_age_hours: 48,
|
|
$session_id: `mock-extreme-internal`,
|
|
$device_type: 'Desktop'
|
|
});
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// ========== GO SDK TESTING FUNCTIONS ==========
|
|
|
|
// Global Go SDK version data
|
|
let goVersionData = null;
|
|
|
|
// Fetch Go SDK versions
|
|
async function fetchGoVersionData() {
|
|
try {
|
|
log('🔷 Fetching Go SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-go/master/CHANGELOG.md', {
|
|
cache: 'no-cache'
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
const changelog = await response.text();
|
|
// Parse Go SDK versions - looking for "## 1.6.8" format
|
|
const versionMatches = changelog.match(/^## (\d+\.\d+\.\d+)$/gm);
|
|
if (versionMatches && versionMatches.length >= 5) {
|
|
const goVersions = versionMatches
|
|
.map(match => match.replace(/^## /, ''))
|
|
.slice(0, 10); // Get first 10 versions
|
|
goVersionData = {
|
|
latest: goVersions[0],
|
|
closeEnough: goVersions[1],
|
|
outdated: goVersions[6] || goVersions[goVersions.length - 1],
|
|
versions: goVersions
|
|
};
|
|
log(`✅ Latest Go SDK: ${goVersionData.latest}`, 'success');
|
|
log(`📋 Found ${goVersions.length} Go versions for testing`, 'info');
|
|
updateGoVersionDisplay();
|
|
return true;
|
|
} else {
|
|
throw new Error('Could not parse Go versions from CHANGELOG');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Failed to fetch Go version data: ${error.message}`, 'error');
|
|
log(`❌ Go tests cannot run without real version data - no fallbacks used`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function updateGoVersionDisplay() {
|
|
if (!goVersionData) return;
|
|
const versionDisplay = `
|
|
<strong>Go SDK Test Versions:</strong><br>
|
|
• Latest: v${goVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${goVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${goVersionData.outdated} (Outdated)
|
|
`;
|
|
document.getElementById('versionInfo').innerHTML = versionDisplay;
|
|
}
|
|
|
|
function updateiOSVersionDisplay() {
|
|
if (!iosVersionData) return;
|
|
|
|
// Update iOS version info display
|
|
document.getElementById('ios-real-version-info').innerHTML = `
|
|
<strong>iOS Versions:</strong><br>
|
|
• Latest: v${iosVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${iosVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${iosVersionData.outdated} (Outdated)
|
|
`;
|
|
|
|
log('📱 iOS version display updated', 'info');
|
|
}
|
|
|
|
function updateAndroidVersionDisplay() {
|
|
if (!androidVersionData) return;
|
|
|
|
// Update Android version info display
|
|
document.getElementById('android-real-version-info').innerHTML = `
|
|
<strong>Android Versions:</strong><br>
|
|
• Latest: v${androidVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${androidVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${androidVersionData.outdated} (Outdated)
|
|
`;
|
|
|
|
log('🤖 Android version display updated', 'info');
|
|
}
|
|
|
|
function ensureGoVersionsLoaded() {
|
|
return goVersionData ? Promise.resolve() : fetchGoVersionData();
|
|
}
|
|
|
|
// Initialize Insights for Go SDK testing
|
|
function initInsightsForGo() {
|
|
if (window.insights) {
|
|
window.insights.reset();
|
|
}
|
|
!function (t, e) { var o, n, p, r; e.__SV || (window.insights = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split("."); 2 == o.length && (t = t[o[0]], e = o[1]); t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = "insights", u.people = u.people || [], u.toString = function (t) { var e = "insights"; return "insights" !== a && (e += "." + a), t || (e += " (stub)"), e }, u.people.toString = function () { return u.toString(1) + ".people (stub)" }, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.insights || []);
|
|
insights.init(currentApiKey, {
|
|
api_host: 'http://localhost:8010',
|
|
debug: true,
|
|
capture_pageview: false,
|
|
disable_session_recording: true,
|
|
autocapture: false
|
|
});
|
|
insights.identify(distinctId);
|
|
}
|
|
|
|
// Send Go SDK test events
|
|
async function sendGoTestEvent(version, scenario, eventIndex) {
|
|
try {
|
|
insights.capture('test_go_time_based_detection', {
|
|
$lib: 'insights-go',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
event_index: eventIndex,
|
|
test_timestamp: new Date().toISOString(),
|
|
$current_url: window.location.href,
|
|
$session_id: `go-test-${Date.now()}`,
|
|
$device_type: 'Desktop'
|
|
});
|
|
log(`📤 Sent: Go v${version} - ${scenario}`, 'info');
|
|
} catch (error) {
|
|
log(`❌ Error sending Go event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// Go Real Version Tests
|
|
async function testGoRealCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!goVersionData) {
|
|
alert('Go version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'go_real_current';
|
|
log('✅ Testing REAL Go Current Version...', 'info');
|
|
initInsightsForGo();
|
|
const version = goVersionData.latest;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendGoTestEvent(version, 'go_real_current_version', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Go real current test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (Go version matches latest)`, 'info');
|
|
}
|
|
|
|
async function testGoRealCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!goVersionData) {
|
|
alert('Go version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'go_real_close_enough';
|
|
log('🟡 Testing REAL Go Close Enough Version...', 'info');
|
|
initInsightsForGo();
|
|
const version = goVersionData.closeEnough;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendGoTestEvent(version, 'go_real_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Go real close enough test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (1 release behind)`, 'info');
|
|
}
|
|
|
|
async function testGoRealOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!goVersionData) {
|
|
alert('Go version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'go_real_outdated';
|
|
log('🔴 Testing REAL Go Outdated Version...', 'info');
|
|
initInsightsForGo();
|
|
const version = goVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendGoTestEvent(version, 'go_real_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Go real outdated test complete: 16 events with v${version}`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (6+ releases behind)`, 'info');
|
|
}
|
|
|
|
async function testGoEdgeCaseSimplified() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
if (!goVersionData) {
|
|
alert('Go version data not loaded yet. Please wait a moment and try again.');
|
|
return;
|
|
}
|
|
currentTest = 'go_edge_case_simplified';
|
|
log('🎯 Testing Go Edge Case: 2 Releases Behind (Go SDK Exception)...', 'info');
|
|
|
|
// Use version that's exactly 2 releases behind
|
|
const edgeVersion = goVersionData.versions[2]; // 3rd version (2 behind: 1.6.8 → 1.6.7 → 1.6.6)
|
|
|
|
log(`🧪 Using Go v${edgeVersion} (should be 2 releases behind)`, 'info');
|
|
log(`🎯 Go SDK Exception: Shows "Close enough" for 1-2 releases behind (no time check)`, 'warning');
|
|
log(`🔍 Expected: "Close enough" badge due to Go SDK infrequent release pattern`, 'info');
|
|
|
|
initInsightsForGo();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendGoTestEvent(edgeVersion, 'go_edge_case_simplified', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Go edge case test complete: 16 events with v${edgeVersion}`, 'success');
|
|
}
|
|
|
|
async function testAllGoRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_go_real';
|
|
log('🤖 Testing All Go Real Versions...', 'info');
|
|
await testGoRealCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
await testGoRealCloseEnoughInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
await testGoRealOutdatedInternal();
|
|
log('🎉 All Go real version tests completed!', 'success');
|
|
}
|
|
|
|
// Internal Go test functions
|
|
async function testGoRealCurrentVersionInternal() {
|
|
log('🤖 Go Current (internal)...', 'info');
|
|
await ensureGoVersionsLoaded();
|
|
initInsightsForGo();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendGoTestEvent(goVersionData.latest, 'go_current_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testGoRealCloseEnoughInternal() {
|
|
log('🤖 Go Close Enough (internal)...', 'info');
|
|
await ensureGoVersionsLoaded();
|
|
initInsightsForGo();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendGoTestEvent(goVersionData.closeEnough, 'go_close_enough_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testGoRealOutdatedInternal() {
|
|
log('🤖 Go Outdated (internal)...', 'info');
|
|
await ensureGoVersionsLoaded();
|
|
initInsightsForGo();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendGoTestEvent(goVersionData.outdated, 'go_outdated_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// Initialize on page load
|
|
window.onload = async function () {
|
|
updateApiKeyDisplay();
|
|
log('🕒 Enhanced Time-Based Detection Test Ready', 'success');
|
|
log('📱 NEW: Multi-SDK support + Real version tests + 🧪 Mock edge case tests', 'info');
|
|
log('🎯 Dual check logic: releasesBehind >= 3 OR (releasesBehind >= 2 && versionAge > 48h)', 'info');
|
|
|
|
await fetchVersionData();
|
|
|
|
// Fetch real version data for CDN testing
|
|
realVersionData = await fetchRealVersions();
|
|
log(`✅ Loaded real version data: latest=${realVersionData.latest}, close=${realVersionData.closeEnough}, outdated=${realVersionData.outdated}`, 'success');
|
|
|
|
// Update real version info display
|
|
document.getElementById('real-version-info').innerHTML = `
|
|
<strong>Real Versions:</strong><br>
|
|
• Latest: v${realVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${realVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${realVersionData.outdated} (Outdated)
|
|
`;
|
|
|
|
// Initialize SDK selector - restore saved selection or use default
|
|
restoreSavedSdk();
|
|
if (!localStorage.getItem('selectedSdk')) {
|
|
changeSdk();
|
|
}
|
|
};
|
|
|
|
// PHP SDK version data
|
|
let phpVersionData = null;
|
|
|
|
// Fetch PHP SDK versions
|
|
async function fetchPhpVersionData() {
|
|
try {
|
|
log('🐘 Fetching PHP SDK version data from History.md...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-php/master/History.md', {
|
|
cache: 'no-cache'
|
|
});
|
|
const text = await response.text();
|
|
|
|
// Parse PHP SDK versions (format: "3.6.0 / 2025-04-30")
|
|
const versionRegex = /^(\d+\.\d+\.\d+)\s*\/\s*(\d{4}-\d{2}-\d{2})/gm;
|
|
const versions = [];
|
|
let match;
|
|
|
|
while ((match = versionRegex.exec(text)) !== null) {
|
|
versions.push(match[1]);
|
|
}
|
|
|
|
if (versions.length >= 3) {
|
|
phpVersionData = {
|
|
latest: versions[0], // Current version
|
|
closeEnough: versions[1], // 1 release behind
|
|
twoReleasesBehind: versions[2], // 2 releases behind
|
|
outdated: versions[3] || versions[versions.length - 1], // 3+ releases behind
|
|
versions: versions
|
|
};
|
|
|
|
log(`🐘 PHP SDK versions loaded: latest=${phpVersionData.latest}, 1 behind=${phpVersionData.closeEnough}, 2 behind=${phpVersionData.twoReleasesBehind}, outdated=${phpVersionData.outdated}`, 'success');
|
|
updatePhpVersionDisplay();
|
|
} else {
|
|
log('❌ Could not find enough PHP versions', 'error');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Error fetching PHP versions: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
function updatePhpVersionDisplay() {
|
|
if (!phpVersionData) return;
|
|
|
|
document.getElementById('php-version-info').innerHTML = `
|
|
<strong>PHP SDK Test Versions:</strong><br>
|
|
• Latest: v${phpVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${phpVersionData.closeEnough} (Close enough)<br>
|
|
• 2 Behind: v${phpVersionData.twoReleasesBehind} (Close enough)<br>
|
|
• 3+ Behind: v${phpVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
|
|
async function sendPhpTestEvent(version, scenario, eventIndex) {
|
|
insights.capture('php_test_event', {
|
|
$lib: 'insights-php',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
event_index: eventIndex,
|
|
$session_id: `php-${scenario}-${Date.now()}`,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
|
|
// PHP Test Functions
|
|
async function testPhpCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'php_current';
|
|
|
|
log('🐘 Testing PHP Current Version...', 'info');
|
|
await fetchPhpVersionData();
|
|
if (!phpVersionData) {
|
|
alert('PHP version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.latest, 'php_current', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ PHP current version test complete: 16 events with v${phpVersionData.latest}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (PHP version matches latest)`, 'info');
|
|
}
|
|
|
|
async function testPhpCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'php_close_enough';
|
|
|
|
log('🐘 Testing PHP 1 Release Behind...', 'info');
|
|
await fetchPhpVersionData();
|
|
if (!phpVersionData) {
|
|
alert('PHP version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.closeEnough, 'php_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ PHP 1 release behind test complete: 16 events with v${phpVersionData.closeEnough}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (1 release behind)`, 'info');
|
|
}
|
|
|
|
async function testPhpTwoReleasesBehind() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'php_two_behind';
|
|
|
|
log('🐘 Testing PHP 2 Releases Behind...', 'info');
|
|
await fetchPhpVersionData();
|
|
if (!phpVersionData) {
|
|
alert('PHP version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.twoReleasesBehind, 'php_two_behind', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ PHP 2 releases behind test complete: 16 events with v${phpVersionData.twoReleasesBehind}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (2 releases behind, simplified logic)`, 'info');
|
|
}
|
|
|
|
async function testPhpOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'php_outdated';
|
|
|
|
log('🐘 Testing PHP 3+ Releases Behind...', 'info');
|
|
await fetchPhpVersionData();
|
|
if (!phpVersionData) {
|
|
alert('PHP version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.outdated, 'php_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ PHP 3+ releases behind test complete: 16 events with v${phpVersionData.outdated}`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (3+ releases behind)`, 'info');
|
|
}
|
|
|
|
async function testAllPhpVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'php_all';
|
|
|
|
log('🐘 Testing All PHP Versions...', 'info');
|
|
await fetchPhpVersionData();
|
|
if (!phpVersionData) {
|
|
alert('PHP version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
|
|
// Test all PHP versions in sequence
|
|
initInsights();
|
|
|
|
// Current
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.latest, 'php_all_current', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
// 1 release behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.closeEnough, 'php_all_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
// 2 releases behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.twoReleasesBehind, 'php_all_two_behind', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
// 3+ releases behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendPhpTestEvent(phpVersionData.outdated, 'php_all_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
log(`✅ All PHP tests complete: 64 events across all versions`, 'success');
|
|
log(`🔍 Expected: Current, Close enough, Close enough, Outdated badges`, 'info');
|
|
}
|
|
|
|
// Ruby SDK version data
|
|
let rubyVersionData = null;
|
|
|
|
// Fetch Ruby SDK versions
|
|
async function fetchRubyVersionData() {
|
|
try {
|
|
log('💎 Fetching Ruby SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-ruby/main/CHANGELOG.md', {
|
|
cache: 'no-cache'
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch Ruby CHANGELOG: ${response.status}`);
|
|
}
|
|
|
|
const text = await response.text();
|
|
|
|
// Debug: Log first 500 characters to see actual format
|
|
log(`🔍 Ruby CHANGELOG first 500 chars: ${text.substring(0, 500)}`, 'info');
|
|
|
|
// Try multiple regex patterns to find what works
|
|
const patterns = [
|
|
/^## (\d+\.\d+\.\d+)\s*$/gm, // Original with optional whitespace
|
|
/^## (\d+\.\d+\.\d+)$/gm, // Strict end
|
|
/## (\d+\.\d+\.\d+)/gm, // Anywhere in line
|
|
/^##\s+(\d+\.\d+\.\d+)/gm // Flexible spacing after ##
|
|
];
|
|
|
|
let versionMatches = null;
|
|
let workingPattern = null;
|
|
|
|
for (let i = 0; i < patterns.length; i++) {
|
|
const matches = [...text.matchAll(patterns[i])];
|
|
log(`🔍 Pattern ${i + 1} found ${matches.length} matches`, 'info');
|
|
if (matches.length > 0) {
|
|
versionMatches = matches;
|
|
workingPattern = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!versionMatches || versionMatches.length === 0) {
|
|
throw new Error('No Ruby versions found in CHANGELOG.md with any pattern');
|
|
}
|
|
|
|
log(`✅ Using pattern ${workingPattern}, found ${versionMatches.length} versions`, 'success');
|
|
|
|
// Extract versions (Ruby CHANGELOG has no dates)
|
|
const versions = versionMatches.map(match => match[1]);
|
|
|
|
rubyVersionData = {
|
|
latest: versions[0],
|
|
closeEnough: versions[1] || versions[0], // 1 release behind
|
|
outdated: versions[3] || versions[2] || versions[1], // 3+ releases behind
|
|
versions: versions,
|
|
versionDates: versionDates
|
|
};
|
|
|
|
log(`✅ Ruby SDK data loaded: latest=${rubyVersionData.latest}, closeEnough=${rubyVersionData.closeEnough}, outdated=${rubyVersionData.outdated}`, 'success');
|
|
|
|
// Update version info display
|
|
const versionInfo = document.getElementById('ruby-real-version-info');
|
|
if (versionInfo) {
|
|
versionInfo.innerHTML = `
|
|
<strong>Ruby Versions:</strong><br>
|
|
• Latest: v${rubyVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${rubyVersionData.closeEnough} (Close enough)<br>
|
|
• 6+ Behind: v${rubyVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
|
|
return rubyVersionData;
|
|
} catch (error) {
|
|
log(`❌ Failed to fetch Ruby SDK versions: ${error.message}`, 'error');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function ensureRubyVersionsLoaded() {
|
|
return rubyVersionData ? Promise.resolve() : fetchRubyVersionData();
|
|
}
|
|
|
|
// Send Ruby SDK test events
|
|
async function sendRubyTestEvent(version, scenario, eventIndex) {
|
|
try {
|
|
insights.capture('test_ruby_time_based_detection', {
|
|
$lib: 'insights-ruby',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
event_index: eventIndex,
|
|
$session_id: `ruby-${scenario}-${Date.now()}`,
|
|
framework: 'Rails'
|
|
});
|
|
} catch (error) {
|
|
log(`❌ Error sending Ruby event: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// Ruby test functions
|
|
async function testRubyRealCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ruby_current';
|
|
log('💎 Testing Ruby Current Version...', 'info');
|
|
await ensureRubyVersionsLoaded();
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendRubyTestEvent(rubyVersionData.latest, 'ruby_current', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Ruby current version test complete: 16 events with v${rubyVersionData.latest}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (Ruby version matches latest)`, 'info');
|
|
}
|
|
|
|
async function testRubyRealCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ruby_close_enough';
|
|
log('💎 Testing Ruby Close Enough Version...', 'info');
|
|
await ensureRubyVersionsLoaded();
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendRubyTestEvent(rubyVersionData.closeEnough, 'ruby_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Ruby close enough test complete: 16 events with v${rubyVersionData.closeEnough}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (1 release behind)`, 'info');
|
|
}
|
|
|
|
async function testRubyRealOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ruby_outdated';
|
|
log('💎 Testing Ruby Outdated Version...', 'info');
|
|
await ensureRubyVersionsLoaded();
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendRubyTestEvent(rubyVersionData.outdated, 'ruby_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Ruby outdated test complete: 16 events with v${rubyVersionData.outdated}`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (3+ releases behind, >48h old)`, 'info');
|
|
}
|
|
|
|
async function testRubyEdgeCase() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'ruby_edge_case';
|
|
log('💎 Testing Ruby Edge Case...', 'info');
|
|
await ensureRubyVersionsLoaded();
|
|
initInsights();
|
|
// Use outdated version for edge case testing
|
|
const edgeVersion = rubyVersionData.outdated;
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendRubyTestEvent(edgeVersion, 'ruby_edge_case', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ Ruby edge case test complete: 16 events with v${edgeVersion}`, 'success');
|
|
log(`🔍 Edge case: Temporarily adjust time threshold to test dual-check logic`, 'info');
|
|
}
|
|
|
|
async function testAllRubyRealVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'all_ruby_real';
|
|
log('💎 Testing All Ruby Real Versions...', 'info');
|
|
await testRubyRealCurrentVersionInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
await testRubyRealCloseEnoughInternal();
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
await testRubyRealOutdatedInternal();
|
|
log('🎉 All Ruby real version tests completed!', 'success');
|
|
}
|
|
|
|
// Internal Ruby test functions
|
|
async function testRubyRealCurrentVersionInternal() {
|
|
log('💎 Ruby Current (internal)...', 'info');
|
|
await ensureRubyVersionsLoaded();
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendRubyTestEvent(rubyVersionData.latest, 'ruby_current_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testRubyRealCloseEnoughInternal() {
|
|
log('💎 Ruby Close Enough (internal)...', 'info');
|
|
await ensureRubyVersionsLoaded();
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendRubyTestEvent(rubyVersionData.closeEnough, 'ruby_close_enough_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
async function testRubyRealOutdatedInternal() {
|
|
log('💎 Ruby Outdated (internal)...', 'info');
|
|
await ensureRubyVersionsLoaded();
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendRubyTestEvent(rubyVersionData.outdated, 'ruby_outdated_internal', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
}
|
|
|
|
// Elixir SDK version data
|
|
let elixirVersionData = null;
|
|
|
|
// Fetch Elixir SDK versions
|
|
async function fetchElixirVersionData() {
|
|
try {
|
|
log('⚗️ Fetching Elixir SDK version data from CHANGELOG...', 'info');
|
|
const response = await fetch('https://raw.githubusercontent.com/Insights/insights-elixir/master/CHANGELOG.md', {
|
|
cache: 'no-cache'
|
|
});
|
|
const text = await response.text();
|
|
|
|
// Parse Elixir SDK versions (format: "## 1.1.0 - 2025-07-01")
|
|
const versionRegex = /^## (\d+\.\d+\.\d+)\s*-\s*(\d{4}-\d{2}-\d{2})/gm;
|
|
const versions = [];
|
|
let match;
|
|
|
|
while ((match = versionRegex.exec(text)) !== null) {
|
|
versions.push(match[1]);
|
|
}
|
|
|
|
if (versions.length >= 3) {
|
|
elixirVersionData = {
|
|
latest: versions[0], // Current version
|
|
closeEnough: versions[1], // 1 release behind
|
|
twoReleasesBehind: versions[2], // 2 releases behind
|
|
outdated: versions[3] || versions[versions.length - 1], // 3+ releases behind
|
|
versions: versions
|
|
};
|
|
|
|
log(`⚗️ Elixir SDK versions loaded: latest=${elixirVersionData.latest}, 1 behind=${elixirVersionData.closeEnough}, 2 behind=${elixirVersionData.twoReleasesBehind}, outdated=${elixirVersionData.outdated}`, 'success');
|
|
updateElixirVersionDisplay();
|
|
} else {
|
|
log('❌ Could not find enough Elixir versions', 'error');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Error fetching Elixir versions: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
function updateElixirVersionDisplay() {
|
|
if (!elixirVersionData) return;
|
|
|
|
document.getElementById('elixir-version-info').innerHTML = `
|
|
<strong>Elixir SDK Test Versions:</strong><br>
|
|
• Latest: v${elixirVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${elixirVersionData.closeEnough} (Close enough)<br>
|
|
• 2 Behind: v${elixirVersionData.twoReleasesBehind} (Close enough)<br>
|
|
• 3+ Behind: v${elixirVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
|
|
async function sendElixirTestEvent(version, scenario, eventIndex) {
|
|
insights.capture('elixir_test_event', {
|
|
$lib: 'insights-elixir',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
event_index: eventIndex,
|
|
$session_id: `elixir-${scenario}-${Date.now()}`,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
|
|
// Elixir Test Functions
|
|
async function testElixirCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'elixir_current';
|
|
|
|
log('⚗️ Testing Elixir Current Version...', 'info');
|
|
await fetchElixirVersionData();
|
|
if (!elixirVersionData) {
|
|
alert('Elixir version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.latest, 'elixir_current', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Elixir current version test complete: 16 events with v${elixirVersionData.latest}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (Elixir version matches latest)`, 'info');
|
|
}
|
|
|
|
async function testElixirCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'elixir_close_enough';
|
|
|
|
log('⚗️ Testing Elixir 1 Release Behind...', 'info');
|
|
await fetchElixirVersionData();
|
|
if (!elixirVersionData) {
|
|
alert('Elixir version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.closeEnough, 'elixir_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Elixir 1 release behind test complete: 16 events with v${elixirVersionData.closeEnough}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (1 release behind)`, 'info');
|
|
}
|
|
|
|
async function testElixirTwoReleasesBehind() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'elixir_two_behind';
|
|
|
|
log('⚗️ Testing Elixir 2 Releases Behind...', 'info');
|
|
await fetchElixirVersionData();
|
|
if (!elixirVersionData) {
|
|
alert('Elixir version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.twoReleasesBehind, 'elixir_two_behind', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Elixir 2 releases behind test complete: 16 events with v${elixirVersionData.twoReleasesBehind}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (2 releases behind, simplified logic)`, 'info');
|
|
}
|
|
|
|
async function testElixirOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'elixir_outdated';
|
|
|
|
log('⚗️ Testing Elixir 3+ Releases Behind...', 'info');
|
|
await fetchElixirVersionData();
|
|
if (!elixirVersionData) {
|
|
alert('Elixir version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.outdated, 'elixir_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
log(`✅ Elixir 3+ releases behind test complete: 16 events with v${elixirVersionData.outdated}`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (3+ releases behind)`, 'info');
|
|
}
|
|
|
|
async function testAllElixirVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'elixir_all';
|
|
|
|
log('⚗️ Testing All Elixir Versions...', 'info');
|
|
await fetchElixirVersionData();
|
|
if (!elixirVersionData) {
|
|
alert('Elixir version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
|
|
// Test all Elixir versions in sequence
|
|
initInsights();
|
|
|
|
// Current
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.latest, 'elixir_all_current', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
// 1 release behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.closeEnough, 'elixir_all_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
// 2 releases behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.twoReleasesBehind, 'elixir_all_two_behind', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
// 3+ releases behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendElixirTestEvent(elixirVersionData.outdated, 'elixir_all_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
log(`✅ All Elixir tests complete: 64 events across all versions`, 'success');
|
|
log(`🔍 Expected: Current, Close enough, Close enough, Outdated badges`, 'info');
|
|
}
|
|
|
|
// .NET SDK Test Functions
|
|
let dotnetVersionData = null;
|
|
|
|
async function fetchDotnetVersionData() {
|
|
try {
|
|
log('🔷 Fetching .NET SDK version data from GitHub Releases...', 'info');
|
|
const response = await fetch('https://api.github.com/repos/Insights/insights-dotnet/releases', {
|
|
cache: 'no-cache'
|
|
});
|
|
const releases = await response.json();
|
|
// Parse .NET SDK versions from GitHub releases (format: "v2.0.0")
|
|
const versions = releases
|
|
.filter(r => r.tag_name && r.tag_name.startsWith('v'))
|
|
.map(r => r.tag_name.replace('v', ''))
|
|
.filter(v => /^\d+\.\d+\.\d+$/.test(v)); // Only semantic versions
|
|
|
|
if (versions.length >= 3) {
|
|
dotnetVersionData = {
|
|
latest: versions[0], // Current version
|
|
closeEnough: versions[1], // 1 release behind
|
|
twoReleasesBehind: versions[2], // 2 releases behind
|
|
outdated: versions[3] || versions[versions.length - 1], // 3+ releases behind
|
|
versions: versions
|
|
};
|
|
log(`🔷 .NET SDK versions loaded: latest=${dotnetVersionData.latest}, 1 behind=${dotnetVersionData.closeEnough}, 2 behind=${dotnetVersionData.twoReleasesBehind}, outdated=${dotnetVersionData.outdated}`, 'success');
|
|
updateDotnetVersionDisplay();
|
|
} else {
|
|
log('❌ Could not find enough .NET versions', 'error');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Error fetching .NET versions: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
function updateDotnetVersionDisplay() {
|
|
if (!dotnetVersionData) return;
|
|
document.getElementById('dotnet-version-info').innerHTML = `
|
|
<strong>.NET SDK Test Versions:</strong><br>
|
|
• Latest: v${dotnetVersionData.latest} (Current)<br>
|
|
• 1 Behind: v${dotnetVersionData.closeEnough} (Close enough)<br>
|
|
• 2 Behind: v${dotnetVersionData.twoReleasesBehind} (Close enough)<br>
|
|
• 3+ Behind: v${dotnetVersionData.outdated} (Outdated)
|
|
`;
|
|
}
|
|
|
|
async function sendDotnetTestEvent(version, scenario, eventIndex) {
|
|
insights.capture('dotnet_test_event', {
|
|
$lib: 'insights-dotnet',
|
|
$lib_version: version,
|
|
test_scenario: scenario,
|
|
test_event_index: eventIndex,
|
|
timestamp: new Date().toISOString(),
|
|
distinct_id: `test_user_dotnet_${scenario}`
|
|
});
|
|
}
|
|
|
|
async function testDotnetCurrentVersion() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'dotnet_current';
|
|
log('🔷 Testing .NET Current Version...', 'info');
|
|
|
|
await fetchDotnetVersionData();
|
|
if (!dotnetVersionData) {
|
|
alert('.NET version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.latest, 'dotnet_current', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ .NET current version test complete: 16 events with v${dotnetVersionData.latest}`, 'success');
|
|
log(`🔍 Expected: "Current" badge (.NET version matches latest)`, 'info');
|
|
}
|
|
|
|
async function testDotnetCloseEnough() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'dotnet_close_enough';
|
|
log('🔷 Testing .NET 1 Release Behind...', 'info');
|
|
|
|
await fetchDotnetVersionData();
|
|
if (!dotnetVersionData) {
|
|
alert('.NET version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.closeEnough, 'dotnet_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ .NET 1 release behind test complete: 16 events with v${dotnetVersionData.closeEnough}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (1 release behind)`, 'info');
|
|
}
|
|
|
|
async function testDotnetTwoReleasesBehind() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'dotnet_two_behind';
|
|
log('🔷 Testing .NET 2 Releases Behind...', 'info');
|
|
|
|
await fetchDotnetVersionData();
|
|
if (!dotnetVersionData) {
|
|
alert('.NET version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.twoReleasesBehind, 'dotnet_two_behind', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ .NET 2 releases behind test complete: 16 events with v${dotnetVersionData.twoReleasesBehind}`, 'success');
|
|
log(`🔍 Expected: "Close enough" badge (2 releases behind, simplified logic)`, 'info');
|
|
}
|
|
|
|
async function testDotnetOutdated() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'dotnet_outdated';
|
|
log('🔷 Testing .NET 3+ Releases Behind...', 'info');
|
|
|
|
await fetchDotnetVersionData();
|
|
if (!dotnetVersionData) {
|
|
alert('.NET version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
initInsights();
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.outdated, 'dotnet_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
log(`✅ .NET 3+ releases behind test complete: 16 events with v${dotnetVersionData.outdated}`, 'success');
|
|
log(`🔍 Expected: "Outdated" badge (3+ releases behind)`, 'info');
|
|
}
|
|
|
|
async function testAllDotnetVersions() {
|
|
if (currentTest) {
|
|
alert('Please reload the page before running another test');
|
|
return;
|
|
}
|
|
currentTest = 'dotnet_all';
|
|
log('🔷 Testing All .NET Versions...', 'info');
|
|
|
|
await fetchDotnetVersionData();
|
|
if (!dotnetVersionData) {
|
|
alert('.NET version data could not be loaded. Please try again.');
|
|
return;
|
|
}
|
|
// Test all .NET versions in sequence
|
|
initInsights();
|
|
// Current
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.latest, 'dotnet_all_current', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
// 1 release behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.closeEnough, 'dotnet_all_close_enough', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
// 2 releases behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.twoReleasesBehind, 'dotnet_all_two_behind', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
// 3+ releases behind
|
|
for (let i = 0; i < 16; i++) {
|
|
await sendDotnetTestEvent(dotnetVersionData.outdated, 'dotnet_all_outdated', i);
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
log(`✅ All .NET tests complete: 64 events across all versions`, 'success');
|
|
log(`🔍 Expected: Current, Close enough, Close enough, Outdated badges`, 'info');
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
|
|
</html> |