カテゴリー
未分類

TypeScript Error TS2307: Cannot find module ‘fs’. was resolved by installing the @types/node package. [2020]

Node.js has many useful built-in modules.

The fs module to handle the file system is one of them.

In TypeScript, it seems that @types/node is needed to use these modules provided by Node.js.

To add the @types/node package, run the following command.

npm install --save-dev @types/node

More details

I tried to write a little useful program in TypeScript, so I created a tool folder by executing the following commands in sequence.

I installed the TypeScript module and created an empty index.ts file.

mkdir tool
cd tool
npm init -y 
npm install typescript
touch index.ts

Since the index.ts file is empty to begin with, I used a text editor to write the following and saved it.

import * as fs from 'fs';
fs.writeFileSync('a.txt', 'b')

Then I ll compile it with the following command.

npx tsc index.ts 

At this stage, an error has occurred.

The errors that occurred are as follows.

index.ts:1:21 - error TS2307: Cannot find module 'fs'.


1 import * as fs from 'fs';
                      ~~~~




Found 1 error.

It should have created the index.js file automatically, but due to this error, it was not created.

The error message says that the fs module is not found.

The fs module is already bundled with Node.js.
If I wrote the code in JavaScript, I did not need to do any special preparation to use it.

However, in order to write code in TypeScript, a suitable type definition file seems to be needed.

So, run the following command as described above.

npm install --save-dev @types/node

Then we’ll try compiling again.

npx tsc index.ts 

Then the index.js file will be created successfully.

Let’s run the index.js file by the node command.

node index.js

Then an a.txt file will be created, and if the string “b” is written in it, it is as intended.

So TypeScript might not know what Node.js standard library has. And it seems to me that it’s the @types/node package that tells you that.

カテゴリー
未分類

In the sudo npm install -g xxx command, ‘sudo’ seems to be deprecated. [2019]

To install the Vue CLI and to install Angular CLI, you can find the following commands on their official websites.

npm install -g @vue/cli
npm install -g @angular/cli

However, when I actually ran the above command, I got an Error: EACCES: permission denied, access '/usr/local/lib/node_modules'.

npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules
npm ERR! path /usr/local/lib/node_modules
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall access
npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
npm ERR!  { [Error: EACCES: permission denied, access '/usr/local/lib/node_modules']
npm ERR!   stack:
npm ERR!    'Error: EACCES: permission denied, access \'/usr/local/lib/node_modules\'',
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/usr/local/lib/node_modules' }
npm ERR! 
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR! 
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though this is not recommended).

According to various online sources, using the sudo command seems to solve the problem for the time being.

sudo npm install -g @vue/cli

However, the error message ended with the following notation.

the command again as root/Administrator (though this is not recommended).

Apparently, the npm development team doesn’t really recommend to use the sudo command.

So what is the ideal form?

The official Node.js installer is not recommended.

I searched the npm documentation site and found the following description

We do not recommend using a Node installer, since the Node installation process installs npm in a directory with local permissions and can cause permissions errors when you run npm packages globally.

https://docs.npmjs.com/downloading-and-installing-node-js-and-npm

You can download the Node installer from the Node.js official site.

(By the way, the official Node.js site and the official npm site are two different sites.)

This installer installs the npm command as well as the node command.

The problem is where to install the npm command. In this way, by default, each time you use the npm install -g command, you get a permission error.

My environment was also built using the Node installer and I had same problem.

To solve this problem, the official npm website seems to recommend using the Node installer itself instead of using the sudo command.

So what do you recommend using to install npm?

Installing Node.js using the Node Version Manager

The above document says the following (in bold)

 you must install Node.js and the npm command line interface using either a Node version manager or a Node installer. We strongly recommend using a Node version manager to install Node.js and npm.

https://docs.npmjs.com/downloading-and-installing-node-js-and-npm

There are several ways to install the Node.js and npm.

One way is to use the Node installer, but this is not recommended by the npm team.

The other way to install is to use the Node version manager.

So what is the Node Version Manager?

Node version manager

Node Version Manager is a software that allows multiple versions of Node.js to be installed on a single computer.

For example, you can install two versions of the software, v10.15.3 and v12.1.0, and switch between them as needed.

As you can see, the software was originally designed to switch between multiple versions, but there is another advantage to using Node version manager.

The Node version manager installs the npm command in a folder that does not require special permissions.

This allows you to use the npm install -g command without having to use sudo.

Node Version Manager, which one to install?

In truth, the phrase “install the node’s version manager” is not very appropriate.

This is because there is no software named “Node version manager”.

Just as there are Chrome and Firefox in the “Browser” category, and you can use whatever you want, the Node version manager has multiple software programs, such as nvm and nodist, each developed by a different team.

You can choose one of them, install it and use it.

In the above document introduces two versions, one for Linux/Mac and one for Windows.

OSX or Linux Node version managers

Windows Node version managers

Each one will be used slightly differently, so you can install the one you like.

I use Mac, so I decided to install nvm. The operation is intuitive and easy to understand, and I like it.

By the way, I had Node.js that installed by the official Node installer. But I did not uninstall this existing Node.js. I installed nvm additionally.

