Files
safetynet/tests/category-editor.test.mjs
T

11 lines
2.7 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {readFileSync} from 'node:fs';
import vm from 'node:vm';
import {DomainCategorySchema} from '../packages/core/user-profiles.mjs';
const source=readFileSync(new URL('../apps/server/public/profile-admin.js',import.meta.url),'utf8');
function fixture(){const fields=new Map();const get=id=>{if(!fields.has(id))fields.set(id,{value:'',checked:false,disabled:false,dataset:{},querySelectorAll:()=>[],addEventListener(){},replaceChildren(){}});return fields.get(id);};const context=vm.createContext({$:get,task:fn=>fn,currentPrincipal:null,structuredClone,document:{},independentApprovalRequired:false});vm.runInContext(source,context);return {context,get};}
test('category validation matches backend host, identifier, duplicate and bounds constraints',()=>{const {context}=fixture();const valid=[{id:'social',name:'Social',hosts:['*.social.example','intranet']}];assert.equal(vm.runInContext(`validateCategoryDraft(${JSON.stringify(valid)}).length`,context),1);DomainCategorySchema.parse(valid[0]);for(const change of [{id:'bad id'},{name:''},{hosts:['https://host.example']},{hosts:['host.example:443']},{hosts:['x','x']},{hosts:['a'.repeat(254)]}]){const category={...valid[0],...change};assert.equal(DomainCategorySchema.safeParse(category).success,false);assert.throws(()=>vm.runInContext(`validateCategoryDraft(${JSON.stringify([category])})`,context));}assert.throws(()=>vm.runInContext(`validateCategoryDraft(${JSON.stringify([valid[0],valid[0]])})`,context));});
test('dirty state retains original CAS base and referenced category removal remains locked',()=>{const {context,get}=fixture();vm.runInContext("categoryDraftVersion=12;profileState={version:13,profiles:[{name:'Employees',blockedCategoryIds:['social']}],categories:[]};categoryChanged()",context);assert.equal(vm.runInContext('categoryDraftVersion',context),12);assert.equal(vm.runInContext('categoryDraftDirty',context),true);assert.equal(vm.runInContext("categoryReferences('social').length",context),1);assert.match(get('profile-category-status').textContent,/v12/);assert.match(source,/expectedVersion:categoryDraftVersion/);assert.match(source,/if\(!categoryDraftDirty\)/);});
test('structured accessible controls replace mandatory JSON and retain explicit publication',()=>{const html=readFileSync(new URL('../apps/server/public/index.html',import.meta.url),'utf8');assert.ok(html.includes('id="profile-category-editor"'));assert.ok(html.includes('id="profile-category-status" role="status"'));assert.ok(!html.includes('id="profile-category-json"'));assert.match(source,/input.readOnly=profileState.categories.some/);assert.match(source,/button.dataset.categoryReferenced==='true'/);});