Jest with Vue 3 - ReferenceError: define is not defined

Jest with Vue 3 - ReferenceError: define is not defined

我想用 Jest 和内部组件测试我的组件,我导入了 @vue/apollo-composable 库,当我 运行 测试时我得到错误:

ReferenceError: define is not defined

      2 |   // libraries
      3 |   import { defineComponent, ref, watch } from '@vue/composition-api'
    > 4 |   import { useLazyQuery, useResult } from '@vue/apollo-composable'
        | ^
      5 |   import gql from 'graphql-tag'

在开玩笑的测试中,我不使用 apollo-composable,也不打算使用。代码:

import '@/plugins/composition-api'
import App from '@/components/App.vue'
import Vue from 'vue'
import { Wrapper, createLocalVue, mount } from '@vue/test-utils'

Vue.use(Vuetify)

describe('SelectMediaProcess.vue', () => {
  let wrapper: Wrapper<Vue>
  const localVue = createLocalVue()
  beforeEach(() => {
    wrapper = mount(SelectMediaProcess, { localVue })
  })

  it('render', () => {
    expect(wrapper.exists()).toBe(true)
  })
})

我在网上看到我可以使用的东西:

jest.mock('@vue/apollo-composable', () => {
   // mock implementation
})

但是当我在测试中使用这段代码时。我收到错误消息:(useLazyQuery@vue/apollo-composable 库中的一个函数)

TypeError: Cannot read property 'useLazyQuery' of undefined

      19 |
      20 |       // get default media process
    > 21 |       const { onResult, load: loadDefaultMP } = useLazyQuery<
         | ^
      22 |         getDefaultMediaProcess,
      23 |         getDefaultMediaProcessVariables
      24 |       >(

有人知道我能做什么吗?

编辑

我将这些行添加到我的jest.config.js。它帮助了别人而不是我。

transformIgnorePatterns: ['<rootDir>/node_modules/(?!@vue/apollo-composable).+\.js$']

moduleNameMapper: { '@vue/apollo-composable': '@vue/apollo-composable/dist/index.js' }

完整 jest.config.js:

module.exports = {
  preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
  moduleFileExtensions: ['js', 'ts', 'json', 'vue'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/',
    'vuetify/lib(.*)': '<rootDir>/node_modules/vuetify/es5',
    '@vue/apollo-composable': '@vue/apollo-composable/dist/index.js'
  },
  modulePaths: ['<rootDir>/src', '<rootDir>/node_modules'],
  transform: {
    '.+\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$':
      'jest-transform-stub',
    '^.+\.ts?$': 'ts-jest',
    '.*\.(vue)$': 'vue-jest'
  },
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!(vuetify)/)',
    '<rootDir>/node_modules/(?!@vue/apollo-composable).+\.js$'
  ]
}

我收到了这些新错误:

FAIL  tests/unit/selectMediaProcess.spec.ts
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    C:\Users\u112200\Documents\deposit-frontend\node_modules\@vue\apollo-composable\dist\index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export { useQuery, } from './useQuery';
                                                                                             ^^^^^^

    SyntaxError: Unexpected token 'export'

      2 |   // libraries
      3 |   import { defineComponent, ref, watch } from '@vue/composition-api'
    > 4 |   import { useLazyQuery, useResult } from '@vue/apollo-composable'
        | ^
      5 |   import gql from 'graphql-tag'
      6 |   // models
      7 |   import { allMediaProcesses } from '../models/__generated__/allMediaProcesses'

      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:537:17)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:579:25)
      at src/components/SelectMediaProcess.vue:4:1
      at Object.<anonymous> (src/components/SelectMediaProcess.vue:89:3)

有谁知道我接下来该做什么吗?

您需要在 mock 语句中定义函数。

目前,您说过应该使用模拟而不是使用真实的东西。然后你取消定义的原因是因为模拟是空的(你没有在其中定义任何函数)。

因此,接下来要做的是指定模拟库应如何交互。您正在导入两个函数,因此您需要在 mock 语句中定义这些函数:

jest.mock('@vue/apollo-composable', () => {
  return {
    __esModule: true,
    useLazyQuery: jest.fn(() => 42), // Replace 42 with whatever result you'd expect
    useResult: jest.fn(() => 43), // Replace 43 with whatever result you'd expect
  };
}) 

jest documentation.

中有更多关于此的详细信息

您的项目中是否有 .babelrc 文件?如果是这样,您需要将其更改为 babel.config.js(不要问我为什么,只对我有用)。

此外,您需要将以下行添加到 jest.config.js

transformIgnorePatterns: ['node_modules/(?!@vue/apollo-composable)/']

在您的情况下,您已经在使用 jest.config.js 文件,但如果您使用 package.json 来定义测试配置,则需要创建 jest 配置文件。

GitHub 上的这个问题对我解决这个问题帮助很大: https://github.com/facebook/jest/issues/9395

如果你想用笑话来模拟,你可以使用下面的方法

jest.mock("apollo-client", () => ({
  __esModule: true,
  useQuery: (query: any) => {
    //other mocks if needed
  },
  useLazyQuery: jest.fn().mockReturnValue([
    jest.fn(), 
    {
      data: {
        yourProperties: "Add Here",
      },
      loading: false,
    },
  ]),
}));

如您所见,这种方法甚至 returns 在要测试的代码中调用的模拟函数。