Cucumber-js: Dukungan modul JS asli dalam definisi langkah dan kode dukungan

Dibuat pada 3 Apr 2020  ·  13Komentar  ·  Sumber: cucumber/cucumber-js

Masalah

Ketika saya mencoba menjalankan Cucumber.js dengan definisi langkah yang ditentukan dalam modul ECMAScript asli (seperti yang didokumentasikan di sini ), upaya tersebut gagal dengan peringatan bahwa saya menggunakan require() CommonJS pada modul ES.

Versi mentimun.js: 6.0.5
Versi simpul

Langkah-langkah untuk mereproduksi

  1. Siapkan direktori paket NPM dasar menggunakan npm init dan npm i cucumber

    • Setel "type": "module" di file package.json untuk memastikan bahwa file JS akan diperlakukan sebagai modul asli

  2. Buat file fitur dasar, features/mjs.feature :

    Feature: Native JS Modules
    
        Scenario: Load a native JS module step definition
            Given I have 42 cucumbers in my belly
    
  3. Buat file definisi langkah dasar, features/step_definitions.js :

    import { Given } from "cucumber";
    
    Given("I have {int} cucumbers in my belly", function (cucumberCount) {
        console.log("Step parsed.");
    });
    
  4. Mencoba menjalankan Mentimun:

    $ ./node_modules/.bin/cucumber-js
    

Hasil yang diharapkan

Modul definisi langkah harus dimuat dan digunakan untuk mengurai langkah.

