CodeceptJS icon indicating copy to clipboard operation
CodeceptJS copied to clipboard

Intellisense and custom steps file using Javascript

Open sethvanwykJET opened this issue 1 year ago • 12 comments

Discussed in https://github.com/codeceptjs/CodeceptJS/discussions/4091

Originally posted by sethvanwykJET December 28, 2023 Please note. This issue is Javascript specific. It doesn't seem to occur in typescript repos

So I've run into a bit of a nuisance.

I noticed that any code we add into the custom steps file isn't detected by VS Code

https://codecept.io/pageobjects/#actor

This is leading to a lot of confusion and sometimes team members removing required code due to their IDE telling them it's redundant.

Our codebase uses Javascript

module.exports = function() {
  return actor({
    async myAsyncFunction(param) {
      // logic goes here
    },

    async myOtherFunction(param) {
      await this.myAsyncFunction(param)
    }
  });
};

In this example there will are 2 problems.

One, You can't deep-link back to myAsyncFunction by cmd+clicking it (MacOS)

And two, the IDE will berate you for using await on a non-promise Refactor this redundant 'await' on a non-promise.

These are example from within the steps file itself, but it extends past that.

When using these functions inside of tests they also don't support intellisense and complain about using await on non-promises.

Additional note, the native CodeceptJS functions do support intellisense, this only happens for code that's new in the steps file.

The problem does not seem to exist in other IDE's. Colleagues that use Jetbrains seem to be able to use this without issues.

sethvanwykJET avatar Jan 24 '24 13:01 sethvanwykJET

Hmm strange. When I create page objects, I can successfully command+click onto them to preview the exported function, on Mac w/vs code too.

test

Scenario('sign in with username & password @cred', async ({ I }) => {
    Login.signInWithUsernameAndPassword(email, password);
    Login.signOut();
});

page object

signInWithUsernameAndPassword(email: string, password: string) {
    I.runOnAndroid(() => { I.tap(Login.emailfield.android); }, "");
    I.fillField({ android: Login.emailfield.android, ios: Login.emailfield.ios }, email);
    I.runOnAndroid(() => { I.tap(Login.passwordField.android); }, "");
    I.fillField({ android: Login.passwordField.android, ios: Login.passwordField.ios }, secret(password));
    I.tap(Login.signInBtn);
    I.waitForElement({ android: Login.signOutBtn.android, ios: Login.signOutBtn.ios }, 3);
  },
Screenshot 2024-02-04 at 10 13 56 pm

alaz-aura avatar Feb 04 '24 11:02 alaz-aura

@sethvanwykJET have you try to setup your function inside page-object or inside helper (i prefer async function inside helper)

I don't use much actor option.

Horsty80 avatar Feb 09 '24 14:02 Horsty80

I'm kinda love to go with this approach, combining all related steps into a file then importing it in steps file. https://github.com/kobenguyent/codeceptjs-rest-demo/blob/master/stepObjects/custom.steps.ts

kobenguyent avatar Feb 12 '24 08:02 kobenguyent

@alaz-aura is your repo in typescript or JS? From what I understand the issue is not present in Typescript repo's.

@Horsty80 The steps file is capable of using codeceptJS methods, while helpers are unable to due to it creating a circular dependency.

@kobenguyent not really familiar with that approach, but the code I have currently aligns with the codeceptJS documentation, so if it needs adjustment then the documentation needs to be updated with the expected layout

sethvanwykJET avatar Feb 12 '24 08:02 sethvanwykJET

You can use codeceptjs method inside an help

class MyCustomHelper extends Helper {

  async customMethod(params) {
    const { I } = inject();
    I.seeElement(myLocator);
    ...

Otherwise if check my method inside step file my steps.d.ts because i have the intellisense working fine.

/// <reference types='codeceptjs' />
type steps_file = typeof import('./custom-steps');

declare namespace CodeceptJS {

  interface I extends ReturnType<steps_file> {}

Have you try this ?

My step file is very simple with a login function

export = () =>
  actor({
    customLogin: () => {},
  });

And in any of my test i have the autocomplete on I with customLogin available.

Have you link for you repo ?

You speak about InteliJ & Vscode, don't forget that InteliJ is "smarter" than vscode and can index all your code to propose enhanced ctrl+click naviagation. Vscode don't and need good Ts configuration and Plugin to do the same.

I use Vscode, and my codecept project is with typescript. I only have you issue about await not expected that can be tricky

Horsty80 avatar Feb 12 '24 09:02 Horsty80

I'm unable to link the repo as it's private

But I'll have a look to see if your suggestions work throughout the week, just got back from leave and have a backlog of tasks to get through first 😅

sethvanwykJET avatar Feb 12 '24 09:02 sethvanwykJET

Hey @sethvanwykJET - yup it's in a TS repo. Hmmm sounds like you need further investigation. Good luck! 🤞

alaz-aura avatar Feb 12 '24 23:02 alaz-aura

Have you try this ?

My step file is very simple with a login function

export = () =>
  actor({
    customLogin: () => {},
  });

And in any of my test i have the autocomplete on I with customLogin available.

This doesn't really work in a JS repo, as this is TS. From what I understand this issue is JS specific

I'll see if I can migrate the contents to a helper instead to see how that goes.

sethvanwykJET avatar Feb 13 '24 12:02 sethvanwykJET

@Horsty80

You can use codeceptjs method inside an help

class MyCustomHelper extends Helper {

 async customMethod(params) {
   const { I } = inject();
   I.seeElement(myLocator);
   ...

When I try to do this, test execution stalls as soon as I try to use any I.xyz methods

It doesn't crash the test, it just doesn't do anything when it reaches that step within a helper file.

Worth noting, it doesn't return an error saying that it's not a function.

If I try to invoke a function that does not exist in I then it fails, but when using one that does exist it just stalls without actioning anything.

sethvanwykJET avatar Feb 29 '24 10:02 sethvanwykJET

Have you follow the doc about custom helper ?

https://codecept.io/helpers/#development

You need two steps for this to work:

  • extends the class Helper
const Helper = require('@codeceptjs/helper');

class MyHelper extends Helper {
  • update your codecept.conf.ts with the new helper
helpers: {
 WebDriver: {  },
 MyHelper: {
   require: './path/to/module'
 }
}

Horsty80 avatar Feb 29 '24 10:02 Horsty80

Have you follow the doc about custom helper ?

https://codecept.io/helpers/#development

You need two steps for this to work:

  • extends the class Helper
const Helper = require('@codeceptjs/helper');

class MyHelper extends Helper {
  • update your codecept.conf.ts with the new helper
helpers: {
 WebDriver: {  },
 MyHelper: {
   require: './path/to/module'
 }
}

This work was already present. We've got a few helpers already configured. The intellisense works with the code being in the helper, but it remains non-functional when using any I. calls.

everything outside of I. works

Also our codebase is js, so only the defs file is .ts

sethvanwykJET avatar Mar 01 '24 09:03 sethvanwykJET

This issue is stale because it has been open for 90 days with no activity.

github-actions[bot] avatar May 31 '24 02:05 github-actions[bot]