Compare commits
3 Commits
994075920d
...
aa6a9ed1b5
| Author | SHA1 | Date | |
|---|---|---|---|
| aa6a9ed1b5 | |||
| 36281e02fd | |||
| 88f67f5e13 |
@@ -383,7 +383,7 @@
|
||||
</ul>
|
||||
<p class="text-sm mb-3"><strong>Проверить карту</strong> выполняет каждое правило на подключённой карте и показывает строку прогресса и отчёт прохождения. Рядом с путём файла указывается, что именно проверялось (например, <em>тип файла и размер, содержимое</em> или <em>полный FCI</em>); если часть проверок прошла, а часть нет — каждый аспект помечается (<em>тип файла ✓, размер ✗, содержимое ✓</em>), а расхождения расписываются ниже. Несовпавшие сырые данные (FCI, содержимое, данные записей) показываются как поля только для чтения с моноширинным шрифтом — ожидаемое над фактическим, в одной и той же колонке — для удобного сравнения; для расхождений FCI дополнительно показывается декодированное сравнение по параметрам (размер файла, дескриптор/структура, жизненный цикл, FID, SFI, проприетарные параметры…). Декодированный просмотр FCI также отображается рядом с полем FCI hex при редактировании правила. Если данные FCI повреждены, показывается всё, что удалось декодировать до места ошибки, вместе с явным сообщением об ошибке декодирования. Для record-файлов при расхождении содержимого добавляется пометка <em>совпадающие записи: 1-5, 7-10</em> со списком записей, которые совпали.</p>
|
||||
<h4 class="font-medium mb-1">Опции сканирования «Профиль с карты»</h4>
|
||||
<p class="text-sm mb-2">Диалог сканирования запрашивает имя профиля и предлагает селектор <strong>«Проверка FCP/FCI»</strong> (те же три режима, по умолчанию <strong>Тип файла + размер (FCP)</strong>), применяемый ко всем создаваемым правилам, а также список <strong>«Игнорировать содержимое файлов»</strong> (все отмечены по умолчанию) часто перезаписываемых файлов, содержимое которых пропускается: <code class="font-mono text-sm">EF.LOCI</code>, <code class="font-mono text-sm">EF.PSLOCI</code>, <code class="font-mono text-sm">EF.EPSLOCI</code>, <code class="font-mono text-sm">EF.5GS3GPPLOCI</code>, <code class="font-mono text-sm">EF.Keys</code>, <code class="font-mono text-sm">EF.KeysPS</code>, <code class="font-mono text-sm">EF.SMS</code>, <code class="font-mono text-sm">EF.Kc</code>, <code class="font-mono text-sm">EF.KcGPRS</code>, <code class="font-mono text-sm">EF.LOCIGPRS</code>, <code class="font-mono text-sm">EF.CBMID</code>, <code class="font-mono text-sm">EF.SMSS</code>. Ещё две отмеченные по умолчанию опции <strong>«Сравнивать первые 4 байта для»</strong> <code class="font-mono text-sm">EF.IMSI</code> и <code class="font-mono text-sm">EF.ICCID</code> захватывают содержимое этих файлов как маску только первых 4 байт (снимите для точного сравнения). Строка прогресса показывает <em>N / всего файлов</em> с текущим путём файла во время сканирования; при сканировании опции скрываются, а кнопки блокируются. Правила создаются только для файлов, которые реально существуют на карте (возвращён FCP-шаблон); отсутствующие файлы пропускаются. Пользовательские файлы из подвкладки <strong>«Пользовательские файлы»</strong> включаются с той же проверкой существования.</p>
|
||||
<p class="text-sm mb-2">Диалог сканирования запрашивает имя профиля и предлагает селектор <strong>«Проверка FCP/FCI»</strong> (те же три режима, по умолчанию <strong>Тип файла + размер (FCP)</strong>), применяемый ко всем создаваемым правилам, а также список <strong>«Игнорировать содержимое файлов»</strong> (все отмечены по умолчанию, кроме <code class="font-mono text-sm">EF.ARR</code>; флажок в заголовке отмечает или снимает весь список) часто перезаписываемых файлов, содержимое которых пропускается: <code class="font-mono text-sm">EF.LOCI</code>, <code class="font-mono text-sm">EF.PSLOCI</code>, <code class="font-mono text-sm">EF.EPSLOCI</code>, <code class="font-mono text-sm">EF.5GS3GPPLOCI</code>, <code class="font-mono text-sm">EF.Keys</code>, <code class="font-mono text-sm">EF.KeysPS</code>, <code class="font-mono text-sm">EF.SMS</code>, <code class="font-mono text-sm">EF.Kc</code>, <code class="font-mono text-sm">EF.KcGPRS</code>, <code class="font-mono text-sm">EF.LOCIGPRS</code>, <code class="font-mono text-sm">EF.CBMID</code>, <code class="font-mono text-sm">EF.SMSS</code>, <code class="font-mono text-sm">EF.ACC</code>, <code class="font-mono text-sm">EF.EPSNSC</code>, <code class="font-mono text-sm">EF.START-HFN</code>, <code class="font-mono text-sm">EF.ARR</code>. Ещё две отмеченные по умолчанию опции <strong>«Сравнивать первые 4 байта для»</strong> <code class="font-mono text-sm">EF.IMSI</code> и <code class="font-mono text-sm">EF.ICCID</code> захватывают содержимое этих файлов как маску только первых 4 байт (снимите для точного сравнения). Строка прогресса показывает <em>N / всего файлов</em> с текущим путём файла во время сканирования; при сканировании опции скрываются, а кнопки блокируются. Правила создаются только для файлов, которые реально существуют на карте (возвращён FCP-шаблон); отсутствующие файлы пропускаются. Пользовательские файлы из подвкладки <strong>«Пользовательские файлы»</strong> включаются с той же проверкой существования.</p>
|
||||
|
||||
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">5.7 Сценарии использования</h3>
|
||||
|
||||
|
||||
+1
-1
@@ -383,7 +383,7 @@
|
||||
</ul>
|
||||
<p class="text-sm mb-3"><strong>Check card</strong> runs every rule against the equipped card and shows a live progress line plus a pass/fail report. Each row states exactly what was verified next to the file path (e.g. <em>filetype and size, contents</em> or <em>exact FCI</em>); when some checks pass and others fail, each aspect is marked (<em>filetype ✓, size ✗, contents ✓</em>) with the mismatches detailed below. Mismatched raw data (FCI, contents, record data) is shown as read-only monospace fields — expected above actual, aligned in the same column — for easy comparison; FCI mismatches additionally show a decoded per-parameter comparison (file size, file descriptor/structure, life cycle, FID, SFI, proprietary parameters…). A decoded FCI preview is also shown beside the FCI hex field while editing a rule. If the FCI data is corrupt, whatever was decoded before the faulty part is shown together with an explicit decode-failure note. For record files with a contents mismatch, a <em>matching records: 1-5, 7-10</em> note lists the records that did match.</p>
|
||||
<h4 class="font-medium mb-1">“Profile from card” scan options</h4>
|
||||
<p class="text-sm mb-2">The scan dialog asks for a profile name and offers a <strong>“FCP/FCI check”</strong> selector (the same three modes above, default <strong>Filetype + size</strong>) applied to every generated rule, plus an <strong>“Ignore contents of files”</strong> checklist (all checked by default) of frequently-overwritten files whose contents are skipped: <code class="font-mono text-sm">EF.LOCI</code>, <code class="font-mono text-sm">EF.PSLOCI</code>, <code class="font-mono text-sm">EF.EPSLOCI</code>, <code class="font-mono text-sm">EF.5GS3GPPLOCI</code>, <code class="font-mono text-sm">EF.Keys</code>, <code class="font-mono text-sm">EF.KeysPS</code>, <code class="font-mono text-sm">EF.SMS</code>, <code class="font-mono text-sm">EF.Kc</code>, <code class="font-mono text-sm">EF.KcGPRS</code>, <code class="font-mono text-sm">EF.LOCIGPRS</code>, <code class="font-mono text-sm">EF.CBMID</code>, <code class="font-mono text-sm">EF.SMSS</code>. Two further checked-by-default options <strong>“Match first 4 bytes for”</strong> <code class="font-mono text-sm">EF.IMSI</code> and <code class="font-mono text-sm">EF.ICCID</code> capture those files’ contents as a mask of only the first 4 bytes (uncheck for exact matching). A progress line shows <em>N / total files</em> with the current file path while scanning; during the scan the options are hidden and the buttons are locked. Rules are created only for files that actually exist on the card (a FCP template is returned); missing files are skipped. Custom files from the <strong>Custom files</strong> sub-tab are included under the same existence check.</p>
|
||||
<p class="text-sm mb-2">The scan dialog asks for a profile name and offers a <strong>“FCP/FCI check”</strong> selector (the same three modes above, default <strong>Filetype + size</strong>) applied to every generated rule, plus an <strong>“Ignore contents of files”</strong> checklist (all checked by default except <code class="font-mono text-sm">EF.ARR</code>; the header checkbox checks or unchecks the whole list) of frequently-overwritten files whose contents are skipped: <code class="font-mono text-sm">EF.LOCI</code>, <code class="font-mono text-sm">EF.PSLOCI</code>, <code class="font-mono text-sm">EF.EPSLOCI</code>, <code class="font-mono text-sm">EF.5GS3GPPLOCI</code>, <code class="font-mono text-sm">EF.Keys</code>, <code class="font-mono text-sm">EF.KeysPS</code>, <code class="font-mono text-sm">EF.SMS</code>, <code class="font-mono text-sm">EF.Kc</code>, <code class="font-mono text-sm">EF.KcGPRS</code>, <code class="font-mono text-sm">EF.LOCIGPRS</code>, <code class="font-mono text-sm">EF.CBMID</code>, <code class="font-mono text-sm">EF.SMSS</code>, <code class="font-mono text-sm">EF.ACC</code>, <code class="font-mono text-sm">EF.EPSNSC</code>, <code class="font-mono text-sm">EF.START-HFN</code>, <code class="font-mono text-sm">EF.ARR</code>. Two further checked-by-default options <strong>“Match first 4 bytes for”</strong> <code class="font-mono text-sm">EF.IMSI</code> and <code class="font-mono text-sm">EF.ICCID</code> capture those files’ contents as a mask of only the first 4 bytes (uncheck for exact matching). A progress line shows <em>N / total files</em> with the current file path while scanning; during the scan the options are hidden and the buttons are locked. Rules are created only for files that actually exist on the card (a FCP template is returned); missing files are skipped. Custom files from the <strong>Custom files</strong> sub-tab are included under the same existence check.</p>
|
||||
|
||||
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">5.7 Usage scenarios</h3>
|
||||
|
||||
|
||||
+30
-4
@@ -913,7 +913,13 @@
|
||||
<label class="block mb-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="Profile name">Profile name</label>
|
||||
<input id="profiler-scan-name" class="w-full font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-2 dark:bg-slate-800 mb-3" placeholder="Profile name">
|
||||
<div id="profiler-scan-options">
|
||||
<div class="mb-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="Ignore contents of files:">Ignore contents of files:</div>
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="Ignore contents of files:">Ignore contents of files:</span>
|
||||
<label class="ml-auto flex items-center gap-1 text-xs text-gray-500 dark:text-slate-400 cursor-pointer">
|
||||
<input type="checkbox" id="profiler-scan-ignore-all" onchange="profilerScanToggleAll(this.checked)" class="rounded">
|
||||
<span data-l10n="All">All</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="profiler-scan-ignore" class="grid grid-cols-2 gap-x-3 gap-y-1 mb-3 max-h-56 overflow-auto"></div>
|
||||
<div id="profiler-scan-mask" class="space-y-1 mb-3"></div>
|
||||
<label class="block mb-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="FCP/FCI check">FCP/FCI check</label>
|
||||
@@ -6960,6 +6966,10 @@ const PROFILER_IGNORE_FILES = [
|
||||
{ fid: '6F53', name: 'EF.LOCIGPRS' },
|
||||
{ fid: '6F48', name: 'EF.CBMID' },
|
||||
{ fid: '6F43', name: 'EF.SMSS' },
|
||||
{ fid: '6F78', name: 'EF.ACC' },
|
||||
{ fid: '6FE4', name: 'EF.EPSNSC' },
|
||||
{ fid: '6F5B', name: 'EF.START-HFN' },
|
||||
{ fid: '2F06', name: 'EF.ARR', checked: false },
|
||||
];
|
||||
|
||||
// Files where contents are captured as a mask matching only the first 4 bytes
|
||||
@@ -7096,6 +7106,20 @@ function profilerNew() {
|
||||
profilerEdit(profiles.length - 1);
|
||||
}
|
||||
|
||||
function profilerScanToggleAll(checked) {
|
||||
document.querySelectorAll('#profiler-scan-ignore input[data-ignore-fid]').forEach(cb => { cb.checked = checked; });
|
||||
}
|
||||
|
||||
function profilerScanIgnoreAllState() {
|
||||
const boxes = document.querySelectorAll('#profiler-scan-ignore input[data-ignore-fid]');
|
||||
const all = document.getElementById('profiler-scan-ignore-all');
|
||||
if (!all) return;
|
||||
let checked = 0;
|
||||
boxes.forEach(cb => { if (cb.checked) checked++; });
|
||||
all.checked = boxes.length > 0 && checked === boxes.length;
|
||||
all.indeterminate = checked > 0 && checked < boxes.length;
|
||||
}
|
||||
|
||||
function profilerFromCard() {
|
||||
document.getElementById('profiler-scan-name').value = '';
|
||||
document.getElementById('profiler-scan-name').readOnly = false;
|
||||
@@ -7104,10 +7128,11 @@ function profilerFromCard() {
|
||||
let html = '';
|
||||
for (const f of PROFILER_IGNORE_FILES) {
|
||||
html += '<label class="flex items-center gap-2 text-sm">' +
|
||||
'<input type="checkbox" data-ignore-fid="' + f.fid + '" data-ignore-name="' + f.name + '" checked>' +
|
||||
'<input type="checkbox" data-ignore-fid="' + f.fid + '" data-ignore-name="' + f.name + '"' + (f.checked === false ? '' : ' checked') + ' onchange="profilerScanIgnoreAllState()">' +
|
||||
'<span>' + esc(f.name) + '</span></label>';
|
||||
}
|
||||
ignore.innerHTML = html;
|
||||
profilerScanIgnoreAllState();
|
||||
const mask = document.getElementById('profiler-scan-mask');
|
||||
let mhtml = '';
|
||||
for (const fid in PROFILER_MASK_PREFIX4_FIDS) {
|
||||
@@ -7966,7 +7991,7 @@ function fcpDiffHtml(expectedHex, actualHex) {
|
||||
for (const it of a.items) if (!eMap[it.key]) keys.push(it.key);
|
||||
let html = '';
|
||||
if (keys.length) {
|
||||
html += '<div class="mt-1 text-xs text-gray-500 dark:text-slate-400">' + esc(t('FCP parameters')) + '</div>';
|
||||
html += '<div class="mt-1 text-xs text-gray-500 dark:text-slate-400">' + esc(t('FCI parameters')) + '</div>';
|
||||
html += '<table class="w-full text-xs border-collapse">';
|
||||
html += '<thead><tr class="border-b border-gray-200 dark:border-slate-700">' +
|
||||
'<th class="text-left py-0.5 px-1 font-medium text-gray-500 dark:text-slate-400">' + esc(t('Parameter')) + '</th>' +
|
||||
@@ -8264,13 +8289,14 @@ const LANG_RU = {
|
||||
'Discovering...': 'Поиск файлов...',
|
||||
'files': 'файлов',
|
||||
'Ignore contents of files:': 'Игнорировать содержимое файлов:',
|
||||
'All': 'Все',
|
||||
'Match first 4 bytes for': 'Сравнивать первые 4 байта для',
|
||||
'FCP/FCI check': 'Проверка FCP/FCI',
|
||||
'Filetype only (FCP)': 'Только тип файла (FCP)',
|
||||
'Filetype + size (FCP)': 'Тип файла + размер (FCP)',
|
||||
'Exact FCI': 'Полный FCI',
|
||||
'FCI hex (raw SELECT response)': 'FCI hex (сырой ответ SELECT)',
|
||||
'FCP parameters': 'Параметры FCP',
|
||||
'FCI parameters': 'Параметры FCI',
|
||||
'Parameter': 'Параметр',
|
||||
'Decoded FCI': 'Декодированный FCI',
|
||||
'Decode failed': 'Ошибка декодирования',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'otaman-v76';
|
||||
const CACHE = 'otaman-v79';
|
||||
const URLS = [
|
||||
'index.html',
|
||||
'help.html',
|
||||
|
||||
@@ -21,7 +21,7 @@ function extractFunc(src, name, asyncFn) {
|
||||
return (asyncFn ? 'async ' : '') + src.slice(m.index, i + 1);
|
||||
}
|
||||
|
||||
const FNS = ['profilerNormHex', 'profilerNormHexStrict', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerFileFields', 'profilerContentKindForFileType', 'profilerEmptyRecordContent', 'profilerValidateProfile', 'profilerCustomNameForPath', 'profilerUpdateRulePath', 'profilerResultAspects', 'profilerAspectSummary', 'profilerNumRanges', 'esc', 'escHtml', 'profilerRawDataCheck', 'profilerRenderReport', 'parseBerLen', 'parseTlvList', 'fcpInt', 'fcpParseTlvs', 'fcpFileDescriptor', 'fcpLifeCycle', 'fcpSfi', 'fcpDo', 'fcpDecode', 'fcpDiffHtml', 'profilerFciPreviewItems', 'profilerUpdateFciPreview', 'profilerUpdateRule', 'profilerFciInput'];
|
||||
const FNS = ['profilerNormHex', 'profilerNormHexStrict', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerFileFields', 'profilerContentKindForFileType', 'profilerEmptyRecordContent', 'profilerValidateProfile', 'profilerCustomNameForPath', 'profilerUpdateRulePath', 'profilerResultAspects', 'profilerAspectSummary', 'profilerNumRanges', 'esc', 'escHtml', 'profilerRawDataCheck', 'profilerRenderReport', 'parseBerLen', 'parseTlvList', 'fcpInt', 'fcpParseTlvs', 'fcpFileDescriptor', 'fcpLifeCycle', 'fcpSfi', 'fcpDo', 'fcpDecode', 'fcpDiffHtml', 'profilerFciPreviewItems', 'profilerUpdateFciPreview', 'profilerUpdateRule', 'profilerFciInput', 'profilerScanToggleAll', 'profilerScanIgnoreAllState'];
|
||||
let code = '';
|
||||
for (const f of FNS) code += extractFunc(html, f) + '\n';
|
||||
code += extractFunc(html, 'profilerBuildFileRule', true) + '\n';
|
||||
@@ -116,17 +116,29 @@ test('profile validation', () => {
|
||||
|
||||
function parseIgnoreFiles() {
|
||||
const raw = html.match(/const PROFILER_IGNORE_FILES = \[([\s\S]*?)\n\];/)[1];
|
||||
return [...raw.matchAll(/\{ fid: '([^']*)', name: '([^']*)' \}/g)].map(m => ({ fid: m[1], name: m[2] }));
|
||||
return [...raw.matchAll(/\{ fid: '([^']*)', name: '([^']*)'(?:, checked: (true|false))? \}/g)]
|
||||
.map(m => ({ fid: m[1], name: m[2], checked: m[3] !== 'false' }));
|
||||
}
|
||||
|
||||
test('ignore list FIDs are well-formed and KcGPRS uses the TS 51.011 FID (6F52)', () => {
|
||||
const files = parseIgnoreFiles();
|
||||
assert.ok(files.length >= 12);
|
||||
assert.ok(files.length >= 16);
|
||||
for (const f of files) {
|
||||
assert.match(f.fid, /^[0-9A-F]{4}$/, f.name + ' has a malformed FID');
|
||||
assert.ok(f.name.startsWith('EF.'), f.fid + ' has a malformed name');
|
||||
}
|
||||
assert.strictEqual(files.find(f => f.name === 'EF.KcGPRS').fid, '6F52');
|
||||
assert.strictEqual(files.find(f => f.name === 'EF.ACC').fid, '6F78');
|
||||
assert.strictEqual(files.find(f => f.name === 'EF.EPSNSC').fid, '6FE4');
|
||||
assert.strictEqual(files.find(f => f.name === 'EF.START-HFN').fid, '6F5B');
|
||||
assert.strictEqual(files.find(f => f.name === 'EF.ARR').fid, '2F06');
|
||||
});
|
||||
|
||||
test('ignore list checks every file by default except EF.ARR', () => {
|
||||
const files = parseIgnoreFiles();
|
||||
for (const f of files) {
|
||||
assert.strictEqual(f.checked, f.name !== 'EF.ARR', f.name + ' default-checked mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
test('ignore list has no duplicate FIDs or names', () => {
|
||||
@@ -670,7 +682,7 @@ test('fcpDecode accepts long-form BER lengths (81/82) — editor preview regress
|
||||
delete global.t;
|
||||
});
|
||||
|
||||
test('fcpDiffHtml highlights differing FCP parameters', () => {
|
||||
test('fcpDiffHtml highlights differing FCI parameters', () => {
|
||||
global.t = s => s;
|
||||
const same = fcpDiffHtml(FCP_TRANSPARENT, FCP_TRANSPARENT);
|
||||
assert.ok(same.includes('File size'));
|
||||
@@ -715,7 +727,7 @@ test('profilerRenderReport shows the decoded FCI diff for a raw fci mismatch', (
|
||||
{ label: 'fci', ok: false, expected: FCP_TRANSPARENT, actual: '62128002000A8202412183026F078A0105880110' },
|
||||
] },
|
||||
]);
|
||||
assert.ok(html.includes('FCP parameters'));
|
||||
assert.ok(html.includes('FCI parameters'));
|
||||
assert.ok(html.includes('9 bytes'));
|
||||
assert.ok(html.includes('10 bytes'));
|
||||
assert.ok(html.includes('text-red-600'));
|
||||
@@ -768,10 +780,42 @@ test('fcpDiffHtml appends decode-failure notes for corrupt sides', () => {
|
||||
global.t = s => s;
|
||||
const trunc = '6216' + FCP_TRANSPARENT.slice(4);
|
||||
const html = fcpDiffHtml(trunc, FCP_TRANSPARENT);
|
||||
assert.ok(html.includes('FCP parameters'), html);
|
||||
assert.ok(html.includes('FCI parameters'), html);
|
||||
assert.ok(html.includes('9 bytes'));
|
||||
assert.ok(html.includes('expected: ') && html.includes('TLV 62 declares 22 bytes'));
|
||||
// both sides empty -> nothing rendered
|
||||
assert.strictEqual(fcpDiffHtml('', ''), '');
|
||||
delete global.t;
|
||||
});
|
||||
|
||||
test('profilerScanToggleAll / profilerScanIgnoreAllState manage the ignore checkboxes', () => {
|
||||
const boxes = [{ checked: true }, { checked: false }, { checked: true }];
|
||||
const header = { checked: false, indeterminate: false };
|
||||
global.document = {
|
||||
querySelectorAll: sel => (sel === '#profiler-scan-ignore input[data-ignore-fid]' ? boxes : []),
|
||||
getElementById: id => (id === 'profiler-scan-ignore-all' ? header : null),
|
||||
};
|
||||
|
||||
profilerScanIgnoreAllState();
|
||||
assert.strictEqual(header.checked, false);
|
||||
assert.strictEqual(header.indeterminate, true);
|
||||
|
||||
boxes[1].checked = true;
|
||||
profilerScanIgnoreAllState();
|
||||
assert.strictEqual(header.checked, true);
|
||||
assert.strictEqual(header.indeterminate, false);
|
||||
|
||||
profilerScanToggleAll(false);
|
||||
assert.ok(boxes.every(b => !b.checked));
|
||||
profilerScanIgnoreAllState();
|
||||
assert.strictEqual(header.checked, false);
|
||||
assert.strictEqual(header.indeterminate, false);
|
||||
|
||||
profilerScanToggleAll(true);
|
||||
assert.ok(boxes.every(b => b.checked));
|
||||
profilerScanIgnoreAllState();
|
||||
assert.strictEqual(header.checked, true);
|
||||
assert.strictEqual(header.indeterminate, false);
|
||||
|
||||
delete global.document;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user