Files
CyberStrikeAI/web/static/js/asset-export-language.test.cjs
T

75 lines
5.2 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const path = require('node:path');
const source = fs.readFileSync(path.join(__dirname, 'assets.js'), 'utf8');
function context(locale) {
const translations = JSON.parse(fs.readFileSync(path.join(__dirname, '../i18n', locale + '.json'))).assets;
const c = vm.createContext({ window: { i18next: { t: key => translations[key.slice(7)] || key } } });
vm.runInContext(source.slice(source.indexOf('function assetT('), source.indexOf('function downloadAssetTemplate(')), c);
vm.runInContext(source.slice(source.indexOf('function assetRiskPresentation('), source.indexOf('function assetOwnershipMarkup(')), c);
return c;
}
for (const locale of ['zh-CN', 'en-US', 'ru-RU']) {
test(locale + ' export headers and enum values can be imported again', () => {
const c = context(locale);
const columns = vm.runInContext('ASSET_IMPORT_COLUMNS.slice()', c);
for (const column of columns) {
const header = c.assetExportHeader(column);
assert.equal(c.assetImportColumnForHeader(header), column);
}
for (const [key, codes] of Object.entries({ environment: ['production', 'staging', 'testing', 'development', 'other'], criticality: ['critical', 'high', 'medium', 'low'], status: ['active', 'inactive'] })) {
for (const code of codes) {
const display = c.assetExportValue(key, code);
assert.equal(c.assetLocalizedEnumMap({ [code]: code }, key)[display.toLowerCase()], code);
}
}
assert.equal(c.assetExportValue('country', 'CN'), 'CN');
assert.equal(c.assetExportValue('environment', 'custom-value'), 'custom-value');
assert.equal(c.assetExportValue('vulnerability_count', 2), 2);
assert.equal(c.assetImportColumnForHeader('responsible_person'), 'responsible_person');
});
}
test('CSV and XLSX both use localized headers and values', () => {
const exportFunction = source.slice(source.indexOf('function exportSelectedAssets('), source.indexOf('async function deleteSelectedAssets('));
assert.match(exportFunction, /headers\.map\(key => assetCsvCell\(assetExportHeader\(key\)\)\)/);
assert.match(exportFunction, /XLSX\.utils\.aoa_to_sheet/);
assert.match(exportFunction, /assetExportValue\(key, row\[key\]\)/);
});
for (const locale of ['zh-CN', 'en-US', 'ru-RU']) {
test(locale + ' actual CSV and XLSX exports round trip through the import parser', async () => {
const c = context(locale);
Object.assign(c, { URL, Blob, document: { getElementById: () => null }, alert: message => { throw new Error(message); } });
vm.runInContext(fs.readFileSync(path.join(__dirname, '../vendor/xlsx.full.min.js'), 'utf8'), c);
c.window.XLSX = c.XLSX;
c.assetPageState = { projects: [{ id: 'p1', name: '项目一' }], selected: new Map() };
const asset = { host: 'https://example.com:443', domain: 'example.com', port: 443, protocol: 'https', project_name: '项目一', title: 'title,"quoted"\nnext', status: 'inactive', environment: 'production', criticality: 'high', country: 'CN', province: 'Beijing', tags: ['one', 'two'] };
c.assetPageState.selected.set('a1', asset);
vm.runInContext(source.slice(source.indexOf('function assetTargetLabel('), source.indexOf('function assetRiskPresentation(')), c);
vm.runInContext(source.slice(source.indexOf('function assetExportRows('), source.indexOf('function downloadAssetBlob(')), c);
vm.runInContext(source.slice(source.indexOf('function exportSelectedAssets('), source.indexOf('async function deleteSelectedAssets(')), c);
vm.runInContext(source.slice(source.indexOf('function assetEditorDefaultPort('), source.indexOf('async function assetEditorResponseError(')), c);
vm.runInContext(source.slice(source.indexOf('function parseAssetImportMatrix('), source.indexOf('function renderAssetImportPreview(')), c);
c.renderAssetImportPreview = () => {};
let csv, workbook;
c.downloadAssetBlob = blob => { csv = blob; };
c.XLSX.writeFile = book => { workbook = book; };
c.exportSelectedAssets('csv');
const csvBook = c.XLSX.read(await csv.text(), { type: 'string' });
c.exportSelectedAssets('xlsx');
const bytes = c.XLSX.write(workbook, { type: 'array', bookType: 'xlsx' });
const xlsxBook = c.XLSX.read(bytes, { type: 'array' });
for (const book of [csvBook, xlsxBook]) {
const matrix = c.XLSX.utils.sheet_to_json(book.Sheets[book.SheetNames[0]], { header: 1, defval: '', raw: false });
assert.equal(matrix[0][0], c.assetExportHeader('target'));
c.parseAssetImportMatrix(matrix, 'export');
const imported = c.assetPageState.importRows[0];
assert.equal(imported.error, '');
for (const key of ['host', 'domain', 'port', 'protocol', 'title', 'status', 'environment', 'criticality', 'country', 'province']) assert.equal(imported.asset[key], asset[key], key);
assert.equal(imported.asset.project_id, 'p1');
assert.deepEqual(Array.from(imported.asset.tags), asset.tags);
}
});
}