Upload files to "/"
This commit is contained in:
70
README.md
70
README.md
@@ -1,2 +1,70 @@
|
|||||||
# TS-CUCUMBER-WDIO-QK
|
# QKForce Framework CWQ
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|||||||
7384
package-lock.json
generated
Normal file
7384
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
qkforce.config.json
Normal file
12
qkforce.config.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"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://the-internet.herokuapp.com" }
|
||||||
|
}
|
||||||
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"target": "ES2022",
|
||||||
|
"lib": ["ES2022", "DOM"],
|
||||||
|
"types": ["node", "@wdio/globals/types", "@wdio/cucumber-framework"],
|
||||||
|
"strict": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": false,
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
"include": ["test", "wdio.conf.ts"]
|
||||||
|
}
|
||||||
28
wdio.conf.ts
Normal file
28
wdio.conf.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { createWdioCucumberAdapter } from '@qacg/qk-test-analytics/adapters/wdio-cucumber';
|
||||||
|
import { loadQkforceRunConfig } from './test/support/qkforce-config.mjs';
|
||||||
|
import { loadQkforceTestData } from './test/support/qkforce-test-data.mjs';
|
||||||
|
|
||||||
|
const qkforce = loadQkforceRunConfig();
|
||||||
|
loadQkforceTestData();
|
||||||
|
|
||||||
|
const analytics = createWdioCucumberAdapter({
|
||||||
|
capture: 'on-failure',
|
||||||
|
projectName: qkforce.profile.id
|
||||||
|
});
|
||||||
|
|
||||||
|
export const config: WebdriverIO.Config = {
|
||||||
|
runner: 'local',
|
||||||
|
tsConfigPath: './tsconfig.json',
|
||||||
|
specs: ['./test/features/**/*.feature'],
|
||||||
|
maxInstances: 1,
|
||||||
|
capabilities: [{ browserName: 'chrome', 'goog:chromeOptions': { args: ['--headless=new','--disable-gpu','--no-sandbox','--window-size=1440,900'] } }],
|
||||||
|
logLevel: 'error',
|
||||||
|
baseUrl: qkforce.run.targetUrl,
|
||||||
|
waitforTimeout: 10_000,
|
||||||
|
connectionRetryTimeout: 120_000,
|
||||||
|
connectionRetryCount: 3,
|
||||||
|
framework: 'cucumber',
|
||||||
|
reporters: ['spec'],
|
||||||
|
cucumberOpts: { import: ['./test/step-definitions/**/*.ts'], language: 'en', timeout: 60_000, retry: 0, failFast: false, strict: true },
|
||||||
|
...analytics.hooks
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user