테스트 해보기

jest 를 설치한다. (기존에 있는 서비스에 테스트를 붙이는 방식)

D:\code\node\lecture>npm i -D jest

added 238 packages, changed 4 packages, and audited 504 packages in 16s

44 packages are looking for funding
  run `npm fund` for details

 

처음 상태에서 test를 실행하면 아래와 같이 test가 없다고 나온다.

D:\code\node\lecture>npm test

> nodebird@0.0.1 test
> jest

No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
In D:\code\node\lecture
  20 files checked.
  testMatch: **/__tests__/**/*.[jt]s?(x), **/?(*.)+(spec|test).[tj]s?(x) - 0 matches
  testPathIgnorePatterns: \\node_modules\\ - 20 matches
  testRegex:  - 0 matches
Pattern:  - 0 matches

 

test 파일을 만들 때는 test나 spec 이 들어가게 만들면 된다.

index.test.js 파일을 만들고 다시 test를 수행하면 index.test.js 는 찾았는데 테스트가 없다고 나온다.

 

D:\code\node\lecture>npm test

> nodebird@0.0.1 test
> jest

 FAIL  middlewares/index.test.js
  ● Test suite failed to run

    Your test suite must contain at least one test.

      at onResult (node_modules/@jest/core/build/TestScheduler.js:133:18)
      at node_modules/@jest/core/build/TestScheduler.js:254:19
      at node_modules/emittery/index.js:363:13
          at Array.map (<anonymous>)
      at Emittery.emit (node_modules/emittery/index.js:361:23)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.972 s
Ran all test suites.

 

test 문법은 첫번째는 test의 설명이고, 그 다음은 실제로 어떤 일을 할지 입력한다.(코드와 결과값을 입력한다.)

 

// index.test.js 파일 내용

test("1+1 은 2입니다.", () => {
    expect(1 + 1).toEqual(2);
  });

 

위와 같이 입력 후 테스트를 실행하면 성공했다고 출력 된다.

D:\code\node\lecture>npm test

> nodebird@0.0.1 test
> jest

 PASS  middlewares/index.test.js
  √ 1+1 2입니다. (4 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.692 s
Ran all test suites.

 

expect 를 여러개 한번에 사용도 가능하다.

expect(res.status).toBeCalledWith(403);
expect(res.send).toBeCalledWith("로그인 필요");

 

index.test.js 를 작성하고 아래처럼 test를 수행해보면 성공한 것을 확인해볼 수 있다.

// middlewares/index.test.js 파일 내용
const { isLoggedIn, isNotLoggedIn } = require("./");

describe("isLoggedIn", () => {
  const res = {
    status: jest.fn(() => res),
    send: jest.fn(),
  };
  const next = jest.fn();

  test("로그인 되어있으면 isLoggedIn이 next를 호출해야 함", () => {
    const req = {
      isAuthenticated: jest.fn(() => true),
    };
    isLoggedIn(req, res, next);
    expect(next).toBeCalledTimes(1);
  });

  test("로그인 되어있지 않으면 isLoggedIn이 에러를 응답해야 함", () => {
    const req = {
      isAuthenticated: jest.fn(() => false),
    };
    isLoggedIn(req, res, next);
    expect(res.status).toBeCalledWith(403);
    expect(res.send).toBeCalledWith("로그인 필요");
  });
});

describe("isNotLoggedIn", () => {
  const res = {
    redirect: jest.fn(),
  };
  const next = jest.fn();

  test("로그인 되어있으면 isNotLoggedIn이 에러를 응답해야 함", () => {
    const req = {
      isAuthenticated: jest.fn(() => true),
    };
    isNotLoggedIn(req, res, next);
    const message = encodeURIComponent("로그인한 상태입니다.");
    expect(res.redirect).toBeCalledWith(`/?error=${message}`);
  });

  test("로그인 되어있지 않으면 isNotLoggedIn이 next를 호출해야 함", () => {
    const req = {
      isAuthenticated: jest.fn(() => false),
    };
    isNotLoggedIn(req, res, next);
    expect(next).toHaveBeenCalledTimes(1);
  });
});

 

결과화면

D:\code\node\lecture>npm test

> nodebird@0.0.1 test
> jest

 PASS  middlewares/index.test.js
  isLoggedIn
    √ 로그인 되어있으면 isLoggedIn이 next를 호출해야 (4 ms)
    √ 로그인 되어있지 않으면 isLoggedIn이 에러를 응답해야 (3 ms)
  isNotLoggedIn
    √ 로그인 되어있으면 isNotLoggedIn이 에러를 응답해야 (1 ms)
    √ 로그인 되어있지 않으면 isNotLoggedIn이 next를 호출해야 (1 ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        2.022 s
Ran all test suites.

 

DB에서 불러오는 파일들은 jes.mock 을 통해서 가짜로 변경해서 테스트를 진행할 수 있다.

mockReturnValue 사용.

// user.js 에 있는  내용
const User = require('../models/user');

// user.test.js 에 있는 내용
jest.mock("../models/user");


  test("사용자를 찾아 팔로잉을 추가하고 success를 응답해야 함", async () => {
    User.findOne.mockReturnValue({
      addFollowing(id) {
        return Promise.resolve(true);
      },
    });
    await follow(req, res, next);
    expect(res.send).toBeCalledWith("success");
  });

 

user.test.js 작성한 후에 테스트 결과 화면

D:\code\node\lecture>npm test

> nodebird@0.0.1 test
> jest

 PASS  middlewares/index.test.js
 PASS  controllers/user.test.js    
  ● Console

    console.error
      DB에러

      11 |     }
      12 |   } catch (error) {
    > 13 |     console.error(error);
         |             ^
      14 |     next(error);
      15 |   }
      16 | };

      at error (controllers/user.js:13:13)
      at Object.<anonymous> (controllers/user.test.js:36:5)


Test Suites: 2 passed, 2 total
Tests:       7 passed, 7 total
Snapshots:   0 total
Time:        3.428 s
Ran all test suites.

 

테스트 커버리지 살펴보기

package.json 에 아래와 같이 추가하고 실행 결과는 아래와 같다.

test 파일을 만든 것 중에서 얼마나 테스트가 되었는지 확인 가능하다.

"scripts": {
    "start": "nodemon app",
    "test": "jest",
    "coverage": "jest --coverage"
  },

 

D:\code\node\lecture>npm run coverage

> nodebird@0.0.1 coverage
> jest --coverage

 PASS  middlewares/index.test.js
 PASS  controllers/user.test.js
  ● Console

    console.error
      DB에러

      11 |     }
      12 |   } catch (error) {
    > 13 |     console.error(error);
         |             ^
      14 |     next(error);
      15 |   }
      16 | };

      at error (controllers/user.js:13:13)
      at Object.<anonymous> (controllers/user.test.js:36:5)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files    |      84 |      100 |      60 |      84 |                  
 controllers |     100 |      100 |     100 |     100 |                  
  user.js    |     100 |      100 |     100 |     100 |                  
 middlewares |     100 |      100 |     100 |     100 |                  
  index.js   |     100 |      100 |     100 |     100 |                  
 models      |   33.33 |      100 |       0 |   33.33 |
  user.js    |   33.33 |      100 |       0 |   33.33 | 5-47
-------------|---------|----------|---------|---------|-------------------

Test Suites: 2 passed, 2 total
Tests:       7 passed, 7 total
Snapshots:   0 total
Time:        2.246 s, estimated 4 s
Ran all test suites.

 

통합 테스트

통합 테스트를 위해서 supertest를 설치한다.

 

D:\code\node\lecture>npm i -D supertest

added 24 packages, changed 5 packages, and audited 528 packages in 5s

52 packages are looking for funding
  run `npm fund` for details

 

테스트를 위해 DB 설정을 해주고 아래와 같이 db 를 생성해준다.

D:\code\node\lecture>npx sequelize db:create --env test

Sequelize CLI [Node: 20.16.0, CLI: 6.4.1, ORM: 6.29.0]

Loaded configuration file "config\config.json".
Using environment "test".
Database nodejs_test created.

 

routes/auth.test.js 파일에 test 내용을 작성해주고 실행하면 아래와 같이 결과를 알려준다.

D:\code\node\lecture>npm test

> nodebird@0.0.1 test
> jest

 PASS  middlewares/index.test.js
 PASS  controllers/user.test.js    
......

POST /auth/join 302 342.534 ms - 23
POST /auth/login 302 249.889 ms - 23
POST /auth/join 302 14.069 ms - 115
POST /auth/login 302 3.168 ms - 136
POST /auth/login 302 242.653 ms - 23
POST /auth/login 302 245.272 ms - 154
POST /auth/login 302 246.092 ms - 23
GET /auth/logout 403 2.080 ms - 16  
POST /auth/login 302 7.814 ms - 115
GET /auth/logout 302 6.094 ms - 23  
 PASS  routes/auth.test.js (7.015 s)
  ● Console

......
Test Suites: 3 passed, 3 total
Tests:       14 passed, 14 total
Snapshots:   0 total
Time:        8.013 s
Ran all test suites.

 

부하테스트를 위해 artillery를 설치해준다.

D:\code\node\lecture>npm i -D artillery

 

실제 수행을 해본다.

100명이 50번씩 수행한다는 의미 (—count 100 -n 50)

 

D:\code\node\lecture>npx artillery quick --count 100 -n 50 http://localhost:8001
Test run id: t5xdb_xrpacx8tc4mh993pg9jp357yby3m4_mta3
Phase started: unnamed (index: 0, duration: 1s) 02:08:04(+0900)

Phase completed: unnamed (index: 0, duration: 1s) 02:08:05(+0900)

--------------------------------------
Metrics for period to: 02:08:10(+0900) (width: 5.328s)
--------------------------------------

http.codes.200: ................................................................ 3129
http.downloaded_bytes: ......................................................... 11195562
http.request_rate: ............................................................. 608/sec
http.requests: ................................................................. 3229
http.response_time:
  min: ......................................................................... 23
  max: ......................................................................... 261
  mean: ........................................................................ 151.7
  median: ...................................................................... 147
  p95: ......................................................................... 198.4
  p99: ......................................................................... 214.9
http.responses: ................................................................ 3129
vusers.created: ................................................................ 100
vusers.created_by_name.0: ...................................................... 100


--------------------------------------
Metrics for period to: 02:08:20(+0900) (width: 2.594s)
--------------------------------------

http.codes.200: ................................................................ 1871
http.downloaded_bytes: ......................................................... 6694438
http.request_rate: ............................................................. 689/sec
http.requests: ................................................................. 1771
http.response_time:
  min: ......................................................................... 23
  max: ......................................................................... 188
  mean: ........................................................................ 128.2
  median: ...................................................................... 133
  p95: ......................................................................... 162.4
  p99: ......................................................................... 179.5
http.responses: ................................................................ 1871
vusers.completed: .............................................................. 100
vusers.failed: ................................................................. 0
vusers.session_length:
  min: ......................................................................... 6934.4
  max: ......................................................................... 7363.9
  mean: ........................................................................ 7174
  median: ...................................................................... 7117
  p95: ......................................................................... 7407.5
  p99: ......................................................................... 7407.5


All VUs finished. Total time: 9 seconds

--------------------------------
Summary report @ 02:08:14(+0900)
--------------------------------

http.codes.200: ................................................................ 5000
http.downloaded_bytes: ......................................................... 17890000
http.request_rate: ............................................................. 649/sec
http.requests: ................................................................. 5000
http.response_time:
  min: ......................................................................... 23
  max: ......................................................................... 261
  mean: ........................................................................ 142.9
  median: ...................................................................... 141.2
  p95: ......................................................................... 194.4
  p99: ......................................................................... 210.6
http.responses: ................................................................ 5000
vusers.completed: .............................................................. 100
vusers.created: ................................................................ 100
vusers.created_by_name.0: ...................................................... 100
vusers.failed: ................................................................. 0
vusers.session_length:
  min: ......................................................................... 6934.4
  max: ......................................................................... 7363.9
  mean: ........................................................................ 7174
  median: ...................................................................... 7117
  p95: ......................................................................... 7407.5
  p99: ......................................................................... 7407.5

D:\code\node\lecture>

 

loadtest.json에 주로 사용될 만한 시나리오를 작성해서 부하 테스트도 가능하다.

결과는 아래와 같다.

D:\code\node\lecture>npx artillery run loadtest.json
Test run id: tqepa_rt48nfkae5zb6xp6jynb53p6x4y6w_a3jj
Phase started: unnamed (index: 0, duration: 30s) 02:33:04(+0900)

--------------------------------------
Metrics for period to: 02:33:10(+0900) (width: 4.575s)
--------------------------------------

