93 lines
4.2 KiB
JavaScript
93 lines
4.2 KiB
JavaScript
import './setup.mjs';
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { load } from './setup.mjs';
|
|
|
|
const { listRecipes, searchRecipes, getRecipe, buildRecipeArtifacts } =
|
|
await load('../services/recipeService.js');
|
|
|
|
// --- catalog -----------------------------------------------------------------
|
|
|
|
test('listRecipes exposes a sanitized catalog with the fields the UI needs', () => {
|
|
const list = listRecipes();
|
|
assert.ok(list.length >= 10, 'catalog has a useful number of recipes');
|
|
const chrome = list.find((r) => r.id === 'google-chrome');
|
|
assert.ok(chrome);
|
|
assert.equal(chrome.wingetId, 'Google.Chrome');
|
|
assert.ok(chrome.installArgs.includes('/qn'));
|
|
assert.ok(chrome.homepage.startsWith('https://'));
|
|
});
|
|
|
|
test('every recipe references a known installer technology and a valid detection footprint', async () => {
|
|
const { listInstallerTechnologies } = await load('../services/installerIntelService.js');
|
|
const techIds = new Set(listInstallerTechnologies().map((t) => t.id));
|
|
for (const r of listRecipes()) {
|
|
assert.ok(techIds.has(r.installerType), `${r.id} -> ${r.installerType} is a known technology`);
|
|
// Detection must not throw when applied (file/registry/msi all valid here).
|
|
assert.doesNotThrow(() => buildRecipeArtifacts(getRecipe(r.id)), `${r.id} detection builds`);
|
|
}
|
|
});
|
|
|
|
test('enterprise agents without a winget id still build, but skip the catalog app', () => {
|
|
const falcon = getRecipe('crowdstrike-falcon');
|
|
assert.equal(falcon.wingetId, '');
|
|
const { application, deployment } = buildRecipeArtifacts(falcon);
|
|
assert.equal(application, null, 'no winget id -> no auto-tracked app');
|
|
assert.ok(deployment.detectionRule.includes('CSFalconService.exe'));
|
|
});
|
|
|
|
test('searchRecipes matches vendor, name, and winget id case-insensitively', () => {
|
|
assert.ok(searchRecipes('mozilla').some((r) => r.id === 'mozilla-firefox'));
|
|
assert.ok(searchRecipes('VLC').some((r) => r.id === 'vlc'));
|
|
assert.ok(searchRecipes('Microsoft.PowerShell').some((r) => r.id === 'powershell-7'));
|
|
assert.equal(searchRecipes('nonexistent-app-xyz').length, 0);
|
|
assert.equal(searchRecipes('').length, listRecipes().length);
|
|
});
|
|
|
|
// --- apply transform (pure) --------------------------------------------------
|
|
|
|
test('buildRecipeArtifacts produces profile + deployment + tracked app for an MSI recipe', () => {
|
|
const { profile, deployment, application } = buildRecipeArtifacts(getRecipe('google-chrome'));
|
|
|
|
// Profile carries the raw silent install as a PSADT install task.
|
|
assert.equal(profile.name, 'Google Chrome');
|
|
assert.equal(profile.appVendor, 'Google');
|
|
assert.equal(profile.installTasks.length, 1);
|
|
assert.equal(profile.installTasks[0].type, 'msi');
|
|
assert.equal(profile.installTasks[0].filePath, 'googlechromestandaloneenterprise64.msi');
|
|
assert.ok(profile.installTasks[0].arguments.includes('/qn'));
|
|
|
|
// Deployment wraps it in PSADT v4 with a file-detection rule.
|
|
assert.equal(deployment.commandStyle, 'v4');
|
|
assert.equal(deployment.detectionType, 'custom-script');
|
|
assert.ok(deployment.detectionRule.includes('chrome.exe'));
|
|
assert.equal(deployment.status, 'draft');
|
|
|
|
// Catalog app is wired to the winget version watcher.
|
|
assert.equal(application.versionSource, 'winget');
|
|
assert.equal(application.versionSourceRef, 'Google.Chrome');
|
|
assert.equal(application.autoCheck, true);
|
|
});
|
|
|
|
test('EXE-based recipes become exe install tasks with the silent switch', () => {
|
|
const { profile } = buildRecipeArtifacts(getRecipe('git'));
|
|
assert.equal(profile.installTasks[0].type, 'exe');
|
|
assert.ok(profile.installTasks[0].arguments.includes('/VERYSILENT'));
|
|
});
|
|
|
|
test('applying with group visibility scopes the group id', () => {
|
|
const { profile, deployment } = buildRecipeArtifacts(getRecipe('7zip'), { visibility: 'group', groupId: 'grp_1' });
|
|
assert.equal(profile.visibility, 'group');
|
|
assert.equal(profile.groupId, 'grp_1');
|
|
assert.equal(deployment.groupId, 'grp_1');
|
|
});
|
|
|
|
test('group id is dropped when visibility is not group', () => {
|
|
const { profile } = buildRecipeArtifacts(getRecipe('7zip'), { visibility: 'personal', groupId: 'grp_1' });
|
|
assert.equal(profile.groupId, null);
|
|
});
|
|
|
|
test('buildRecipeArtifacts throws on a missing recipe', () => {
|
|
assert.throws(() => buildRecipeArtifacts(null));
|
|
});
|