[{"data":1,"prerenderedAt":4542},["ShallowReactive",2],{"post-nestjs-ci-environment-hands-on":3},{"id":4,"title":5,"body":6,"date":4528,"description":4529,"extension":4530,"meta":4531,"navigation":162,"path":4538,"seo":4539,"stem":4540,"__hash__":4541},"blog\u002Fblog\u002Fnestjs-ci-environment-hands-on.md","NestJS + Jest + GitHub ActionsでCI環境を構築する実践ガイド",{"type":7,"value":8,"toc":4489},"minimark",[9,13,17,21,24,34,37,56,59,70,73,112,115,120,242,245,263,267,270,275,389,393,488,492,628,632,703,707,711,895,898,978,982,985,1019,1022,1205,1209,1539,1543,1546,1574,1578,2037,2041,2213,2216,2284,2288,2307,2545,2549,2575,3016,3019,3023,3161,3165,3182,3883,3886,3929,3932,3946,3950,3954,4007,4010,4261,4265,4430,4433,4436,4441,4455,4460,4482,4485],[10,11,12],"h2",{"id":12},"はじめに",[14,15,16],"p",{},"NestJSプロジェクトにJestを使ったE2Eテストを導入し、GitHub Actionsで自動化するまでの手順を解説します。",[10,18,20],{"id":19},"ciとは","CIとは",[14,22,23],{},"CI（継続的インテグレーション）は、開発者がコード変更を定期的にリポジトリにマージし、自動化されたビルドとテストを実行するDevOps開発手法です。",[14,25,26,27],{},"参考: ",[28,29,33],"a",{"href":30,"rel":31},"https:\u002F\u002Faws.amazon.com\u002Fjp\u002Fdevops\u002Fcontinuous-integration\u002F",[32],"nofollow","AWS - 継続的インテグレーション",[10,35,36],{"id":36},"ハンズオンのゴール",[38,39,40,44,47,50,53],"ul",{},[41,42,43],"li",{},"NestJSプロジェクトの構築",[41,45,46],{},"Docker + MySQLでの開発環境構築",[41,48,49],{},"TypeORMを使ったCRUD機能の実装",[41,51,52],{},"E2Eテストの実装",[41,54,55],{},"GitHub ActionsでのCI自動化",[10,57,58],{"id":58},"前提条件",[38,60,61,64,67],{},[41,62,63],{},"macOS環境（Windows環境では一部動作が異なる可能性あり）",[41,65,66],{},"Docker Desktop v3.4.0以上がインストール済み",[41,68,69],{},"Node.js v14以上がインストール済み",[10,71,72],{"id":72},"技術スタック",[38,74,75,82,88,94,100,106],{},[41,76,77,81],{},[78,79,80],"strong",{},"Node.js"," サーバーサイドJavaScript実行環境",[41,83,84,87],{},[78,85,86],{},"NestJS"," スケーラブルなNode.jsフレームワーク",[41,89,90,93],{},[78,91,92],{},"TypeORM"," TypeScript用ORマッパー",[41,95,96,99],{},[78,97,98],{},"MySQL 8.0"," リレーショナルデータベース",[41,101,102,105],{},[78,103,104],{},"Jest"," JavaScriptテストフレームワーク",[41,107,108,111],{},[78,109,110],{},"Docker"," コンテナ仮想化プラットフォーム",[10,113,114],{"id":114},"プロジェクトセットアップ",[116,117,119],"h3",{"id":118},"nestjs-cliのインストールとプロジェクト作成","NestJS CLIのインストールとプロジェクト作成",[121,122,127],"pre",{"className":123,"code":124,"language":125,"meta":126,"style":126},"language-bash shiki shiki-themes github-light github-dark","# グローバルにCLIをインストール\nnpm install -g @nestjs\u002Fcli\n\n# プロジェクトを作成（npmを選択）\nnest new meetup-dev\n\n# プロジェクトディレクトリに移動\ncd meetup-dev\n\n# 依存関係をインストール\nnpm install\n\n# 開発サーバーを起動\nnpm run start:dev\n","bash","",[128,129,130,139,157,164,170,182,187,193,201,206,212,220,225,231],"code",{"__ignoreMap":126},[131,132,135],"span",{"class":133,"line":134},"line",1,[131,136,138],{"class":137},"sJ8bj","# グローバルにCLIをインストール\n",[131,140,142,146,150,154],{"class":133,"line":141},2,[131,143,145],{"class":144},"sScJk","npm",[131,147,149],{"class":148},"sZZnC"," install",[131,151,153],{"class":152},"sj4cs"," -g",[131,155,156],{"class":148}," @nestjs\u002Fcli\n",[131,158,160],{"class":133,"line":159},3,[131,161,163],{"emptyLinePlaceholder":162},true,"\n",[131,165,167],{"class":133,"line":166},4,[131,168,169],{"class":137},"# プロジェクトを作成（npmを選択）\n",[131,171,173,176,179],{"class":133,"line":172},5,[131,174,175],{"class":144},"nest",[131,177,178],{"class":148}," new",[131,180,181],{"class":148}," meetup-dev\n",[131,183,185],{"class":133,"line":184},6,[131,186,163],{"emptyLinePlaceholder":162},[131,188,190],{"class":133,"line":189},7,[131,191,192],{"class":137},"# プロジェクトディレクトリに移動\n",[131,194,196,199],{"class":133,"line":195},8,[131,197,198],{"class":152},"cd",[131,200,181],{"class":148},[131,202,204],{"class":133,"line":203},9,[131,205,163],{"emptyLinePlaceholder":162},[131,207,209],{"class":133,"line":208},10,[131,210,211],{"class":137},"# 依存関係をインストール\n",[131,213,215,217],{"class":133,"line":214},11,[131,216,145],{"class":144},[131,218,219],{"class":148}," install\n",[131,221,223],{"class":133,"line":222},12,[131,224,163],{"emptyLinePlaceholder":162},[131,226,228],{"class":133,"line":227},13,[131,229,230],{"class":137},"# 開発サーバーを起動\n",[131,232,234,236,239],{"class":133,"line":233},14,[131,235,145],{"class":144},[131,237,238],{"class":148}," run",[131,240,241],{"class":148}," start:dev\n",[14,243,244],{},"動作確認：",[121,246,248],{"className":123,"code":247,"language":125,"meta":126,"style":126},"curl http:\u002F\u002Flocalhost:3000\n# \"Hello World!\" が返ればOK\n",[128,249,250,258],{"__ignoreMap":126},[131,251,252,255],{"class":133,"line":134},[131,253,254],{"class":144},"curl",[131,256,257],{"class":148}," http:\u002F\u002Flocalhost:3000\n",[131,259,260],{"class":133,"line":141},[131,261,262],{"class":137},"# \"Hello World!\" が返ればOK\n",[116,264,266],{"id":265},"nestjsの基本構造","NestJSの基本構造",[14,268,269],{},"NestJSは以下のコンポーネントで構成されます",[271,272,274],"h4",{"id":273},"maints-エントリーポイント","main.ts - エントリーポイント",[121,276,280],{"className":277,"code":278,"language":279,"meta":126,"style":126},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F src\u002Fmain.ts\nimport { NestFactory } from '@nestjs\u002Fcore'\nimport { AppModule } from '.\u002Fapp.module'\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule)\n  await app.listen(3000)\n}\nbootstrap()\n","typescript",[128,281,282,287,303,315,319,333,356,376,381],{"__ignoreMap":126},[131,283,284],{"class":133,"line":134},[131,285,286],{"class":137},"\u002F\u002F src\u002Fmain.ts\n",[131,288,289,293,297,300],{"class":133,"line":141},[131,290,292],{"class":291},"szBVR","import",[131,294,296],{"class":295},"sVt8B"," { NestFactory } ",[131,298,299],{"class":291},"from",[131,301,302],{"class":148}," '@nestjs\u002Fcore'\n",[131,304,305,307,310,312],{"class":133,"line":159},[131,306,292],{"class":291},[131,308,309],{"class":295}," { AppModule } ",[131,311,299],{"class":291},[131,313,314],{"class":148}," '.\u002Fapp.module'\n",[131,316,317],{"class":133,"line":166},[131,318,163],{"emptyLinePlaceholder":162},[131,320,321,324,327,330],{"class":133,"line":172},[131,322,323],{"class":291},"async",[131,325,326],{"class":291}," function",[131,328,329],{"class":144}," bootstrap",[131,331,332],{"class":295},"() {\n",[131,334,335,338,341,344,347,350,353],{"class":133,"line":184},[131,336,337],{"class":291},"  const",[131,339,340],{"class":152}," app",[131,342,343],{"class":291}," =",[131,345,346],{"class":291}," await",[131,348,349],{"class":295}," NestFactory.",[131,351,352],{"class":144},"create",[131,354,355],{"class":295},"(AppModule)\n",[131,357,358,361,364,367,370,373],{"class":133,"line":189},[131,359,360],{"class":291},"  await",[131,362,363],{"class":295}," app.",[131,365,366],{"class":144},"listen",[131,368,369],{"class":295},"(",[131,371,372],{"class":152},"3000",[131,374,375],{"class":295},")\n",[131,377,378],{"class":133,"line":195},[131,379,380],{"class":295},"}\n",[131,382,383,386],{"class":133,"line":203},[131,384,385],{"class":144},"bootstrap",[131,387,388],{"class":295},"()\n",[271,390,392],{"id":391},"module-依存関係の管理","Module - 依存関係の管理",[121,394,396],{"className":277,"code":395,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fmodules\u002Fapp.module.ts\nimport { Module } from '@nestjs\u002Fcommon'\nimport { AppController } from '..\u002Fcontrollers\u002Fapp.controller'\nimport { AppService } from '..\u002Fservices\u002Fapp.service'\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n",[128,397,398,403,415,427,439,443,454,459,464,469,474],{"__ignoreMap":126},[131,399,400],{"class":133,"line":134},[131,401,402],{"class":137},"\u002F\u002F src\u002Fmodules\u002Fapp.module.ts\n",[131,404,405,407,410,412],{"class":133,"line":141},[131,406,292],{"class":291},[131,408,409],{"class":295}," { Module } ",[131,411,299],{"class":291},[131,413,414],{"class":148}," '@nestjs\u002Fcommon'\n",[131,416,417,419,422,424],{"class":133,"line":159},[131,418,292],{"class":291},[131,420,421],{"class":295}," { AppController } ",[131,423,299],{"class":291},[131,425,426],{"class":148}," '..\u002Fcontrollers\u002Fapp.controller'\n",[131,428,429,431,434,436],{"class":133,"line":166},[131,430,292],{"class":291},[131,432,433],{"class":295}," { AppService } ",[131,435,299],{"class":291},[131,437,438],{"class":148}," '..\u002Fservices\u002Fapp.service'\n",[131,440,441],{"class":133,"line":172},[131,442,163],{"emptyLinePlaceholder":162},[131,444,445,448,451],{"class":133,"line":184},[131,446,447],{"class":295},"@",[131,449,450],{"class":144},"Module",[131,452,453],{"class":295},"({\n",[131,455,456],{"class":133,"line":189},[131,457,458],{"class":295},"  imports: [],\n",[131,460,461],{"class":133,"line":195},[131,462,463],{"class":295},"  controllers: [AppController],\n",[131,465,466],{"class":133,"line":203},[131,467,468],{"class":295},"  providers: [AppService],\n",[131,470,471],{"class":133,"line":208},[131,472,473],{"class":295},"})\n",[131,475,476,479,482,485],{"class":133,"line":214},[131,477,478],{"class":291},"export",[131,480,481],{"class":291}," class",[131,483,484],{"class":144}," AppModule",[131,486,487],{"class":295}," {}\n",[271,489,491],{"id":490},"controller-ルーティング","Controller - ルーティング",[121,493,495],{"className":277,"code":494,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fcontrollers\u002Fapp.controller.ts\nimport { Controller, Get } from '@nestjs\u002Fcommon'\nimport { AppService } from '..\u002Fservices\u002Fapp.service'\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello()\n  }\n}\n",[128,496,497,502,513,523,527,536,548,574,578,588,603,619,624],{"__ignoreMap":126},[131,498,499],{"class":133,"line":134},[131,500,501],{"class":137},"\u002F\u002F src\u002Fcontrollers\u002Fapp.controller.ts\n",[131,503,504,506,509,511],{"class":133,"line":141},[131,505,292],{"class":291},[131,507,508],{"class":295}," { Controller, Get } ",[131,510,299],{"class":291},[131,512,414],{"class":148},[131,514,515,517,519,521],{"class":133,"line":159},[131,516,292],{"class":291},[131,518,433],{"class":295},[131,520,299],{"class":291},[131,522,438],{"class":148},[131,524,525],{"class":133,"line":166},[131,526,163],{"emptyLinePlaceholder":162},[131,528,529,531,534],{"class":133,"line":172},[131,530,447],{"class":295},[131,532,533],{"class":144},"Controller",[131,535,388],{"class":295},[131,537,538,540,542,545],{"class":133,"line":184},[131,539,478],{"class":291},[131,541,481],{"class":291},[131,543,544],{"class":144}," AppController",[131,546,547],{"class":295}," {\n",[131,549,550,553,555,558,561,565,568,571],{"class":133,"line":189},[131,551,552],{"class":291},"  constructor",[131,554,369],{"class":295},[131,556,557],{"class":291},"private",[131,559,560],{"class":291}," readonly",[131,562,564],{"class":563},"s4XuR"," appService",[131,566,567],{"class":291},":",[131,569,570],{"class":144}," AppService",[131,572,573],{"class":295},") {}\n",[131,575,576],{"class":133,"line":195},[131,577,163],{"emptyLinePlaceholder":162},[131,579,580,583,586],{"class":133,"line":203},[131,581,582],{"class":295},"  @",[131,584,585],{"class":144},"Get",[131,587,388],{"class":295},[131,589,590,593,596,598,601],{"class":133,"line":208},[131,591,592],{"class":144},"  getHello",[131,594,595],{"class":295},"()",[131,597,567],{"class":291},[131,599,600],{"class":152}," string",[131,602,547],{"class":295},[131,604,605,608,611,614,617],{"class":133,"line":214},[131,606,607],{"class":291},"    return",[131,609,610],{"class":152}," this",[131,612,613],{"class":295},".appService.",[131,615,616],{"class":144},"getHello",[131,618,388],{"class":295},[131,620,621],{"class":133,"line":222},[131,622,623],{"class":295},"  }\n",[131,625,626],{"class":133,"line":227},[131,627,380],{"class":295},[271,629,631],{"id":630},"service-ビジネスロジック","Service - ビジネスロジック",[121,633,635],{"className":277,"code":634,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fservices\u002Fapp.service.ts\nimport { Injectable } from '@nestjs\u002Fcommon'\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!'\n  }\n}\n",[128,636,637,642,653,657,666,676,688,695,699],{"__ignoreMap":126},[131,638,639],{"class":133,"line":134},[131,640,641],{"class":137},"\u002F\u002F src\u002Fservices\u002Fapp.service.ts\n",[131,643,644,646,649,651],{"class":133,"line":141},[131,645,292],{"class":291},[131,647,648],{"class":295}," { Injectable } ",[131,650,299],{"class":291},[131,652,414],{"class":148},[131,654,655],{"class":133,"line":159},[131,656,163],{"emptyLinePlaceholder":162},[131,658,659,661,664],{"class":133,"line":166},[131,660,447],{"class":295},[131,662,663],{"class":144},"Injectable",[131,665,388],{"class":295},[131,667,668,670,672,674],{"class":133,"line":172},[131,669,478],{"class":291},[131,671,481],{"class":291},[131,673,570],{"class":144},[131,675,547],{"class":295},[131,677,678,680,682,684,686],{"class":133,"line":184},[131,679,592],{"class":144},[131,681,595],{"class":295},[131,683,567],{"class":291},[131,685,600],{"class":152},[131,687,547],{"class":295},[131,689,690,692],{"class":133,"line":189},[131,691,607],{"class":291},[131,693,694],{"class":148}," 'Hello World!'\n",[131,696,697],{"class":133,"line":195},[131,698,623],{"class":295},[131,700,701],{"class":133,"line":203},[131,702,380],{"class":295},[10,704,706],{"id":705},"mysql環境の構築","MySQL環境の構築",[116,708,710],{"id":709},"docker-composeymlの作成","docker-compose.ymlの作成",[121,712,716],{"className":713,"code":714,"language":715,"meta":126,"style":126},"language-yaml shiki shiki-themes github-light github-dark","# docker-compose.yml\nversion: '3'\n\nservices:\n  db:\n    image: mysql:8.0\n    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci\n    container_name: meetup_db_container\n    volumes:\n      - mysql-data-volume:\u002Fvar\u002Flib\u002Fmysql\n    ports:\n      - \"3306:3306\"\n    environment:\n      TZ: 'Asia\u002FTokyo'\n      MYSQL_ROOT_PASSWORD: password\n      MYSQL_DATABASE: meetup\n      MYSQL_USER: app\n      MYSQL_PASSWORD: secret\n\nvolumes:\n  mysql-data-volume:\n","yaml",[128,717,718,723,735,739,747,754,764,774,784,791,799,806,813,820,830,841,852,863,874,879,887],{"__ignoreMap":126},[131,719,720],{"class":133,"line":134},[131,721,722],{"class":137},"# docker-compose.yml\n",[131,724,725,729,732],{"class":133,"line":141},[131,726,728],{"class":727},"s9eBZ","version",[131,730,731],{"class":295},": ",[131,733,734],{"class":148},"'3'\n",[131,736,737],{"class":133,"line":159},[131,738,163],{"emptyLinePlaceholder":162},[131,740,741,744],{"class":133,"line":166},[131,742,743],{"class":727},"services",[131,745,746],{"class":295},":\n",[131,748,749,752],{"class":133,"line":172},[131,750,751],{"class":727},"  db",[131,753,746],{"class":295},[131,755,756,759,761],{"class":133,"line":184},[131,757,758],{"class":727},"    image",[131,760,731],{"class":295},[131,762,763],{"class":148},"mysql:8.0\n",[131,765,766,769,771],{"class":133,"line":189},[131,767,768],{"class":727},"    command",[131,770,731],{"class":295},[131,772,773],{"class":148},"mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci\n",[131,775,776,779,781],{"class":133,"line":195},[131,777,778],{"class":727},"    container_name",[131,780,731],{"class":295},[131,782,783],{"class":148},"meetup_db_container\n",[131,785,786,789],{"class":133,"line":203},[131,787,788],{"class":727},"    volumes",[131,790,746],{"class":295},[131,792,793,796],{"class":133,"line":208},[131,794,795],{"class":295},"      - ",[131,797,798],{"class":148},"mysql-data-volume:\u002Fvar\u002Flib\u002Fmysql\n",[131,800,801,804],{"class":133,"line":214},[131,802,803],{"class":727},"    ports",[131,805,746],{"class":295},[131,807,808,810],{"class":133,"line":222},[131,809,795],{"class":295},[131,811,812],{"class":148},"\"3306:3306\"\n",[131,814,815,818],{"class":133,"line":227},[131,816,817],{"class":727},"    environment",[131,819,746],{"class":295},[131,821,822,825,827],{"class":133,"line":233},[131,823,824],{"class":727},"      TZ",[131,826,731],{"class":295},[131,828,829],{"class":148},"'Asia\u002FTokyo'\n",[131,831,833,836,838],{"class":133,"line":832},15,[131,834,835],{"class":727},"      MYSQL_ROOT_PASSWORD",[131,837,731],{"class":295},[131,839,840],{"class":148},"password\n",[131,842,844,847,849],{"class":133,"line":843},16,[131,845,846],{"class":727},"      MYSQL_DATABASE",[131,848,731],{"class":295},[131,850,851],{"class":148},"meetup\n",[131,853,855,858,860],{"class":133,"line":854},17,[131,856,857],{"class":727},"      MYSQL_USER",[131,859,731],{"class":295},[131,861,862],{"class":148},"app\n",[131,864,866,869,871],{"class":133,"line":865},18,[131,867,868],{"class":727},"      MYSQL_PASSWORD",[131,870,731],{"class":295},[131,872,873],{"class":148},"secret\n",[131,875,877],{"class":133,"line":876},19,[131,878,163],{"emptyLinePlaceholder":162},[131,880,882,885],{"class":133,"line":881},20,[131,883,884],{"class":727},"volumes",[131,886,746],{"class":295},[131,888,890,893],{"class":133,"line":889},21,[131,891,892],{"class":727},"  mysql-data-volume",[131,894,746],{"class":295},[116,896,897],{"id":897},"コンテナの起動",[121,899,901],{"className":123,"code":900,"language":125,"meta":126,"style":126},"docker compose up -d\n\n# 起動確認\ndocker compose ps\n\n# コンテナに入って接続確認\ndocker compose exec db bash\nmysql -u root -p\n# password: password\n",[128,902,903,917,921,926,935,939,944,959,973],{"__ignoreMap":126},[131,904,905,908,911,914],{"class":133,"line":134},[131,906,907],{"class":144},"docker",[131,909,910],{"class":148}," compose",[131,912,913],{"class":148}," up",[131,915,916],{"class":152}," -d\n",[131,918,919],{"class":133,"line":141},[131,920,163],{"emptyLinePlaceholder":162},[131,922,923],{"class":133,"line":159},[131,924,925],{"class":137},"# 起動確認\n",[131,927,928,930,932],{"class":133,"line":166},[131,929,907],{"class":144},[131,931,910],{"class":148},[131,933,934],{"class":148}," ps\n",[131,936,937],{"class":133,"line":172},[131,938,163],{"emptyLinePlaceholder":162},[131,940,941],{"class":133,"line":184},[131,942,943],{"class":137},"# コンテナに入って接続確認\n",[131,945,946,948,950,953,956],{"class":133,"line":189},[131,947,907],{"class":144},[131,949,910],{"class":148},[131,951,952],{"class":148}," exec",[131,954,955],{"class":148}," db",[131,957,958],{"class":148}," bash\n",[131,960,961,964,967,970],{"class":133,"line":195},[131,962,963],{"class":144},"mysql",[131,965,966],{"class":152}," -u",[131,968,969],{"class":148}," root",[131,971,972],{"class":152}," -p\n",[131,974,975],{"class":133,"line":203},[131,976,977],{"class":137},"# password: password\n",[10,979,981],{"id":980},"typeormの設定","TypeORMの設定",[116,983,984],{"id":984},"必要なパッケージのインストール",[121,986,988],{"className":123,"code":987,"language":125,"meta":126,"style":126},"npm install --save @nestjs\u002Ftypeorm typeorm@0.2 mysql2\nnpm install --save @nestjs\u002Fconfig\n",[128,989,990,1008],{"__ignoreMap":126},[131,991,992,994,996,999,1002,1005],{"class":133,"line":134},[131,993,145],{"class":144},[131,995,149],{"class":148},[131,997,998],{"class":152}," --save",[131,1000,1001],{"class":148}," @nestjs\u002Ftypeorm",[131,1003,1004],{"class":148}," typeorm@0.2",[131,1006,1007],{"class":148}," mysql2\n",[131,1009,1010,1012,1014,1016],{"class":133,"line":141},[131,1011,145],{"class":144},[131,1013,149],{"class":148},[131,1015,998],{"class":152},[131,1017,1018],{"class":148}," @nestjs\u002Fconfig\n",[116,1020,1021],{"id":1021},"設定ファイルの作成",[121,1023,1025],{"className":277,"code":1024,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fconfig\u002Fconfiguration.ts\nexport default () => ({\n  nodeEnv: process.env.NODE_ENV || 'development',\n  server: {\n    port: parseInt(process.env.PORT) || 3000,\n    hostName: process.env.hostname || 'localhost:3000',\n  },\n  database: {\n    host: process.env.DB_HOST || 'localhost',\n    port: parseInt(process.env.DB_PORT) || 3306,\n    user: process.env.DB_USERNAME || 'root',\n    pass: process.env.DB_PASSWORD || 'password',\n    name: process.env.DB_NAME || 'meetup',\n  },\n})\n",[128,1026,1027,1032,1048,1065,1070,1095,1107,1112,1117,1132,1152,1167,1182,1197,1201],{"__ignoreMap":126},[131,1028,1029],{"class":133,"line":134},[131,1030,1031],{"class":137},"\u002F\u002F src\u002Fconfig\u002Fconfiguration.ts\n",[131,1033,1034,1036,1039,1042,1045],{"class":133,"line":141},[131,1035,478],{"class":291},[131,1037,1038],{"class":291}," default",[131,1040,1041],{"class":295}," () ",[131,1043,1044],{"class":291},"=>",[131,1046,1047],{"class":295}," ({\n",[131,1049,1050,1053,1056,1059,1062],{"class":133,"line":159},[131,1051,1052],{"class":295},"  nodeEnv: process.env.",[131,1054,1055],{"class":152},"NODE_ENV",[131,1057,1058],{"class":291}," ||",[131,1060,1061],{"class":148}," 'development'",[131,1063,1064],{"class":295},",\n",[131,1066,1067],{"class":133,"line":166},[131,1068,1069],{"class":295},"  server: {\n",[131,1071,1072,1075,1078,1081,1084,1087,1090,1093],{"class":133,"line":172},[131,1073,1074],{"class":295},"    port: ",[131,1076,1077],{"class":144},"parseInt",[131,1079,1080],{"class":295},"(process.env.",[131,1082,1083],{"class":152},"PORT",[131,1085,1086],{"class":295},") ",[131,1088,1089],{"class":291},"||",[131,1091,1092],{"class":152}," 3000",[131,1094,1064],{"class":295},[131,1096,1097,1100,1102,1105],{"class":133,"line":184},[131,1098,1099],{"class":295},"    hostName: process.env.hostname ",[131,1101,1089],{"class":291},[131,1103,1104],{"class":148}," 'localhost:3000'",[131,1106,1064],{"class":295},[131,1108,1109],{"class":133,"line":189},[131,1110,1111],{"class":295},"  },\n",[131,1113,1114],{"class":133,"line":195},[131,1115,1116],{"class":295},"  database: {\n",[131,1118,1119,1122,1125,1127,1130],{"class":133,"line":203},[131,1120,1121],{"class":295},"    host: process.env.",[131,1123,1124],{"class":152},"DB_HOST",[131,1126,1058],{"class":291},[131,1128,1129],{"class":148}," 'localhost'",[131,1131,1064],{"class":295},[131,1133,1134,1136,1138,1140,1143,1145,1147,1150],{"class":133,"line":208},[131,1135,1074],{"class":295},[131,1137,1077],{"class":144},[131,1139,1080],{"class":295},[131,1141,1142],{"class":152},"DB_PORT",[131,1144,1086],{"class":295},[131,1146,1089],{"class":291},[131,1148,1149],{"class":152}," 3306",[131,1151,1064],{"class":295},[131,1153,1154,1157,1160,1162,1165],{"class":133,"line":214},[131,1155,1156],{"class":295},"    user: process.env.",[131,1158,1159],{"class":152},"DB_USERNAME",[131,1161,1058],{"class":291},[131,1163,1164],{"class":148}," 'root'",[131,1166,1064],{"class":295},[131,1168,1169,1172,1175,1177,1180],{"class":133,"line":222},[131,1170,1171],{"class":295},"    pass: process.env.",[131,1173,1174],{"class":152},"DB_PASSWORD",[131,1176,1058],{"class":291},[131,1178,1179],{"class":148}," 'password'",[131,1181,1064],{"class":295},[131,1183,1184,1187,1190,1192,1195],{"class":133,"line":227},[131,1185,1186],{"class":295},"    name: process.env.",[131,1188,1189],{"class":152},"DB_NAME",[131,1191,1058],{"class":291},[131,1193,1194],{"class":148}," 'meetup'",[131,1196,1064],{"class":295},[131,1198,1199],{"class":133,"line":233},[131,1200,1111],{"class":295},[131,1202,1203],{"class":133,"line":832},[131,1204,473],{"class":295},[116,1206,1208],{"id":1207},"appmoduleへの統合","AppModuleへの統合",[121,1210,1212],{"className":277,"code":1211,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fmodules\u002Fapp.module.ts\nimport { Module } from '@nestjs\u002Fcommon'\nimport { ConfigModule, ConfigService } from '@nestjs\u002Fconfig'\nimport { TypeOrmModule } from '@nestjs\u002Ftypeorm'\nimport configuration from '..\u002Fconfig\u002Fconfiguration'\nimport { join } from 'path'\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      isGlobal: true,\n      load: [configuration],\n    }),\n    TypeOrmModule.forRootAsync({\n      imports: [ConfigModule],\n      useFactory: (configService: ConfigService) => ({\n        type: 'mysql',\n        host: configService.get('database.host'),\n        port: configService.get('database.port'),\n        username: configService.get('database.user'),\n        password: configService.get('database.pass'),\n        database: configService.get('database.name'),\n        entities: [join(__dirname, '..\u002Fentities\u002F*.entity.{ts,js}')],\n        synchronize: false,\n        logging: configService.get('nodeEnv') === 'development',\n      }),\n      inject: [ConfigService],\n    }),\n  ],\n  \u002F\u002F ...\n})\nexport class AppModule {}\n",[128,1213,1214,1218,1228,1240,1252,1264,1276,1280,1288,1293,1303,1313,1318,1323,1333,1338,1360,1370,1386,1400,1414,1428,1443,1461,1472,1494,1500,1506,1511,1517,1523,1528],{"__ignoreMap":126},[131,1215,1216],{"class":133,"line":134},[131,1217,402],{"class":137},[131,1219,1220,1222,1224,1226],{"class":133,"line":141},[131,1221,292],{"class":291},[131,1223,409],{"class":295},[131,1225,299],{"class":291},[131,1227,414],{"class":148},[131,1229,1230,1232,1235,1237],{"class":133,"line":159},[131,1231,292],{"class":291},[131,1233,1234],{"class":295}," { ConfigModule, ConfigService } ",[131,1236,299],{"class":291},[131,1238,1239],{"class":148}," '@nestjs\u002Fconfig'\n",[131,1241,1242,1244,1247,1249],{"class":133,"line":166},[131,1243,292],{"class":291},[131,1245,1246],{"class":295}," { TypeOrmModule } ",[131,1248,299],{"class":291},[131,1250,1251],{"class":148}," '@nestjs\u002Ftypeorm'\n",[131,1253,1254,1256,1259,1261],{"class":133,"line":172},[131,1255,292],{"class":291},[131,1257,1258],{"class":295}," configuration ",[131,1260,299],{"class":291},[131,1262,1263],{"class":148}," '..\u002Fconfig\u002Fconfiguration'\n",[131,1265,1266,1268,1271,1273],{"class":133,"line":184},[131,1267,292],{"class":291},[131,1269,1270],{"class":295}," { join } ",[131,1272,299],{"class":291},[131,1274,1275],{"class":148}," 'path'\n",[131,1277,1278],{"class":133,"line":189},[131,1279,163],{"emptyLinePlaceholder":162},[131,1281,1282,1284,1286],{"class":133,"line":195},[131,1283,447],{"class":295},[131,1285,450],{"class":144},[131,1287,453],{"class":295},[131,1289,1290],{"class":133,"line":203},[131,1291,1292],{"class":295},"  imports: [\n",[131,1294,1295,1298,1301],{"class":133,"line":208},[131,1296,1297],{"class":295},"    ConfigModule.",[131,1299,1300],{"class":144},"forRoot",[131,1302,453],{"class":295},[131,1304,1305,1308,1311],{"class":133,"line":214},[131,1306,1307],{"class":295},"      isGlobal: ",[131,1309,1310],{"class":152},"true",[131,1312,1064],{"class":295},[131,1314,1315],{"class":133,"line":222},[131,1316,1317],{"class":295},"      load: [configuration],\n",[131,1319,1320],{"class":133,"line":227},[131,1321,1322],{"class":295},"    }),\n",[131,1324,1325,1328,1331],{"class":133,"line":233},[131,1326,1327],{"class":295},"    TypeOrmModule.",[131,1329,1330],{"class":144},"forRootAsync",[131,1332,453],{"class":295},[131,1334,1335],{"class":133,"line":832},[131,1336,1337],{"class":295},"      imports: [ConfigModule],\n",[131,1339,1340,1343,1346,1349,1351,1354,1356,1358],{"class":133,"line":843},[131,1341,1342],{"class":144},"      useFactory",[131,1344,1345],{"class":295},": (",[131,1347,1348],{"class":563},"configService",[131,1350,567],{"class":291},[131,1352,1353],{"class":144}," ConfigService",[131,1355,1086],{"class":295},[131,1357,1044],{"class":291},[131,1359,1047],{"class":295},[131,1361,1362,1365,1368],{"class":133,"line":854},[131,1363,1364],{"class":295},"        type: ",[131,1366,1367],{"class":148},"'mysql'",[131,1369,1064],{"class":295},[131,1371,1372,1375,1378,1380,1383],{"class":133,"line":865},[131,1373,1374],{"class":295},"        host: configService.",[131,1376,1377],{"class":144},"get",[131,1379,369],{"class":295},[131,1381,1382],{"class":148},"'database.host'",[131,1384,1385],{"class":295},"),\n",[131,1387,1388,1391,1393,1395,1398],{"class":133,"line":876},[131,1389,1390],{"class":295},"        port: configService.",[131,1392,1377],{"class":144},[131,1394,369],{"class":295},[131,1396,1397],{"class":148},"'database.port'",[131,1399,1385],{"class":295},[131,1401,1402,1405,1407,1409,1412],{"class":133,"line":881},[131,1403,1404],{"class":295},"        username: configService.",[131,1406,1377],{"class":144},[131,1408,369],{"class":295},[131,1410,1411],{"class":148},"'database.user'",[131,1413,1385],{"class":295},[131,1415,1416,1419,1421,1423,1426],{"class":133,"line":889},[131,1417,1418],{"class":295},"        password: configService.",[131,1420,1377],{"class":144},[131,1422,369],{"class":295},[131,1424,1425],{"class":148},"'database.pass'",[131,1427,1385],{"class":295},[131,1429,1431,1434,1436,1438,1441],{"class":133,"line":1430},22,[131,1432,1433],{"class":295},"        database: configService.",[131,1435,1377],{"class":144},[131,1437,369],{"class":295},[131,1439,1440],{"class":148},"'database.name'",[131,1442,1385],{"class":295},[131,1444,1446,1449,1452,1455,1458],{"class":133,"line":1445},23,[131,1447,1448],{"class":295},"        entities: [",[131,1450,1451],{"class":144},"join",[131,1453,1454],{"class":295},"(__dirname, ",[131,1456,1457],{"class":148},"'..\u002Fentities\u002F*.entity.{ts,js}'",[131,1459,1460],{"class":295},")],\n",[131,1462,1464,1467,1470],{"class":133,"line":1463},24,[131,1465,1466],{"class":295},"        synchronize: ",[131,1468,1469],{"class":152},"false",[131,1471,1064],{"class":295},[131,1473,1475,1478,1480,1482,1485,1487,1490,1492],{"class":133,"line":1474},25,[131,1476,1477],{"class":295},"        logging: configService.",[131,1479,1377],{"class":144},[131,1481,369],{"class":295},[131,1483,1484],{"class":148},"'nodeEnv'",[131,1486,1086],{"class":295},[131,1488,1489],{"class":291},"===",[131,1491,1061],{"class":148},[131,1493,1064],{"class":295},[131,1495,1497],{"class":133,"line":1496},26,[131,1498,1499],{"class":295},"      }),\n",[131,1501,1503],{"class":133,"line":1502},27,[131,1504,1505],{"class":295},"      inject: [ConfigService],\n",[131,1507,1509],{"class":133,"line":1508},28,[131,1510,1322],{"class":295},[131,1512,1514],{"class":133,"line":1513},29,[131,1515,1516],{"class":295},"  ],\n",[131,1518,1520],{"class":133,"line":1519},30,[131,1521,1522],{"class":137},"  \u002F\u002F ...\n",[131,1524,1526],{"class":133,"line":1525},31,[131,1527,473],{"class":295},[131,1529,1531,1533,1535,1537],{"class":133,"line":1530},32,[131,1532,478],{"class":291},[131,1534,481],{"class":291},[131,1536,484],{"class":144},[131,1538,487],{"class":295},[10,1540,1542],{"id":1541},"crudアプリケーションの実装","CRUDアプリケーションの実装",[116,1544,1545],{"id":1545},"リソースの生成",[121,1547,1549],{"className":123,"code":1548,"language":125,"meta":126,"style":126},"nest generate resource users\n# REST APIを選択\n# CRUD entry pointsを有効化\n",[128,1550,1551,1564,1569],{"__ignoreMap":126},[131,1552,1553,1555,1558,1561],{"class":133,"line":134},[131,1554,175],{"class":144},[131,1556,1557],{"class":148}," generate",[131,1559,1560],{"class":148}," resource",[131,1562,1563],{"class":148}," users\n",[131,1565,1566],{"class":133,"line":141},[131,1567,1568],{"class":137},"# REST APIを選択\n",[131,1570,1571],{"class":133,"line":159},[131,1572,1573],{"class":137},"# CRUD entry pointsを有効化\n",[116,1575,1577],{"id":1576},"entity定義","Entity定義",[121,1579,1581],{"className":277,"code":1580,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fentities\u002Fuser.entity.ts\nimport {\n  Column,\n  CreateDateColumn,\n  DeleteDateColumn,\n  Entity,\n  PrimaryGeneratedColumn,\n  Timestamp,\n  UpdateDateColumn,\n} from 'typeorm'\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn({\n    name: 'id',\n    unsigned: true,\n    type: 'bigint',\n    comment: 'ユーザーID',\n  })\n  readonly id: number\n\n  @Column({ type: 'varchar', length: 255, comment: 'ユーザー名' })\n  name: string\n\n  @Column({ type: 'varchar', length: 255, comment: 'メールアドレス', unique: true })\n  email: string\n\n  @Column({ type: 'varchar', length: 255, comment: 'パスワード' })\n  password: string\n\n  @CreateDateColumn({ comment: '登録日時' })\n  readonly ins_ts?: Timestamp\n\n  @UpdateDateColumn({ comment: '最終更新日時' })\n  readonly upd_ts?: Timestamp\n\n  @DeleteDateColumn({ comment: '削除日時' })\n  readonly delete_ts?: Timestamp\n\n  constructor(name: string, email: string, password: string) {\n    this.name = name\n    this.email = email\n    this.password = password\n  }\n}\n",[128,1582,1583,1588,1594,1599,1604,1609,1614,1619,1624,1629,1639,1643,1657,1668,1677,1687,1696,1706,1716,1721,1734,1738,1766,1776,1780,1806,1815,1819,1840,1849,1853,1868,1881,1886,1901,1913,1918,1933,1945,1950,1986,2001,2014,2027,2032],{"__ignoreMap":126},[131,1584,1585],{"class":133,"line":134},[131,1586,1587],{"class":137},"\u002F\u002F src\u002Fentities\u002Fuser.entity.ts\n",[131,1589,1590,1592],{"class":133,"line":141},[131,1591,292],{"class":291},[131,1593,547],{"class":295},[131,1595,1596],{"class":133,"line":159},[131,1597,1598],{"class":295},"  Column,\n",[131,1600,1601],{"class":133,"line":166},[131,1602,1603],{"class":295},"  CreateDateColumn,\n",[131,1605,1606],{"class":133,"line":172},[131,1607,1608],{"class":295},"  DeleteDateColumn,\n",[131,1610,1611],{"class":133,"line":184},[131,1612,1613],{"class":295},"  Entity,\n",[131,1615,1616],{"class":133,"line":189},[131,1617,1618],{"class":295},"  PrimaryGeneratedColumn,\n",[131,1620,1621],{"class":133,"line":195},[131,1622,1623],{"class":295},"  Timestamp,\n",[131,1625,1626],{"class":133,"line":203},[131,1627,1628],{"class":295},"  UpdateDateColumn,\n",[131,1630,1631,1634,1636],{"class":133,"line":208},[131,1632,1633],{"class":295},"} ",[131,1635,299],{"class":291},[131,1637,1638],{"class":148}," 'typeorm'\n",[131,1640,1641],{"class":133,"line":214},[131,1642,163],{"emptyLinePlaceholder":162},[131,1644,1645,1647,1650,1652,1655],{"class":133,"line":222},[131,1646,447],{"class":295},[131,1648,1649],{"class":144},"Entity",[131,1651,369],{"class":295},[131,1653,1654],{"class":148},"'users'",[131,1656,375],{"class":295},[131,1658,1659,1661,1663,1666],{"class":133,"line":227},[131,1660,478],{"class":291},[131,1662,481],{"class":291},[131,1664,1665],{"class":144}," User",[131,1667,547],{"class":295},[131,1669,1670,1672,1675],{"class":133,"line":233},[131,1671,582],{"class":295},[131,1673,1674],{"class":144},"PrimaryGeneratedColumn",[131,1676,453],{"class":295},[131,1678,1679,1682,1685],{"class":133,"line":832},[131,1680,1681],{"class":295},"    name: ",[131,1683,1684],{"class":148},"'id'",[131,1686,1064],{"class":295},[131,1688,1689,1692,1694],{"class":133,"line":843},[131,1690,1691],{"class":295},"    unsigned: ",[131,1693,1310],{"class":152},[131,1695,1064],{"class":295},[131,1697,1698,1701,1704],{"class":133,"line":854},[131,1699,1700],{"class":295},"    type: ",[131,1702,1703],{"class":148},"'bigint'",[131,1705,1064],{"class":295},[131,1707,1708,1711,1714],{"class":133,"line":865},[131,1709,1710],{"class":295},"    comment: ",[131,1712,1713],{"class":148},"'ユーザーID'",[131,1715,1064],{"class":295},[131,1717,1718],{"class":133,"line":876},[131,1719,1720],{"class":295},"  })\n",[131,1722,1723,1726,1729,1731],{"class":133,"line":881},[131,1724,1725],{"class":291},"  readonly",[131,1727,1728],{"class":563}," id",[131,1730,567],{"class":291},[131,1732,1733],{"class":152}," number\n",[131,1735,1736],{"class":133,"line":889},[131,1737,163],{"emptyLinePlaceholder":162},[131,1739,1740,1742,1745,1748,1751,1754,1757,1760,1763],{"class":133,"line":1430},[131,1741,582],{"class":295},[131,1743,1744],{"class":144},"Column",[131,1746,1747],{"class":295},"({ type: ",[131,1749,1750],{"class":148},"'varchar'",[131,1752,1753],{"class":295},", length: ",[131,1755,1756],{"class":152},"255",[131,1758,1759],{"class":295},", comment: ",[131,1761,1762],{"class":148},"'ユーザー名'",[131,1764,1765],{"class":295}," })\n",[131,1767,1768,1771,1773],{"class":133,"line":1445},[131,1769,1770],{"class":563},"  name",[131,1772,567],{"class":291},[131,1774,1775],{"class":152}," string\n",[131,1777,1778],{"class":133,"line":1463},[131,1779,163],{"emptyLinePlaceholder":162},[131,1781,1782,1784,1786,1788,1790,1792,1794,1796,1799,1802,1804],{"class":133,"line":1474},[131,1783,582],{"class":295},[131,1785,1744],{"class":144},[131,1787,1747],{"class":295},[131,1789,1750],{"class":148},[131,1791,1753],{"class":295},[131,1793,1756],{"class":152},[131,1795,1759],{"class":295},[131,1797,1798],{"class":148},"'メールアドレス'",[131,1800,1801],{"class":295},", unique: ",[131,1803,1310],{"class":152},[131,1805,1765],{"class":295},[131,1807,1808,1811,1813],{"class":133,"line":1496},[131,1809,1810],{"class":563},"  email",[131,1812,567],{"class":291},[131,1814,1775],{"class":152},[131,1816,1817],{"class":133,"line":1502},[131,1818,163],{"emptyLinePlaceholder":162},[131,1820,1821,1823,1825,1827,1829,1831,1833,1835,1838],{"class":133,"line":1508},[131,1822,582],{"class":295},[131,1824,1744],{"class":144},[131,1826,1747],{"class":295},[131,1828,1750],{"class":148},[131,1830,1753],{"class":295},[131,1832,1756],{"class":152},[131,1834,1759],{"class":295},[131,1836,1837],{"class":148},"'パスワード'",[131,1839,1765],{"class":295},[131,1841,1842,1845,1847],{"class":133,"line":1513},[131,1843,1844],{"class":563},"  password",[131,1846,567],{"class":291},[131,1848,1775],{"class":152},[131,1850,1851],{"class":133,"line":1519},[131,1852,163],{"emptyLinePlaceholder":162},[131,1854,1855,1857,1860,1863,1866],{"class":133,"line":1525},[131,1856,582],{"class":295},[131,1858,1859],{"class":144},"CreateDateColumn",[131,1861,1862],{"class":295},"({ comment: ",[131,1864,1865],{"class":148},"'登録日時'",[131,1867,1765],{"class":295},[131,1869,1870,1872,1875,1878],{"class":133,"line":1530},[131,1871,1725],{"class":291},[131,1873,1874],{"class":563}," ins_ts",[131,1876,1877],{"class":291},"?:",[131,1879,1880],{"class":144}," Timestamp\n",[131,1882,1884],{"class":133,"line":1883},33,[131,1885,163],{"emptyLinePlaceholder":162},[131,1887,1889,1891,1894,1896,1899],{"class":133,"line":1888},34,[131,1890,582],{"class":295},[131,1892,1893],{"class":144},"UpdateDateColumn",[131,1895,1862],{"class":295},[131,1897,1898],{"class":148},"'最終更新日時'",[131,1900,1765],{"class":295},[131,1902,1904,1906,1909,1911],{"class":133,"line":1903},35,[131,1905,1725],{"class":291},[131,1907,1908],{"class":563}," upd_ts",[131,1910,1877],{"class":291},[131,1912,1880],{"class":144},[131,1914,1916],{"class":133,"line":1915},36,[131,1917,163],{"emptyLinePlaceholder":162},[131,1919,1921,1923,1926,1928,1931],{"class":133,"line":1920},37,[131,1922,582],{"class":295},[131,1924,1925],{"class":144},"DeleteDateColumn",[131,1927,1862],{"class":295},[131,1929,1930],{"class":148},"'削除日時'",[131,1932,1765],{"class":295},[131,1934,1936,1938,1941,1943],{"class":133,"line":1935},38,[131,1937,1725],{"class":291},[131,1939,1940],{"class":563}," delete_ts",[131,1942,1877],{"class":291},[131,1944,1880],{"class":144},[131,1946,1948],{"class":133,"line":1947},39,[131,1949,163],{"emptyLinePlaceholder":162},[131,1951,1953,1955,1957,1960,1962,1964,1967,1970,1972,1974,1976,1979,1981,1983],{"class":133,"line":1952},40,[131,1954,552],{"class":291},[131,1956,369],{"class":295},[131,1958,1959],{"class":563},"name",[131,1961,567],{"class":291},[131,1963,600],{"class":152},[131,1965,1966],{"class":295},", ",[131,1968,1969],{"class":563},"email",[131,1971,567],{"class":291},[131,1973,600],{"class":152},[131,1975,1966],{"class":295},[131,1977,1978],{"class":563},"password",[131,1980,567],{"class":291},[131,1982,600],{"class":152},[131,1984,1985],{"class":295},") {\n",[131,1987,1989,1992,1995,1998],{"class":133,"line":1988},41,[131,1990,1991],{"class":152},"    this",[131,1993,1994],{"class":295},".name ",[131,1996,1997],{"class":291},"=",[131,1999,2000],{"class":295}," name\n",[131,2002,2004,2006,2009,2011],{"class":133,"line":2003},42,[131,2005,1991],{"class":152},[131,2007,2008],{"class":295},".email ",[131,2010,1997],{"class":291},[131,2012,2013],{"class":295}," email\n",[131,2015,2017,2019,2022,2024],{"class":133,"line":2016},43,[131,2018,1991],{"class":152},[131,2020,2021],{"class":295},".password ",[131,2023,1997],{"class":291},[131,2025,2026],{"class":295}," password\n",[131,2028,2030],{"class":133,"line":2029},44,[131,2031,623],{"class":295},[131,2033,2035],{"class":133,"line":2034},45,[131,2036,380],{"class":295},[116,2038,2040],{"id":2039},"typeorm設定ファイル","TypeORM設定ファイル",[121,2042,2044],{"className":277,"code":2043,"language":279,"meta":126,"style":126},"\u002F\u002F ormconfig.ts\nmodule.exports = {\n  type: 'mysql',\n  host: process.env.DB_HOST || 'localhost',\n  port: process.env.DB_PORT || '3306',\n  username: process.env.DB_USERNAME || 'root',\n  password: process.env.DB_PASSWORD || 'password',\n  database: process.env.DB_NAME || 'meetup',\n  synchronize: false,\n  logging: true,\n  entities: ['src\u002Fentities\u002F*.ts'],\n  migrations: ['src\u002Fdatabases\u002Fmigrations\u002F*.ts'],\n  cli: {\n    migrationsDir: 'src\u002Fdatabases\u002Fmigrations',\n    entitiesDir: 'src\u002Fentities',\n  },\n}\n",[128,2045,2046,2051,2066,2075,2088,2102,2115,2128,2141,2150,2159,2170,2180,2185,2195,2205,2209],{"__ignoreMap":126},[131,2047,2048],{"class":133,"line":134},[131,2049,2050],{"class":137},"\u002F\u002F ormconfig.ts\n",[131,2052,2053,2056,2059,2062,2064],{"class":133,"line":141},[131,2054,2055],{"class":152},"module",[131,2057,2058],{"class":295},".",[131,2060,2061],{"class":152},"exports",[131,2063,343],{"class":291},[131,2065,547],{"class":295},[131,2067,2068,2071,2073],{"class":133,"line":159},[131,2069,2070],{"class":295},"  type: ",[131,2072,1367],{"class":148},[131,2074,1064],{"class":295},[131,2076,2077,2080,2082,2084,2086],{"class":133,"line":166},[131,2078,2079],{"class":295},"  host: process.env.",[131,2081,1124],{"class":152},[131,2083,1058],{"class":291},[131,2085,1129],{"class":148},[131,2087,1064],{"class":295},[131,2089,2090,2093,2095,2097,2100],{"class":133,"line":172},[131,2091,2092],{"class":295},"  port: process.env.",[131,2094,1142],{"class":152},[131,2096,1058],{"class":291},[131,2098,2099],{"class":148}," '3306'",[131,2101,1064],{"class":295},[131,2103,2104,2107,2109,2111,2113],{"class":133,"line":184},[131,2105,2106],{"class":295},"  username: process.env.",[131,2108,1159],{"class":152},[131,2110,1058],{"class":291},[131,2112,1164],{"class":148},[131,2114,1064],{"class":295},[131,2116,2117,2120,2122,2124,2126],{"class":133,"line":189},[131,2118,2119],{"class":295},"  password: process.env.",[131,2121,1174],{"class":152},[131,2123,1058],{"class":291},[131,2125,1179],{"class":148},[131,2127,1064],{"class":295},[131,2129,2130,2133,2135,2137,2139],{"class":133,"line":195},[131,2131,2132],{"class":295},"  database: process.env.",[131,2134,1189],{"class":152},[131,2136,1058],{"class":291},[131,2138,1194],{"class":148},[131,2140,1064],{"class":295},[131,2142,2143,2146,2148],{"class":133,"line":203},[131,2144,2145],{"class":295},"  synchronize: ",[131,2147,1469],{"class":152},[131,2149,1064],{"class":295},[131,2151,2152,2155,2157],{"class":133,"line":208},[131,2153,2154],{"class":295},"  logging: ",[131,2156,1310],{"class":152},[131,2158,1064],{"class":295},[131,2160,2161,2164,2167],{"class":133,"line":214},[131,2162,2163],{"class":295},"  entities: [",[131,2165,2166],{"class":148},"'src\u002Fentities\u002F*.ts'",[131,2168,2169],{"class":295},"],\n",[131,2171,2172,2175,2178],{"class":133,"line":222},[131,2173,2174],{"class":295},"  migrations: [",[131,2176,2177],{"class":148},"'src\u002Fdatabases\u002Fmigrations\u002F*.ts'",[131,2179,2169],{"class":295},[131,2181,2182],{"class":133,"line":227},[131,2183,2184],{"class":295},"  cli: {\n",[131,2186,2187,2190,2193],{"class":133,"line":233},[131,2188,2189],{"class":295},"    migrationsDir: ",[131,2191,2192],{"class":148},"'src\u002Fdatabases\u002Fmigrations'",[131,2194,1064],{"class":295},[131,2196,2197,2200,2203],{"class":133,"line":832},[131,2198,2199],{"class":295},"    entitiesDir: ",[131,2201,2202],{"class":148},"'src\u002Fentities'",[131,2204,1064],{"class":295},[131,2206,2207],{"class":133,"line":843},[131,2208,1111],{"class":295},[131,2210,2211],{"class":133,"line":854},[131,2212,380],{"class":295},[116,2214,2215],{"id":2215},"マイグレーションの実行",[121,2217,2219],{"className":123,"code":2218,"language":125,"meta":126,"style":126},"# ビルド\nnpm run build\n\n# マイグレーションファイルを生成\nnpx ts-node .\u002Fnode_modules\u002F.bin\u002Ftypeorm migration:generate --name user\n\n# マイグレーションを実行\nnpx ts-node .\u002Fnode_modules\u002F.bin\u002Ftypeorm migration:run\n",[128,2220,2221,2226,2235,2239,2244,2264,2268,2273],{"__ignoreMap":126},[131,2222,2223],{"class":133,"line":134},[131,2224,2225],{"class":137},"# ビルド\n",[131,2227,2228,2230,2232],{"class":133,"line":141},[131,2229,145],{"class":144},[131,2231,238],{"class":148},[131,2233,2234],{"class":148}," build\n",[131,2236,2237],{"class":133,"line":159},[131,2238,163],{"emptyLinePlaceholder":162},[131,2240,2241],{"class":133,"line":166},[131,2242,2243],{"class":137},"# マイグレーションファイルを生成\n",[131,2245,2246,2249,2252,2255,2258,2261],{"class":133,"line":172},[131,2247,2248],{"class":144},"npx",[131,2250,2251],{"class":148}," ts-node",[131,2253,2254],{"class":148}," .\u002Fnode_modules\u002F.bin\u002Ftypeorm",[131,2256,2257],{"class":148}," migration:generate",[131,2259,2260],{"class":152}," --name",[131,2262,2263],{"class":148}," user\n",[131,2265,2266],{"class":133,"line":184},[131,2267,163],{"emptyLinePlaceholder":162},[131,2269,2270],{"class":133,"line":189},[131,2271,2272],{"class":137},"# マイグレーションを実行\n",[131,2274,2275,2277,2279,2281],{"class":133,"line":195},[131,2276,2248],{"class":144},[131,2278,2251],{"class":148},[131,2280,2254],{"class":148},[131,2282,2283],{"class":148}," migration:run\n",[116,2285,2287],{"id":2286},"dto定義","DTO定義",[121,2289,2291],{"className":123,"code":2290,"language":125,"meta":126,"style":126},"npm install --save class-validator class-transformer\n",[128,2292,2293],{"__ignoreMap":126},[131,2294,2295,2297,2299,2301,2304],{"class":133,"line":134},[131,2296,145],{"class":144},[131,2298,149],{"class":148},[131,2300,998],{"class":152},[131,2302,2303],{"class":148}," class-validator",[131,2305,2306],{"class":148}," class-transformer\n",[121,2308,2310],{"className":277,"code":2309,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fdto\u002Fcreate-user.dto.ts\nimport { IsEmail, IsNotEmpty, Matches, MaxLength } from 'class-validator'\n\nexport class CreateUserDto {\n  @IsNotEmpty({ message: '名前は必ず入力してください' })\n  @MaxLength(255, { message: '名前は255文字以内で入力してください' })\n  name: string\n\n  @IsNotEmpty({ message: 'Emailは必ず入力してください' })\n  @MaxLength(255, { message: 'Emailは255文字以内で入力してください' })\n  @IsEmail({}, { message: '正しいEmail形式で入力してください' })\n  email: string\n\n  @IsNotEmpty({ message: 'パスワードは必ず入力してください' })\n  @Matches(\u002F^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,25}$\u002F, {\n    message: 'パスワードは大文字小文字を含む8文字以上25文字以内で設定してください',\n  })\n  password: string\n}\n",[128,2311,2312,2317,2329,2333,2344,2359,2378,2386,2390,2403,2420,2435,2443,2447,2460,2519,2529,2533,2541],{"__ignoreMap":126},[131,2313,2314],{"class":133,"line":134},[131,2315,2316],{"class":137},"\u002F\u002F src\u002Fdto\u002Fcreate-user.dto.ts\n",[131,2318,2319,2321,2324,2326],{"class":133,"line":141},[131,2320,292],{"class":291},[131,2322,2323],{"class":295}," { IsEmail, IsNotEmpty, Matches, MaxLength } ",[131,2325,299],{"class":291},[131,2327,2328],{"class":148}," 'class-validator'\n",[131,2330,2331],{"class":133,"line":159},[131,2332,163],{"emptyLinePlaceholder":162},[131,2334,2335,2337,2339,2342],{"class":133,"line":166},[131,2336,478],{"class":291},[131,2338,481],{"class":291},[131,2340,2341],{"class":144}," CreateUserDto",[131,2343,547],{"class":295},[131,2345,2346,2348,2351,2354,2357],{"class":133,"line":172},[131,2347,582],{"class":295},[131,2349,2350],{"class":144},"IsNotEmpty",[131,2352,2353],{"class":295},"({ message: ",[131,2355,2356],{"class":148},"'名前は必ず入力してください'",[131,2358,1765],{"class":295},[131,2360,2361,2363,2366,2368,2370,2373,2376],{"class":133,"line":184},[131,2362,582],{"class":295},[131,2364,2365],{"class":144},"MaxLength",[131,2367,369],{"class":295},[131,2369,1756],{"class":152},[131,2371,2372],{"class":295},", { message: ",[131,2374,2375],{"class":148},"'名前は255文字以内で入力してください'",[131,2377,1765],{"class":295},[131,2379,2380,2382,2384],{"class":133,"line":189},[131,2381,1770],{"class":563},[131,2383,567],{"class":291},[131,2385,1775],{"class":152},[131,2387,2388],{"class":133,"line":195},[131,2389,163],{"emptyLinePlaceholder":162},[131,2391,2392,2394,2396,2398,2401],{"class":133,"line":203},[131,2393,582],{"class":295},[131,2395,2350],{"class":144},[131,2397,2353],{"class":295},[131,2399,2400],{"class":148},"'Emailは必ず入力してください'",[131,2402,1765],{"class":295},[131,2404,2405,2407,2409,2411,2413,2415,2418],{"class":133,"line":208},[131,2406,582],{"class":295},[131,2408,2365],{"class":144},[131,2410,369],{"class":295},[131,2412,1756],{"class":152},[131,2414,2372],{"class":295},[131,2416,2417],{"class":148},"'Emailは255文字以内で入力してください'",[131,2419,1765],{"class":295},[131,2421,2422,2424,2427,2430,2433],{"class":133,"line":214},[131,2423,582],{"class":295},[131,2425,2426],{"class":144},"IsEmail",[131,2428,2429],{"class":295},"({}, { message: ",[131,2431,2432],{"class":148},"'正しいEmail形式で入力してください'",[131,2434,1765],{"class":295},[131,2436,2437,2439,2441],{"class":133,"line":222},[131,2438,1810],{"class":563},[131,2440,567],{"class":291},[131,2442,1775],{"class":152},[131,2444,2445],{"class":133,"line":227},[131,2446,163],{"emptyLinePlaceholder":162},[131,2448,2449,2451,2453,2455,2458],{"class":133,"line":233},[131,2450,582],{"class":295},[131,2452,2350],{"class":144},[131,2454,2353],{"class":295},[131,2456,2457],{"class":148},"'パスワードは必ず入力してください'",[131,2459,1765],{"class":295},[131,2461,2462,2464,2467,2469,2472,2475,2479,2481,2484,2487,2490,2492,2494,2497,2499,2501,2503,2506,2509,2511,2514,2516],{"class":133,"line":832},[131,2463,582],{"class":295},[131,2465,2466],{"class":144},"Matches",[131,2468,369],{"class":295},[131,2470,2471],{"class":148},"\u002F",[131,2473,2474],{"class":291},"^",[131,2476,2478],{"class":2477},"sA_wV","(?=",[131,2480,2058],{"class":152},[131,2482,2483],{"class":291},"*",[131,2485,2486],{"class":152},"\\d",[131,2488,2489],{"class":2477},")(?=",[131,2491,2058],{"class":152},[131,2493,2483],{"class":291},[131,2495,2496],{"class":152},"[a-z]",[131,2498,2489],{"class":2477},[131,2500,2058],{"class":152},[131,2502,2483],{"class":291},[131,2504,2505],{"class":152},"[A-Z]",[131,2507,2508],{"class":2477},")",[131,2510,2058],{"class":152},[131,2512,2513],{"class":291},"{8,25}$",[131,2515,2471],{"class":148},[131,2517,2518],{"class":295},", {\n",[131,2520,2521,2524,2527],{"class":133,"line":843},[131,2522,2523],{"class":295},"    message: ",[131,2525,2526],{"class":148},"'パスワードは大文字小文字を含む8文字以上25文字以内で設定してください'",[131,2528,1064],{"class":295},[131,2530,2531],{"class":133,"line":854},[131,2532,1720],{"class":295},[131,2534,2535,2537,2539],{"class":133,"line":865},[131,2536,1844],{"class":563},[131,2538,567],{"class":291},[131,2540,1775],{"class":152},[131,2542,2543],{"class":133,"line":876},[131,2544,380],{"class":295},[116,2546,2548],{"id":2547},"service実装","Service実装",[121,2550,2552],{"className":123,"code":2551,"language":125,"meta":126,"style":126},"npm install bcrypt\nnpm install -D @types\u002Fbcrypt\n",[128,2553,2554,2563],{"__ignoreMap":126},[131,2555,2556,2558,2560],{"class":133,"line":134},[131,2557,145],{"class":144},[131,2559,149],{"class":148},[131,2561,2562],{"class":148}," bcrypt\n",[131,2564,2565,2567,2569,2572],{"class":133,"line":141},[131,2566,145],{"class":144},[131,2568,149],{"class":148},[131,2570,2571],{"class":152}," -D",[131,2573,2574],{"class":148}," @types\u002Fbcrypt\n",[121,2576,2578],{"className":277,"code":2577,"language":279,"meta":126,"style":126},"\u002F\u002F src\u002Fservices\u002Fusers.service.ts\nimport { Injectable, BadRequestException } from '@nestjs\u002Fcommon'\nimport { InjectRepository } from '@nestjs\u002Ftypeorm'\nimport { Repository } from 'typeorm'\nimport { User } from '..\u002Fentities\u002Fuser.entity'\nimport { CreateUserDto } from '..\u002Fdto\u002Fcreate-user.dto'\nimport * as bcrypt from 'bcrypt'\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private usersRepository: Repository\u003CUser>,\n  ) {}\n\n  async create(createUserDto: CreateUserDto): Promise\u003C{ message: string }> {\n    const existingUser = await this.usersRepository.findOne({\n      where: { email: createUserDto.email },\n    })\n\n    if (existingUser) {\n      throw new BadRequestException('既に登録済みのメールアドレスです')\n    }\n\n    await this.usersRepository.save({\n      name: createUserDto.name,\n      email: createUserDto.email,\n      password: await bcrypt.hash(createUserDto.password, 10),\n    })\n\n    return { message: 'ユーザーの登録に成功しました' }\n  }\n\n  async findAll(): Promise\u003CUser[]> {\n    return this.usersRepository.find()\n  }\n\n  async findOne(id: number): Promise\u003CUser> {\n    return this.usersRepository.findOneOrFail(id)\n  }\n\n  \u002F\u002F update, removeメソッドも同様に実装\n}\n",[128,2579,2580,2585,2596,2607,2618,2630,2642,2660,2664,2672,2683,2690,2701,2723,2728,2732,2769,2791,2796,2801,2805,2813,2830,2835,2839,2853,2858,2863,2885,2889,2893,2906,2910,2914,2934,2947,2951,2955,2985,2999,3003,3007,3012],{"__ignoreMap":126},[131,2581,2582],{"class":133,"line":134},[131,2583,2584],{"class":137},"\u002F\u002F src\u002Fservices\u002Fusers.service.ts\n",[131,2586,2587,2589,2592,2594],{"class":133,"line":141},[131,2588,292],{"class":291},[131,2590,2591],{"class":295}," { Injectable, BadRequestException } ",[131,2593,299],{"class":291},[131,2595,414],{"class":148},[131,2597,2598,2600,2603,2605],{"class":133,"line":159},[131,2599,292],{"class":291},[131,2601,2602],{"class":295}," { InjectRepository } ",[131,2604,299],{"class":291},[131,2606,1251],{"class":148},[131,2608,2609,2611,2614,2616],{"class":133,"line":166},[131,2610,292],{"class":291},[131,2612,2613],{"class":295}," { Repository } ",[131,2615,299],{"class":291},[131,2617,1638],{"class":148},[131,2619,2620,2622,2625,2627],{"class":133,"line":172},[131,2621,292],{"class":291},[131,2623,2624],{"class":295}," { User } ",[131,2626,299],{"class":291},[131,2628,2629],{"class":148}," '..\u002Fentities\u002Fuser.entity'\n",[131,2631,2632,2634,2637,2639],{"class":133,"line":184},[131,2633,292],{"class":291},[131,2635,2636],{"class":295}," { CreateUserDto } ",[131,2638,299],{"class":291},[131,2640,2641],{"class":148}," '..\u002Fdto\u002Fcreate-user.dto'\n",[131,2643,2644,2646,2649,2652,2655,2657],{"class":133,"line":189},[131,2645,292],{"class":291},[131,2647,2648],{"class":152}," *",[131,2650,2651],{"class":291}," as",[131,2653,2654],{"class":295}," bcrypt ",[131,2656,299],{"class":291},[131,2658,2659],{"class":148}," 'bcrypt'\n",[131,2661,2662],{"class":133,"line":195},[131,2663,163],{"emptyLinePlaceholder":162},[131,2665,2666,2668,2670],{"class":133,"line":203},[131,2667,447],{"class":295},[131,2669,663],{"class":144},[131,2671,388],{"class":295},[131,2673,2674,2676,2678,2681],{"class":133,"line":208},[131,2675,478],{"class":291},[131,2677,481],{"class":291},[131,2679,2680],{"class":144}," UsersService",[131,2682,547],{"class":295},[131,2684,2685,2687],{"class":133,"line":214},[131,2686,552],{"class":291},[131,2688,2689],{"class":295},"(\n",[131,2691,2692,2695,2698],{"class":133,"line":222},[131,2693,2694],{"class":295},"    @",[131,2696,2697],{"class":144},"InjectRepository",[131,2699,2700],{"class":295},"(User)\n",[131,2702,2703,2706,2709,2711,2714,2717,2720],{"class":133,"line":227},[131,2704,2705],{"class":291},"    private",[131,2707,2708],{"class":563}," usersRepository",[131,2710,567],{"class":291},[131,2712,2713],{"class":144}," Repository",[131,2715,2716],{"class":295},"\u003C",[131,2718,2719],{"class":144},"User",[131,2721,2722],{"class":295},">,\n",[131,2724,2725],{"class":133,"line":233},[131,2726,2727],{"class":295},"  ) {}\n",[131,2729,2730],{"class":133,"line":832},[131,2731,163],{"emptyLinePlaceholder":162},[131,2733,2734,2737,2740,2742,2745,2747,2749,2751,2753,2756,2759,2762,2764,2766],{"class":133,"line":843},[131,2735,2736],{"class":291},"  async",[131,2738,2739],{"class":144}," create",[131,2741,369],{"class":295},[131,2743,2744],{"class":563},"createUserDto",[131,2746,567],{"class":291},[131,2748,2341],{"class":144},[131,2750,2508],{"class":295},[131,2752,567],{"class":291},[131,2754,2755],{"class":144}," Promise",[131,2757,2758],{"class":295},"\u003C{ ",[131,2760,2761],{"class":563},"message",[131,2763,567],{"class":291},[131,2765,600],{"class":152},[131,2767,2768],{"class":295}," }> {\n",[131,2770,2771,2774,2777,2779,2781,2783,2786,2789],{"class":133,"line":854},[131,2772,2773],{"class":291},"    const",[131,2775,2776],{"class":152}," existingUser",[131,2778,343],{"class":291},[131,2780,346],{"class":291},[131,2782,610],{"class":152},[131,2784,2785],{"class":295},".usersRepository.",[131,2787,2788],{"class":144},"findOne",[131,2790,453],{"class":295},[131,2792,2793],{"class":133,"line":865},[131,2794,2795],{"class":295},"      where: { email: createUserDto.email },\n",[131,2797,2798],{"class":133,"line":876},[131,2799,2800],{"class":295},"    })\n",[131,2802,2803],{"class":133,"line":881},[131,2804,163],{"emptyLinePlaceholder":162},[131,2806,2807,2810],{"class":133,"line":889},[131,2808,2809],{"class":291},"    if",[131,2811,2812],{"class":295}," (existingUser) {\n",[131,2814,2815,2818,2820,2823,2825,2828],{"class":133,"line":1430},[131,2816,2817],{"class":291},"      throw",[131,2819,178],{"class":291},[131,2821,2822],{"class":144}," BadRequestException",[131,2824,369],{"class":295},[131,2826,2827],{"class":148},"'既に登録済みのメールアドレスです'",[131,2829,375],{"class":295},[131,2831,2832],{"class":133,"line":1445},[131,2833,2834],{"class":295},"    }\n",[131,2836,2837],{"class":133,"line":1463},[131,2838,163],{"emptyLinePlaceholder":162},[131,2840,2841,2844,2846,2848,2851],{"class":133,"line":1474},[131,2842,2843],{"class":291},"    await",[131,2845,610],{"class":152},[131,2847,2785],{"class":295},[131,2849,2850],{"class":144},"save",[131,2852,453],{"class":295},[131,2854,2855],{"class":133,"line":1496},[131,2856,2857],{"class":295},"      name: createUserDto.name,\n",[131,2859,2860],{"class":133,"line":1502},[131,2861,2862],{"class":295},"      email: createUserDto.email,\n",[131,2864,2865,2868,2871,2874,2877,2880,2883],{"class":133,"line":1508},[131,2866,2867],{"class":295},"      password: ",[131,2869,2870],{"class":291},"await",[131,2872,2873],{"class":295}," bcrypt.",[131,2875,2876],{"class":144},"hash",[131,2878,2879],{"class":295},"(createUserDto.password, ",[131,2881,2882],{"class":152},"10",[131,2884,1385],{"class":295},[131,2886,2887],{"class":133,"line":1513},[131,2888,2800],{"class":295},[131,2890,2891],{"class":133,"line":1519},[131,2892,163],{"emptyLinePlaceholder":162},[131,2894,2895,2897,2900,2903],{"class":133,"line":1525},[131,2896,607],{"class":291},[131,2898,2899],{"class":295}," { message: ",[131,2901,2902],{"class":148},"'ユーザーの登録に成功しました'",[131,2904,2905],{"class":295}," }\n",[131,2907,2908],{"class":133,"line":1530},[131,2909,623],{"class":295},[131,2911,2912],{"class":133,"line":1883},[131,2913,163],{"emptyLinePlaceholder":162},[131,2915,2916,2918,2921,2923,2925,2927,2929,2931],{"class":133,"line":1888},[131,2917,2736],{"class":291},[131,2919,2920],{"class":144}," findAll",[131,2922,595],{"class":295},[131,2924,567],{"class":291},[131,2926,2755],{"class":144},[131,2928,2716],{"class":295},[131,2930,2719],{"class":144},[131,2932,2933],{"class":295},"[]> {\n",[131,2935,2936,2938,2940,2942,2945],{"class":133,"line":1903},[131,2937,607],{"class":291},[131,2939,610],{"class":152},[131,2941,2785],{"class":295},[131,2943,2944],{"class":144},"find",[131,2946,388],{"class":295},[131,2948,2949],{"class":133,"line":1915},[131,2950,623],{"class":295},[131,2952,2953],{"class":133,"line":1920},[131,2954,163],{"emptyLinePlaceholder":162},[131,2956,2957,2959,2962,2964,2967,2969,2972,2974,2976,2978,2980,2982],{"class":133,"line":1935},[131,2958,2736],{"class":291},[131,2960,2961],{"class":144}," findOne",[131,2963,369],{"class":295},[131,2965,2966],{"class":563},"id",[131,2968,567],{"class":291},[131,2970,2971],{"class":152}," number",[131,2973,2508],{"class":295},[131,2975,567],{"class":291},[131,2977,2755],{"class":144},[131,2979,2716],{"class":295},[131,2981,2719],{"class":144},[131,2983,2984],{"class":295},"> {\n",[131,2986,2987,2989,2991,2993,2996],{"class":133,"line":1947},[131,2988,607],{"class":291},[131,2990,610],{"class":152},[131,2992,2785],{"class":295},[131,2994,2995],{"class":144},"findOneOrFail",[131,2997,2998],{"class":295},"(id)\n",[131,3000,3001],{"class":133,"line":1952},[131,3002,623],{"class":295},[131,3004,3005],{"class":133,"line":1988},[131,3006,163],{"emptyLinePlaceholder":162},[131,3008,3009],{"class":133,"line":2003},[131,3010,3011],{"class":137},"  \u002F\u002F update, removeメソッドも同様に実装\n",[131,3013,3014],{"class":133,"line":2016},[131,3015,380],{"class":295},[10,3017,52],{"id":3018},"e2eテストの実装",[116,3020,3022],{"id":3021},"テスト用typeorm設定","テスト用TypeORM設定",[121,3024,3026],{"className":277,"code":3025,"language":279,"meta":126,"style":126},"\u002F\u002F ormconfig.test.ts\nmodule.exports = {\n  type: 'mysql',\n  host: process.env.DB_HOST || 'localhost',\n  port: process.env.DB_PORT || '3306',\n  username: process.env.DB_USERNAME || 'root',\n  password: process.env.DB_PASSWORD || 'password',\n  database: process.env.DB_NAME || 'meetup',\n  synchronize: true, \u002F\u002F テスト環境のみ有効化\n  logging: true,\n  dropSchema: true,\n  entities: ['src\u002Fentities\u002F*.ts'],\n  migrations: ['src\u002Fdatabases\u002Fmigrations\u002F*.ts'],\n}\n",[128,3027,3028,3033,3045,3053,3065,3077,3089,3101,3113,3124,3132,3141,3149,3157],{"__ignoreMap":126},[131,3029,3030],{"class":133,"line":134},[131,3031,3032],{"class":137},"\u002F\u002F ormconfig.test.ts\n",[131,3034,3035,3037,3039,3041,3043],{"class":133,"line":141},[131,3036,2055],{"class":152},[131,3038,2058],{"class":295},[131,3040,2061],{"class":152},[131,3042,343],{"class":291},[131,3044,547],{"class":295},[131,3046,3047,3049,3051],{"class":133,"line":159},[131,3048,2070],{"class":295},[131,3050,1367],{"class":148},[131,3052,1064],{"class":295},[131,3054,3055,3057,3059,3061,3063],{"class":133,"line":166},[131,3056,2079],{"class":295},[131,3058,1124],{"class":152},[131,3060,1058],{"class":291},[131,3062,1129],{"class":148},[131,3064,1064],{"class":295},[131,3066,3067,3069,3071,3073,3075],{"class":133,"line":172},[131,3068,2092],{"class":295},[131,3070,1142],{"class":152},[131,3072,1058],{"class":291},[131,3074,2099],{"class":148},[131,3076,1064],{"class":295},[131,3078,3079,3081,3083,3085,3087],{"class":133,"line":184},[131,3080,2106],{"class":295},[131,3082,1159],{"class":152},[131,3084,1058],{"class":291},[131,3086,1164],{"class":148},[131,3088,1064],{"class":295},[131,3090,3091,3093,3095,3097,3099],{"class":133,"line":189},[131,3092,2119],{"class":295},[131,3094,1174],{"class":152},[131,3096,1058],{"class":291},[131,3098,1179],{"class":148},[131,3100,1064],{"class":295},[131,3102,3103,3105,3107,3109,3111],{"class":133,"line":195},[131,3104,2132],{"class":295},[131,3106,1189],{"class":152},[131,3108,1058],{"class":291},[131,3110,1194],{"class":148},[131,3112,1064],{"class":295},[131,3114,3115,3117,3119,3121],{"class":133,"line":203},[131,3116,2145],{"class":295},[131,3118,1310],{"class":152},[131,3120,1966],{"class":295},[131,3122,3123],{"class":137},"\u002F\u002F テスト環境のみ有効化\n",[131,3125,3126,3128,3130],{"class":133,"line":208},[131,3127,2154],{"class":295},[131,3129,1310],{"class":152},[131,3131,1064],{"class":295},[131,3133,3134,3137,3139],{"class":133,"line":214},[131,3135,3136],{"class":295},"  dropSchema: ",[131,3138,1310],{"class":152},[131,3140,1064],{"class":295},[131,3142,3143,3145,3147],{"class":133,"line":222},[131,3144,2163],{"class":295},[131,3146,2166],{"class":148},[131,3148,2169],{"class":295},[131,3150,3151,3153,3155],{"class":133,"line":227},[131,3152,2174],{"class":295},[131,3154,2177],{"class":148},[131,3156,2169],{"class":295},[131,3158,3159],{"class":133,"line":233},[131,3160,380],{"class":295},[116,3162,3164],{"id":3163},"e2eテストコード","E2Eテストコード",[121,3166,3168],{"className":123,"code":3167,"language":125,"meta":126,"style":126},"npm install randomstring typeorm-seeding\n",[128,3169,3170],{"__ignoreMap":126},[131,3171,3172,3174,3176,3179],{"class":133,"line":134},[131,3173,145],{"class":144},[131,3175,149],{"class":148},[131,3177,3178],{"class":148}," randomstring",[131,3180,3181],{"class":148}," typeorm-seeding\n",[121,3183,3185],{"className":277,"code":3184,"language":279,"meta":126,"style":126},"\u002F\u002F test\u002Fuser.e2e-spec.ts\nimport { INestApplication, ValidationPipe } from '@nestjs\u002Fcommon'\nimport { Test, TestingModule } from '@nestjs\u002Ftesting'\nimport { TypeOrmModule } from '@nestjs\u002Ftypeorm'\nimport * as request from 'supertest'\nimport { useRefreshDatabase } from 'typeorm-seeding'\nimport { User } from '..\u002Fsrc\u002Fentities\u002Fuser.entity'\nimport { AppModule } from '..\u002Fsrc\u002Fmodules\u002Fapp.module'\nimport { CreateUserDto } from '..\u002Fsrc\u002Fdto\u002Fcreate-user.dto'\n\ndescribe('UserController (E2E)', () => {\n  let app: INestApplication\n\n  beforeEach(async () => {\n    await useRefreshDatabase()\n  })\n\n  beforeAll(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [TypeOrmModule.forFeature([User]), AppModule],\n    }).compile()\n\n    app = moduleFixture.createNestApplication()\n    app.useGlobalPipes(new ValidationPipe())\n    await app.init()\n  })\n\n  afterAll(async () => {\n    await app.close()\n  })\n\n  describe('ユーザー登録テスト', () => {\n    it('正常にユーザーを登録できる', async () => {\n      const body: CreateUserDto = {\n        name: 'Test User',\n        email: 'test@example.com',\n        password: 'Password1234',\n      }\n\n      const res = await request(app.getHttpServer())\n        .post('\u002Fusers')\n        .set('Accept', 'application\u002Fjson')\n        .send(body)\n\n      expect(res.status).toEqual(201)\n      expect(res.body.message).toEqual('ユーザーの登録に成功しました')\n    })\n\n    it('重複メールアドレスでエラーになる', async () => {\n      const body: CreateUserDto = {\n        name: 'Test User',\n        email: 'test@example.com',\n        password: 'Password1234',\n      }\n\n      await request(app.getHttpServer()).post('\u002Fusers').send(body)\n\n      const res = await request(app.getHttpServer()).post('\u002Fusers').send(body)\n\n      expect(res.status).toEqual(400)\n    })\n  })\n})\n",[128,3186,3187,3192,3203,3215,3225,3241,3253,3264,3275,3286,3290,3307,3319,3323,3338,3347,3351,3355,3370,3394,3405,3415,3419,3434,3453,3464,3468,3472,3487,3498,3502,3506,3522,3542,3558,3568,3578,3588,3593,3597,3619,3634,3653,3663,3667,3685,3701,3706,3711,3731,3746,3755,3764,3773,3778,3783,3811,3816,3847,3852,3868,3873,3878],{"__ignoreMap":126},[131,3188,3189],{"class":133,"line":134},[131,3190,3191],{"class":137},"\u002F\u002F test\u002Fuser.e2e-spec.ts\n",[131,3193,3194,3196,3199,3201],{"class":133,"line":141},[131,3195,292],{"class":291},[131,3197,3198],{"class":295}," { INestApplication, ValidationPipe } ",[131,3200,299],{"class":291},[131,3202,414],{"class":148},[131,3204,3205,3207,3210,3212],{"class":133,"line":159},[131,3206,292],{"class":291},[131,3208,3209],{"class":295}," { Test, TestingModule } ",[131,3211,299],{"class":291},[131,3213,3214],{"class":148}," '@nestjs\u002Ftesting'\n",[131,3216,3217,3219,3221,3223],{"class":133,"line":166},[131,3218,292],{"class":291},[131,3220,1246],{"class":295},[131,3222,299],{"class":291},[131,3224,1251],{"class":148},[131,3226,3227,3229,3231,3233,3236,3238],{"class":133,"line":172},[131,3228,292],{"class":291},[131,3230,2648],{"class":152},[131,3232,2651],{"class":291},[131,3234,3235],{"class":295}," request ",[131,3237,299],{"class":291},[131,3239,3240],{"class":148}," 'supertest'\n",[131,3242,3243,3245,3248,3250],{"class":133,"line":184},[131,3244,292],{"class":291},[131,3246,3247],{"class":295}," { useRefreshDatabase } ",[131,3249,299],{"class":291},[131,3251,3252],{"class":148}," 'typeorm-seeding'\n",[131,3254,3255,3257,3259,3261],{"class":133,"line":189},[131,3256,292],{"class":291},[131,3258,2624],{"class":295},[131,3260,299],{"class":291},[131,3262,3263],{"class":148}," '..\u002Fsrc\u002Fentities\u002Fuser.entity'\n",[131,3265,3266,3268,3270,3272],{"class":133,"line":195},[131,3267,292],{"class":291},[131,3269,309],{"class":295},[131,3271,299],{"class":291},[131,3273,3274],{"class":148}," '..\u002Fsrc\u002Fmodules\u002Fapp.module'\n",[131,3276,3277,3279,3281,3283],{"class":133,"line":203},[131,3278,292],{"class":291},[131,3280,2636],{"class":295},[131,3282,299],{"class":291},[131,3284,3285],{"class":148}," '..\u002Fsrc\u002Fdto\u002Fcreate-user.dto'\n",[131,3287,3288],{"class":133,"line":208},[131,3289,163],{"emptyLinePlaceholder":162},[131,3291,3292,3295,3297,3300,3303,3305],{"class":133,"line":214},[131,3293,3294],{"class":144},"describe",[131,3296,369],{"class":295},[131,3298,3299],{"class":148},"'UserController (E2E)'",[131,3301,3302],{"class":295},", () ",[131,3304,1044],{"class":291},[131,3306,547],{"class":295},[131,3308,3309,3312,3314,3316],{"class":133,"line":222},[131,3310,3311],{"class":291},"  let",[131,3313,340],{"class":295},[131,3315,567],{"class":291},[131,3317,3318],{"class":144}," INestApplication\n",[131,3320,3321],{"class":133,"line":227},[131,3322,163],{"emptyLinePlaceholder":162},[131,3324,3325,3328,3330,3332,3334,3336],{"class":133,"line":233},[131,3326,3327],{"class":144},"  beforeEach",[131,3329,369],{"class":295},[131,3331,323],{"class":291},[131,3333,1041],{"class":295},[131,3335,1044],{"class":291},[131,3337,547],{"class":295},[131,3339,3340,3342,3345],{"class":133,"line":832},[131,3341,2843],{"class":291},[131,3343,3344],{"class":144}," useRefreshDatabase",[131,3346,388],{"class":295},[131,3348,3349],{"class":133,"line":843},[131,3350,1720],{"class":295},[131,3352,3353],{"class":133,"line":854},[131,3354,163],{"emptyLinePlaceholder":162},[131,3356,3357,3360,3362,3364,3366,3368],{"class":133,"line":865},[131,3358,3359],{"class":144},"  beforeAll",[131,3361,369],{"class":295},[131,3363,323],{"class":291},[131,3365,1041],{"class":295},[131,3367,1044],{"class":291},[131,3369,547],{"class":295},[131,3371,3372,3374,3377,3379,3382,3384,3386,3389,3392],{"class":133,"line":876},[131,3373,2773],{"class":291},[131,3375,3376],{"class":152}," moduleFixture",[131,3378,567],{"class":291},[131,3380,3381],{"class":144}," TestingModule",[131,3383,343],{"class":291},[131,3385,346],{"class":291},[131,3387,3388],{"class":295}," Test.",[131,3390,3391],{"class":144},"createTestingModule",[131,3393,453],{"class":295},[131,3395,3396,3399,3402],{"class":133,"line":881},[131,3397,3398],{"class":295},"      imports: [TypeOrmModule.",[131,3400,3401],{"class":144},"forFeature",[131,3403,3404],{"class":295},"([User]), AppModule],\n",[131,3406,3407,3410,3413],{"class":133,"line":889},[131,3408,3409],{"class":295},"    }).",[131,3411,3412],{"class":144},"compile",[131,3414,388],{"class":295},[131,3416,3417],{"class":133,"line":1430},[131,3418,163],{"emptyLinePlaceholder":162},[131,3420,3421,3424,3426,3429,3432],{"class":133,"line":1445},[131,3422,3423],{"class":295},"    app ",[131,3425,1997],{"class":291},[131,3427,3428],{"class":295}," moduleFixture.",[131,3430,3431],{"class":144},"createNestApplication",[131,3433,388],{"class":295},[131,3435,3436,3439,3442,3444,3447,3450],{"class":133,"line":1463},[131,3437,3438],{"class":295},"    app.",[131,3440,3441],{"class":144},"useGlobalPipes",[131,3443,369],{"class":295},[131,3445,3446],{"class":291},"new",[131,3448,3449],{"class":144}," ValidationPipe",[131,3451,3452],{"class":295},"())\n",[131,3454,3455,3457,3459,3462],{"class":133,"line":1474},[131,3456,2843],{"class":291},[131,3458,363],{"class":295},[131,3460,3461],{"class":144},"init",[131,3463,388],{"class":295},[131,3465,3466],{"class":133,"line":1496},[131,3467,1720],{"class":295},[131,3469,3470],{"class":133,"line":1502},[131,3471,163],{"emptyLinePlaceholder":162},[131,3473,3474,3477,3479,3481,3483,3485],{"class":133,"line":1508},[131,3475,3476],{"class":144},"  afterAll",[131,3478,369],{"class":295},[131,3480,323],{"class":291},[131,3482,1041],{"class":295},[131,3484,1044],{"class":291},[131,3486,547],{"class":295},[131,3488,3489,3491,3493,3496],{"class":133,"line":1513},[131,3490,2843],{"class":291},[131,3492,363],{"class":295},[131,3494,3495],{"class":144},"close",[131,3497,388],{"class":295},[131,3499,3500],{"class":133,"line":1519},[131,3501,1720],{"class":295},[131,3503,3504],{"class":133,"line":1525},[131,3505,163],{"emptyLinePlaceholder":162},[131,3507,3508,3511,3513,3516,3518,3520],{"class":133,"line":1530},[131,3509,3510],{"class":144},"  describe",[131,3512,369],{"class":295},[131,3514,3515],{"class":148},"'ユーザー登録テスト'",[131,3517,3302],{"class":295},[131,3519,1044],{"class":291},[131,3521,547],{"class":295},[131,3523,3524,3527,3529,3532,3534,3536,3538,3540],{"class":133,"line":1883},[131,3525,3526],{"class":144},"    it",[131,3528,369],{"class":295},[131,3530,3531],{"class":148},"'正常にユーザーを登録できる'",[131,3533,1966],{"class":295},[131,3535,323],{"class":291},[131,3537,1041],{"class":295},[131,3539,1044],{"class":291},[131,3541,547],{"class":295},[131,3543,3544,3547,3550,3552,3554,3556],{"class":133,"line":1888},[131,3545,3546],{"class":291},"      const",[131,3548,3549],{"class":152}," body",[131,3551,567],{"class":291},[131,3553,2341],{"class":144},[131,3555,343],{"class":291},[131,3557,547],{"class":295},[131,3559,3560,3563,3566],{"class":133,"line":1903},[131,3561,3562],{"class":295},"        name: ",[131,3564,3565],{"class":148},"'Test User'",[131,3567,1064],{"class":295},[131,3569,3570,3573,3576],{"class":133,"line":1915},[131,3571,3572],{"class":295},"        email: ",[131,3574,3575],{"class":148},"'test@example.com'",[131,3577,1064],{"class":295},[131,3579,3580,3583,3586],{"class":133,"line":1920},[131,3581,3582],{"class":295},"        password: ",[131,3584,3585],{"class":148},"'Password1234'",[131,3587,1064],{"class":295},[131,3589,3590],{"class":133,"line":1935},[131,3591,3592],{"class":295},"      }\n",[131,3594,3595],{"class":133,"line":1947},[131,3596,163],{"emptyLinePlaceholder":162},[131,3598,3599,3601,3604,3606,3608,3611,3614,3617],{"class":133,"line":1952},[131,3600,3546],{"class":291},[131,3602,3603],{"class":152}," res",[131,3605,343],{"class":291},[131,3607,346],{"class":291},[131,3609,3610],{"class":144}," request",[131,3612,3613],{"class":295},"(app.",[131,3615,3616],{"class":144},"getHttpServer",[131,3618,3452],{"class":295},[131,3620,3621,3624,3627,3629,3632],{"class":133,"line":1988},[131,3622,3623],{"class":295},"        .",[131,3625,3626],{"class":144},"post",[131,3628,369],{"class":295},[131,3630,3631],{"class":148},"'\u002Fusers'",[131,3633,375],{"class":295},[131,3635,3636,3638,3641,3643,3646,3648,3651],{"class":133,"line":2003},[131,3637,3623],{"class":295},[131,3639,3640],{"class":144},"set",[131,3642,369],{"class":295},[131,3644,3645],{"class":148},"'Accept'",[131,3647,1966],{"class":295},[131,3649,3650],{"class":148},"'application\u002Fjson'",[131,3652,375],{"class":295},[131,3654,3655,3657,3660],{"class":133,"line":2016},[131,3656,3623],{"class":295},[131,3658,3659],{"class":144},"send",[131,3661,3662],{"class":295},"(body)\n",[131,3664,3665],{"class":133,"line":2029},[131,3666,163],{"emptyLinePlaceholder":162},[131,3668,3669,3672,3675,3678,3680,3683],{"class":133,"line":2034},[131,3670,3671],{"class":144},"      expect",[131,3673,3674],{"class":295},"(res.status).",[131,3676,3677],{"class":144},"toEqual",[131,3679,369],{"class":295},[131,3681,3682],{"class":152},"201",[131,3684,375],{"class":295},[131,3686,3688,3690,3693,3695,3697,3699],{"class":133,"line":3687},46,[131,3689,3671],{"class":144},[131,3691,3692],{"class":295},"(res.body.message).",[131,3694,3677],{"class":144},[131,3696,369],{"class":295},[131,3698,2902],{"class":148},[131,3700,375],{"class":295},[131,3702,3704],{"class":133,"line":3703},47,[131,3705,2800],{"class":295},[131,3707,3709],{"class":133,"line":3708},48,[131,3710,163],{"emptyLinePlaceholder":162},[131,3712,3714,3716,3718,3721,3723,3725,3727,3729],{"class":133,"line":3713},49,[131,3715,3526],{"class":144},[131,3717,369],{"class":295},[131,3719,3720],{"class":148},"'重複メールアドレスでエラーになる'",[131,3722,1966],{"class":295},[131,3724,323],{"class":291},[131,3726,1041],{"class":295},[131,3728,1044],{"class":291},[131,3730,547],{"class":295},[131,3732,3734,3736,3738,3740,3742,3744],{"class":133,"line":3733},50,[131,3735,3546],{"class":291},[131,3737,3549],{"class":152},[131,3739,567],{"class":291},[131,3741,2341],{"class":144},[131,3743,343],{"class":291},[131,3745,547],{"class":295},[131,3747,3749,3751,3753],{"class":133,"line":3748},51,[131,3750,3562],{"class":295},[131,3752,3565],{"class":148},[131,3754,1064],{"class":295},[131,3756,3758,3760,3762],{"class":133,"line":3757},52,[131,3759,3572],{"class":295},[131,3761,3575],{"class":148},[131,3763,1064],{"class":295},[131,3765,3767,3769,3771],{"class":133,"line":3766},53,[131,3768,3582],{"class":295},[131,3770,3585],{"class":148},[131,3772,1064],{"class":295},[131,3774,3776],{"class":133,"line":3775},54,[131,3777,3592],{"class":295},[131,3779,3781],{"class":133,"line":3780},55,[131,3782,163],{"emptyLinePlaceholder":162},[131,3784,3786,3789,3791,3793,3795,3798,3800,3802,3804,3807,3809],{"class":133,"line":3785},56,[131,3787,3788],{"class":291},"      await",[131,3790,3610],{"class":144},[131,3792,3613],{"class":295},[131,3794,3616],{"class":144},[131,3796,3797],{"class":295},"()).",[131,3799,3626],{"class":144},[131,3801,369],{"class":295},[131,3803,3631],{"class":148},[131,3805,3806],{"class":295},").",[131,3808,3659],{"class":144},[131,3810,3662],{"class":295},[131,3812,3814],{"class":133,"line":3813},57,[131,3815,163],{"emptyLinePlaceholder":162},[131,3817,3819,3821,3823,3825,3827,3829,3831,3833,3835,3837,3839,3841,3843,3845],{"class":133,"line":3818},58,[131,3820,3546],{"class":291},[131,3822,3603],{"class":152},[131,3824,343],{"class":291},[131,3826,346],{"class":291},[131,3828,3610],{"class":144},[131,3830,3613],{"class":295},[131,3832,3616],{"class":144},[131,3834,3797],{"class":295},[131,3836,3626],{"class":144},[131,3838,369],{"class":295},[131,3840,3631],{"class":148},[131,3842,3806],{"class":295},[131,3844,3659],{"class":144},[131,3846,3662],{"class":295},[131,3848,3850],{"class":133,"line":3849},59,[131,3851,163],{"emptyLinePlaceholder":162},[131,3853,3855,3857,3859,3861,3863,3866],{"class":133,"line":3854},60,[131,3856,3671],{"class":144},[131,3858,3674],{"class":295},[131,3860,3677],{"class":144},[131,3862,369],{"class":295},[131,3864,3865],{"class":152},"400",[131,3867,375],{"class":295},[131,3869,3871],{"class":133,"line":3870},61,[131,3872,2800],{"class":295},[131,3874,3876],{"class":133,"line":3875},62,[131,3877,1720],{"class":295},[131,3879,3881],{"class":133,"line":3880},63,[131,3882,473],{"class":295},[116,3884,3885],{"id":3885},"テストスクリプトの設定",[121,3887,3891],{"className":3888,"code":3889,"language":3890,"meta":126,"style":126},"language-json shiki shiki-themes github-light github-dark","\u002F\u002F package.json\n{\n  \"scripts\": {\n    \"test:e2e\": \"jest --runInBand --forceExit --detectOpenHandles --config .\u002Ftest\u002Fjest-e2e.json\"\n  }\n}\n","json",[128,3892,3893,3898,3903,3911,3921,3925],{"__ignoreMap":126},[131,3894,3895],{"class":133,"line":134},[131,3896,3897],{"class":137},"\u002F\u002F package.json\n",[131,3899,3900],{"class":133,"line":141},[131,3901,3902],{"class":295},"{\n",[131,3904,3905,3908],{"class":133,"line":159},[131,3906,3907],{"class":152},"  \"scripts\"",[131,3909,3910],{"class":295},": {\n",[131,3912,3913,3916,3918],{"class":133,"line":166},[131,3914,3915],{"class":152},"    \"test:e2e\"",[131,3917,731],{"class":295},[131,3919,3920],{"class":148},"\"jest --runInBand --forceExit --detectOpenHandles --config .\u002Ftest\u002Fjest-e2e.json\"\n",[131,3922,3923],{"class":133,"line":172},[131,3924,623],{"class":295},[131,3926,3927],{"class":133,"line":184},[131,3928,380],{"class":295},[14,3930,3931],{},"テスト実行：",[121,3933,3935],{"className":123,"code":3934,"language":125,"meta":126,"style":126},"npm run test:e2e\n",[128,3936,3937],{"__ignoreMap":126},[131,3938,3939,3941,3943],{"class":133,"line":134},[131,3940,145],{"class":144},[131,3942,238],{"class":148},[131,3944,3945],{"class":148}," test:e2e\n",[10,3947,3949],{"id":3948},"github-actionsの設定","GitHub Actionsの設定",[116,3951,3953],{"id":3952},"テスト用dockerfile","テスト用Dockerfile",[121,3955,3959],{"className":3956,"code":3957,"language":3958,"meta":126,"style":126},"language-dockerfile shiki shiki-themes github-light github-dark","# DockerfileTest\nFROM node:14.16.1-alpine as build-stage\n\nWORKDIR \u002Fwork\n\nCOPY . \u002Fwork\u002F\n\nRUN npm install\n\nCMD [\"npm\",\"run\",\"test:e2e\"]\n","dockerfile",[128,3960,3961,3966,3971,3975,3980,3984,3989,3993,3998,4002],{"__ignoreMap":126},[131,3962,3963],{"class":133,"line":134},[131,3964,3965],{},"# DockerfileTest\n",[131,3967,3968],{"class":133,"line":141},[131,3969,3970],{},"FROM node:14.16.1-alpine as build-stage\n",[131,3972,3973],{"class":133,"line":159},[131,3974,163],{"emptyLinePlaceholder":162},[131,3976,3977],{"class":133,"line":166},[131,3978,3979],{},"WORKDIR \u002Fwork\n",[131,3981,3982],{"class":133,"line":172},[131,3983,163],{"emptyLinePlaceholder":162},[131,3985,3986],{"class":133,"line":184},[131,3987,3988],{},"COPY . \u002Fwork\u002F\n",[131,3990,3991],{"class":133,"line":189},[131,3992,163],{"emptyLinePlaceholder":162},[131,3994,3995],{"class":133,"line":195},[131,3996,3997],{},"RUN npm install\n",[131,3999,4000],{"class":133,"line":203},[131,4001,163],{"emptyLinePlaceholder":162},[131,4003,4004],{"class":133,"line":208},[131,4005,4006],{},"CMD [\"npm\",\"run\",\"test:e2e\"]\n",[116,4008,4009],{"id":4009},"テスト用docker-compose",[121,4011,4013],{"className":713,"code":4012,"language":715,"meta":126,"style":126},"# unit-test.yml\nversion: '3'\n\nservices:\n  app:\n    build:\n      context: \".\"\n      dockerfile: \"DockerfileTest\"\n    container_name: github-actions-api-test\n    ports:\n      - '3000:3000'\n    environment:\n      PORT: 3000\n      TZ: 'Asia\u002FTokyo'\n      DB_HOST: 'testdb'\n      DB_PORT: '3306'\n      DB_USERNAME: 'root'\n      DB_PASSWORD: 'password'\n      DB_NAME: 'meetup'\n    depends_on:\n      - testdb\n\n  testdb:\n    image: mysql:8.0\n    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci\n    container_name: db_container_e2e_test\n    ports:\n      - 3306:3306\n    environment:\n      TZ: 'Asia\u002FTokyo'\n      MYSQL_ROOT_PASSWORD: password\n      MYSQL_DATABASE: meetup\n",[128,4014,4015,4020,4028,4032,4038,4045,4052,4062,4072,4081,4087,4094,4100,4110,4118,4128,4138,4148,4158,4168,4175,4182,4186,4193,4201,4209,4218,4224,4231,4237,4245,4253],{"__ignoreMap":126},[131,4016,4017],{"class":133,"line":134},[131,4018,4019],{"class":137},"# unit-test.yml\n",[131,4021,4022,4024,4026],{"class":133,"line":141},[131,4023,728],{"class":727},[131,4025,731],{"class":295},[131,4027,734],{"class":148},[131,4029,4030],{"class":133,"line":159},[131,4031,163],{"emptyLinePlaceholder":162},[131,4033,4034,4036],{"class":133,"line":166},[131,4035,743],{"class":727},[131,4037,746],{"class":295},[131,4039,4040,4043],{"class":133,"line":172},[131,4041,4042],{"class":727},"  app",[131,4044,746],{"class":295},[131,4046,4047,4050],{"class":133,"line":184},[131,4048,4049],{"class":727},"    build",[131,4051,746],{"class":295},[131,4053,4054,4057,4059],{"class":133,"line":189},[131,4055,4056],{"class":727},"      context",[131,4058,731],{"class":295},[131,4060,4061],{"class":148},"\".\"\n",[131,4063,4064,4067,4069],{"class":133,"line":195},[131,4065,4066],{"class":727},"      dockerfile",[131,4068,731],{"class":295},[131,4070,4071],{"class":148},"\"DockerfileTest\"\n",[131,4073,4074,4076,4078],{"class":133,"line":203},[131,4075,778],{"class":727},[131,4077,731],{"class":295},[131,4079,4080],{"class":148},"github-actions-api-test\n",[131,4082,4083,4085],{"class":133,"line":208},[131,4084,803],{"class":727},[131,4086,746],{"class":295},[131,4088,4089,4091],{"class":133,"line":214},[131,4090,795],{"class":295},[131,4092,4093],{"class":148},"'3000:3000'\n",[131,4095,4096,4098],{"class":133,"line":222},[131,4097,817],{"class":727},[131,4099,746],{"class":295},[131,4101,4102,4105,4107],{"class":133,"line":227},[131,4103,4104],{"class":727},"      PORT",[131,4106,731],{"class":295},[131,4108,4109],{"class":152},"3000\n",[131,4111,4112,4114,4116],{"class":133,"line":233},[131,4113,824],{"class":727},[131,4115,731],{"class":295},[131,4117,829],{"class":148},[131,4119,4120,4123,4125],{"class":133,"line":832},[131,4121,4122],{"class":727},"      DB_HOST",[131,4124,731],{"class":295},[131,4126,4127],{"class":148},"'testdb'\n",[131,4129,4130,4133,4135],{"class":133,"line":843},[131,4131,4132],{"class":727},"      DB_PORT",[131,4134,731],{"class":295},[131,4136,4137],{"class":148},"'3306'\n",[131,4139,4140,4143,4145],{"class":133,"line":854},[131,4141,4142],{"class":727},"      DB_USERNAME",[131,4144,731],{"class":295},[131,4146,4147],{"class":148},"'root'\n",[131,4149,4150,4153,4155],{"class":133,"line":865},[131,4151,4152],{"class":727},"      DB_PASSWORD",[131,4154,731],{"class":295},[131,4156,4157],{"class":148},"'password'\n",[131,4159,4160,4163,4165],{"class":133,"line":876},[131,4161,4162],{"class":727},"      DB_NAME",[131,4164,731],{"class":295},[131,4166,4167],{"class":148},"'meetup'\n",[131,4169,4170,4173],{"class":133,"line":881},[131,4171,4172],{"class":727},"    depends_on",[131,4174,746],{"class":295},[131,4176,4177,4179],{"class":133,"line":889},[131,4178,795],{"class":295},[131,4180,4181],{"class":148},"testdb\n",[131,4183,4184],{"class":133,"line":1430},[131,4185,163],{"emptyLinePlaceholder":162},[131,4187,4188,4191],{"class":133,"line":1445},[131,4189,4190],{"class":727},"  testdb",[131,4192,746],{"class":295},[131,4194,4195,4197,4199],{"class":133,"line":1463},[131,4196,758],{"class":727},[131,4198,731],{"class":295},[131,4200,763],{"class":148},[131,4202,4203,4205,4207],{"class":133,"line":1474},[131,4204,768],{"class":727},[131,4206,731],{"class":295},[131,4208,773],{"class":148},[131,4210,4211,4213,4215],{"class":133,"line":1496},[131,4212,778],{"class":727},[131,4214,731],{"class":295},[131,4216,4217],{"class":148},"db_container_e2e_test\n",[131,4219,4220,4222],{"class":133,"line":1502},[131,4221,803],{"class":727},[131,4223,746],{"class":295},[131,4225,4226,4228],{"class":133,"line":1508},[131,4227,795],{"class":295},[131,4229,4230],{"class":148},"3306:3306\n",[131,4232,4233,4235],{"class":133,"line":1513},[131,4234,817],{"class":727},[131,4236,746],{"class":295},[131,4238,4239,4241,4243],{"class":133,"line":1519},[131,4240,824],{"class":727},[131,4242,731],{"class":295},[131,4244,829],{"class":148},[131,4246,4247,4249,4251],{"class":133,"line":1525},[131,4248,835],{"class":727},[131,4250,731],{"class":295},[131,4252,840],{"class":148},[131,4254,4255,4257,4259],{"class":133,"line":1530},[131,4256,846],{"class":727},[131,4258,731],{"class":295},[131,4260,851],{"class":148},[116,4262,4264],{"id":4263},"github-actionsワークフロー","GitHub Actionsワークフロー",[121,4266,4268],{"className":713,"code":4267,"language":715,"meta":126,"style":126},"# .github\u002Fworkflows\u002Frun_test.yml\nname: Run E2E Tests\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  run-test:\n    name: Run E2E Tests\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions\u002Fcheckout@v2\n\n      - name: Run tests with docker-compose\n        run: |\n          docker-compose -f .\u002Funit-test.yml build\n          docker-compose -f .\u002Funit-test.yml up --abort-on-container-exit\n        working-directory: .\u002F\n",[128,4269,4270,4275,4284,4288,4295,4302,4309,4316,4320,4327,4334,4343,4353,4357,4364,4375,4385,4389,4400,4410,4415,4420],{"__ignoreMap":126},[131,4271,4272],{"class":133,"line":134},[131,4273,4274],{"class":137},"# .github\u002Fworkflows\u002Frun_test.yml\n",[131,4276,4277,4279,4281],{"class":133,"line":141},[131,4278,1959],{"class":727},[131,4280,731],{"class":295},[131,4282,4283],{"class":148},"Run E2E Tests\n",[131,4285,4286],{"class":133,"line":159},[131,4287,163],{"emptyLinePlaceholder":162},[131,4289,4290,4293],{"class":133,"line":166},[131,4291,4292],{"class":152},"on",[131,4294,746],{"class":295},[131,4296,4297,4300],{"class":133,"line":172},[131,4298,4299],{"class":727},"  push",[131,4301,746],{"class":295},[131,4303,4304,4307],{"class":133,"line":184},[131,4305,4306],{"class":727},"    branches",[131,4308,746],{"class":295},[131,4310,4311,4313],{"class":133,"line":189},[131,4312,795],{"class":295},[131,4314,4315],{"class":148},"main\n",[131,4317,4318],{"class":133,"line":195},[131,4319,163],{"emptyLinePlaceholder":162},[131,4321,4322,4325],{"class":133,"line":203},[131,4323,4324],{"class":727},"jobs",[131,4326,746],{"class":295},[131,4328,4329,4332],{"class":133,"line":208},[131,4330,4331],{"class":727},"  run-test",[131,4333,746],{"class":295},[131,4335,4336,4339,4341],{"class":133,"line":214},[131,4337,4338],{"class":727},"    name",[131,4340,731],{"class":295},[131,4342,4283],{"class":148},[131,4344,4345,4348,4350],{"class":133,"line":222},[131,4346,4347],{"class":727},"    runs-on",[131,4349,731],{"class":295},[131,4351,4352],{"class":148},"ubuntu-latest\n",[131,4354,4355],{"class":133,"line":227},[131,4356,163],{"emptyLinePlaceholder":162},[131,4358,4359,4362],{"class":133,"line":233},[131,4360,4361],{"class":727},"    steps",[131,4363,746],{"class":295},[131,4365,4366,4368,4370,4372],{"class":133,"line":832},[131,4367,795],{"class":295},[131,4369,1959],{"class":727},[131,4371,731],{"class":295},[131,4373,4374],{"class":148},"Checkout code\n",[131,4376,4377,4380,4382],{"class":133,"line":843},[131,4378,4379],{"class":727},"        uses",[131,4381,731],{"class":295},[131,4383,4384],{"class":148},"actions\u002Fcheckout@v2\n",[131,4386,4387],{"class":133,"line":854},[131,4388,163],{"emptyLinePlaceholder":162},[131,4390,4391,4393,4395,4397],{"class":133,"line":865},[131,4392,795],{"class":295},[131,4394,1959],{"class":727},[131,4396,731],{"class":295},[131,4398,4399],{"class":148},"Run tests with docker-compose\n",[131,4401,4402,4405,4407],{"class":133,"line":876},[131,4403,4404],{"class":727},"        run",[131,4406,731],{"class":295},[131,4408,4409],{"class":291},"|\n",[131,4411,4412],{"class":133,"line":881},[131,4413,4414],{"class":148},"          docker-compose -f .\u002Funit-test.yml build\n",[131,4416,4417],{"class":133,"line":889},[131,4418,4419],{"class":148},"          docker-compose -f .\u002Funit-test.yml up --abort-on-container-exit\n",[131,4421,4422,4425,4427],{"class":133,"line":1430},[131,4423,4424],{"class":727},"        working-directory",[131,4426,731],{"class":295},[131,4428,4429],{"class":148},".\u002F\n",[10,4431,4432],{"id":4432},"まとめ",[14,4434,4435],{},"NestJS + Jest + GitHub ActionsでCI環境を構築する手順を解説しました。",[14,4437,4438],{},[78,4439,4440],{},"構築したもの：",[38,4442,4443,4446,4449,4452],{},[41,4444,4445],{},"NestJSを使ったCRUDアプリケーション",[41,4447,4448],{},"TypeORMとMySQLを使ったデータベース連携",[41,4450,4451],{},"Jestを使ったE2Eテスト",[41,4453,4454],{},"GitHub Actionsによる自動テスト実行",[14,4456,4457],{},[78,4458,4459],{},"重要なポイント：",[38,4461,4462,4469,4476,4479],{},[41,4463,4464,4465,4468],{},"TypeORMの",[128,4466,4467],{},"synchronize","はテスト環境のみで有効化",[41,4470,4471,4472,4475],{},"E2Eテストでは",[128,4473,4474],{},"beforeEach","でデータベースをリセット",[41,4477,4478],{},"docker-composeで本番環境に近い構成でテスト",[41,4480,4481],{},"GitHub Actionsでプッシュごとに自動テスト実行",[14,4483,4484],{},"このCI環境により、コード変更による不具合を早期に検出できます。",[4486,4487,4488],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}",{"title":126,"searchDepth":141,"depth":141,"links":4490},[4491,4492,4493,4494,4495,4496,4500,4504,4509,4517,4522,4527],{"id":12,"depth":141,"text":12},{"id":19,"depth":141,"text":20},{"id":36,"depth":141,"text":36},{"id":58,"depth":141,"text":58},{"id":72,"depth":141,"text":72},{"id":114,"depth":141,"text":114,"children":4497},[4498,4499],{"id":118,"depth":159,"text":119},{"id":265,"depth":159,"text":266},{"id":705,"depth":141,"text":706,"children":4501},[4502,4503],{"id":709,"depth":159,"text":710},{"id":897,"depth":159,"text":897},{"id":980,"depth":141,"text":981,"children":4505},[4506,4507,4508],{"id":984,"depth":159,"text":984},{"id":1021,"depth":159,"text":1021},{"id":1207,"depth":159,"text":1208},{"id":1541,"depth":141,"text":1542,"children":4510},[4511,4512,4513,4514,4515,4516],{"id":1545,"depth":159,"text":1545},{"id":1576,"depth":159,"text":1577},{"id":2039,"depth":159,"text":2040},{"id":2215,"depth":159,"text":2215},{"id":2286,"depth":159,"text":2287},{"id":2547,"depth":159,"text":2548},{"id":3018,"depth":141,"text":52,"children":4518},[4519,4520,4521],{"id":3021,"depth":159,"text":3022},{"id":3163,"depth":159,"text":3164},{"id":3885,"depth":159,"text":3885},{"id":3948,"depth":141,"text":3949,"children":4523},[4524,4525,4526],{"id":3952,"depth":159,"text":3953},{"id":4009,"depth":159,"text":4009},{"id":4263,"depth":159,"text":4264},{"id":4432,"depth":141,"text":4432},"2022-03-29","NestJSプロジェクトにJestを使ったE2Eテストを導入し、GitHub Actionsで自動化する手順を解説します。TypeORMとMySQLを使ったCRUDアプリケーションの実装も含む実践的なハンズオン記事です。","md",{"tags":4532},[4533,4534,4535,4536,4537],"githubactions","ci","jest","nestjs","e2e","\u002Fblog\u002Fnestjs-ci-environment-hands-on",{"title":5,"description":4529},"blog\u002Fnestjs-ci-environment-hands-on","u2mR_Ur0DC5r-lL7AhEcz7WKCtgYTTAXm0deFf0oPmA",1773664053981]