-1

I have red swiggly lines in visual studio code even when the variable is defined (error message).

If I disable eslint it will go away, but I don't think that's the correct approach and this would stop linting the rest of the ts/js files. (I have ESLint extension installed)

I have Visual Studio Code: 1.57.1 (Universal) on Mac OS Catalina.

I can right click and go to the browser definition.

enter image description here

beforeAll(async () => {
await browser.url('https://example.com/');

})

If I go to definition it looks like this below enter image description here

enter image description here

The code snippet is in a .js file and this is the bottom right of visual studio code

enter image description here

How can I fix this? I also tried deleting this .vs folder, in one of the solutions mentioned here, but no luck: Visual Studio compiles fine, but it still shows red lines

Also installed these libraries in my code:

npm i
npm install @wdio/cli (https://webdriver.io/docs/gettingstarted/)
npx wdio config

I can compile my project, but how do I get rid of these red lines without disabling ESLint?

Thanks for the help!

beforeAll(async () => {
    await browser.url('https://example.com/');
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.2.3/jquery.min.js">
</script>

Note: I'm not sure how to create a mvp of this code. But the beforeAll is defined from a node module. I have included relevant files below. node_modules/@types/jest/index.d.ts declare var beforeAll: jest.Lifecycle;

My package.json file looks like this

{
  "name": "test-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/user-event": "^12.1.10",
    "@types/jest": "^26.0.15",
    "@types/node": "^12.0.0",
    "@types/react": "^16.14.2",
    "@types/react-dom": "^16.9.8",
    "axios": "^0.21.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.1",
    "web-vitals": "^0.2.4"
  },
  "jest": {
    "preset": "jest-playwright-preset"
  },
  "globals": {
    "browserName": "BrowserType",
    "browser": "Browser",
    "context": "BrowserContext",
    "page": "page"
  },
  "devDependencies": {
    "@testing-library/react": "^11.2.3",
    "@wdio/cli": "^7.7.4",
    "@wdio/jasmine-framework": "^7.7.3",
    "@wdio/local-runner": "^7.7.4",
    "@wdio/mocha-framework": "^7.7.4",
    "@wdio/spec-reporter": "^7.7.3",
    "chromedriver": "^91.0.1",
    "jest": "^26.6.0",
    "jest-junit": "^12.0.0",
    "jest-playwright-preset": "^1.6.1",
    "playwright": "^1.12.3",
    "ts-jest": "^26.5.4",
    "ts-node": "^10.0.0",
    "typescript": "^4.2.4",
    "wdio-chromedriver-service": "^7.1.1",
    "webdriverio": "^7.5.7"
  },
  "proxy": "https://localhost:5001",
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  }
}

This is using Jest and Web Driver for UI automation for browsers

This is the node_modules/jest-playwright-preset/types/global.d.ts file in the screenshots above

import {
  Browser,
  BrowserContext,
  Page,
  BrowserContextOptions,
  LaunchOptions,
  ConnectOptions,
  ConnectOverCDPOptions,
  BrowserType as PlaywrightBrowserType,
  ViewportSize,
  ChromiumBrowser,
  FirefoxBrowser,
  WebKitBrowser,
  devices,
} from 'playwright-core'
import { Config as JestConfig } from '@jest/types'
import { Test } from 'jest-runner'
import { JestProcessManagerOptions } from 'jest-process-manager'

// TODO Find out flex ways to reuse constants
declare const IMPORT_KIND_PLAYWRIGHT = 'playwright'

declare const CHROMIUM = 'chromium'
declare const FIREFOX = 'firefox'
declare const WEBKIT = 'webkit'

declare const LAUNCH = 'LAUNCH'
declare const PERSISTENT = 'PERSISTENT'
declare const SERVER = 'SERVER'

declare module 'jest-playwright-preset' {
  const globalSetup: (config: JestConfig.GlobalConfig) => void
  const globalTeardown: (config: JestConfig.GlobalConfig) => void
  const getPlaywrightEnv: (env?: string) => void
}

export type BrowserType = typeof CHROMIUM | typeof FIREFOX | typeof WEBKIT

export type SkipOption = {
  browsers: BrowserType[]
  devices?: string[] | RegExp
}

export interface TestPlaywrightConfigOptions extends JestPlaywrightConfig {
  browser?: BrowserType
  device?: ConfigDeviceType
}

export type GenericBrowser = PlaywrightBrowserType<
  WebKitBrowser | ChromiumBrowser | FirefoxBrowser
>

type Nullable<T> = T | null

interface JestPlaywright {
  /**
   * Reset global.page
   *
   * ```ts
   * it('should reset page', async () => {
   *   await jestPlaywright.resetPage()
   * })
   * ```
   */
  resetPage: () => Promise<void>
  /**
   * Reset global.context
   *
   * ```ts
   * it('should reset context', async () => {
   *   await jestPlaywright.resetContext()
   * })
   * ```
   */
  resetContext: (newOptions?: BrowserContextOptions) => Promise<void>
  /**
   * Reset global.browser, global.context, and global.page
   *
   * ```ts
   * it('should reset page', async () => {
   *   await jestPlaywright.resetBrowser()
   * })
   * ```
   */
  resetBrowser: (newOptions?: BrowserContextOptions) => Promise<void>
  /**
   * Saves the coverage to the disk which will only work if `collectCoverage`
   * in `jest-playwright.config.js` file is set to true. The merged coverage file
   * is then available in `.nyc_output/coverage.json`. Mostly its needed in the
   * `afterEach` handler like that:
   *
   * ```ts
   * afterEach(async () => {
   *   await jestPlaywright.saveCoverage(page)
   * })
   * ```
   */
  saveCoverage: (page: Page) => Promise<void>
  configSeparateEnv: (
    config: Partial<TestPlaywrightConfigOptions>,
    isDebug?: boolean,
  ) => Promise<ConfigParams>
}

interface JestParams<T> {
  (options: T, name: string, fn?: jest.ProvidesCallback, timeout?: number): void
}

type ProvidesCallback = (cb: ConfigParams) => void

interface JestParamsWithConfigParams<T> {
  (
    options: Partial<T>,
    name: string,
    fn?: ProvidesCallback,
    timeout?: number,
  ): void
}

interface JestPlaywrightTestDebug
  extends JestParamsWithConfigParams<JestPlaywrightConfig> {
  (name: string, fn?: ProvidesCallback, timeout?: number): void
  skip:
    | JestParamsWithConfigParams<JestPlaywrightConfig>
    | JestPlaywrightTestDebug
  only:
    | JestParamsWithConfigParams<JestPlaywrightConfig>
    | JestPlaywrightTestDebug
}

interface JestPlaywrightTestConfig
  extends JestParamsWithConfigParams<JestPlaywrightConfig> {
  skip:
    | JestParamsWithConfigParams<JestPlaywrightConfig>
    | JestPlaywrightTestConfig
  only:
    | JestParamsWithConfigParams<JestPlaywrightConfig>
    | JestPlaywrightTestConfig
}

declare global {
  const browserName: BrowserType
  const deviceName: Nullable<string>
  const page: Page
  const browser: Browser
  const context: BrowserContext
  const jestPlaywright: JestPlaywright
  namespace jest {
    interface It {
      jestPlaywrightSkip: JestParams<SkipOption>
      jestPlaywrightDebug: JestPlaywrightTestDebug
      jestPlaywrightConfig: JestPlaywrightTestConfig
    }
    interface Describe {
      jestPlaywrightSkip: JestParams<SkipOption>
    }
  }
}

type DeviceDescriptor = {
  viewport: Nullable<ViewportSize>
  userAgent: string
  deviceScaleFactor: number
  isMobile: boolean
  hasTouch: boolean
  defaultBrowserType: BrowserType
}

export type CustomDeviceType = Partial<DeviceDescriptor> & {
  name: string
}

export type ConfigDeviceType = CustomDeviceType | string

export type DeviceType = Nullable<ConfigDeviceType>

export type WsEndpointType = Nullable<string>

export type SelectorType = {
  script: string | Function | { path?: string; content?: string }
  name: string
}

export type PlaywrightRequireType = BrowserType | typeof IMPORT_KIND_PLAYWRIGHT

export interface Playwright {
  name: PlaywrightRequireType
  instance: GenericBrowser | Record<BrowserType, GenericBrowser>
  devices: typeof devices
}

type LaunchType = typeof LAUNCH | typeof SERVER | typeof PERSISTENT

type Options<T> = T & Partial<Record<BrowserType, T>>

export type ServerOptions = JestProcessManagerOptions & {
  teardown?: string
}

export interface JestPlaywrightConfig {
  haveSkippedTests?: boolean
  skipInitialization?: boolean
  debugOptions?: JestPlaywrightConfig
  launchType?: LaunchType
  launchOptions?: Options<LaunchOptions>
  connectOptions?: Options<ConnectOptions | ConnectOverCDPOptions>
  contextOptions?: Options<BrowserContextOptions>
  userDataDir?: string
  exitOnPageError?: boolean
  displayName?: string
  browsers: (BrowserType | (JestPlaywrightConfig & { name: BrowserType }))[]
  devices?: ConfigDeviceType[] | RegExp
  useDefaultBrowserType?: boolean
  serverOptions?: ServerOptions | ServerOptions[]
  selectors?: SelectorType[]
  collectCoverage?: boolean
}

export type JestPlaywrightProjectConfig = Test['context']['config'] & {
  browserName: BrowserType
  wsEndpoint: WsEndpointType
  device: DeviceType
}

export type JestPlaywrightContext = Omit<Test['context'], 'config'> & {
  config: JestPlaywrightProjectConfig
}

export type JestPlaywrightTest = Omit<Test, 'context'> & {
  context: JestPlaywrightContext
}

export interface BrowserTest {
  test: JestPlaywrightTest
  config: JestPlaywrightConfig
  browser: BrowserType
  wsEndpoint: WsEndpointType
  device: DeviceType
}

export type ConfigParams = {
  browserName: BrowserType
  deviceName: Nullable<string>
  browser: Nullable<Browser | BrowserContext>
  context: BrowserContext
  page: Page
}
Suzy
  • 231
  • 4
  • 14
  • 1
    Please show a [mcve]. These appear to be legitimate linting errors, so you need to either fix them or [remove the lint rule](https://eslint.org/docs/2.13.1/user-guide/configuring). – Liam Jul 07 '21 at 13:31
  • 1
    *Visual Studio compiles fine* linting is not the same as compilation. – Liam Jul 07 '21 at 13:32
  • 2
    You need to tell eslint about global variables as described in the docs: https://eslint.org/docs/user-guide/configuring/language-options#specifying-globals – Christoph Lütjen Jul 07 '21 at 13:36
  • @Liam I added a code snippet, I'm not sure how to add a reproducible example since this is VS Code specific in that IDE? – Suzy Jul 07 '21 at 13:44
  • Well the error *Cannot redeclare block scoped variable* implies you have more than one context. TBh it depends what your expecting from this question? Do you just want to make the errors go away ([info on that here](https://eslint.org/docs/2.13.1/user-guide/configuring)) or do you want to actually fix the problems. In which case we need a [mcve] – Liam Jul 07 '21 at 13:47
  • @Christoph Lütjen thanks, I tried adding this to my package.json file but no luck? "globals": { "browser": "Browser" }, – Suzy Jul 07 '21 at 13:48
  • Worth pointing out that lint is erroring here for a reason. You best bet is to actually fix the problems – Liam Jul 07 '21 at 13:48
  • @Liam, honestly I don't know how to set it up properly. I tried adding a code snippet but I can't import node_modules. I added a few more code snippets to try to explain – Suzy Jul 07 '21 at 14:13
  • 1
    @Liam the reason here is, that eslint does not know about this global variable. The global variable seems to be ok here, so in this case we're talking about eslint config only. – Christoph Lütjen Jul 07 '21 at 14:30
  • @Liam I think the question is not about the "cannot redeclare". This error is inside of a node module. It's about the missing global variable and the node module code is provided as a reference where `browser` is defined. – Christoph Lütjen Jul 07 '21 at 14:33
  • @Suzy eslint has its own configuration file, e.g. .eslintrc.json, package.json is the wrong place. – Christoph Lütjen Jul 07 '21 at 14:35
  • If it's clear and comeplete @ChristophLütjen then feel free the answer it – Liam Jul 07 '21 at 15:04
  • @Liam - I already answered it in the comments. I can't write this as an answer because I didn't test the solution which may lead to down-votes ;-) – Christoph Lütjen Jul 07 '21 at 15:07
  • *eslint has its own configuration file* isn't really an answer... It's also [basically what I've already said](https://stackoverflow.com/questions/68287002/visual-studio-code-shows-red-swiggly-lines-even-when-variable-is-defined?noredirect=1#comment120687780_68287002) – Liam Jul 07 '21 at 15:11
  • 1
    Thanks for the support and comment about helping each other @Christoph Lütjen! I have modified the eslint configs and there is no more red lines – Suzy Jul 07 '21 at 15:35
  • Thanks @Liam for the quick response – Suzy Jul 07 '21 at 15:35
  • @Liam sorry if my comments sounded like an offence. This was not my intention. I've added the result of our comments as an answer flagged as community wiki so I will get no reputation for any upvotes. Feel free to modify if you have additional input. – Christoph Lütjen Jul 08 '21 at 19:37

1 Answers1

2

Eslint does not know about global variables. To solve this, you have two options:

  • Tell eslint which variables are defined
  • Disable the eslint rule that checks for undefined variables

To tell eslint which globals are defined, add them to your eslint config file

{
    "globals": {
        "var1": true,
    }
}

Docs: https://eslint.org/docs/2.13.1/user-guide/configuring#specifying-globals

To simplify this, eslint provides so called 'environments' which include all global variables for e.g. a framework as described here: https://eslint.org/docs/2.13.1/user-guide/configuring#specifying-environments

Christoph Lütjen
  • 5,403
  • 2
  • 24
  • 33