http.codes.200: ................................................................ 182
http.codes.302: ................................................................ 91
http.downloaded_bytes: ......................................................... 616343
http.request_rate: ............................................................. 71/sec
http.requests: ................................................................. 273
http.response_time:
  min: ......................................................................... 2
  max: ......................................................................... 45
  mean: ........................................................................ 3.7
  median: ...................................................................... 3
  p95: ......................................................................... 6
  p99: ......................................................................... 13.1
http.responses: ................................................................ 273
vusers.completed: .............................................................. 91
vusers.created: ................................................................ 91
vusers.created_by_name.0: ...................................................... 91
vusers.failed: ................................................................. 0
vusers.session_length:
  min: ......................................................................... 12.9
  max: ......................................................................... 112.9
  mean: ........................................................................ 22.1
  median: ...................................................................... 16.9
  p95: ......................................................................... 51.9
  p99: ......................................................................... 67.4


--------------------------------------
Metrics for period to: 02:33:20(+0900) (width: 9.95s)
--------------------------------------

http.codes.200: ................................................................ 400
http.codes.302: ................................................................ 200
http.downloaded_bytes: ......................................................... 1354600
http.request_rate: ............................................................. 60/sec
http.requests: ................................................................. 600
http.response_time:
  min: ......................................................................... 1
  max: ......................................................................... 10
  mean: ........................................................................ 2.9
  median: ...................................................................... 3
  p95: ......................................................................... 4
  p99: ......................................................................... 6
http.responses: ................................................................ 600
vusers.completed: .............................................................. 200
vusers.created: ................................................................ 200
vusers.created_by_name.0: ...................................................... 200
vusers.failed: ................................................................. 0
vusers.session_length:
  min: ......................................................................... 10.5
  max: ......................................................................... 37
  mean: ........................................................................ 14.2
  median: ...................................................................... 13.6
  p95: ......................................................................... 17.6
  p99: ......................................................................... 27.4


Phase completed: unnamed (index: 0, duration: 30s) 02:33:34(+0900)

--------------------------------------
Metrics for period to: 02:33:30(+0900) (width: 9.952s)
--------------------------------------

http.codes.200: ................................................................ 400
http.codes.302: ................................................................ 200
http.downloaded_bytes: ......................................................... 1354600
http.request_rate: ............................................................. 60/sec
http.requests: ................................................................. 600
http.response_time:
  min: ......................................................................... 1
  max: ......................................................................... 6
  mean: ........................................................................ 2.7
  median: ...................................................................... 3
  p95: ......................................................................... 4
  p99: ......................................................................... 5
http.responses: ................................................................ 600
vusers.completed: .............................................................. 200
vusers.created: ................................................................ 200
vusers.created_by_name.0: ...................................................... 200
vusers.failed: ................................................................. 0
vusers.session_length:
  min: ......................................................................... 10.3
  max: ......................................................................... 18.8
  mean: ........................................................................ 12.9
  median: ...................................................................... 12.6
  p95: ......................................................................... 16
  p99: ......................................................................... 17.6


--------------------------------------
Metrics for period to: 02:33:40(+0900) (width: 5.493s)
--------------------------------------

http.codes.200: ................................................................ 218
http.codes.302: ................................................................ 109
http.downloaded_bytes: ......................................................... 738257
http.request_rate: ............................................................. 71/sec
http.requests: ................................................................. 327
http.response_time:
  min: ......................................................................... 1
  max: ......................................................................... 6
  mean: ........................................................................ 2.5
  median: ...................................................................... 2
  p95: ......................................................................... 4
  p99: ......................................................................... 4
http.responses: ................................................................ 327
vusers.completed: .............................................................. 109
vusers.created: ................................................................ 109
vusers.created_by_name.0: ...................................................... 109
vusers.failed: ................................................................. 0
vusers.session_length:
  min: ......................................................................... 9.9
  max: ......................................................................... 17.6
  mean: ........................................................................ 12.1
  median: ...................................................................... 11.8
  p95: ......................................................................... 14.4
  p99: ......................................................................... 15.3


All VUs finished. Total time: 31 seconds

--------------------------------
Summary report @ 02:33:36(+0900)
--------------------------------

http.codes.200: ................................................................ 1200
http.codes.302: ................................................................ 600
http.downloaded_bytes: ......................................................... 4063800
http.request_rate: ............................................................. 71/sec
http.requests: ................................................................. 1800
http.response_time:
  min: ......................................................................... 1
  max: ......................................................................... 45
  mean: ........................................................................ 2.9
  median: ...................................................................... 3
  p95: ......................................................................... 4
  p99: ......................................................................... 6