By using the nvm ls command, we can show a choice of which version of Node.js to use. I found named item “system” appears in the choice. This pointed to the existing Node.js installed from the Node installer.

You can use the nvm use system command to switch to an existing Node.js command, or use the nvm use v10.15.3 command to switch to your v10.15.3 that nvm’s own installation

In addition to the four mentioned, there are several other Node version managers that have been developed. You may want to try them out.

As we participate in more and more front-end projects, we’re seeing more and more “the version of Node.js used in one project is not the same as the version of Node.js used in another project” and so on.

Whether you use the sudo command or not, you should probably try to use the Node version manager.

It’s kind of strange that the official Node.js site and the official npm site have different views on where to install npm, but maybe sooner or later they’ll agree on a discussion.

カテゴリー
未分類

An Error: Call to a member function make() on null in Laravel 8.5 PHPUnit test

When you override the setUP() method on your own, you need to call the parent::setUp() method

In my case, we implemented our own setUp() method, but did not call parent::setUp().

The documentation says the following.

If you define your own setUp / tearDown methods within a test class, be sure to call the respective parent::setUp() / parent::tearDown() methods on the parent class.

https://laravel.com/docs/8.x/testing#creating-and-running-tests

I solved this problem by calling parent::setUp() inside a setUp() method I wrote.

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    protected function setUp():void {
        parent::setUp(); //I had to add this line.
        //Custom setups are performed after the setUp() process of the parent class
    }
    protected function tearDown():void {
        //Custom cleanup is performed before the parent class tearDown() process
        parent::tearDown();
    }

    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

If you want to provide a tearDown method, you need to use parent::tearDown() as well.

More details

In my case, I had our own setUp() method, but I did not call parent::setUp() as shown below.

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    protected function setUp():void {
        //I forgot to write parent::setUp();.
        //Custom setups are performed after the setUp() process of the parent class
    }
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

In this state, an error occurred when calling $this->get(‘/’).

1) Tests\Feature\UserTest::testExample
Error: Call to a member function make() on null

/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:498
/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:292
/var/www/tests/Feature/UserTest.php:21

Laravel provides its own useful features for automated testing.

In my case , $this->get(‘/’), is one such example.

A test class created by artisan make:test command is prepared to use such a useful feature.

php artisan make:test UserTest

This test class does not have a setUp() method by default.

In this state, PHPUnit will execute the setUP() method of the parent class. This sets up some useful features.

However, if you implement the setUp() method on your own, it will not do what it is supposed to do in the parent class.

To fix this, we need to write a manual call to the setUp() method of the parent class.

カテゴリー
未分類

Laravel 8.5 PHPUnit テスト で Error: Call to a member function make() on null が発生した話

独自にsetUP()メソッドをオーバーライドしたときは、parent::setUp()メソッドをコールする必要がある

今回のケースでは、独自に setUp() メソッドを実装したのに、 parent::setUp() をコールしていなかったことが原因でした。

ドキュメントには、以下の記述があります。

If you define your own setUp / tearDown methods within a test class, be sure to call the respective parent::setUp() / parent::tearDown() methods on the parent class.

もし、あなた独自の setUp / tearDown メソッドをテストクラスに書くときは、それぞれの親クラスについて parent::setUp() / parent::tearDown() をコールすることを忘れないでください。

https://laravel.com/docs/8.x/testing#creating-and-running-tests

自作した setUp() メソッドの内側で parent::setUp() をコールすることで解消しました。

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    protected function setUp():void {
        parent::setUp(); //この行を追記する必要がありました。
        //独自の準備処理を親クラスの setUp() 処理のあとに行う
    }
    protected function tearDown():void {
        //独自の後片付け処理を親クラスの tearDown() 処理の前に行う
        parent::tearDown();
    }

    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

なお、 tearDownメソッドを用意する場合には、 同様に parent::tearDown() が必要とのことです。

もっと詳しく

今回のケースでは、独自に setUp() メソッドを用意したにもかかわらず、 以下のようにparent::setUp() をコールしていませんでした。

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    protected function setUp():void {
        //parent::setUp();を書き忘れている。
        //独自の準備処理を親クラスの setUp() 処理のあとに行う
    }
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

この状態では、 $this->get('/') をコールしたときにエラーが発生しました。

1) Tests\Feature\UserTest::testExample
Error: Call to a member function make() on null

/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:498
/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:292
/var/www/tests/Feature/UserTest.php:21

Laravel では、自動テストに便利な機能を独自に用意してくれています。

今回のコードの $this->get('/') もその一つです。

artisan make:test コマンドで作成したテストクラスでは、このような便利機能を使う準備がされています。

php artisan make:test UserTest

このテストクラスには、初期状態では setUp() メソッドが存在していません。

この状態では、PHPUnit は親クラスの setUP() メソッドを実行します。これにより、便利な機能がいくつか準備されます。

しかし、 setUp() メソッドを独自に実装した場合は、親クラスで行うはずの処理が行われません。

これを解消するために、手作業で親クラスの setUp() メソッドをコールする記述が必要となります。