Skip to content
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

Logging middleware #125

Open
donverduyn opened this issue Apr 12, 2021 · 3 comments
Open

Logging middleware #125

donverduyn opened this issue Apr 12, 2021 · 3 comments
Labels
enhancement New feature or request

Comments

@donverduyn
Copy link

donverduyn commented Apr 12, 2021

Hi. I would like to propose adding additional utilities to this repo to support debugging. For example, something like below would be really beneficial in logging the return values of the step definition callbacks and manage the visibility of the logging statements. It could also serve other purposes like applying default assertions, but that might be out of scope for this repo.

EDIT:
I took the plunge to create a reusable middleware factory and it turned out pretty well. Its API is still a little crazy so that might need some extra work.

const createMiddleware: DefineStepMiddleware = (
  create: (stepFn: DefineStepFunction, fnName: string) => DefineStepFunction
) => (stepDefinitionFn) => ({ pending, ...rest }) =>
  stepDefinitionFn({
    pending,
    ...Object.entries(rest).reduce(
      (acc, [fnName, stepFn]: [fnName: string, stepFn: DefineStepFunction]) =>
        Object.assign(acc, {
          [fnName]: create(stepFn, fnName)
        }),
      rest
    )
  });

const withLogging = createMiddleware((stepFn, fnName) => (matcher, cb) =>
  stepFn(matcher, (...args) => {
    console.log(fnName.green['bold'], matcher.toString().green);
    return cb(...args);
  })
);

It then can be used to wrap the test definition.

test(
  '1 + 2 = 3',
  withLogging(({ given, when, then }) => {
    let number = 1;

    given('number is 1', () => {
      expect(number).toBe(1);
    });
    when('adding 2', () => {
      number += 2;
    });
    then('number should be 3', () => {
      expect(number).toBe(3)
    });
  })
);

Please let me know if anyone is interested in having this.

@bencompton
Copy link
Owner

Middleware like this is an interesting idea, especially if there were a publicly exported middleware creation function that provided a simple API for creating middleware that abstracted away all of the stepsDefinitionCallback stuff.

I will say that your use case might be better served with proper reporting functionality, though. See #27.

@donverduyn
Copy link
Author

You are right about the logging part. This is definitely not something you want to pollute your tests with. However, i got really excited about this idea of putting middleware layers between those callbacks. It opens up a lot of possibilities of drying up tests and improving their readability.

I just recently started picking up TDD, so my awareness about the available tools is most likely insufficient. I know about Jest its mocking/stubbing features and its ability to output to JSON, but i don't know if they really solve the problem of drying up our tests. jest-cucumber also afforts an autobinding feature which to my awareness makes step definitions reusable on the test suite level?

Providing an API to attach middleware to step definition handlers at multiple levels in the test suite hierarchy, would relate very well to the concept of Gherkin its backgrounds. It might be a good starting point to reason about any inconsistencies between Gherkin its concepts and the tooling jest-cucumber provides, in order to support these concepts.

@bencompton
Copy link
Owner

bencompton commented Apr 13, 2021

I definitely agree that some sort of a middleware / plug-in architecture in general would be helpful in this library. The goal with Jest Cucumber is to not stray too far from what people would expect from Jest and Cucumber, but at the same time, a lot of people have specific preferences or requirements that this library can't easily accommodate without imposing these opinions on everyone else.

jest-cucumber also afforts an autobinding feature which to my awareness makes step definitions reusable on the test suite level?

In typical Jest tests, you use describe and it or test blocks to make your tests readable and easy to understand. The default in Jest Cucumber is designed to accomplish the same thing where the contents of your feature files are fully represented in your Jest tests and you don't have to continuously cross-reference your Jest tests and feature files, don't have to deal with global step matching, etc. At the same time, Jest Cucumber ensures that your Jest tests stay in sync with your feature files, and also generates code suggestions when your Jests tests don't match your feature files. This allows teams to practice ATDT with business-readable feature files, and then automate them in Jest without worrying about Jest tests and feature files getting out of sync.

Some people would prefer that Jest Cucumber work more like Cucumber.js, which is what autoBindSteps is designed to accomplish. Rather than defining Jest tests that mirror the feature file, autoBindSteps allows you to define only step definitions and it creates your Jest tests for you automatically.

There are pros and cons to each approach, and it comes down to being a matter of preference, so I'd suggest you look over the docs / examples and decide which you prefer. Basically, do you prefer more Jest-like tests, or more Cucumber-like tests.

@bencompton bencompton added the enhancement New feature or request label Apr 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants