import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { loadQkforceRunConfig, validateQkforceRunConfig } from '../support/qkforce-config.mjs'; const validConfig = () => ({ schemaVersion:1, profile:{ id:'qkforce-wdio-cucumber-qkta', language:'typescript', bdd:'cucumber', runner:'webdriverio', adapter:'webdriverio-cucumber-node', reporter:'qk-test-analytics' }, run:{ targetUrl:'https://example.test/application' } }); test('accepts the central fixed profile and run.targetUrl', () => { const config = validateQkforceRunConfig(validConfig()); assert.equal(config.baseUrl,'https://example.test/application'); assert.equal(config.profile.id,'qkforce-wdio-cucumber-qkta'); }); test('allows HTTP only for exact loopback development targets', () => { for (const targetUrl of ['http://localhost:8080','http://127.0.0.1:8080','http://[::1]:8080']) { const config=validConfig(); config.run.targetUrl=targetUrl; assert.match(validateQkforceRunConfig(config).baseUrl,/^http:/); } }); test('rejects unsafe target URLs without echoing them', () => { for (const unsafeUrl of ['http://example.test','https://user:secret@example.test','https://example.test/#token','https://example.test/?token=secret']) { const config=validConfig(); config.run.targetUrl=unsafeUrl; assert.throws(() => validateQkforceRunConfig(config), error => { assert.match(error.message,/Invalid QKForce run configuration/); assert.doesNotMatch(error.message,/secret|token/); return true; }); } }); test('enforces the 2048 UTF-8 byte target URL limit', () => { const config=validConfig(); config.run.targetUrl=`https://example.test/${'é'.repeat(1015)}`; assert.throws(() => validateQkforceRunConfig(config),/2048-byte maximum/); }); test('rejects a profile other than the central fixed profile', () => { const config=validConfig(); config.profile.adapter='playwright-cucumber-node'; assert.throws(() => validateQkforceRunConfig(config),/profile.adapter/); }); test('rejects the previous repository-local target/template shape', () => { const config=validConfig(); config.template={id:'qkforce-framework-cwq',version:'0.2.0'}; assert.throws(() => validateQkforceRunConfig(config),/config.template/); }); test('fails clearly when the workspace configuration is missing or malformed', () => { const directory=fs.mkdtempSync(path.join(os.tmpdir(),'qkforce-config-')); try { assert.throws(() => loadQkforceRunConfig(directory),/qkforce.config.json is missing/); fs.writeFileSync(path.join(directory,'qkforce.config.json'),'{'); assert.throws(() => loadQkforceRunConfig(directory),/not valid JSON/); } finally { fs.rmSync(directory,{recursive:true,force:true}); } });