http.responses: ................................................................ 1800
vusers.completed: .............................................................. 600
vusers.created: ................................................................ 600
vusers.created_by_name.0: ...................................................... 600
vusers.failed: ................................................................. 0
vusers.session_length:
  min: ......................................................................... 9.9
  max: ......................................................................... 112.9
  mean: ........................................................................ 14.6
  median: ...................................................................... 13.1
  p95: ......................................................................... 19.9
  p99: ......................................................................... 49.9

'Javascript > Node' 카테고리의 다른 글

노드 교과서 섹션 8  (0) 2023.08.23
노드 교과서 섹션 9  (0) 2023.08.22
노드 교과서 섹션 11  (0) 2023.08.18
노드 교과서 섹션 12  (0) 2023.08.17
노드 교과서 섹션 13  (0) 2023.08.09

웹 소켓으로 실시간 데이터 전송하기

WS 모듈 사용하기

필요한 것들을 아래와 같이 설치해준다.

 

D:\code\node\gifchat>npm i cookie-parser dotenv express express-session morgan nunjucks && npm -i D nodemon

added 82 packages, and audited 83 packages in 5s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Unknown command: "D"

To see a list of supported npm commands, run:
  npm help

 

이번에 사용할 ws 도 추가로 설치해준다.

D:\code\node\gifchat>npm i ws

added 1 package, and audited 84 packages in 1s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

웹소켓에는 네 가지 상태가 있다. CONNECTING(연결 중), OPEN(열림), CLOSING(닫는 중), CLOSED(당힘) 이다. OPEN일 때만 에러 없이 메세지를 보낼 수 있다.

보낼 때는 ws.send 로 보내고 받을 때는 ws.on 으로 받는다.

//socket.js 파일

const WebSocket = require("ws");

module.exports = (server) => {
  const wss = new WebSocket.Server({ server });

  wss.on("connection", (ws, req) => {
    // 웹소켓 연결 시
    const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
    console.log("새로운 클라이언트 접속", ip);
    ws.on("message", (message) => {
      // 클라이언트로부터 메시지
      console.log(message.toString());
    });
    ws.on("error", (error) => {
      // 에러 시
      console.error(error);
    });
    ws.on("close", () => {
      // 연결 종료 시
      console.log("클라이언트 접속 해제", ip);
      clearInterval(ws.interval);
    });

    ws.interval = setInterval(() => {
      // 3초마다 클라이언트로 메시지 전송
      if (ws.readyState === ws.OPEN) {
        ws.send("서버에서 클라이언트로 메시지를 보냅니다.");
      }
    }, 3000);
  });
};

 

서버를 실행하면 아래와 같이 서버에서 클라이언트로 메세지를 보내는 것 확인 가능

 

 

서버에서도 확인 가능

 

 

Socket.IO 모듈 사용하기

socket.io에서는 키와 값으로 보낸다.

emit(’키’,’값’)

socket.io는 http로 연결을 한다.

socket.io는 polling 과 websocket 을 둘 다 지원한다.websocket으로만 사용하도록 설정할 수도 있다.

socket.js 와 index.html을 변경하면 아래와 같이 확인이 가능하다.

 

//socket.js

const SocketIO = require("socket.io");

module.exports = (server) => {
  const io = SocketIO(server, { path: "/socket.io" });

  io.on("connection", (socket) => {
    // 웹소켓 연결 시
    const req = socket.request;
    const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
    console.log("새로운 클라이언트 접속!", ip, socket.id, req.ip);
    socket.on("disconnect", () => {
      // 연결 종료 시
      console.log("클라이언트 접속 해제", ip, socket.id);
      clearInterval(socket.interval);
    });
    socket.on("error", (error) => {
      // 에러 시
      console.error(error);
    });
    socket.on("reply", (data) => {
      // 클라이언트로부터 메시지
      console.log(data);
    });
    socket.interval = setInterval(() => {
      // 3초마다 클라이언트로 메시지 전송
      socket.emit("news", "Hello Socket.IO");
    }, 3000);
  });
};


