"use strict"; import assert from "assert"; import assertThrows from "./assert_throws"; import CucumberExpression from "../src/CucumberExpression"; import RegularExpression from "../src/RegularExpression"; import ParameterTypeRegistry from "../src/ParameterTypeRegistry"; import ParameterType from "../src/ParameterType"; class Color { /// [color-constructor] constructor(public readonly name: string) {} /// [color-constructor] } class CssColor { constructor(public readonly name: string) {} } describe("Custom parameter type", () => { let parameterTypeRegistry: ParameterTypeRegistry; beforeEach(() => { parameterTypeRegistry = new ParameterTypeRegistry(); /* eslint-disable prettier/prettier */ /// [add-color-parameter-type] parameterTypeRegistry.defineParameterType( new ParameterType( "color", // name /red|blue|yellow/, // regexp Color, // type s => new Color(s), // transformer false, // useForSnippets true // preferForRegexpMatch ) ); /// [add-color-parameter-type] /* eslint-enable prettier/prettier */ }); describe("CucumberExpression", () => { it("throws exception for illegal character in parameter name", () => { assertThrows( () => new ParameterType("[string]", /.*/, String, s => s, false, true), "Illegal character '[' in parameter name {[string]}" ); }); it("matches parameters with custom parameter type", () => { const expression = new CucumberExpression( "I have a {color} ball", parameterTypeRegistry ); const value = expression.match("I have a red ball")[0].getValue(null); assert.strictEqual(value.name, "red"); }); it("matches parameters with multiple capture groups", () => { class Coordinate { constructor( public readonly x: number, public readonly y: number, public readonly z: number ) {} } parameterTypeRegistry.defineParameterType( new ParameterType( "coordinate", /(\d+),\s*(\d+),\s*(\d+)/, Coordinate, (x: string, y: string, z: string) => new Coordinate(Number(x), Number(y), Number(z)), true, true ) ); const expression = new CucumberExpression( "A {int} thick line from {coordinate} to {coordinate}", parameterTypeRegistry ); const args = expression.match("A 5 thick line from 10,20,30 to 40,50,60"); const thick = args[0].getValue(null); assert.strictEqual(thick, 5); const from = args[1].getValue(null); assert.strictEqual(from.x, 10); assert.strictEqual(from.y, 20); assert.strictEqual(from.z, 30); const to = args[2].getValue(null); assert.strictEqual(to.x, 40); assert.strictEqual(to.y, 50); assert.strictEqual(to.z, 60); }); it("matches parameters with custom parameter type using optional capture group", () => { parameterTypeRegistry = new ParameterTypeRegistry(); parameterTypeRegistry.defineParameterType( new ParameterType( "color", [/red|blue|yellow/, /(?:dark|light) (?:red|blue|yellow)/], Color, s => new Color(s), false, true ) ); const expression = new CucumberExpression( "I have a {color} ball", parameterTypeRegistry ); const value = expression .match("I have a dark red ball")[0] .getValue(null); assert.strictEqual(value.name, "dark red"); }); it("defers transformation until queried from argument", () => { parameterTypeRegistry.defineParameterType( new ParameterType( "throwing", /bad/, null, s => { throw new Error(`Can't transform [${s}]`); }, false, true ) ); const expression = new CucumberExpression( "I have a {throwing} parameter", parameterTypeRegistry ); const args = expression.match("I have a bad parameter"); assertThrows(() => args[0].getValue(null), "Can't transform [bad]"); }); describe("conflicting parameter type", () => { it("is detected for type name", () => { assertThrows( () => parameterTypeRegistry.defineParameterType( new ParameterType( "color", /.*/, CssColor, s => new CssColor(s), false, true ) ), "There is already a parameter type with name color" ); }); it("is not detected for type", () => { parameterTypeRegistry.defineParameterType( new ParameterType( "whatever", /.*/, Color, s => new Color(s), false, false ) ); }); it("is not detected for regexp", () => { parameterTypeRegistry.defineParameterType( new ParameterType( "css-color", /red|blue|yellow/, CssColor, s => new CssColor(s), true, false ) ); assert.strictEqual( new CucumberExpression( "I have a {css-color} ball", parameterTypeRegistry ) .match("I have a blue ball")[0] .getValue(null).constructor, CssColor ); assert.strictEqual( new CucumberExpression( "I have a {css-color} ball", parameterTypeRegistry ) .match("I have a blue ball")[0] .getValue(null).name, "blue" ); assert.strictEqual( new CucumberExpression("I have a {color} ball", parameterTypeRegistry) .match("I have a blue ball")[0] .getValue(null).constructor, Color ); assert.strictEqual( new CucumberExpression("I have a {color} ball", parameterTypeRegistry) .match("I have a blue ball")[0] .getValue(null).name, "blue" ); }); }); // JavaScript-specific it("creates arguments using async transform", async () => { parameterTypeRegistry = new ParameterTypeRegistry(); /// [add-async-parameter-type] parameterTypeRegistry.defineParameterType( new ParameterType( "asyncColor", /red|blue|yellow/, Color, async s => new Color(s), false, true ) ); /// [add-async-parameter-type] const expression = new CucumberExpression( "I have a {asyncColor} ball", parameterTypeRegistry ); const args = await expression.match("I have a red ball"); const value = await args[0].getValue(null); assert.strictEqual(value.name, "red"); }); }); describe("RegularExpression", () => { it("matches arguments with custom parameter type", () => { const expression = new RegularExpression( /I have a (red|blue|yellow) ball/, parameterTypeRegistry ); const value = expression.match("I have a red ball")[0].getValue(null); assert.strictEqual(value.constructor, Color); assert.strictEqual(value.name, "red"); }); }); });