# QKForce Framework CWQ ## Generated project execution Frontend-generated suites use `test/qkforce/manifest.json` (schema 1), exact feature paths, `steps.mjs` and `selectors.json`. The runtime loads only that selection, supplies explicit Cucumber imports and drains legacy palette actions in order. Packaged workspaces without generated inputs fail instead of running template examples. Regenerate projects after migrating to this template revision; publish the runtime to the actual DB-configured Git remote before deploying API #108/frontend #61. `npm run test:contract` covers config, immutable test data and generated-workspace validation. The separate HTML-report entrypoint gap remains #8. Real browser/client execution remains the release gate. The QKForce browser-automation template is the fixed `TypeScript + Cucumber + WebdriverIO + QKTestAnalytics` profile. ## Contract status CWQ consumes the central v1.1 run config and optional package-local version-locked CSV inputs before WDIO starts. It does not create packages or receive results; those are API/Client responsibilities. The remaining documentation/operational concern is a verifiable required CI check, tracked in [CWQ #6](https://github.com/QACGBDT/QKForce-Framework-CWQ/issues/6). ## Run ```bash npm ci npm run qkforce:test npm run qkforce:report ``` `qkforce:test` is the only execution entry point used by QKForce Client. Results belong under `qreport-results/`; raw test-data CSV files must not be copied into results archives. ## Immutable run configuration Every v1.1 workspace contains `qkforce.config.json` with numeric `schemaVersion: 1`, fixed profile id `qkforce-wdio-cucumber-qkta`, and `run.targetUrl`. The loader rejects unknown fields, non-fixed profiles, credentials/query/fragment URLs, non-HTTPS non-loopback targets, and target URLs over 2048 UTF-8 bytes. ```json { "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" } } ``` ## Version-locked CSV test data When test data is bound, QKForce materializes only immutable selected CSV versions below `test-data/` and writes `qkforce.test-data.lock.json`. No lock is required for executions without bound test data. The framework preflights every present lock before WDIO starts and never fetches live data. Validation covers schema version, unknown/duplicate metadata, safe package-local `test-data/*.csv` paths, regular-file/symlink checks, SHA-256, UTF-8, RFC-4180 quoting, unique headers and declared row count. Use the typed step-definition helper: ```ts import { Given } from '@wdio/cucumber-framework'; import { loadTestData } from '../support/test-data.js'; const testData = loadTestData(); Given('I use customer {string}', async (id: string) => { const customer = testData.dataset('customers').first({ id }); await $('#username').setValue(customer.name); }); ``` Rows are immutable and scenario selection is never stored in global mutable state. Use `row(index)`, `where({...})` or `first({...})` for deterministic addressing. `typedRow(index, schema)` supports `string`, `integer`, `number`, `boolean` (`true`/`false`) and ISO `date` (`YYYY-MM-DD`); `{ type, nullable: true }` maps an empty cell to `null`. Diagnostics identify dataset/version, row and column without printing cell contents. `provenance()` returns only `testDataLockSha256` and `{datasetId, versionId, sha256}` entries, matching the QKForce results-manifest contract without raw CSV values. Starter positive/negative fixtures live under `test/fixtures/test-data/`. Execution-specific CSV files are generated by QKForce and should not be hand-edited in the template. Run non-browser validation with: ```bash npm run check ``` Active development is performed on `develop`. ## Fixed execution and reporting `npm run qkforce:test` archives the previous cycle, runs WDIO, then builds `qreport-results/index.html` even when WDIO fails. The runner exit code is preserved; report failure makes a successful run fail. No command is accepted from the execution manifest. `qkforce:report` remains available for rebuilding an existing report. Cancellation or a forcibly terminated client cannot guarantee report generation.