feat: track Memind product analytics

This commit is contained in:
john
2026-07-20 20:19:52 +08:00
parent 258e4a8a07
commit d479e89fc7
10 changed files with 446 additions and 8 deletions
+48 -1
View File
@@ -3,14 +3,58 @@ import assert from 'node:assert/strict';
import vm from 'node:vm';
import {
buildProductAnalyticsContext,
injectMindSpaceAnalytics,
pseudonymizeAnalyticsId,
resolveAnalyticsOwnerSegment,
resolveAnalyticsOwnerLabel,
resolveMindSpaceAnalyticsConfig,
resolveProductAnalyticsConfig,
sendMindSpaceAnalyticsEvent,
} from './mindspace-analytics.mjs';
test('product analytics uses a separate website and the existing pseudonymization secret', () => {
const base = resolveMindSpaceAnalyticsConfig({
MEMIND_ANALYTICS_ENABLED: 'true',
MEMIND_ANALYTICS_WEBSITE_ID: 'generated-pages',
MEMIND_ANALYTICS_ID_SECRET: 'local-secret',
});
const config = resolveProductAnalyticsConfig({
MEMIND_PRODUCT_ANALYTICS_ENABLED: 'true',
MEMIND_PRODUCT_ANALYTICS_WEBSITE_ID: 'product-shell',
}, base);
assert.equal(config.enabled, true);
assert.equal(config.websiteId, 'product-shell');
assert.notEqual(config.websiteId, base.websiteId);
const context = buildProductAnalyticsContext({
config,
user: { id: 'user-123', displayName: '张三', role: 'user', planType: 'pro' },
});
assert.deepEqual(context.identity, {
distinctId: pseudonymizeAnalyticsId('user-123', 'local-secret'),
username: '张三',
ownerSegment: 'plan:pro',
channel: 'h5',
surface: 'product',
});
});
test('product analytics context stays public-safe before login', () => {
const context = buildProductAnalyticsContext({
config: {
enabled: true,
websiteId: 'product-shell',
idSecret: 'local-secret',
scriptPath: '/analytics/script.js',
hostPath: '/analytics',
},
});
assert.equal(context.enabled, true);
assert.equal(context.websiteId, 'product-shell');
assert.equal(context.identity, null);
assert.equal('idSecret' in context, false);
});
test('analytics config is disabled unless explicitly enabled and configured', () => {
assert.equal(resolveMindSpaceAnalyticsConfig({ MEMIND_ANALYTICS_ENABLED: 'true' }).enabled, false);
assert.equal(resolveMindSpaceAnalyticsConfig({
@@ -65,7 +109,7 @@ test('injects one local same-origin tracker with page dimensions', () => {
assert.match(out, /src="\/analytics\/script\.js"/);
assert.match(out, /data-host-url="\/analytics"/);
assert.match(out, /data-auto-track="false"/);
assert.match(out, /window\.umami\.identify\(d\.owner_id,\{username:d\.username,memind_page_url:location\.href,owner_segment:d\.owner_segment,channel:d\.channel\}\)/);
assert.match(out, /window\.umami\.identify\(d\.owner_id,\{username:d\.username,memind_page_url:location\.href,owner_segment:d\.owner_segment,channel:d\.channel,surface:d\.surface\}\)/);
assert.match(out, /function pageview\(\).*window\.umami\.track\(\)/);
assert.ok(out.indexOf('identify();pageview();') > 0);
assert.doesNotMatch(out, /t\('page_view'\)/);
@@ -74,6 +118,8 @@ test('injects one local same-origin tracker with page dimensions', () => {
assert.doesNotMatch(out, /owner_label/);
assert.match(out, /"username":"张三"/);
assert.match(out, /page_click/);
assert.match(out, /target_path/);
assert.doesNotMatch(out, /target_url/);
assert.match(out, /page_form_submit/);
assert.match(out, /page_scroll_/);
assert.match(out, /page_engaged_10s/);
@@ -125,6 +171,7 @@ test('identifies the pseudonymous owner before sending a standard page view', ()
memind_page_url: 'https://m.tkmind.cn/MindSpace/demo/public/page.html',
owner_segment: 'plan:pro',
channel: 'h5',
surface: 'generated_page',
}],
['track'],
]);