diff --git a/src/cucumber-runner.ts b/src/cucumber-runner.ts index 3a75bf36..8647bb8a 100644 --- a/src/cucumber-runner.ts +++ b/src/cucumber-runner.ts @@ -7,7 +7,7 @@ import type { CucumberRunnerConfig } from './types'; import * as utils from './utils'; import { NodeContext } from 'sauce-testrunner-utils/lib/types'; -function buildArgs(runCfg: CucumberRunnerConfig, cucumberBin: string) { +export function buildArgs(runCfg: CucumberRunnerConfig, cucumberBin: string) { const paths: string[] = []; runCfg.suite.options.paths.forEach((p) => { paths.push(path.join(runCfg.projectPath, p)); @@ -50,32 +50,10 @@ function buildArgs(runCfg: CucumberRunnerConfig, cucumberBin: string) { procArgs.push(tag); }); - function parseNewFormat(format: string, assetsDir: string) { - // Regex to validate and extract key and value from the new format. - // Example: "html":"file://hostname/formatter/report.html" - const match = format.match(/^"([^"]+)":"(.+)"$/); - if (!match) { - return null; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_, key, value] = match; - return `"${key}":"${path.join(assetsDir, value)}"`; - } - runCfg.suite.options.format?.forEach((format) => { + const updatedFormat = normalizeFormat(format, runCfg.assetsDir); procArgs.push('--format'); - - const newFormat = parseNewFormat(format, runCfg.assetsDir); - if (newFormat) { - return newFormat; - } - - const opts = format.split(':'); - if (opts.length === 2) { - return `"${opts[0]}":"${path.join(runCfg.assetsDir, opts[1])}"`; - } - - return `"${format}"`; + procArgs.push(updatedFormat); }); if (runCfg.suite.options.parallel) { @@ -87,6 +65,35 @@ function buildArgs(runCfg: CucumberRunnerConfig, cucumberBin: string) { return procArgs; } +/** + * Normalizes a Cucumber format string by ensuring it is in the form of `"key":"value"`. + * + * @param {string} format - The input format string, which can be in various forms: + * - `"key:value"` + * - `"key":"value"` + * - `key:value` + * @param {string} assetDir - The asset directory. + * @throws {Error} If the input format is invalid (e.g., missing a colon separator). + * @returns {string} The normalized format string in the form of `"key":"value"`, + * with the asset directory prepended to relative paths. + * + * Example: + * Input: `"html:formatter/report.html"`, `"/project/assets"` + * Output: `"html":"/project/assets/formatter/report.html"` + */ +export function normalizeFormat(format: string, assetDir: string): string { + const match = format.match(/^"?([^:]+):"?([^"]+)"?$/); + if (!match) { + throw new Error(`Invalid format: ${format}`); + } + + let [, key, value] = match; + key = key.replace(/^"|"$/g, ''); + value = value.replace(/^"|"$/g, ''); + const updatedPath = path.join(assetDir, value); + return `"${key}":"${updatedPath}"`; +} + export async function runCucumber( nodeBin: string, runCfg: CucumberRunnerConfig, diff --git a/tests/unit/src/cucumber-runner.spec.js b/tests/unit/src/cucumber-runner.spec.js new file mode 100644 index 00000000..f51539d1 --- /dev/null +++ b/tests/unit/src/cucumber-runner.spec.js @@ -0,0 +1,65 @@ +const { buildArgs, normalizeFormat } = require('../../../src/cucumber-runner'); + +describe('buildArgs', () => { + const cucumberBin = '/usr/local/bin/cucumber'; + + it('should build correct arguments with basic configuration', () => { + const runCfg = { + sauce: { + metadata: {}, + }, + projectPath: '/project', + assetsDir: '/project/assets', + suite: { + options: { + paths: ['features/test.feature'], + }, + }, + }; + + const result = buildArgs(runCfg, cucumberBin); + + expect(result).toEqual([ + cucumberBin, + '/project/features/test.feature', + '--force-exit', + '--require-module', + 'ts-node/register', + '--format', + '@saucelabs/cucumber-reporter', + '--format-options', + '{"upload":false,"outputFile":"/project/assets/sauce-test-report.json"}', + ]); + }); +}); + +describe('normalizeFormat', () => { + const assetDir = '/project/assets'; + + it('should normalize formats with both quoted format type and path', () => { + expect(normalizeFormat(`"html":"formatter/report.html"`, assetDir)).toBe( + `"html":"/project/assets/formatter/report.html"`, + ); + }); + + it('should normalize formats with only one pair of quote', () => { + expect(normalizeFormat(`"html:formatter/report.html"`, assetDir)).toBe( + `"html":"/project/assets/formatter/report.html"`, + ); + }); + + it('should normalize formats with no quotes', () => { + expect(normalizeFormat(`html:formatter/report.html`, assetDir)).toBe( + `"html":"/project/assets/formatter/report.html"`, + ); + }); + + it('should throw an error for invalid formats', () => { + expect(() => + normalizeFormat(`html-formatter/report.html`, assetDir), + ).toThrow('Invalid format: html-formatter/report.html'); + expect(() => + normalizeFormat(`"htmlformatter/report.html"`, assetDir), + ).toThrow('Invalid format: "htmlformatter/report.html"'); + }); +});