Hasil sebenarnya

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /some/path/cucumbertest/features/step_definitions.js
require() of ES modules is not supported.
require() of /some/path/cucumbertest/features/step_definitions.js from /some/path/cucumbertest/node_modules/cucumber/lib/cli/index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename step_definitions.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /some/path/cucumbertest/package.json.

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:13)
    at Module.load (internal/modules/cjs/loader.js:1000:32)
    at Function.Module._load (internal/modules/cjs/loader.js:899:14)
    at Module.require (internal/modules/cjs/loader.js:1040:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at /some/path/cucumbertest/node_modules/cucumber/lib/cli/index.js:119:42
    at Array.forEach (<anonymous>)
    at Cli.getSupportCodeLibrary (/some/path/cucumbertest/node_modules/cucumber/lib/cli/index.js:119:22)
    at Cli.run (/some/path/cucumbertest/node_modules/cucumber/lib/cli/index.js:141:37)
    at async Object.run [as default] (/some/path/cucumbertest/node_modules/cucumber/lib/cli/run.js:30:14)

Penutupan

Untuk apa nilainya, saya sangat menghargai pekerjaan yang telah dilakukan tim Cucumber.js dalam proyek ini, ini telah menjadi aset utama bagi saya dan perusahaan saya. Tim saya telah menginvestasikan beberapa waktu dalam membangun beberapa komponen aplikasi bersama dalam modul JS asli, dan sampai saat ini saya berasumsi (berdasarkan sintaks import dalam dokumentasi terbaru) bahwa hal ini akan bekerja dengan Mentimun ketika kami berhasil mengintegrasikan dengan kerangka pengujian kami. Itu tampaknya tidak terjadi, meskipun. Karena komponen bersama sudah ditulis dan diintegrasikan ke bagian lain dari aplikasi kita, saya enggan hanya menggunakan definisi langkah dan kode dukungan yang ditulis dalam CommonJS karena tantangan interoperabilitas.

Hal-hal lain yang saya coba agar ini berfungsi termasuk ...

  • Memberikan ekstensi .mjs file modul asli, per konvensi Node.js (ini menyebabkan mereka diabaikan oleh logika pemuatan otomatis Cucumber, dan menggunakan --require untuk memuat secara eksplisit modul definisi langkah melemparkan Error [ERR_REQUIRE_ESM]: Must use import to load ES Module
  • Membungkus modul asli dalam modul CJS yang menggunakan fungsi dinamis import() ; masalahnya adalah bahwa pendekatan ini tidak sinkron, dan bahkan jika janji impor diekspor oleh modul CJS, Mentimun tampaknya tidak menunggu janji itu untuk diselesaikan sebelum melanjutkan, karena langkah itu ditandai sebagai tidak terdefinisi (menunjukkan bahwa definisi langkah dalam modul asli belum terdaftar).

Jika itu dalam kemampuan saya, saya akan dengan senang hati mengirimkan PR untuk membantu menyelesaikan masalah ini, tetapi saya tidak terbiasa dengan cara kerja internal Cucumber.js dan akan menghargai jika seseorang dapat mengarahkan saya ke arah yang benar.

accepted enhancement

Komentar yang paling membantu

Saya menggunakan ekstensi .js dan "type":"module" karena saya berharap ini akan menjadi norma dalam jangka panjang.

Semua 13 komentar

Saya ingin mentimun-js bekerja dengan ESM. Kami sudah membuka beberapa masalah lain tentang itu.

Kami dapat membuat opsi CLI (atau menggunakan cara lain untuk mencari kapan menggunakannya) yang membuat mentimun-js menggunakan import alih-alih meminta dan menunggu janji yang dikembalikan.

Mengingat contoh yang Anda tambahkan, kami dapat menambahkan kasus uji khusus untuk ini dan berupaya membuatnya lulus. Bereksperimen dengan beralih perlu mengimpor dan menunggu janji saya kemudian mengalami kesalahan lain:

⋊> ~/p/test ./node_modules/.bin/cucumber-js                                21:05:22
(node:7422) ExperimentalWarning: The ESM module loader is experimental.
file:///test/features/steps.js:1
import { Given } from "cucumber";
         ^^^^^
SyntaxError: The requested module 'cucumber' does not provide an export named 'Given'
    at ModuleJob._instantiate (internal/modules/esm/module_job.js:92:21)
    at async ModuleJob.run (internal/modules/esm/module_job.js:107:20)
    at async Loader.import (internal/modules/esm/loader.js:176:24)
    at async Promise.all (index 0)
    at async Cli.getSupportCodeLibrary (/test/node_modules/cucumber/lib/cli/index.js:119:5)
    at async Cli.run (/test/node_modules/cucumber/lib/cli/index.js:141:32)
    at async Object.run [as default] (/test/node_modules/cucumber/lib/cli/run.js:30:14)

Saya mengambil contoh (sedikit dimodifikasi) dari dokumentasi definisi langkah, tetapi Anda benar, itu tidak akan berfungsi seperti yang tertulis. Karena Cucumber.js adalah modul CommonJS, ia hanya menyediakan ekspor default. Dalam jangka pendek, saya mungkin hanya akan mengimpor default modul dan kemudian mengakses metode Diberikan/Kapan/Kemudian dari itu:

import cucumber from "cucumber";

cucumber.Given(...);

Jangka panjang, alangkah baiknya jika Mentimun memiliki titik masuk terpisah untuk impor dan kebutuhan, seperti yang ditunjukkan di sini .

Terima kasih telah melihat ini. Untuk apa nilainya, opsi CLI untuk memberi tahu Mentimun untuk mengimpor alih-alih membutuhkan akan cocok untuk saya. Akan sangat bagus jika Mentimun akan mencari file dukungan dengan ekstensi .cjs dan .mjs, dan secara otomatis memperlakukannya sebagai modul CommonJS dan asli.

EDIT: hanya ingin menegaskan kembali bahwa saya senang membantu dengan semua ini jika saya bisa; arahkan saja aku ke arah yang benar.

Saya mungkin hanya akan mengimpor modul default dan kemudian mengakses metode Diberikan/Kapan/Kemudian dari itu:
impor mentimun dari "mentimun";
mentimun.Diberikan(...);

Ini tidak bekerja. Saya mendapatkan pesan yang sama.
Saya memiliki "type": "module" di package.json dan sisa proyek saya menggunakan modul sehingga mengubah itu bukanlah pilihan.

Jika saya menggunakan salah satu dari ini:

import cucumber from '@cucumber/cucumber';
// OR
import { When } from '@cucumber/cucumber';

Saya mendapatkan pesan kesalahan yang sama dengan posting asli.
Jika saya berubah menjadi

const cucumber = require('@cucumber/cucumber');

Lalu saya mendapatkan pesan ini:

Ganti nama /some/path/cucumbertest/features/step_definitions.js menjadi .cjs, ubah kode yang diperlukan untuk menggunakan import(), atau hapus "type": "module" dari project/package.json.

Jika saya mengganti nama step_definitions.js menjadi _either_ step_definitions.cjs atau step_definitions.mjs , itu akan diabaikan dan saya mendapatkan pesan umum dari mentimun yang mengatakan untuk membuat rintisan untuk langkah saya:

UUUUUU

Failures:

1) Scenario: Empty Payload # spec\cucumber\features\users\create\main.feature:4
   ? When the client creates a POST request to /users
       Undefined. Implement with the following snippet:

         When('the client creates a POST request to \/users', function () {
           // Write code here that turns the phrase above into concrete actions
           return 'pending';
         });

... etc

Saya mendapatkan pesan yang sama persis jika saya menghapus file sepenuhnya, jadi jelas diabaikan.

Solusi (semacam)

Pada akhirnya, satu-satunya cara saya bisa menjalankan mentimun dalam proyek dengan "type": "module" adalah dengan membuat specpackage.json terpisah tanpa "type": "module" dan menginstal mentimun ke spec/node_modules .

Sejauh ini sepertinya akan bekerja. Mari kita lihat apakah itu masih berfungsi setelah saya membuat beberapa tes yang sebenarnya.

Untuk pengelola: ini pertama kalinya saya menggunakan mentimun, dan sejauh ini saya menyukainya. Namun, ini benar-benar menghambat kemajuan saya. Alih-alih menghabiskan sore hari untuk belajar mentimun, saya menghabiskannya untuk men-debug impor. Saya tahu betapa menjengkelkannya mencoba membuat perpustakaan yang mendukung impor ES6 dan CJS sehingga Anda bersimpati.

Solusi yang mungkin:
Dimungkinkan untuk mempublikasikan build CJS dan ES6 sekaligus jika Anda membuat file dist kedua:

dist/mentimun.js
dist/cucumber.module.js

Kemudian tambahkan baris ini ke package.json:

"modul": "dist/mentimun.module.js"

Ini akan mengaktifkan node untuk menyelesaikan impor ES6.

harus ada cara yang lebih baik untuk melakukan ini. Saya juga mengalami masalah itu, dan karena impor tidak dapat digunakan dengan commonJS, saya harus menggunakan
https://nodejs.org/api/esm.html#esm_import_expressions

di mana pun...

apakah ada cara agar Mentimun dapat memiliki bendera untuk membantu memungkinkan kita menggunakan ES?

Cepat untuk orang yang tertarik dengan ini: ketika Anda menggunakan ESM dalam proyek dengan mentimun, apakah Anda akan:

  • Gunakan ekstensi .js dan "type":"module"
  • Gunakan ekstensi .mjs
  • Sesuatu yang lain?

Terima kasih!

Saya cenderung mengikuti konvensi menggunakan ekstensi .mjs dan .cjs untuk semua file JavaScript saya untuk menghindari ambiguitas, dan itu akan menjadi preferensi saya untuk melakukannya dalam kasus ini juga. Namun, tidak ada ketidaknyamanan besar untuk mengatur "type": "module" di tingkat proyek dan membiarkan ini sebagai file .js jika itu adalah solusi yang lebih baik untuk lebih banyak pengguna.

Saya menggunakan ekstensi .js dan "type":"module" karena saya berharap ini akan menjadi norma dalam jangka panjang.

Terima kasih atas umpan baliknya @adamlacoste @looeee

@davidjgoss apakah #1589 digabung sudah cukup untuk menutup masalah itu? Atau kita butuh yang lain?

Terima kasih atas dorongannya @aurelien-reeves!

Versi 7.2.0 dari @cucumber/cucumber sekarang ada di npm, termasuk dukungan eksperimental untuk ESM seperti yang dijelaskan dalam dokumen di sini:
https://github.com/cucumber/cucumber-js/blob/master/docs/cli.md#es-modules-experimental-nodejs-12

Jika mereka yang tertarik dapat mencobanya dan melaporkan apa yang menurut Anda bagus. Saya meletakkan proyek contoh super minimal di sini:
https://github.com/davidjgoss/cucumber-esm-example

Senang membiarkan masalah ini terbuka sebentar hanya untuk mendapatkan umpan balik awal di satu tempat.

Jadi perubahan ini menyebabkan masalah dengan kerangka kerja dan pemformat pihak ketiga yang require hal-hal tertentu secara langsung (sebagai lawan dari titik masuk). Saya telah merilis 7.2.1 yang pada dasarnya kembali ke 7.1.0 untuk membuka blokir orang-orang itu, dan saya akan menggali penyebabnya dan melihat apakah kita dapat menghindarinya sambil tetap mendukung ESM. Sementara itu, jika itu tidak memengaruhi Anda, 7.2.0 masih ada untuk bereksperimen.

saya telah mencoba untuk mencoba v7.2.0 bersama dengan flag --esm . saya menggunakan testdouble dalam tes untuk paket yang saya coba konversi ke ESM.

untuk menggunakan td.replaceEsm , loader harus digunakan seperti --loader=testdouble . ketika saya mencoba menyediakan loader langsung ke cli mentimun, saya mendapatkan kesalahan berikut:

> cucumber-js test/integration --esm --loader=testdouble

error: unknown option '--loader=testdouble'

karena opsi itu tidak tersedia, saya kemudian mencoba dengan NODE_OPTIONS :

> NODE_OPTIONS='--loader=testdouble' cucumber-js test/integration --esm

(node:62231) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
internal/process/esm_loader.js:74
    internalBinding('errors').triggerUncaughtException(
                              ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for /path/to/project/node_modules/@cucumber/cucumber/bin/cucumber-js
    at defaultGetFormat (internal/modules/esm/get_format.js:71:15)
    at getFormat (file:///path/to/project/node_modules/quibble/lib/quibble.mjs:65:12)
    at Loader.getFormat (internal/modules/esm/loader.js:104:42)
    at Loader.getModuleJob (internal/modules/esm/loader.js:242:31)
    at async Loader.import (internal/modules/esm/loader.js:176:17)
    at async Object.loadESM (internal/process/esm_loader.js:68:5) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

untuk referensi, ini bertentangan dengan simpul v14.17.0

akan lebih baik jika ini bekerja dengan pendekatan NODE_OPTIONS , tetapi idealnya opsi --loader akan didukung langsung oleh cli seperti beberapa kerangka kerja pengujian telah mulai mendukung. harap pertimbangkan pendekatan ini dengan versi Anda berikutnya yang mendekati dukungan ESM :)

apakah ada pendekatan untuk mendefinisikan loader yang Anda harapkan dapat bekerja dengan v7.2.0 ?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat