CircleCI上でng serveしながらCypressでテスト実行

タイトル通りですが、CircleCIでng serve（Angular）が必要なCypressのテストをする方法です
(ドキュメント少ないけどCypressって流行ってないのかなぁ:santa:)

# なぜそんなことをしたいのか
jestとかでmock（のデータはあったほうがいいと思うが）を作って、そのmockにmockであることを振る舞わせるのはなんだかテストしているようでしていないような（jest.fn()とか）

なんか操り人形を使うことも記述しないといけないのが面倒だし結構複雑になる。。（ごめんなさい初心者です）

ので、実際にlocalhostを立ち上げて、ちゃんと振る舞うかテストするのがmockの振る舞いも記述しなくていいのでテストしやすいと思ったのが背景です:santa:


# TL;DR

- Cypressでヘッドレスなテストを行う
- CircleCI上でlocalhostを立ち上げる
- CircleCIでng serveしてテストが終わったら、次のworkflowへ移る
- npmパッケージのwait-onを使う

# いきなり正解の設定から

必要だと思われる部分だけです:santa:

spa(Angular)なのでpackage.jsonとcircleciのconfig.ymlです

```package.json
{
  "scripts": {
    "ng": "ng",
    "serve": "ng serve",
    "start": "node server",
    "build": "ng build",
    "build:prod": "ng build --aot --prod",
    "lint": "ng lint",
    "test": "cypress run --spec 'src/app/**/*.spec.ts'",
    "test:e2e": "./node_modules/.bin/cypress open",
    "cypress:install": "cypress install",
    "test:wait": "wait-on http://localhost:4200 && yarn test",
    "postinstall": "node ./ng-add-pug-loader.js && ng build --aot --prod"
  },
  "dependencies": {
    "@angular/core": "^6.1.1",
    "typescript": "2.9.2",
    "wait-on": "^3.0.1",
  },
  "devDependencies": {
    "cypress": "^3.1.0",
  }
}

```

```.circleci/config.yml
version: 2

container: &container
  working_directory: ~/my-template
  docker:
    - image: circleci/node:8.11-browsers
      environment:
        TZ: Asia/Tokyo
        TERM: xterm

jobs:
  install-and-build:
    <<: *container
    steps:
      - checkout
      - restore_cache:
          name: Restore Yarn Package Cache
          key: dependency-cache-{{ checksum "yarn.lock" }}
      - run: yarn install
      - run: yarn build:prod
      - save_cache:
          name: Save Yarn Package Cache
          key: dependency-cache-{{ checksum "yarn.lock" }}
          paths:
            - ~/.cache
            - ./node_modules
      - persist_to_workspace:
          root: .
          paths:
            - .

  test:
    <<: *container
    steps:
      - attach_workspace:
          at: .
      - run:
          command: yarn serve
          background: true
      - run:
          command: yarn cypress:install
      - run:
          command: yarn test:wait

  master-jobs:
    <<: *container
    steps:
      - checkout
      - attach_workspace:
          at: .
      - run: ./scripts/create-mastertag.sh

workflows:
  version: 2
  build-and-test:
    jobs:
      - install-and-build
      - test:
          requires:
            - install-and-build
      - master-jobs:
          requires:
            - test
          filters:
            branches:
              only: master

```

# 罠(勝手にハマったのかも)
config.ymlの```save_cache```で```~/.cache```を保存しているのに、cypress実行時にcypressがいないのでインストールしてきて出直してきて反省してくださいって赤文字でエラーになります:fish:

インストールしてるはずなのに・・・:santa:

dockerで、「cypress:base8」というcypressが入っているはずのやつでもだめなので、```yarn cypress:install```してcypressをインストールしています:santa::anger:

誰かわかる人いましたらご指摘お願いします:bow_tone5:


# 大きな流れ

流れはconfig.ymlに設定として載ってますが、やりたいことはCircleCI上でlocalhostを立ち上げてテストをしたいのです。

1. yarn install
2. CircleCI上でng serve（localhostを立ち上げ）
3. localhost立ち上がり次第、cypressでテスト実行
4. テストが完了したら、次へ進む（localhostは捨てる）


# ポイント①　wait-onを使用する
[cypressの公式ドキュメント](https://docs.cypress.io/guides/guides/continuous-integration.html#Booting-Your-Server)にもあるのですが[wait-on](https://www.npmjs.com/package/wait-on)を使用します:santa:

これがないとlocalhostが立ち上がる前に、CircleCIでテストコマンドが走っててテストがコケます:fish:

# ポイント② wait-onを実行するコマンドを作ろう
```
scripts: {
     "test:wait": "wait-on http://localhost:4200 && yarn test",
```
こんなかんじでlocalhostが立ち上がるまで待ち、localhostが立ち上がり次第、```yarn test```でテストが実行されるようにしましょう。
公式ではいきなりwait-onコマンド実行してますが、そんなコマンドはないと怒られてしまうので第二の罠です

# ポイント③　サーバー立ち上げはbackgroundで行う
これはやってもやらなくてもいいですが、circleciの設定で

```config.yml

  test:
    <<: *container
    steps:
      - attach_workspace:
          at: .
      - run:
          command: yarn serve
          background: true
      - run:
          command: yarn cypress:install
      - run:
          command: yarn test:wait
```

```
      - run:
          command: yarn serve
          background: true
```
backgroundをtrueとすると、serverの立ち上げしつつ、cypressのインストールしつつ、localhostの立ち上がりを待ちつつ、テストコマンドを実行することができます

これでテストが無事通れば、サーバーは立ち上がりっぱなしになることなく
つぎのworkflowへと移行します

>
Most CI providers will automatically kill background processes so you don’t have to worry about cleaning up your server process once Cypress finishes.

https://docs.cypress.io/guides/guides/continuous-integration.html#Command-Line

とあるように、テストが終わればbackgroundのプロセスは勝手に消去されるようですね:haircut_tone1:

上記ポイントをおさえていれば、サーバーが立ち上がりっぱなし（CIの時間消耗）だったり、サーバーが立ち上がる前にテスト実行してコケたりということは回避できました:santa: