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

[Request] Better support for worlds in TypeScript #864

Closed
3 tasks done
moretti opened this issue Oct 26, 2022 · 6 comments
Closed
3 tasks done

[Request] Better support for worlds in TypeScript #864

moretti opened this issue Oct 26, 2022 · 6 comments

Comments

@moretti
Copy link

moretti commented Oct 26, 2022

Current behavior

When using TypeScript it's not possible to override the type associated to this.
For example the following step definition:

interface CustomWorld {
  count: number
  eat: (count: number) => void
}

When('I eat {int} cucumbers', function(this: CustomWorld, count: number) {
  this.eat(count);
});

will raise:

Argument of type '(this: CustomWorld, count: number) => void' is not assignable to parameter of type 'IStepDefinitionBody<[count: number]>'.
  The 'this' types of each signature are incompatible.
    Type 'Context' is missing the following properties from type 'CustomWorld': count

Desired behavior

A workaround for the time being is to define this as unknown and then use a type assertion:

interface CustomWorld {
  count: number
  eat: (count: number) => void
}

When('I eat {int} cucumbers', function(this: unknown, count: number) {
  const that = this as CustomWorld;
  that.eat(count);
});

The desired behaviour would be to have the function context not hardcoded to Mocha.Context, similar to cucumber-js, so that the first example could compile without any errors.

Test code to reproduce

Versions

  • Cypress version: 10.9.0
  • Preprocessor version: 13.0.2
  • Node version: 16.16.0

Checklist

@badeball
Copy link
Owner

Yeah, no. The type is a correct reflection of the reality and useful in other regards. You can extend the type with your own properties, as shown below.

// declarations.d.ts
interface CustomWorld {
  count: number;
  eat: (count: number) => void;
}

declare namespace Mocha {
  interface Context extends CustomWorld {}
}

// steps.ts
import { Given } from "@badeball/cypress-cucumber-preprocessor";

Given("foo", function () {
  this.eat(123);
});

@moretti
Copy link
Author

moretti commented Oct 26, 2022

I know that you can extend Mocha.Context with *.d.ts file, but it's common to have more than one world, with your suggestion it's only possible to have a single custom world shared across every scenario.

In cucumber-js the callback context is generic:
https://github.com/cucumber/cucumber-js/blob/d46c797aba67d36b5f446d202667d9d554b81462/src/support_code_library_builder/types.ts#L41-L44

@badeball
Copy link
Owner

We're already provided a context by simply existing in the Cypress domain. How do your propose that we retain this context and expose it to users that need it, and allow for generic contexts?

@moretti
Copy link
Author

moretti commented Oct 26, 2022

I'm not sure if I understand your question.
Basically what I'm suggesting is to change the signature of defineStep to something like:

export declare function defineStep<T extends unknown[], C extends Mocha.Context>(description: string | RegExp, implementation: IStepDefinitionBody<T, C>): void;

export interface IStepDefinitionBody<T extends unknown[], C extends Mocha.Context> {
    (this: C, ...args: T): void;
}

so that each feature file can potentially define its own "world":

import { Given } from "@badeball/cypress-cucumber-preprocessor";

interface CustomWorld extends Mocha.Context {
  homepage: HomePageDriver;
}

Given("I'm on the homepage", function (this: CustomWorld) {
  cy.visit("/");
  this.homepage = new HomePageDriver(cy);
});

@badeball
Copy link
Owner

badeball commented Oct 26, 2022

Aha, I see. If it doesn't affect current types and allows more extensibility, then I'd be open for it. Feel free to give it a shot and open up a PR.

Edit: I imagine maybe a generic that extends with a default à C extends Mocha.Context = Mocha.Context

@badeball
Copy link
Owner

badeball commented Nov 7, 2022

Released as v13.1.0.

@badeball badeball closed this as completed Nov 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants