Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,34 +44,34 @@
},
"homepage": "https://github.com/Hypersequent/qas-cli#readme",
"devDependencies": {
"@eslint/js": "^9.25.1",
"@eslint/js": "^10.0.1",
"@types/escape-html": "^1.0.4",
"@types/node": "^20.17.32",
"@types/semver": "^7.7.0",
"@types/xml2js": "^0.4.14",
"@types/yargs": "^17.0.33",
"eslint": "^9.25.1",
"eslint": "^10.5.0",
"eslint-config-prettier": "^10.1.8",
"globals": "^16.0.0",
"husky": "^9.1.7",
"lint-staged": "^15.2.11",
"msw": "^2.7.5",
"prettier": "^3.4.2",
"ts-add-js-extension": "^1.6.6",
"typescript": "^5.8.3",
"typescript-eslint": "^8.31.1",
"typescript": "^6.0.3",
"typescript-eslint": "^8.61.1",
"vitest": "^4.1.0"
},
"dependencies": {
"@napi-rs/keyring": "^1.2.0",
"chalk": "^5.4.1",
"dotenv": "^16.5.0",
"dotenv": "^17.4.2",
"escape-html": "^1.0.3",
"semver": "^7.7.1",
"strip-ansi": "^7.1.2",
"xml2js": "^0.6.2",
"yargs": "^17.7.2",
"zod": "^3.24.3"
"yargs": "^18.0.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve Node 18 support when bumping yargs

This package still advertises Node 18 support (engines.node is >=18.0.0, and mnode-test/docker-test.sh tests Node 18), but the lockfile now resolves yargs@18.0.0/yargs-parser@22.0.0 with engines requiring Node ^20.19.0 || ^22.12.0 || >=23. Users on the documented Node 18 runtime, or CI jobs running the multi-node smoke test, will install a dependency outside the supported runtime and can fail under engine-strict or execute unsupported code; keep yargs on 17.x or update the package engine/tests together.

Useful? React with 👍 / 👎.

"zod": "^4.4.3"
},
"bin": {
"qasphere": "build/bin/qasphere.js"
Expand Down
1,444 changes: 673 additions & 771 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/commands/api/manifests/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const upload: ApiEndpointSpec = {
execute: async (api, { body }) => {
const filePath = body as string
const filename = basename(filePath)
const blob = new Blob([await readFile(filePath)])
const blob = new Blob([new Uint8Array(await readFile(filePath))])
const [result] = await api.files.upload([{ blob, filename }])
printJson(result)
},
Expand Down
5 changes: 3 additions & 2 deletions src/commands/api/manifests/runs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { printJson, apiDocsEpilog, kebabToCamelCaseKeys } from '../utils'
import { commonHelp, projectCodeParam } from './utils'
import type { ApiEndpointSpec } from '../types'

// CreateRunRequestSchema uses .superRefine() → ZodEffects, so extract inner ZodObject
const CreateRunShape = CreateRunRequestSchema.sourceType().shape
// CreateRunRequestSchema attaches a refinement via .superRefine(), but in Zod 4
// the result stays a ZodObject, so .shape is accessed directly.
const CreateRunShape = CreateRunRequestSchema.shape

const help = {
...commonHelp,
Expand Down
5 changes: 3 additions & 2 deletions src/commands/api/manifests/test-cases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import { printJson, apiDocsEpilog, kebabToCamelCaseKeys } from '../utils'
import { commonHelp, projectCodeParam } from './utils'
import type { ApiEndpointSpec } from '../types'

// CreateTCaseRequestSchema uses .superRefine() → ZodEffects, so extract inner ZodObject
const CreateTCaseShape = CreateTCaseRequestSchema.sourceType().shape
// CreateTCaseRequestSchema attaches a refinement via .superRefine(), but in Zod 4
// the result stays a ZodObject, so .shape is accessed directly.
const CreateTCaseShape = CreateTCaseRequestSchema.shape

const help = {
...commonHelp,
Expand Down
10 changes: 7 additions & 3 deletions src/commands/api/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function parseJsonFieldValue(value: unknown, fieldName: string): unknown {
return JSON.parse(value)
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
throw new Error(`Failed to parse --${fieldName} as JSON: ${msg}`)
throw new Error(`Failed to parse --${fieldName} as JSON: ${msg}`, { cause: e })
}
}

Expand Down Expand Up @@ -205,7 +205,8 @@ export function parseBodyInput(args: Record<string, unknown>): unknown {
`Failed to parse --body as JSON: ${errorMessage}\n` +
` Provide valid inline JSON or use --body-file to read from a file.\n` +
` Inline example: --body '{"title": "Test"}'\n` +
` File example: --body-file body.json`
` File example: --body-file body.json`,
{ cause: e }
)
}
}
Expand All @@ -219,7 +220,10 @@ export function parseBodyInput(args: Record<string, unknown>): unknown {
return JSON.parse(content)
} catch (e) {
const errorMessage = e instanceof Error ? e.message : String(e)
throw new Error(`Failed to parse JSON from file ${bodyFile} for --body-file: ${errorMessage}`)
throw new Error(
`Failed to parse JSON from file ${bodyFile} for --body-file: ${errorMessage}`,
{ cause: e }
)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/tests/api/audit-logs/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ describe('validation errors', () => {
test('rejects --after -1', async () => {
await expectValidationError(
() => runCommand('--after', '-1'),
/--after.*must be greater than or equal to 0/i
/--after.*expected number to be >=0/i
)
})

test('rejects --count 0', async () => {
await expectValidationError(
() => runCommand('--count', '0'),
/--count.*must be greater than 0/i
/--count.*expected number to be >0/i
)
})
})
6 changes: 3 additions & 3 deletions src/tests/api/folders/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,21 @@ describe('validation errors', () => {
test('rejects --page with non-integer', async () => {
await expectValidationError(
() => runCommand('--project-code', 'PRJ', '--page', '1.5'),
/--page.*integer/i
/--page.*expected int/i
)
})

test('rejects --offset -1', async () => {
await expectValidationError(
() => runCommand('--project-code', 'PRJ', '--offset', '-1'),
/--offset.*greater than or equal to 0/i
/--offset.*expected number to be >=0/i
)
})

test('rejects --limit -1', async () => {
await expectValidationError(
() => runCommand('--project-code', 'PRJ', '--limit', '-1'),
/--limit.*greater than or equal to 0/i
/--limit.*expected number to be >=0/i
)
})
})
Expand Down
2 changes: 1 addition & 1 deletion src/tests/api/projects/create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('validation errors', () => {
'--links',
'[{"title": "Docs", "url": "https://example.com"}]'
),
/--links.*Required/
/--links.*received undefined/
)
})

