shakacode / cypress-on-rails

Use cypress.io or playwright.dev with your rails application. This Ruby gem lets you use your regular Rails test setup and clean-up, such as FactoryBot.
MIT License
414 stars 61 forks source link

TypeScript typings #78

Open stevenpetryk opened 3 years ago

stevenpetryk commented 3 years ago

Howdy, would you be open to giving the generator the ability to generate TypeScript declarations in addition to the JS code it already generates? It would be handy because it would give some editors autocomplete when typing things like cy.appFactories.

Could be something opt-in like this:

bin/rails g cypress_on_rails:types

I've taken a stab at making some basic types. I could work on it more and add them as a PR, if you're interested. If not, I can just add them to the DefinitelyTyped repository (so people can do yarn add --dev @types/cypress-on-rails to get the types).

/// <reference types="cypress" />

type FactoryBotPrefix = 'create' | 'build'  | 'build_stubbed' | 'attributes_for'
type FactoryDefinition =
| [action: FactoryBotPrefix, model: string, attributes: object]
| [action: FactoryBotPrefix, model: string, trait: string, attributes: object]
| [action: FactoryBotPrefix, model: string, trait: string, trait2: string, attributes: object]
| [action: FactoryBotPrefix, model: string, trait: string, trait2: string, trait3: string, attributes: object]
| [action: `${FactoryBotPrefix}_list`, model: string, count: number]

type AhaRecord<ModelName extends string> = object & { _recordType: ModelName }

declare namespace Cypress {

  interface Chainable<Subject> {
    app(route: string, options: any): Promise<any>;

    appCommands(params: { name: string; options: any }): Promise<any>;

    /**
     * Load one or more factory_bot factories.
     *
     * @example
     *   const [feature, epic] = await cy.appFactories([
     *     ['create', 'feature', { name: 'Test feature' }],
     *     ['create', 'epic', 'shipped', { name: 'Epic with shipped trait' }],
     *   ])
     */
    appFactories<F extends readonly FactoryDefinition[]>(options: F): Promise<F>;

    /** 
     * Use app fixtures by key 
     * 
     * @example
     *   const fixtures = await cy.appFixtures({ return: { users: ['user1', 'user2'] } })
     * 
     *   fixtures.users.user1 // => { ... }
     *   fixtures.users.user2 // => { ... }
     */
    appFixtures<
      T extends Record<keyof T, readonly K[]>,
      K extends string,
    >(payload: { return: T }): Promise<{ [K in keyof T]: { [P in T[K][number]]: any } }>

    appScenario(name, options?: object): Promise<any>;

    appWriteCoverage(): void;
  }
}

Like I said, definitely incomplete—but for example this lets me use some factory bot things.

stevenpetryk commented 3 years ago

In retrospect, it might be better to add it to DefinitelyTyped—that way users don't have to generate any code to stay up-to-date with the gem.

grantspeelman commented 3 years ago

This looks like a great start. I am definitely open to a PR 👍🏽

yagudaev commented 3 years ago

In retrospect, it might be better to add it to DefinitelyTyped—that way users don't have to generate any code to stay up-to-date with the gem.

That leads to a good question if we should have the javascript portion, the custom commands inside of its own NPM module that way it is always up-to-date and users don't need to regenerate the assets.

grantspeelman commented 3 years ago

Yes, after some discussion, that is part of the idea for Version 2 https://github.com/shakacode/cypress-on-rails/issues/24#issuecomment-610762755 Finding the time to do it is another question 😄