【JavaScript 】 create-nuxt-app直後のプロジェクトでjestが「SyntaxError: Cannot use import statement outside a module」エラー

困った時対応ログ

create-nuxt-app した直後のアプリケーションでjestのテストが失敗する事象が発生しましたので、その原因と解決策です。

原因はjestの NODE_ENV の扱いでした。

※このエラー自体は他の原因でも起こる可能性がありますので、チェックするべき観点の一つとしてご覧ください

環境

  • Docker for Mac : 2.3.0.3
  • コンテナのbase : node:12-alpine3.10
  • create-nuxt-app : 2.15.0
  • npm 6.14.4
  • node v12.18.0
  • jest 24.9.0

事象

$ npm run test

> firestore-kanzen-rikai-sample@1.0.0 test /app
> jest

 FAIL  test/Logo.spec.js
  ● Test suite failed to run

    /app/test/Logo.spec.js:2
    import { mount } from '@vue/test-utils';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:537:17)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:579:25)

------------------|----------|----------|----------|----------|-------------------|
File              |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
------------------|----------|----------|----------|----------|-------------------|
All files         |        0 |      100 |        0 |        0 |                   |
 components       |        0 |      100 |        0 |        0 |                   |
  Logo.vue        |        0 |      100 |        0 |        0 |                 1 |
  VuetifyLogo.vue |        0 |      100 |        0 |        0 |                 1 |
 pages            |        0 |      100 |        0 |        0 |                   |
  index.vue       |        0 |      100 |        0 |        0 |                 1 |
  inspire.vue     |        0 |      100 |        0 |        0 |                 1 |
------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        6.663s
Ran all test suites.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! firestore-kanzen-rikai-sample@1.0.0 test: `jest`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the firestore-kanzen-rikai-sample@1.0.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2020-06-08T00_13_59_051Z-debug.log
/app #

Logo.spec.js

console.log(process.env.NODE_ENV)

import { mount } from '@vue/test-utils'
import Logo from '@/components/Logo.vue'

describe('Logo', () => {
  test('is a Vue instance', () => {
    const wrapper = mount(Logo)
    expect(wrapper.isVueInstance()).toBeTruthy()
  })
})

.babelrc

{
  "env": {
    "test": {
      "presets": [
        [
          "@babel/preset-env",
          {
            "targets": {
              "node": "current"
            }
          }
        ]
      ]
    }
  }
}

Dockerfile

# ベースイメージを指定
FROM node:12-alpine3.10

# node.js の環境変数を定義する
# 本番環境では production
ENV NODE_ENV=development

# 雛形を生成するのに必要なパッケージのインストール
RUN npm install -g create-nuxt-app
RUN apk update && apk add \
    python\
    make\
    g++


# ディレクトリを移動する
WORKDIR /app

# ポート3000番を開放する
EXPOSE 3000

対応

結論としては、Dockerfileの

ENV NODE_ENV=development

が原因です。

この行を削除すれば動きます。

$ npm run test

> firestore-kanzen-rikai-sample@1.0.0 test /app
> jest

 PASS  test/Logo.spec.js
  Logo
    ✓ is a Vue instance (31ms)

  console.log test/Logo.spec.js:1
    test

  console.error node_modules/@vue/test-utils/dist/vue-test-utils.js:1735
    [vue-test-utils]: isVueInstance is deprecated and will be removed in the next major version.

------------------|----------|----------|----------|----------|-------------------|
File              |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
------------------|----------|----------|----------|----------|-------------------|
All files         |    16.67 |      100 |       25 |    16.67 |                   |
 components       |       50 |      100 |       50 |       50 |                   |
  Logo.vue        |      100 |      100 |      100 |      100 |                   |
  VuetifyLogo.vue |        0 |      100 |        0 |        0 |                 1 |
 pages            |        0 |      100 |        0 |        0 |                   |
  index.vue       |        0 |      100 |        0 |        0 |           1,66,67 |
  inspire.vue     |        0 |      100 |        0 |        0 |                 1 |
------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.744s

原因

まず、エラーログから、import をうまく処理できていない事がわかります。

これはjestを実行しているnodeが Commonjsのrequire を使った構文しか解釈できないからです。

jsのimportとrequireの違い - Qiita
はじめに jsで外部ファイルを読み込む際に、 importと書いてある場合とrequireと書いてある場合があります。 この2つの違いがよくわからなかったので確認しました。 モジュールとは importとrequireの...

で、そのために良い感じに変換してくれるbabelを使うのですが、.babelrc で設定済のはずです。が、babelが効いていない。

もう1回 .babelrc を見てみると、

{
  "env": {
    "test": {
      "presets": [
        [
          "@babel/preset-env",
          {
            "targets": {
              "node": "current"
            }
          }
        ]
      ]
    }
  }
}

となっていて、process.env.BABEL_ENV または process.env.NODE_ENVtest の時にbabelが効くようになっています。

.babelrc · Babel
All Babel API (/docs/en/6.26.3/babel-core#options) except the callbacks are allowed (because `.babelrc` files are serialized as (

で、jestの process.env.NODE_ENV については、

Jest will set process.env.NODE_ENV to 'test' if it’s not set to something else. You can use that in your configuration to conditionally setup only the compilation needed for Jest, e.g.

Getting Started · Jest
次のコマンドで ( を使用して Jest をインストールします。

と記載されていて、「test が自動的にセットされるよ」と書いてありますが、ちゃんと読むと、他に設定されていなければ(if it’s not set to something else.)とあります。

私の最初の環境では、

ENV NODE_ENV=development

としているので、こちらが優先されてしまうんですね〜〜。

というわけで、↑を削除するか、jest.config.js

process.env.NODE_ENV='test'
module.exports = {
 // 省略
}

としてあげると正常に動きました。ちゃんちゃん。

コメント

タイトルとURLをコピーしました