// index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>GIF 채팅방</title>
  </head>
  <body>
    <div>F12를 눌러 console 탭과 network 탭을 확인하세요.</div>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io.connect("http://localhost:8005", {
        path: "/socket.io",
        transports: ["websocket"],
      });
      socket.on("news", function (data) {
        console.log(data);
        socket.emit("reply", "Hello Node.JS");
      });
    </script>
  </body>
</html>

 

실시간 채팅방 만들기

몽고디비를 사용한다. 필요한 파일들을 아래과 같이 설치한다.

 

D:\code\node\gifchat>npm i mongoose multer color-hash@2

added 39 packages, and audited 167 packages in 9s

 

몽고디비를 사용해야 하기 때문에 실행시켜준다.

PS C:\Program Files\MongoDB\Server\7.0\bin> ./mongod --ipv6

 

서버를 시작해서 몽고디비까지 접속이 잘 되는 것을 확인다.

D:\code\node\gifchat>npm start

> gif-chat@0.0.1 start
> nodemon app

[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node app.js`
(node:4060) [MONGODB DRIVER] Warning: useNewUrlParser is a deprecated option: useNewUrlParser has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version
(Use `node --trace-warnings ...` to show where the warning was created)
8005 번 포트에서 대기중
몽고디비 연결 성공

 

에러 없이 서버가 잘 실행되면 아래와 같이 2개의 웹브라우저에서 접속해본다.

서버에서도 2개의 세션이 붙은 것을 확인할 수 있다.

 

#c587b0 J5RByMDgnkNN_nux7zrvG6EGaEi0d-QJ
Mongoose: rooms.find({}, {})
GET / 304 27.828 ms - -
room 네임스페이스 접속 해제
GET /main.css 304 1.593 ms - -
room 네임스페이스에 접속
Mongoose: rooms.find({}, {})
GET / 304 4.459 ms - -
room 네임스페이스 접속 해제
GET /main.css 304 1.506 ms - -
room 네임스페이스에 접속
room 네임스페이스 접속 해제
chat 네임스페이스에 접속
#76862d 6t7e0goBwVLrd4Ny2Ok5g6FDYK-5Cmsj
GET /room 200 3.556 ms - 806

 

방을 생성하면 다른 세션에서 실시간으로 방이 생성된 것을 확인할 수 있고 방 입장도 가능하다.

 

입장하거나 퇴장하는 메세지도 잘 출력 되는지 확인한다.

 

메세지도 양쪽에서 잘 출력 되는지 확인한다.

 

최종적으로 gif 파일 올리기 까지 정상적으로 올라가는 것을 확인할 수 있다.

'Javascript > Node' 카테고리의 다른 글

노드 교과서 섹션 8  (0) 2023.08.23
노드 교과서 섹션 9  (0) 2023.08.22
노드 교과서 섹션 10  (0) 2023.08.19
노드 교과서 섹션 12  (0) 2023.08.17
노드 교과서 섹션 13  (0) 2023.08.09

CLI 프로그램 만들기

index.js 파일 제일 위에 #!/usr/bin/env node 를 적어 준다.

윈도우에서는 아무 역할이 없지만 리눅스나 맥에서는 이 파일을 노드로 실행하라는 역할을 한다.

 

#!/usr/bin/env node
console.log("hello cli");

 

package.json 파일에 bin 부분을 추가한다.

cli를 실행하면 index.js가 실행된다.

 

{
    "name": "node-cli",
    "version": "0.0.1",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "bin": {
      "cli": "./index.js"
    }
  }

 

아래처럼 글로벌로 설치하면 index.js 가 프로그램을 설치가 된 것이다.

D:\code\node\cli>npm i -g

added 1 package in 1s

 

실행을 하면 console가 실행되는 것을 확인할 수 있다.

D:\code\node\cli>npx cli
hello cli

 

아래와 같이 코드를 수정했어도 다시 설치할 필요 없이 정상적으로 실행이 된다.

//index.js 파일

#!/usr/bin/env node
console.log("hello cli", process.argv);

 

D:\code\node\cli>npx cli
hello cli [
  'C:\\Program Files\\nodejs\\node.exe',
  'C:\\Users\\john\\AppData\\Local\\npm-cache\\_npx\\bc67c92c0f4afb79\\node_modules\\node-cli\\index.js'
]

 

process.argv 는 매개변수를 불러올 수 있다.

 

D:\code\node\cli>npx cli one two three four
hello cli [
  'C:\\Program Files\\nodejs\\node.exe',
  'C:\\Users\\john\\AppData\\Local\\npm-cache\\_npx\\bc67c92c0f4afb79\\node_modules\\node-cli\\index.js',
  'one',
  'two',
  'three',
  'four'
]

 

터미널에서 사용자의 답변을 듣는 코드를 작성하고 실행 화면이다.

// index.js 파일

#!/usr/bin/env node
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin, // 터미널 인풋
  output: process.stdout, // 터미널 아웃풋
});

rl.question("예제가 재밌나요?(y/n)", (answer) => {
  if (answer === "y") {
    console.log("감사합니다.");
  } else if (answer === "n") {
    console.log("죄송합니다.");
  } else {
    console.log("y 또는 n 만 입력하세요.");
  }
  rl.close();
});

 

D:\code\node\cli>npx cli                        
예제가 재밌나요?(y/n)b
y 또는 n 입력하세요.

D:\code\node\cli>npx cli
예제가 재밌나요?(y/n)y
감사합니다.

D:\code\node\cli>npx cli
예제가 재밌나요?(y/n)n
죄송합니다.

 

아래와 같이 package.json 이 수정되면 다시 설치를 해줘야 한다.

cli : 이 부분이 index.js → template.js 로 변경

 

{
    "name": "node-cli",
    "version": "0.0.1",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "bin": {
      "cli": "./template.js"
    }
  }
 

 

D:\code\node\cli>npm i -g

up to date in 831ms

 

template를 자동으로 만들어 주는 cli 프로그램을 수행한 결과 화면

자동으로 html 파일을 만들고 안에 내용을 채워진 것을 확인

 

 

설치한 npx cli를 지울 때는 아래 명령어 사용 가능

 

D:\code\node\cli>npm rm -g node-cli

Commander, Inquirer 사용하기

자주 쓰이는 패키지 2개를 알아보자.

버전에 따라서 명령어가 달라질 수 있어서 버전까지 지정해서 설치

D:\code\node\cli>npm i commander@9 inquirer@8

added 53 packages, and audited 54 packages in 7s

15 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

command.js 만들고 package.json 수정 필요, 다시 설치

// package.json 파일
"bin": {
    "cli": "./command.js"
  },

 

// 다시 설치
D:\code\node\cli>npm i -g

up to date in 964ms

 

필수값 , 선택값 구분

program
  .command("template <type>") // <type> 은 필수값, [type] 은 선택 값

 

버전 확인

D:\code\node\cli>npx cli -v
0.0.1

 

설명내용을 확인 가능

D:\code\node\cli>npx cli -h
Usage: cli [options] [command]

Options:
  -v, --version                   output the version number
  -h, --help                      display help for command

Commands:
  template|tmpl [options] <type>  템플릿을 생성합니다.
 
 

 

명령어를 실행하면 아래와 같이 템플릿이 포함된 파일을 자동으로 만들어 준다.

 

아래는 inquirer 버전 URL 이다.

https://www.npmjs.com/package/inquirer?activeTab=versions

 

npx cli 로 실행하고 선택할 때는 화살표로 움직일 수 있다.

D:\code\node\cli>npx cli
? 템플릿 종류를 선택하세요. html    
? 파일의 이름을 입력하세요. new
? 파일이 위치할 폴더의 경로를 입력하세요. public/html
? 생성하시겠습니까? Yes    
이미 해당 파일이 존재합니다
터미널을 종료합니다.

 

조금 더 꾸며볼 수 있다.

chalk 를 설치하면 색깔을 입힐 수 있게 해준다.

 

D:\code\node\cli>npm i chalk@4

up to date, audited 54 packages in 1s

15 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

에러 내용 같은 경우에 아래와 같이 빨간색 볼드체로 보이게 할 수 있다.

console.error(chalk.bold.red("이미 해당 파일이 존재합니다"));

 

성공은 아래와 같이 초록색으로 보이게 할 수 있다.

console.log(chalk.green(pathToFile, "생성 완료"));

 

아래는 색상이 변경된 결과 화면이다.

 

'Javascript > Node' 카테고리의 다른 글

노드 교과서 섹션 8  (0) 2023.08.23
노드 교과서 섹션 9  (0) 2023.08.22
노드 교과서 섹션 10  (0) 2023.08.19
노드 교과서 섹션 11  (0) 2023.08.18
노드 교과서 섹션 12  (0) 2023.08.17

+ Recent posts