Expand Down
4 changes: 2 additions & 2 deletions src/tests/api/results/batch-create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ describe('validation errors', () => {
'--items',
JSON.stringify([{ tcaseId: 'tc1', status: 'invalid-status' }])
),
/Invalid enum value/
/Invalid option/
)
})

Expand All @@ -129,7 +129,7 @@ describe('validation errors', () => {
'--items',
JSON.stringify([{ status: 'passed' }])
),
/tcaseId: Required/
/tcaseId.*expected string, received undefined/
)
})

Expand Down
2 changes: 1 addition & 1 deletion src/tests/api/results/create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('mocked', () => {
requiredArgs,
})
h.testInvalidJson(requiredArgs)
h.testInvalidBody({ status: 'invalid-status' }, /Invalid enum value/, requiredArgs)
h.testInvalidBody({ status: 'invalid-status' }, /Invalid option/, requiredArgs)
}
)
})
Expand Down
4 changes: 2 additions & 2 deletions src/tests/api/runs/create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ describe('validation errors', () => {
'--query-plans',
'[{"priorities": ["critical"]}]'
),
/Invalid enum value.*Expected 'low' \| 'medium' \| 'high'/
/Invalid option.*expected one of "low"\|"medium"\|"high"/
)
})

Expand Down Expand Up @@ -388,7 +388,7 @@ describe('validation errors', () => {
'--query-plans',
'[{"folderIds": [1.5]}]'
),
/integer/
/expected int/
)
})
})
Expand Down
8 changes: 4 additions & 4 deletions src/tests/api/test-cases/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,28 +76,28 @@ describe('validation errors', () => {
test('rejects --page 0', async () => {
await expectValidationError(
() => runCommand('--project-code', 'PRJ', '--page', '0'),
/--page.*must be greater than 0/i
/--page.*expected number to be >0/i
)
})

test('rejects --page -1', async () => {
await expectValidationError(
() => runCommand('--project-code', 'PRJ', '--page', '-1'),
/--page.*must be greater than 0/i
/--page.*expected number to be >0/i
)
})

test('rejects --offset -1', async () => {
await expectValidationError(
() => runCommand('--project-code', 'PRJ', '--offset', '-1'),
/--offset.*greater than or equal to 0/i
/--offset.*expected number to be >=0/i
)
})

test('rejects --limit -1', async () => {
await expectValidationError(
() => runCommand('--project-code', 'PRJ', '--limit', '-1'),
/--limit.*greater than or equal to 0/i
/--limit.*expected number to be >=0/i
)
})

Expand Down
4 changes: 2 additions & 2 deletions src/utils/result-upload/ResultUploadCommandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ export class ResultUploadCommandHandler {
}

let fileResults = await this.parseFiles()
let projectCode = ''
let runId = 0
let projectCode: string
let runId: number

if ('runUrl' in this.args && this.args.runUrl) {
// Handle existing run URL
Expand Down
9 changes: 6 additions & 3 deletions src/utils/result-upload/parsers/allureParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ export const parseAllureResults: Parser = async (
containerFiles = allFiles.filter((f) => f.endsWith('-container.json'))
} catch (error) {
throw new Error(
`Failed to read Allure results directory "${resultsDirectory}": ${getErrorMessage(error)}`
`Failed to read Allure results directory "${resultsDirectory}": ${getErrorMessage(error)}`,
{ cause: error }
)
}

Expand All @@ -146,7 +147,8 @@ export const parseAllureResults: Parser = async (
}

throw new Error(
`Failed to parse Allure result file "${resultFilePath}": ${getErrorMessage(error)}`
`Failed to parse Allure result file "${resultFilePath}": ${getErrorMessage(error)}`,
{ cause: error }
)
}

Expand Down Expand Up @@ -305,7 +307,8 @@ const extractRunFailureLogs = (
continue
}
throw new Error(
`Failed to parse Allure container file "${filePath}": ${getErrorMessage(error)}`
`Failed to parse Allure container file "${filePath}": ${getErrorMessage(error)}`,
{ cause: error }
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/utils/result-upload/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const getFile = async (filePath: string, basePath?: string): Promise<Buffer> =>
typeof e.code === 'string' &&
e.code === 'ENOENT'
) {
throw new Error(`Attachment not found: "${filePath}"`)
throw new Error(`Attachment not found: "${filePath}"`, { cause: e })
}
throw e
}
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"strict": true,
"skipLibCheck": true,
"outDir": "./build",
"rootDir": "./src",
"declaration": true,
"declarationMap": true
},
Expand Down