merge: 최신 main을 행동 기반 접속 집계에 통합
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||
import { resolve } from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
import { chromium } from '@playwright/test';
|
||||
|
||||
const refRoot = resolve(process.env.REF_SAM_ROOT ?? '/home/letrhee/sam_rebuild/ref/sam');
|
||||
const artifactDir = process.env.REF_PERSONAL_BATTLE_LOG_ARTIFACT_DIR;
|
||||
const formatterUrl = pathToFileURL(resolve(refRoot, 'hwe/ts/utilGame/formatLog.ts')).href;
|
||||
const { formatLog } = await import(formatterUrl);
|
||||
const css = await readFile(resolve(refRoot, 'dist_js/hwe_dynamic/vue/v_main.css'), 'utf8');
|
||||
const record =
|
||||
'<S>◆</>188년 2월:<div class="small_war_log">' +
|
||||
'<span class="me"><span class="name_plate"><span class="crew_type">남귀</span> ' +
|
||||
'<span class="name_plate_cover">【<span class="name">운영자</span>】</span></span> ' +
|
||||
'<span class="crew_plate"><span class="remain_crew">0</span>' +
|
||||
'<span class="killed_plate">(<span class="killed_crew">-4404</span>)</span></span></span> ' +
|
||||
'<span class="war_type war_type_defense">←</span> ' +
|
||||
'<span class="you"><span class="crew_plate"><span class="remain_crew">555</span>' +
|
||||
'<span class="killed_plate">(<span class="killed_crew">-6845</span>)</span></span> ' +
|
||||
'<span class="name_plate"><span class="crew_type">기병</span> ' +
|
||||
'<span class="name_plate_cover">【<span class="name">ⓝ독야청정</span>】</span></span></span></div>';
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
try {
|
||||
const context = await browser.newContext({
|
||||
colorScheme: 'dark',
|
||||
deviceScaleFactor: 1,
|
||||
locale: 'ko-KR',
|
||||
timezoneId: 'UTC',
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.setContent(
|
||||
`<!doctype html><html><head><style>${css}</style></head><body>` +
|
||||
`<div id="container"><div class="RecordZone row gx-0"><div class="GeneralLog col col-12 col-lg-6">` +
|
||||
`<div class="bg1 center s-border-tb title">개인 기록</div><div class="fixture-line">${formatLog(record)}</div>` +
|
||||
`</div></div></div></body></html>`,
|
||||
{ waitUntil: 'networkidle' }
|
||||
);
|
||||
await page.evaluate(() => document.fonts.ready);
|
||||
|
||||
for (const viewport of [
|
||||
{ name: 'desktop', width: 1200, height: 900 },
|
||||
{ name: 'mobile', width: 500, height: 900 },
|
||||
]) {
|
||||
await page.setViewportSize(viewport);
|
||||
const measurement = await page.locator('.fixture-line').evaluate((element) => {
|
||||
const requireElement = (selector) => {
|
||||
const target = element.querySelector(selector);
|
||||
if (!(target instanceof HTMLElement)) throw new Error(`Ref 전투기록 요소를 찾지 못했습니다: ${selector}`);
|
||||
return target;
|
||||
};
|
||||
const rect = element.getBoundingClientRect();
|
||||
const battle = requireElement('.small_war_log');
|
||||
const battleRect = battle.getBoundingClientRect();
|
||||
return {
|
||||
text: element.textContent,
|
||||
line: { height: rect.height, fontSize: getComputedStyle(element).fontSize },
|
||||
battle: { height: battleRect.height, display: getComputedStyle(battle).display },
|
||||
styles: {
|
||||
diamondColor: getComputedStyle(requireElement('span[style*="skyblue"]')).color,
|
||||
namePlateFontSize: getComputedStyle(requireElement('.me .name_plate')).fontSize,
|
||||
nameCoverColor: getComputedStyle(requireElement('.me .name_plate_cover')).color,
|
||||
crewPlateColor: getComputedStyle(requireElement('.me .crew_plate')).color,
|
||||
crewPlateFontSize: getComputedStyle(requireElement('.me .crew_plate')).fontSize,
|
||||
defenseArrowColor: getComputedStyle(requireElement('.war_type_defense')).color,
|
||||
},
|
||||
};
|
||||
});
|
||||
const output = { viewport, measurement };
|
||||
console.log(JSON.stringify(output));
|
||||
if (artifactDir) {
|
||||
await mkdir(artifactDir, { recursive: true });
|
||||
await Promise.all([
|
||||
page.screenshot({ path: resolve(artifactDir, `ref-personal-battle-log-colors-${viewport.name}.png`) }),
|
||||
writeFile(
|
||||
resolve(artifactDir, `ref-personal-battle-log-colors-${viewport.name}.json`),
|
||||
`${JSON.stringify(output, null, 2)}\n`
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
@@ -12,6 +12,8 @@ const css = await readFile(resolve(refRoot, 'dist_js/hwe_dynamic/vue/v_main.css'
|
||||
const records = [
|
||||
'<C>●</>10월:천귀병으로 <Y>ⓝ염행</>의 보병을 <M>수비</>합니다. <1>12:54</>',
|
||||
'<C>●</>10월:천귀병으로 <Y>ⓝ염행</>의 보병을 <M>공격</>합니다. <1>12:55</>',
|
||||
'<D><b>위</b></>의 <Y>검증장수</>가 <G><b>낙양</b></>으로 진격합니다.' +
|
||||
'<span class="hidden_but_copyable">(전투시드: 0123456789abcdef)</span>',
|
||||
];
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
@@ -43,6 +45,29 @@ try {
|
||||
const time = spans.find((span) => /^\d{2}:\d{2}$/u.test(span.textContent ?? ''));
|
||||
const name = spans.find((span) => span.textContent === 'ⓝ염행');
|
||||
const action = spans.find((span) => span.textContent === '수비' || span.textContent === '공격');
|
||||
const hiddenSeed = element.querySelector('.hidden_but_copyable');
|
||||
if (hiddenSeed instanceof HTMLElement) {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(hiddenSeed);
|
||||
const selection = window.getSelection();
|
||||
selection?.removeAllRanges();
|
||||
selection?.addRange(range);
|
||||
const hiddenSeedRect = hiddenSeed.getBoundingClientRect();
|
||||
const hiddenSeedStyle = getComputedStyle(hiddenSeed);
|
||||
const result = {
|
||||
text: hiddenSeed.textContent,
|
||||
selectedText: selection?.toString(),
|
||||
color: hiddenSeedStyle.color,
|
||||
fontSize: hiddenSeedStyle.fontSize,
|
||||
width: hiddenSeedRect.width,
|
||||
height: hiddenSeedRect.height,
|
||||
};
|
||||
selection?.removeAllRanges();
|
||||
return {
|
||||
text: element.textContent,
|
||||
hiddenSeed: result,
|
||||
};
|
||||
}
|
||||
if (
|
||||
!(time instanceof HTMLElement) ||
|
||||
!(name instanceof HTMLElement) ||
|
||||
@@ -62,6 +87,7 @@ try {
|
||||
timeFontSize: getComputedStyle(time).fontSize,
|
||||
nameFontSize: getComputedStyle(name).fontSize,
|
||||
actionFontSize: getComputedStyle(action).fontSize,
|
||||
hiddenSeed: null,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
@@ -421,6 +421,21 @@ integration('general command success matrix', () => {
|
||||
ignoredPathPatterns: ignoredLifecyclePaths,
|
||||
})
|
||||
).toEqual([]);
|
||||
if (action === 'che_이동' || action === 'che_강행') {
|
||||
const actionLogSuffix = action === 'che_이동' ? '이동했습니다.' : '강행했습니다.';
|
||||
expect(
|
||||
semanticLogSignatures(
|
||||
core.after.logs.filter((entry) => String(entry.text).includes(actionLogSuffix))
|
||||
)
|
||||
).toEqual(
|
||||
semanticLogSignatures(
|
||||
addedReferenceLogs(reference.before, reference.after.logs).filter((entry) =>
|
||||
String(entry.text).includes(actionLogSuffix)
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(core.after.logs.some((entry) => String(entry.text).includes('도시('))).toBe(false);
|
||||
}
|
||||
},
|
||||
120_000
|
||||
);
|
||||
@@ -564,6 +579,12 @@ integration('NPC active command boundary parity', () => {
|
||||
ignoredPathPatterns: ignoredLifecyclePaths,
|
||||
})
|
||||
).toEqual([]);
|
||||
if (completed) {
|
||||
expect(semanticLogSignatures(core.after.logs)).toEqual(
|
||||
semanticLogSignatures(addedReferenceLogs(reference.before, reference.after.logs))
|
||||
);
|
||||
expect(core.after.logs.some((entry) => String(entry.text).includes('도시('))).toBe(false);
|
||||
}
|
||||
},
|
||||
120_000
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user