|
|
@@ -734,8 +734,9 @@ const devWorkbenchHTML = `<!doctype html>
|
|
|
<button class="ghost" id="btn-flow-result">Finish + Result</button>
|
|
|
<button class="secondary" id="btn-flow-admin-default-publish">一键默认绑定发布</button>
|
|
|
<button class="secondary" id="btn-flow-admin-runtime-publish">一键补齐 Runtime 并发布</button>
|
|
|
+ <button class="secondary" id="btn-flow-standard-regression">一键标准回归</button>
|
|
|
</div>
|
|
|
- <div class="muted-note">这些流程会复用当前表单里的手机号、设备、event、channel 等输入。“一键默认绑定发布” 会自动执行:Get Event -> Import Presentation -> Import Bundle -> Save Event Defaults -> Build Source -> Publish Build -> Get Release。“一键补齐 Runtime 并发布” 会在缺少默认 runtime 时自动创建 Runtime Binding,再继续发布链。</div>
|
|
|
+ <div class="muted-note">这些流程会复用当前表单里的手机号、设备、event、channel 等输入。“一键默认绑定发布” 会自动执行:Get Event -> Import Presentation -> Import Bundle -> Save Event Defaults -> Build Source -> Publish Build -> Get Release。“一键补齐 Runtime 并发布” 会在缺少默认 runtime 时自动创建 Runtime Binding,再继续发布链。“一键标准回归” 会继续执行:play -> launch -> start -> finish -> result -> history。</div>
|
|
|
<div class="subpanel">
|
|
|
<div class="muted-note">预期结果</div>
|
|
|
<div class="kv">
|
|
|
@@ -746,6 +747,18 @@ const devWorkbenchHTML = `<!doctype html>
|
|
|
<div>判定 <code id="flow-admin-verdict">待执行</code></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div class="subpanel">
|
|
|
+ <div class="muted-note">回归结果汇总</div>
|
|
|
+ <div class="kv">
|
|
|
+ <div>发布链 <code id="flow-regression-publish-result">待执行</code></div>
|
|
|
+ <div>Play <code id="flow-regression-play-result">待执行</code></div>
|
|
|
+ <div>Launch <code id="flow-regression-launch-result">待执行</code></div>
|
|
|
+ <div>Result <code id="flow-regression-result-result">待执行</code></div>
|
|
|
+ <div>History <code id="flow-regression-history-result">待执行</code></div>
|
|
|
+ <div>Session ID <code id="flow-regression-session-id">-</code></div>
|
|
|
+ <div>总判定 <code id="flow-regression-overall">待执行</code></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</section>
|
|
|
|
|
|
<section class="panel" data-modes="common">
|
|
|
@@ -2217,6 +2230,70 @@ const devWorkbenchHTML = `<!doctype html>
|
|
|
$('flow-admin-verdict').textContent = verdict;
|
|
|
}
|
|
|
|
|
|
+ function resetStandardRegressionExpectation() {
|
|
|
+ $('flow-regression-publish-result').textContent = '待执行';
|
|
|
+ $('flow-regression-play-result').textContent = '待执行';
|
|
|
+ $('flow-regression-launch-result').textContent = '待执行';
|
|
|
+ $('flow-regression-result-result').textContent = '待执行';
|
|
|
+ $('flow-regression-history-result').textContent = '待执行';
|
|
|
+ $('flow-regression-session-id').textContent = '-';
|
|
|
+ $('flow-regression-overall').textContent = '待执行';
|
|
|
+ }
|
|
|
+
|
|
|
+ function setStandardRegressionExpectation(summary) {
|
|
|
+ const publishText = summary && summary.publish ? summary.publish : '待执行';
|
|
|
+ const playText = summary && summary.play ? summary.play : '待执行';
|
|
|
+ const launchText = summary && summary.launch ? summary.launch : '待执行';
|
|
|
+ const resultText = summary && summary.result ? summary.result : '待执行';
|
|
|
+ const historyText = summary && summary.history ? summary.history : '待执行';
|
|
|
+ const sessionId = summary && summary.sessionId ? summary.sessionId : '-';
|
|
|
+ const overall = summary && summary.overall ? summary.overall : '待执行';
|
|
|
+ $('flow-regression-publish-result').textContent = publishText;
|
|
|
+ $('flow-regression-play-result').textContent = playText;
|
|
|
+ $('flow-regression-launch-result').textContent = launchText;
|
|
|
+ $('flow-regression-result-result').textContent = resultText;
|
|
|
+ $('flow-regression-history-result').textContent = historyText;
|
|
|
+ $('flow-regression-session-id').textContent = sessionId;
|
|
|
+ $('flow-regression-overall').textContent = overall;
|
|
|
+ }
|
|
|
+
|
|
|
+ function extractList(payload) {
|
|
|
+ if (Array.isArray(payload)) {
|
|
|
+ return payload;
|
|
|
+ }
|
|
|
+ if (!payload || typeof payload !== 'object') {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ if (Array.isArray(payload.items)) {
|
|
|
+ return payload.items;
|
|
|
+ }
|
|
|
+ if (Array.isArray(payload.results)) {
|
|
|
+ return payload.results;
|
|
|
+ }
|
|
|
+ if (Array.isArray(payload.sessions)) {
|
|
|
+ return payload.sessions;
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ function listContainsSession(list, sessionId) {
|
|
|
+ if (!sessionId) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return list.some(function(item) {
|
|
|
+ if (!item || typeof item !== 'object') {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (item.id && item.id === sessionId) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (item.session && item.session.id && item.session.id === sessionId) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
async function runAdminDefaultPublishFlow(options) {
|
|
|
const ensureRuntime = options && options.ensureRuntime === true;
|
|
|
const flowTitle = ensureRuntime ? 'flow-admin-runtime-publish' : 'flow-admin-default-publish';
|
|
|
@@ -2407,6 +2484,140 @@ const devWorkbenchHTML = `<!doctype html>
|
|
|
return releaseDetail;
|
|
|
}
|
|
|
|
|
|
+ async function runStandardRegressionFlow() {
|
|
|
+ const flowTitle = 'flow-standard-regression';
|
|
|
+ const eventId = $('event-id').value || $('admin-event-ref-id').value;
|
|
|
+ if (!trimmedOrUndefined(eventId)) {
|
|
|
+ throw new Error('event id is required');
|
|
|
+ }
|
|
|
+ resetStandardRegressionExpectation();
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', { step: 'prepare-release', eventId: eventId });
|
|
|
+ const releaseDetail = await runAdminDefaultPublishFlow({ ensureRuntime: true });
|
|
|
+ const publishPass = $('flow-admin-verdict').textContent.indexOf('通过') === 0;
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', {
|
|
|
+ step: 'login-wechat',
|
|
|
+ code: $('wechat-code').value,
|
|
|
+ deviceKey: $('wechat-device').value
|
|
|
+ });
|
|
|
+ const login = await request('POST', '/auth/login/wechat-mini', {
|
|
|
+ code: $('wechat-code').value,
|
|
|
+ clientType: 'wechat',
|
|
|
+ deviceKey: $('wechat-device').value
|
|
|
+ });
|
|
|
+ state.accessToken = login.data.tokens.accessToken;
|
|
|
+ state.refreshToken = login.data.tokens.refreshToken;
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', {
|
|
|
+ step: 'event-play',
|
|
|
+ eventId: eventId
|
|
|
+ });
|
|
|
+ const play = await request('GET', '/events/' + encodeURIComponent(eventId) + '/play', undefined, true);
|
|
|
+ const playPass = !!(play.data && play.data.play && play.data.resolvedRelease && play.data.resolvedRelease.manifestUrl);
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', {
|
|
|
+ step: 'event-launch',
|
|
|
+ eventId: eventId,
|
|
|
+ releaseId: $('event-release-id').value || state.releaseId,
|
|
|
+ variantId: trimmedOrUndefined($('event-variant-id').value)
|
|
|
+ });
|
|
|
+ const launch = await request('POST', '/events/' + encodeURIComponent(eventId) + '/launch', {
|
|
|
+ releaseId: $('event-release-id').value,
|
|
|
+ variantId: trimmedOrUndefined($('event-variant-id').value),
|
|
|
+ clientType: $('sms-client-type').value,
|
|
|
+ deviceKey: $('event-device').value
|
|
|
+ }, true);
|
|
|
+ state.sessionId = launch.data.launch.business.sessionId;
|
|
|
+ state.sessionToken = launch.data.launch.business.sessionToken;
|
|
|
+ syncState();
|
|
|
+ const launchPass = !!(
|
|
|
+ launch.data &&
|
|
|
+ launch.data.launch &&
|
|
|
+ launch.data.launch.business &&
|
|
|
+ launch.data.launch.business.sessionId &&
|
|
|
+ launch.data.launch.resolvedRelease &&
|
|
|
+ launch.data.launch.resolvedRelease.manifestUrl
|
|
|
+ );
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', {
|
|
|
+ step: 'session-start',
|
|
|
+ sessionId: state.sessionId
|
|
|
+ });
|
|
|
+ await request('POST', '/sessions/' + encodeURIComponent(state.sessionId) + '/start', {
|
|
|
+ sessionToken: state.sessionToken
|
|
|
+ });
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', {
|
|
|
+ step: 'session-finish',
|
|
|
+ sessionId: state.sessionId,
|
|
|
+ status: $('finish-status').value
|
|
|
+ });
|
|
|
+ await request('POST', '/sessions/' + encodeURIComponent(state.sessionId) + '/finish', {
|
|
|
+ sessionToken: state.sessionToken,
|
|
|
+ status: $('finish-status').value,
|
|
|
+ summary: buildFinishSummary()
|
|
|
+ });
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', {
|
|
|
+ step: 'session-result',
|
|
|
+ sessionId: state.sessionId
|
|
|
+ });
|
|
|
+ const sessionResult = await request('GET', '/sessions/' + encodeURIComponent(state.sessionId) + '/result', undefined, true);
|
|
|
+ const resultPass = !!(
|
|
|
+ sessionResult.data &&
|
|
|
+ sessionResult.data.session &&
|
|
|
+ sessionResult.data.session.id === state.sessionId &&
|
|
|
+ sessionResult.data.result
|
|
|
+ );
|
|
|
+
|
|
|
+ writeLog(flowTitle + '.step', {
|
|
|
+ step: 'history-check',
|
|
|
+ sessionId: state.sessionId
|
|
|
+ });
|
|
|
+ const mySessions = await request('GET', '/me/sessions?limit=10', undefined, true);
|
|
|
+ const myResults = await request('GET', '/me/results?limit=10', undefined, true);
|
|
|
+ const sessionsList = extractList(mySessions.data);
|
|
|
+ const resultsList = extractList(myResults.data);
|
|
|
+ const historyPass = listContainsSession(sessionsList, state.sessionId) && listContainsSession(resultsList, state.sessionId);
|
|
|
+
|
|
|
+ const summary = {
|
|
|
+ publish: publishPass ? '通过:发布链可重复跑通' : '未通过:发布链未返回通过判定',
|
|
|
+ play: playPass ? '通过:play 返回 resolvedRelease / play 摘要' : '未通过:play 缺少关键摘要',
|
|
|
+ launch: launchPass ? '通过:launch 返回 manifest + session' : '未通过:launch 缺少 manifest 或 session',
|
|
|
+ result: resultPass ? '通过:单局 result 可直接回查' : '未通过:单局 result 未回查成功',
|
|
|
+ history: historyPass ? '通过:me/sessions + me/results 均收录本局' : '未通过:history 未同时收录本局',
|
|
|
+ sessionId: state.sessionId || '-',
|
|
|
+ overall: publishPass && playPass && launchPass && resultPass && historyPass ? '通过:launch / play / result / history 回归已跑通' : '未通过:请看上面分项和日志'
|
|
|
+ };
|
|
|
+ setStandardRegressionExpectation(summary);
|
|
|
+ writeLog(flowTitle + '.expected', {
|
|
|
+ eventId: eventId,
|
|
|
+ releaseId: releaseDetail && releaseDetail.data ? releaseDetail.data.id : state.releaseId,
|
|
|
+ sessionId: state.sessionId,
|
|
|
+ publish: summary.publish,
|
|
|
+ play: summary.play,
|
|
|
+ launch: summary.launch,
|
|
|
+ result: summary.result,
|
|
|
+ history: summary.history,
|
|
|
+ overall: summary.overall
|
|
|
+ });
|
|
|
+ persistState();
|
|
|
+ return {
|
|
|
+ data: {
|
|
|
+ eventId: eventId,
|
|
|
+ releaseId: releaseDetail && releaseDetail.data ? releaseDetail.data.id : state.releaseId,
|
|
|
+ sessionId: state.sessionId,
|
|
|
+ publish: publishPass,
|
|
|
+ play: playPass,
|
|
|
+ launch: launchPass,
|
|
|
+ result: resultPass,
|
|
|
+ history: historyPass,
|
|
|
+ overall: publishPass && playPass && launchPass && resultPass && historyPass
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
function setStatus(text, isError = false) {
|
|
|
statusEl.textContent = text;
|
|
|
statusEl.className = isError ? 'status error' : 'status';
|
|
|
@@ -4124,6 +4335,10 @@ const devWorkbenchHTML = `<!doctype html>
|
|
|
return await runAdminDefaultPublishFlow({ ensureRuntime: true });
|
|
|
});
|
|
|
|
|
|
+ $('btn-flow-standard-regression').onclick = () => run('flow-standard-regression', async () => {
|
|
|
+ return await runStandardRegressionFlow();
|
|
|
+ });
|
|
|
+
|
|
|
[
|
|
|
'sms-client-type', 'sms-scene', 'sms-mobile', 'sms-device', 'sms-country', 'sms-code',
|
|
|
'wechat-code', 'wechat-device', 'local-config-file', 'config-event-id', 'config-runtime-binding-id', 'config-presentation-id', 'config-content-bundle-id', 'entry-channel-code', 'entry-channel-type',
|