diff --git a/lib/main.dart b/lib/main.dart index 93d6dfa..b2b92cd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -36,7 +36,7 @@ void main() { FlutterError.onError = (details) { FlutterError.presentError(details); print('CK_ERROR: ${details.exceptionAsString()}'); - print('CK_CTX: ${details.context.toString()}'); + print('CK_CTX: ${details.context}'); print('CK_STACK: ${details.stack}'); }; // Enable configureApp will cause route problem. @@ -171,12 +171,12 @@ class MyApp extends StatelessWidget { ), ); } - if (pathElements[1] == 'renew-minioffice') { + if (pathElements[1] == 'renew-minioffice' && pathElements.length >= 3) { return MaterialPageRoute(builder: (BuildContext context) => RenewMiniOffice(int.parse(pathElements[2])) ); } - if (pathElements[1] == 'buy-service') { + if (pathElements[1] == 'buy-service' && pathElements.length >= 4) { return MaterialPageRoute(builder: (BuildContext context) => BuyService(int.parse(pathElements[2]), pathElements[3]) ); diff --git a/tools/e2e/diag_ctx.js b/tools/e2e/diag_ctx.js new file mode 100644 index 0000000..2d4f014 --- /dev/null +++ b/tools/e2e/diag_ctx.js @@ -0,0 +1,16 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + const logs = []; + page.on('console', m => logs.push(m.text())); + await page.goto('http://127.0.0.1:8099/buy-service/1/ministore', { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(8000); + for (let i=0;il.startsWith('CK_CTX')); + if(ctx) console.log(' CTX:', ctx.slice(0,150)); + } + } + await browser.close(); +})(); diff --git a/tools/e2e/diag_deep.js b/tools/e2e/diag_deep.js new file mode 100644 index 0000000..d964be7 --- /dev/null +++ b/tools/e2e/diag_deep.js @@ -0,0 +1,13 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + const logs = []; + page.on('console', m => logs.push(m.text())); + await page.goto('http://127.0.0.1:8099/buy-service/1/ministore', { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(7000); + const ctx = logs.filter(l => l.startsWith('CK_CTX')); + if (ctx.length) console.log(ctx[0].slice(0, 600)); + else console.log('无 CK_CTX'); + await browser.close(); +})(); diff --git a/tools/e2e/diag_exp.js b/tools/e2e/diag_exp.js new file mode 100644 index 0000000..e1cbf52 --- /dev/null +++ b/tools/e2e/diag_exp.js @@ -0,0 +1,14 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + const logs = []; + page.on('console', m => logs.push(m.text())); + await page.goto('http://127.0.0.1:8099/buy-service/1/ministore', { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(7000); + const range = logs.filter(l => l.includes('RangeError')); + const err = logs.filter(l => l.includes('CK_BUY_ERR')); + console.log('RangeError 数:', range.length, err.length ? '| CK_BUY_ERR:'+err[0].slice(0,100) : ''); + if (range.length) console.log(range[0].slice(0,120)); + await browser.close(); +})(); diff --git a/tools/e2e/diag_paths.js b/tools/e2e/diag_paths.js new file mode 100644 index 0000000..633fe3b --- /dev/null +++ b/tools/e2e/diag_paths.js @@ -0,0 +1,15 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + const logs = []; + page.on('console', m => logs.push(m.text())); + await page.goto('http://127.0.0.1:8099/buy-service/1/ministore', { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(7000); + console.log('=== path elements 打印(看是否有短路径)==='); + logs.filter(l => l.includes('path elements')).forEach(l => console.log(' ' + l.slice(0,80))); + console.log('=== RangeError 之前的最后几条 console ==='); + const idx = logs.findIndex(l => l.includes('RangeError')); + if (idx >= 0) logs.slice(Math.max(0,idx-4), idx).forEach(l => console.log(' ' + l.slice(0,90))); + await browser.close(); +})(); diff --git a/tools/e2e/diag_routes.js b/tools/e2e/diag_routes.js new file mode 100644 index 0000000..4b82891 --- /dev/null +++ b/tools/e2e/diag_routes.js @@ -0,0 +1,14 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + for (const route of ['/download', '/contact-stores', '/me', '/orders', '/buy-service/1/ministore']) { + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + let range = 0; + page.on('console', m => { if (m.text().includes('RangeError')) range++; }); + await page.goto('http://127.0.0.1:8099'+route, { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(6000); + console.log(`${range>0?'✗ '+range+' RangeError':'✓ OK'} ${route}`); + await page.close(); + } + await browser.close(); +})(); diff --git a/tools/e2e/diag_seq.js b/tools/e2e/diag_seq.js new file mode 100644 index 0000000..4cb1e1d --- /dev/null +++ b/tools/e2e/diag_seq.js @@ -0,0 +1,13 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + const logs = []; + page.on('console', m => logs.push(m.text())); + await page.goto('http://127.0.0.1:8099/buy-service/1/ministore', { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(7000); + const seq = logs.filter(l => l.startsWith('CK_BS_') || l.includes('RangeError')); + console.log('时序:'); + seq.slice(0,10).forEach(l => console.log(' ' + l.slice(0,90))); + await browser.close(); +})(); diff --git a/tools/e2e/diag_stack.js b/tools/e2e/diag_stack.js new file mode 100644 index 0000000..f5f9fa4 --- /dev/null +++ b/tools/e2e/diag_stack.js @@ -0,0 +1,19 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + const logs = []; + page.on('console', m => logs.push(m.text())); + await page.goto('http://127.0.0.1:8099/buy-service/1/ministore', { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(7000); + const stack = logs.filter(l => l.startsWith('CK_STACK')); + if (stack.length) { + // 找 .dart 源文件帧(非 main.dart.js) + const dartFrames = stack[0].split('\n').filter(l => l.includes('.dart') && !l.includes('main.dart.js')); + console.log('源文件帧:', dartFrames.length ? dartFrames.slice(0,5).join('\n ') : '(无,全是 main.dart.js)'); + // 也看前 3 个 main.dart.js 帧 + const jsFrames = stack[0].split('\n').filter(l => l.includes('main.dart.js')).slice(0,4); + console.log('main.dart.js 帧:', jsFrames.join('\n ')); + } + await browser.close(); +})(); diff --git a/tools/e2e/diag_then.js b/tools/e2e/diag_then.js new file mode 100644 index 0000000..9cb5b37 --- /dev/null +++ b/tools/e2e/diag_then.js @@ -0,0 +1,11 @@ +const { chromium } = require('playwright'); +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await (await browser.newContext({viewport:{width:1280,height:900}})).newPage(); + const logs = []; + page.on('console', m => logs.push(m.text())); + await page.goto('http://127.0.0.1:8099/buy-service/1/ministore', { waitUntil: 'load' }).catch(()=>{}); + await page.waitForTimeout(8000); + logs.filter(l => l.includes('CK_BUY_THEN') || l.includes('RangeError') || l.includes('CK_ERROR')).slice(0,5).forEach(l => console.log(l.slice(0,160))); + await browser.close(); +})(); diff --git a/tools/e2e/main.dart.js b/tools/e2e/main.dart.js new file mode 100644 index 0000000..bddcade --- /dev/null +++ b/tools/e2e/main.dart.js @@ -0,0 +1,46 @@ +"use strict"; + + + +// A map containing the URLs for the bootstrap scripts in debug. +let _scriptUrls = { + "mapper": "stack_trace_mapper.js", + "requireJs": "require.js" +}; + +// Create a TrustedTypes policy so we can attach Scripts... +let _ttPolicy; +if (window.trustedTypes) { + _ttPolicy = trustedTypes.createPolicy("flutter-tools-bootstrap", { + createScriptURL: (url) => { + let scriptUrl = _scriptUrls[url]; + if (!scriptUrl) { + console.error("Unknown Flutter Web bootstrap resource!", url); + } + return scriptUrl; + } + }); +} + +// Creates a TrustedScriptURL for a given `scriptName`. +// See `_scriptUrls` and `_ttPolicy` above. +function getTTScriptUrl(scriptName) { + let defaultUrl = _scriptUrls[scriptName]; + return _ttPolicy ? _ttPolicy.createScriptURL(scriptName) : defaultUrl; +} + +// Attach source mapping. +var mapperEl = document.createElement("script"); +mapperEl.defer = true; +mapperEl.async = false; +mapperEl.src = getTTScriptUrl("mapper"); +document.head.appendChild(mapperEl); + +// Attach require JS. +var requireEl = document.createElement("script"); +requireEl.defer = true; +requireEl.async = false; +requireEl.src = getTTScriptUrl("requireJs"); +// This attribute tells require JS what to load as main (defined below). +requireEl.setAttribute("data-main", "main_module.bootstrap"); +document.head.appendChild(requireEl); diff --git a/tools/e2e/package-lock.json b/tools/e2e/package-lock.json index b2b0cfe..bb4d6ae 100644 --- a/tools/e2e/package-lock.json +++ b/tools/e2e/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "playwright": "^1.62.1" + "playwright": "^1.62.1", + "source-map": "^0.8.0" } }, "node_modules/fsevents": { @@ -55,6 +56,15 @@ "engines": { "node": ">=20" } + }, + "node_modules/source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0.tgz", + "integrity": "sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } } } } diff --git a/tools/e2e/package.json b/tools/e2e/package.json index 74e80f8..d210161 100644 --- a/tools/e2e/package.json +++ b/tools/e2e/package.json @@ -11,6 +11,7 @@ "license": "ISC", "type": "commonjs", "dependencies": { - "playwright": "^1.62.1" + "playwright": "^1.62.1", + "source-map": "^0.8.0" } } diff --git a/tools/e2e/parse_map.js b/tools/e2e/parse_map.js new file mode 100644 index 0000000..891f2b7 --- /dev/null +++ b/tools/e2e/parse_map.js @@ -0,0 +1,15 @@ +const fs = require('fs'); +const { SourceMapConsumer } = require('source-map'); +(async () => { + const mapJson = await (await fetch('http://127.0.0.1:8099/main.dart.js.map')).text().catch(()=>null); + if (!mapJson) { console.log('无 sourcemap'); return; } + const smc = await new SourceMapConsumer(mapJson); + // 解析 299:254 (line:col) + const pos = smc.originalPositionFor({ line: 299, column: 254 }); + console.log('299:254 →', pos.source, pos.line + ':' + pos.column, '|', pos.name); + // 也试 299 的前后几行 + for (const c of [200, 100, 50]) { + const p = smc.originalPositionFor({ line: 299, column: c }); + if (p.source) console.log(`299:${c} →`, p.source.split('/').slice(-2).join('/') + ':' + p.line); + } +})();