New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposal] Enable use of Enums in Cucumber Expressions / Steps #2088
Comments
Can you elaborate on how this might be achieved @nextlevelbeard? TypeScript types are compiler-only and don't exist at runtime, so |
I also struggled to find how exactly it could be done, just assumed there might be a way. I think an alternative could be allowing the use of TypeScript's Users could then easily derive the type in the steps with import { Then, defineParameterTypes, registerTypes } from '@cucumber/cucumber';
enum Fruit { 'Apple', Orange, Cucumber }
enum Vegetables { Potato, Eggplant }
registerTypes({ Fruit, Vegetables })
Then('I should have an? {Fruit} in my basket', async function (fruit: keyof typeof Fruit) {
if(fruit === Fruit[Fruit.Orange]){
// Assert
}
} Internally, we could transform the enum string values into a regular expression and define the parameter type // Internally implement something like this
Object.values(types).forEach(([name, type]) => defineParameterType({
name: name, // i.e. Fruit
// Enum /w numeric keys are not possible, we can safely filter keys
regexp: new RegExp(Object.keys(type).filter(k => !Number(k)).join('|')), // i.e. Apple|Orange|Cucumber
})) |
Maybe you could pull together a TS playground or something that shows this working on a core level? Again I don't think what you want will exist at runtime. enum values will be there (as the ordinal by default but you can make them a string) but the enum declaration won't exist in the JS as far as I know. |
Here's the playground, you can run it. We'd have to implement the
With enum this works because "Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript". You can check what enums turn into on the playground. @davidjgoss Let me know your thoughts on this |
Adding more eyes on this |
I'm a bit uneasy about adding something that's geared specially around a TypeScript concept. I think plain old arrays would be fine though e.g. defineSimpleParameterTypes({
Fruit: ['Apple', 'Orange', 'Cucumber'],
Vegetables: ['Potato', 'Eggplant']
}) And with TS it's fairly trivial to define a type from an array so not much extra overhead. |
I'm confused about why this is useful. Can I see a more realistic example? |
This wouldnn't take anything away from existing users, it's just making it simpler working with TS enums. The arrays would need to be readonly in order for users to be able to reference the parameter type in the steps. // Proposal, a function that takes an array of strings and defines type parameters
const registerTypes = (types: Record<string, readonly string[]>) => {
Object.entries(types).forEach(([name, type]) => defineParameterType({
name: name, // i.e. Fruit
// Enum /w numeric keys are not possible by TypeScript design, we can safely filter keys
regexp: new RegExp(type.filter(k => !Number(k)).join('|')), // i.e. Apple|Orange|Cucumber,
transformer: (s: string) => s
}))
}
import { Then, registerTypes } from '@cucumber/cucumber';
const Fruit = ['Apple', 'Orange', 'Cucumber'] as const
const Vegetables = ['Potato', 'Eggplant'] as const
registerTypes({ Fruit, Vegetables })
Then('I should have an? {Fruit} in my basket', stepFn = async function (fruit: typeof Fruit[number]) {
// Type safety, IDE complains about impossible comparisons
if(fruit === "asd"){
}
})
|
Run-able Proposal Playground
In its essence, allow for something like this to happen:
To take note:
Users don't need to write down their N possible options on neither:
The Cucumber Expression
defineParameterType
but thisregisterTypes
syntax makes things less verboseThere's now no concept of transformer, name and regex, just an enum
The parameter type (new!)
keyof typeof MyEnum
Users can reference the original enum for comparisons inside the step:
fruit === Fruit[Fruit.Orange]
Users will get specific string literal type safety instead of generic string safety:
fruit === 'Worm'
will "error"Because
registerTypes
takes an string-object Record, users will be able to parse huge data sets in JSON with less verbosity thandefineParameterType
(no mapping of name, regex, transformer):For reference, here's the original, impossible, type-based proposal:
The text was updated successfully, but these errors were encountered: