gtm-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGTM Testing - Validation & Debugging
GTM测试 - 验证与调试
Guide users through comprehensive testing of GTM tracking implementation. Prefers automated headless testing over manual steps wherever possible.
引导用户完成GTM跟踪实现的全面测试。在任何可行的情况下,优先选择自动化无头测试而非手动步骤。
Testing Philosophy
测试理念
Four-tier validation approach, ordered by automation level:
- Tier 0 (Automated): Playwright headless tests (no browser needed, fully automated)
- Tier 1 (Manual): Browser Console dataLayer verification
- Tier 2 (Manual): GTM Preview Mode tag firing verification
- Tier 3 (Manual): GA4 DebugView end-to-end verification
Always start with Tier 0 if the user asks "can you do it yourself" or wants automated testing. Fall back to manual tiers only for GTM container and GA4 validation, which require a browser session.
采用四级验证方法,按自动化程度排序:
- Tier 0(自动化):Playwright无头测试(无需浏览器,完全自动化)
- Tier 1(手动):浏览器控制台dataLayer验证
- Tier 2(手动):GTM预览模式标签触发验证
- Tier 3(手动):GA4 DebugView端到端校验
如果用户询问「能否自动完成」或需要自动化测试,始终从Tier 0开始。仅在需要验证GTM容器和GA4配置(需要浏览器会话)时,才退回到手动层级。
Tier 0: Automated Playwright Testing (Preferred)
Tier 0:自动化Playwright测试(优先推荐)
Run this tier first. It requires no browser interaction from the user and can be run entirely by Claude.
首先运行此层级。无需用户进行浏览器交互,可由Claude完全自动执行。
Prerequisites Check
前置检查
bash
undefinedbash
undefinedCheck if Playwright is installed
Check if Playwright is installed
npx playwright --version
npx playwright --version
If not installed as a project dependency:
If not installed as a project dependency:
npm install --save-dev playwright
npx playwright install chromium
npm install --save-dev playwright
npx playwright install chromium
Check if dev server is running
Check if dev server is running
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000
If not running, start it:
If not running, start it:
npm run dev
npm run dev
undefinedundefinedCore Helper: captureDataLayerEvents
核心辅助函数:captureDataLayerEvents
This helper intercepts all calls during an action and returns the captured events. Use it in every test.
dataLayer.push()javascript
async function captureDataLayerEvents(page, action) {
await page.evaluate(() => {
window.__testEvents = [];
const original = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function (...args) {
window.__testEvents.push(args[0]);
return original(...args);
};
});
await action();
await page.waitForTimeout(300);
return await page.evaluate(() => window.__testEvents || []);
}该辅助函数会拦截操作过程中所有调用,并返回捕获到的事件。所有测试中都应使用此函数。
dataLayer.push()javascript
async function captureDataLayerEvents(page, action) {
await page.evaluate(() => {
window.__testEvents = [];
const original = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function (...args) {
window.__testEvents.push(args[0]);
return original(...args);
};
});
await action();
await page.waitForTimeout(300);
return await page.evaluate(() => window.__testEvents || []);
}Key Patterns for Common Element Types
常见元素类型的关键操作模式
Next.js Link components (navigation, course buttons):
Do NOT use — it triggers navigation before the onClick handler fires. Use instead:
page.click()dispatchEventjavascript
await page.evaluate(() => {
const btn = document.querySelector('a.js-module_nav');
if (btn) btn.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
});
await page.waitForTimeout(400);Outbound links (href to external domains):
Block the navigation so the page stays loaded while the event fires:
javascript
await page.route('**github.com**', route => route.abort());
// Then use dispatchEvent as aboveRegular buttons and internal actions:
Standard click works fine:
javascript
await page.locator('#element-id').click({ force: true });Next.js Link组件(导航、课程按钮):
请勿使用——它会在onClick处理器触发前触发导航。请改用:
page.click()dispatchEventjavascript
await page.evaluate(() => {
const btn = document.querySelector('a.js-module_nav');
if (btn) btn.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
});
await page.waitForTimeout(400);外部链接(指向外部域名的href):
阻止导航,以便在事件触发时页面保持加载状态:
javascript
await page.route('**github.com**', route => route.abort());
// Then use dispatchEvent as above常规按钮与内部操作:
标准点击即可正常工作:
javascript
await page.locator('#element-id').click({ force: true });Test Script Template
测试脚本模板
Create in the project root:
scripts/test-tracking.jsjavascript
const { chromium } = require('playwright');
const BASE_URL = 'http://localhost:3000';
const results = { passed: [], failed: [], warnings: [] };
function pass(test, detail = '') {
results.passed.push({ test, detail });
console.log(` PASS ${test}${detail ? ' - ' + detail : ''}`);
}
function fail(test, detail = '') {
results.failed.push({ test, detail });
console.log(` FAIL ${test}${detail ? ' - ' + detail : ''}`);
}
function warn(test, detail = '') {
results.warnings.push({ test, detail });
console.log(` WARN ${test}${detail ? ' - ' + detail : ''}`);
}
async function captureDataLayerEvents(page, action) {
await page.evaluate(() => {
window.__testEvents = [];
const original = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function (...args) {
window.__testEvents.push(args[0]);
return original(...args);
};
});
await action();
await page.waitForTimeout(300);
return await page.evaluate(() => window.__testEvents || []);
}
async function runTests() {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
console.log('\n=== GTM dataLayer Event Tests ===\n');
// TEST: dataLayer initialisation
console.log('Test: dataLayer initialisation');
{
const page = await context.newPage();
await page.goto(BASE_URL, { waitUntil: 'networkidle' });
const hasDataLayer = await page.evaluate(() => Array.isArray(window.dataLayer));
hasDataLayer ? pass('dataLayer initialised') : fail('dataLayer not found');
const gtmEvent = await page.evaluate(() => window.dataLayer.find(e => e['gtm.start']));
gtmEvent ? pass('GTM bootstrap event present') : fail('GTM bootstrap event missing - container may not be installed');
await page.close();
}
// TEST: cta_click event
// Adjust selector to match your actual element ID
console.log('\nTest: cta_click event');
{
const page = await context.newPage();
await page.goto(BASE_URL, { waitUntil: 'networkidle' });
const events = await captureDataLayerEvents(page, async () => {
const el = await page.$('#your-cta-id');
if (el) await page.evaluate(el => el.dispatchEvent(new MouseEvent('click', { bubbles: true })), el);
});
const e = events.find(e => e.event === 'cta_click');
e ? pass('cta_click fired', `location=${e.cta_location}`) : fail('cta_click did not fire');
await page.close();
}
// Add more tests following the same pattern...
// RESULTS
await browser.close();
console.log('\n=== RESULTS ===');
console.log(` Passed: ${results.passed.length}`);
console.log(` Failed: ${results.failed.length}`);
console.log(` Warnings: ${results.warnings.length}`);
if (results.failed.length > 0) {
console.log('\nFailed:');
results.failed.forEach(f => console.log(` - ${f.test}: ${f.detail}`));
}
process.exit(results.failed.length > 0 ? 1 : 0);
}
runTests().catch(err => { console.error('Fatal:', err.message); process.exit(1); });在项目根目录创建:
scripts/test-tracking.jsjavascript
const { chromium } = require('playwright');
const BASE_URL = 'http://localhost:3000';
const results = { passed: [], failed: [], warnings: [] };
function pass(test, detail = '') {
results.passed.push({ test, detail });
console.log(` PASS ${test}${detail ? ' - ' + detail : ''}`);
}
function fail(test, detail = '') {
results.failed.push({ test, detail });
console.log(` FAIL ${test}${detail ? ' - ' + detail : ''}`);
}
function warn(test, detail = '') {
results.warnings.push({ test, detail });
console.log(` WARN ${test}${detail ? ' - ' + detail : ''}`);
}
async function captureDataLayerEvents(page, action) {
await page.evaluate(() => {
window.__testEvents = [];
const original = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function (...args) {
window.__testEvents.push(args[0]);
return original(...args);
};
});
await action();
await page.waitForTimeout(300);
return await page.evaluate(() => window.__testEvents || []);
}
async function runTests() {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
console.log('\n=== GTM dataLayer Event Tests ===\n');
// TEST: dataLayer initialisation
console.log('Test: dataLayer initialisation');
{
const page = await context.newPage();
await page.goto(BASE_URL, { waitUntil: 'networkidle' });
const hasDataLayer = await page.evaluate(() => Array.isArray(window.dataLayer));
hasDataLayer ? pass('dataLayer initialised') : fail('dataLayer not found');
const gtmEvent = await page.evaluate(() => window.dataLayer.find(e => e['gtm.start']));
gtmEvent ? pass('GTM bootstrap event present') : fail('GTM bootstrap event missing - container may not be installed');
await page.close();
}
// TEST: cta_click event
// Adjust selector to match your actual element ID
console.log('\nTest: cta_click event');
{
const page = await context.newPage();
await page.goto(BASE_URL, { waitUntil: 'networkidle' });
const events = await captureDataLayerEvents(page, async () => {
const el = await page.$('#your-cta-id');
if (el) await page.evaluate(el => el.dispatchEvent(new MouseEvent('click', { bubbles: true })), el);
});
const e = events.find(e => e.event === 'cta_click');
e ? pass('cta_click fired', `location=${e.cta_location}`) : fail('cta_click did not fire');
await page.close();
}
// Add more tests following the same pattern...
// RESULTS
await browser.close();
console.log('\n=== RESULTS ===');
console.log(` Passed: ${results.passed.length}`);
console.log(` Failed: ${results.failed.length}`);
console.log(` Warnings: ${results.warnings.length}`);
if (results.failed.length > 0) {
console.log('\nFailed:');
results.failed.forEach(f => console.log(` - ${f.test}: ${f.detail}`));
}
process.exit(results.failed.length > 0 ? 1 : 0);
}
runTests().catch(err => { console.error('Fatal:', err.message); process.exit(1); });Finding Correct Element Selectors
查找正确的元素选择器
Before writing tests, always inspect what's actually rendered. Use this discovery script:
javascript
// Add to test script or run as a separate debug script
const page = await context.newPage();
await page.goto(`${BASE_URL}/your-page`, { waitUntil: 'networkidle' });
const tracked = await page.evaluate(() => {
return Array.from(document.querySelectorAll('[id], .js-track, [data-track]')).map(el => ({
id: el.id,
tag: el.tagName,
class: el.className,
text: el.textContent.trim().substring(0, 40),
href: el.getAttribute('href'),
}));
});
console.log(JSON.stringify(tracked, null, 2));在编写测试前,务必检查实际渲染的内容。使用以下发现脚本:
javascript
// Add to test script or run as a separate debug script
const page = await context.newPage();
await page.goto(`${BASE_URL}/your-page`, { waitUntil: 'networkidle' });
const tracked = await page.evaluate(() => {
return Array.from(document.querySelectorAll('[id], .js-track, [data-track]')).map(el => ({
id: el.id,
tag: el.tagName,
class: el.className,
text: el.textContent.trim().substring(0, 40),
href: el.getAttribute('href'),
}));
});
console.log(JSON.stringify(tracked, null, 2));Validating GTM Container Configuration via API
通过API验证GTM容器配置
Before running browser tests, verify the GTM container itself is correctly configured. This catches orphaned trigger references and missing measurement IDs.
javascript
// scripts/audit-gtm-coverage.js
// Uses googleapis + gtm-credentials.json + gtm-token.json + gtm-config.json
// Critical checks:
// 1. Base GA4 config tag (googtag) - must fire on Page View trigger
// If firingTriggerId references a non-existent trigger, NO pages are tracked
// 2. GA4 event tags (gaawe) - must have measurementIdOverride set
// Parameter key is "measurementIdOverride" NOT "measurementId"
// 3. All triggers must be used by at least one tag
// 4. All tags must have at least one firing triggerCritical GTM API bug to watch for: The (GA4 Event) tag type uses and (not or ). The correct parameter structure is:
gaawemeasurementIdOverrideeventSettingsTablemeasurementIdeventParametersjavascript
// CORRECT structure for gaawe tags via API
{
type: 'gaawe',
parameter: [
{ type: 'boolean', key: 'sendEcommerceData', value: 'false' },
{ type: 'template', key: 'eventName', value: 'your_event_name' },
{ type: 'template', key: 'measurementIdOverride', value: 'G-XXXXXXXXXX' },
{
type: 'list',
key: 'eventSettingsTable',
list: [
{
type: 'map',
map: [
{ type: 'template', key: 'parameter', value: 'param_name' },
{ type: 'template', key: 'parameterValue', value: '{{DL - Variable Name}}' },
],
},
],
},
],
}在运行浏览器测试前,先验证GTM容器本身是否配置正确。这可以捕获孤立的触发器引用和缺失的测量ID。
javascript
// scripts/audit-gtm-coverage.js
// Uses googleapis + gtm-credentials.json + gtm-token.json + gtm-config.json
// Critical checks:
// 1. Base GA4 config tag (googtag) - must fire on Page View trigger
// If firingTriggerId references a non-existent trigger, NO pages are tracked
// 2. GA4 event tags (gaawe) - must have measurementIdOverride set
// Parameter key is "measurementIdOverride" NOT "measurementId"
// 3. All triggers must be used by at least one tag
// 4. All tags must have at least one firing trigger需要注意的GTM API关键bug: (GA4事件)标签类型使用和(而非或)。正确的参数结构如下:
gaawemeasurementIdOverrideeventSettingsTablemeasurementIdeventParametersjavascript
// CORRECT structure for gaawe tags via API
{
type: 'gaawe',
parameter: [
{ type: 'boolean', key: 'sendEcommerceData', value: 'false' },
{ type: 'template', key: 'eventName', value: 'your_event_name' },
{ type: 'template', key: 'measurementIdOverride', value: 'G-XXXXXXXXXX' },
{
type: 'list',
key: 'eventSettingsTable',
list: [
{
type: 'map',
map: [
{ type: 'template', key: 'parameter', value: 'param_name' },
{ type: 'template', key: 'parameterValue', value: '{{DL - Variable Name}}' },
],
},
],
},
],
}Running and Interpreting Results
运行与结果解读
bash
node scripts/test-tracking.jsExit code = all tests passed. Exit code = failures exist.
01Result types:
- - Event fired with correct parameters
PASS - - Event did not fire, or required element not found
FAIL - - Component has tracking code but is not rendered on any page yet (not a bug)
WARN
Common failure causes and fixes:
| Failure | Cause | Fix |
|---|---|---|
| GTM snippet missing from | Add GTM container snippet to layout |
| Event didn't fire | Element uses wrong selector in test | Use discovery script to find real ID/class |
| Event fired but page unloaded | Clicking a Next.js | Use |
| Outbound click not captured | Page navigated away before capture | Use |
| No events on page load | GTM base tag has orphaned trigger reference | Fix via GTM API or UI - re-assign to Page View trigger |
bash
node scripts/test-tracking.js退出码 = 所有测试通过。退出码 = 存在失败项。
01结果类型:
- - 事件触发且参数正确
PASS - - 事件未触发,或未找到所需元素
FAIL - - 组件包含跟踪代码但尚未在任何页面上渲染(不属于bug)
WARN
常见失败原因与修复方案:
| 失败情况 | 原因 | 修复方案 |
|---|---|---|
| | 将GTM容器代码段添加到布局文件中 |
| Event didn't fire | 测试中使用了错误的选择器 | 使用发现脚本查找真实的ID/类名 |
| Event fired but page unloaded | 点击Next.js | 使用 |
| Outbound click not captured | 捕获前页面已导航离开 | 使用 |
| No events on page load | GTM基础标签存在孤立的触发器引用 | 通过GTM API或UI修复 - 重新分配到Page View触发器 |
Tier 1: Browser Console Testing (Manual)
Tier 1:浏览器控制台测试(手动)
Use when you want to manually verify events while interacting with the site.
当你想要在与站点交互时手动验证事件时使用此方法。
Step 1: Check dataLayer Exists
步骤1:检查dataLayer是否存在
javascript
window.dataLayer
// Expected: [...] array
// If undefined: GTM not installedjavascript
window.dataLayer
// Expected: [...] array
// If undefined: GTM not installedStep 2: Monitor dataLayer in Real-Time
步骤2:实时监控dataLayer
javascript
const _push = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function(...args) {
console.log('%c dataLayer.push', 'background:#222;color:#0f0;padding:2px 6px', args[0]);
return _push(...args);
};
// Now every push is logged in greenjavascript
const _push = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function(...args) {
console.log('%c dataLayer.push', 'background:#222;color:#0f0;padding:2px 6px', args[0]);
return _push(...args);
};
// Now every push is logged in greenStep 3: Test Each Event
步骤3:测试每个事件
Click elements one at a time and verify the console output matches expected:
Expected for cta_click:
{
event: "cta_click",
cta_location: "hero",
cta_type: "primary",
cta_text: "Start Course",
cta_destination: "/claude-code"
}逐个点击元素,验证控制台输出是否与预期一致:
Expected for cta_click:
{
event: "cta_click",
cta_location: "hero",
cta_type: "primary",
cta_text: "Start Course",
cta_destination: "/claude-code"
}Validation Checklist - Tier 1
验证清单 - Tier 1
- is an array
window.dataLayer - GTM bootstrap event () present
gtm.start - Each event fires with correct name
event - All required parameters present and non-empty
- No duplicate events on single click
- No JavaScript errors in console
- 是一个数组
window.dataLayer - 存在GTM引导事件()
gtm.start - 每个事件都以正确的名称触发
event - 所有必填参数均存在且非空
- 单次点击不会触发重复事件
- 控制台中无JavaScript错误
Tier 2: GTM Preview Mode (Manual)
Tier 2:GTM预览模式(手动)
Confirms the GTM container receives events and fires tags. Requires GTM UI access.
确认GTM容器接收事件并触发标签。需要GTM UI访问权限。
Setup
设置步骤
- Go to tagmanager.google.com
- Select container
- Click Preview
- Enter site URL, click Connect
- A debug panel appears at the bottom of your site
- 访问tagmanager.google.com
- 选择容器
- 点击预览
- 输入站点URL,点击连接
- 站点底部会出现一个调试面板
What to Verify
验证内容
For each event, the Preview panel should show:
Event fired: "cta_click"
Triggers: CE - CTA Click [FIRED]
Tags: GA4 - CTA Click [FIRED]Click a fired tag to verify:
- has the correct GA4 ID
measurementIdOverride - All event parameters are populated (not empty strings)
{{DL - ...}}
对于每个事件,预览面板应显示:
Event fired: "cta_click"
Triggers: CE - CTA Click [FIRED]
Tags: GA4 - CTA Click [FIRED]点击已触发的标签以验证:
- 包含正确的GA4 ID
measurementIdOverride - 所有事件参数均已填充(非空的字符串)
{{DL - ...}}
Validation Checklist - Tier 2
验证清单 - Tier 2
- Preview mode connects successfully
- GA4 Configuration tag fires on page load (not orphaned)
- Each custom event appears in the event list
- Correct trigger fires for each event
- Correct tag fires for each trigger
- Tag parameters show resolved values (not unresolved variable references)
- No tags firing unexpectedly
- 预览模式连接成功
- GA4配置标签在页面加载时触发(非孤立状态)
- 每个自定义事件都出现在事件列表中
- 每个事件都触发了正确的触发器
- 每个触发器都触发了正确的标签
- 标签参数显示解析后的值(非未解析的变量引用)
- 无意外触发的标签
Tier 3: GA4 DebugView (Manual)
Tier 3:GA4 DebugView(手动)
Confirms events reach GA4 with correct parameters. Requires GA4 property access.
确认事件已正确传递到GA4且参数正确。需要GA4属性访问权限。
Enable Debug Mode
启用调试模式
Option A - URL parameter: append to the page URL
?debug_mode=trueOption B - Chrome extension: install Google Analytics Debugger, enable it
选项A - URL参数:在页面URL后追加
?debug_mode=true选项B - Chrome扩展:安装Google Analytics Debugger并启用
Open DebugView
打开DebugView
GA4 > Admin > Property > DebugView
Events appear in real time as you interact with the site.
GA4 > 管理 > 属性 > DebugView
当你与站点交互时,事件会实时显示。
What to Verify
验证内容
- Event name appears (e.g., )
cta_click - All parameters visible with correct values
- event fires on every page navigation
page_view - Event count increments on repeated actions
- 事件名称显示(例如)
cta_click - 所有参数可见且值正确
- 每次页面导航时事件都会触发
page_view - 重复操作时事件计数递增
Validation Checklist - Tier 3
验证清单 - Tier 3
- events firing on all pages
page_view - Custom events appear within 1-3 seconds of firing
- All event parameters visible and correctly valued
- Events attributed to correct page paths
- No unexpected events
- 事件在所有页面上触发
page_view - 自定义事件在触发后1-3秒内显示
- 所有事件参数可见且值正确
- 事件被归因到正确的页面路径
- 无意外事件
Common Issues Reference
常见问题参考
| Issue | Tier Found | Cause | Fix |
|---|---|---|---|
| 1 | GTM snippet missing | Add GTM snippet to |
| Event fires, trigger doesn't | 2 | Event name mismatch (case-sensitive) | Confirm trigger uses |
| Trigger fires, tag doesn't | 2 | Orphaned trigger or misconfigured tag | Check tag has valid firing trigger assigned |
| Page View tag never fires | 2 | Orphaned trigger reference on base tag | Re-assign base tag to a valid Page View trigger |
Parameters show as | 2 | Data Layer Variable not created | Create DLV with correct dataLayer key name |
| Events in Preview, not DebugView | 3 | Wrong GA4 property or debug mode off | Verify Measurement ID matches, enable debug mode |
| Parameters missing in GA4 | 3 | Not mapped in tag's eventSettingsTable | Add parameter mapping in GTM tag config |
| 问题 | 发现层级 | 原因 | 修复方案 |
|---|---|---|---|
| 1 | 缺少GTM代码段 | 将GTM代码段添加到 |
| Event fires, trigger doesn't | 2 | 事件名称不匹配(区分大小写) | 确认触发器使用 |
| Trigger fires, tag doesn't | 2 | 孤立的触发器或标签配置错误 | 检查标签是否分配了有效的触发触发器 |
| Page View tag never fires | 2 | 基础标签存在孤立的触发器引用 | 将基础标签重新分配到有效的Page View触发器 |
Parameters show as | 2 | 未创建数据层变量 | 使用正确的dataLayer键名创建DLV |
| Events in Preview, not DebugView | 3 | GA4属性错误或调试模式未开启 | 验证测量ID匹配,启用调试模式 |
| Parameters missing in GA4 | 3 | 未在标签的eventSettingsTable中映射 | 在GTM标签配置中添加参数映射 |
Full Workflow
完整工作流程
1. Run Tier 0 (automated)
PASS → proceed to publish GTM
FAIL → fix code or GTM config, re-run
2. Run Tier 1 (console) — optional manual spot-check
PASS → proceed
FAIL → fix before Tier 2
3. Run Tier 2 (GTM Preview)
PASS → proceed
FAIL → fix GTM tags/triggers/variables
4. Run Tier 3 (GA4 DebugView)
PASS → publish GTM container
FAIL → fix GA4 config or parameter mappings
5. Publish GTM → GTM UI > Submit > Publish version
6. Disable debug mode in production
7. Monitor GA4 Reports > Engagement > Events1. 运行Tier 0(自动化)
PASS → 继续发布GTM
FAIL → 修复代码或GTM配置,重新运行
2. 运行Tier 1(控制台)——可选的手动抽查
PASS → 继续
FAIL → 在Tier 2前修复
3. 运行Tier 2(GTM预览)
PASS → 继续
FAIL → 修复GTM标签/触发器/变量
4. 运行Tier 3(GA4 DebugView)
PASS → 发布GTM容器
FAIL → 修复GA4配置或参数映射
5. 发布GTM → GTM UI > 提交 > 发布版本
6. 在生产环境中禁用调试模式
7. 监控GA4报告 > 互动 > 事件References
参考资料
- - Extended issue diagnosis
references/debugging-guide.md - - Printable checklist template
references/test-checklist.md - - Example test run output showing PASS/FAIL/WARN format and common failure fixes
examples/sample.md - Related skills: ,
gtm-implementation,gtm-analytics-auditgtm-reporting
- - 扩展问题诊断
references/debugging-guide.md - - 可打印的清单模板
references/test-checklist.md - - 示例测试运行输出,展示PASS/FAIL/WARN格式及常见失败修复方案
examples/sample.md - 相关技能:,
gtm-implementation,gtm-analytics-auditgtm-reporting