Steps to create an Angular + git-commit-msg-linter + ng-lint-staged + Husky + Jest + Cypress + Coveralls + TravisCI project template
- VSCode IDE Settings and Jest Snippet
- tslint-angular
- prettier@npm
- tslint-config-prettier
- git-commit-msg-linter
- ng-lint-staged
- husky
- jest, ts-jest, jest-preset-angular, @types/jest
- rimraf
- npm-check
- concurrently
- http-server
- npm-run-all
- env-cmd
- TravisCI
- Coveralls
- Cypress
- snyk.io
$ ng n template-app-angular --routing=false --style=css --skip-git --verbose=true --prefix=template-app-angular
$ cd ./template-app-angular
$ ng analytics project off | echo N
$ rm ./README.md
-
create .vscode/settings.json file and add:
{ "files.eol": "\n", "explorer.compactFolders": false, "editor.tabSize": 2, "typescript.updateImportsOnFileMove.enabled": "prompt", "html.format.endWithNewline": true, "html.suggest.html5": true, "html.autoClosingTags": true, "javascript.format.insertSpaceBeforeFunctionParenthesis": true, "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "javascript.referencesCodeLens.showOnAllFunctions": true, "javascript.referencesCodeLens.enabled": true, "typescript.implementationsCodeLens.enabled": true, "typescript.referencesCodeLens.enabled": true, "typescript.referencesCodeLens.showOnAllFunctions": true }
- copy .gitignore file
-
create .gitattributes file and add:
# Auto detect text files and perform LF normalization * text=auto # JS and TS files must always use LF for tools to work *.js eol=lf *.ts eol=lf *.json eol=lf *.html eol=lf *.css eol=lf *.scss eol=lf
-
create .npmrc file and add:
registry = "https://registry.npmjs.org/"
$ git init
$ git config core.eol lf
$ git config core.autocrlf input
$ git config commit.status false
$ git config push.followTags true
$ git config alias.s '!git status -s'
$ git config alias.c '!git add --all && git commit -m'
$ git config alias.l "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %C(green)[%cd...%cr]%Creset %C(bold blue)<%an> %n%C(bold)%s%n%Creset' --abbrev-commit --date=iso-local"
$ git config alias.lnp '!git --no-pager l'
$ git config alias.t "!sh -c 'git tag -a $1 -m $1' -"
- copy license file
-
on package.json file, update:
{ "name": "template-app-angular", "version": "0.0.0", "author": { "name": ".luizhp", "email": "[email protected]", "url": "https://github.com/luizhp/" }, "description": "Angular TDD project template", "keywords": [ "Angular", "Jest", "Travis-CI", "Coveralls", "Cypress", "snyk.io", "GitHub", "git-commit-msg-linter", "ng-lint-staged", "Husky", "TDD" ], "categories": ["Programming Languages", "Testing", "Linters", "Snippets"], "homepage": "https://github.com/luizhp/template-app-angular/tree/main#readme", "readme": "https://github.com/luizhp/template-app-angular/tree/main#readme", "icon": "https://raw.githubusercontent.com/luizhp/template-app-angular/main/src/favicon.ico", "bugs": { "url": "https://github.com/luizhp/template-app-angular/issues", "email": "[email protected]" }, "license": "GPL-3.0-or-later", "repository": { "type": "git", "url": "https://github.com/luizhp/template-app-angular" }, "engines": { "node": ">= 12", "npm": "^6.14.7" }, ... }
$ git c "chore: initial commit"
-
$ npm i -D tslint-angular@latest $ git c "chore(tslint-angular): install package"
-
update tslint.json file with:
{ "extends": ["tslint:recommended", "tslint-angular"], ...
$ git c "chore(tslint-angular): setup tslint.json file"
-
$ npm i -D prettier@latest $ git c "chore(prettier): install package"
-
create .prettierrc file and add:
{ "tabWidth": 2, "singleQuote": true, "endOfLine": "lf", "bracketSpacing": true, "trailingComma": "es5", "printWidth": 80, "arrowParens": "always", "proseWrap": "preserve", "htmlWhitespaceSensitivity": "css", "useTabs": false, "semi": true, "quoteProps": "consistent", "jsxBracketSameLine": true }
-
create .prettierignore file and add:
package-lock.json yarn.lock dist coverage node_modules .travis.yml CHANGELOG.md
$ git c "chore(prettier): setup custom options"
-
$ npm i -D tslint-config-prettier@latest $ git c "chore(tslint-config-prettier): install package"
-
update tslint.json file with:
{ "extends": ["tslint:recommended", "tslint-angular", "tslint-config-prettier"], ...
$ git c "chore(tslint-config-prettier): setup tslint.json file"
-
create .vscode/jest.code-snippets file and add:
{ "Jest Test": { "prefix": ["test"], "body": [ "describe('', () => {", " test('', () => {", "", " })", "})", "" ], "description": "A describe block for Jest" } }
$ git c "chore(vscode): add jest snippet"
-
$ npm i -D git-commit-msg-linter@latest $ git c "chore(git-commit-msg-linter): install package"
-
$ npm i -D ng-lint-staged@latest $ git c "chore(ng-lint-staged): install package"
-
create .lintstagedrc file and add:
{ "lint-staged": { "src/**/*.ts": ["ng-lint-staged lint --fix --"] } }
$ git c "chore(ng-lint-staged): setup .lintstagedrc file"
-
$ npm i -D husky@latest $ git c "chore(husky): install package"
-
create .huskyrc.json file and add:
{ "hooks": { "pre-commit": "ng-lint-staged" } }
$ git c "chore(ng-lint-staged): add husky pre-commit hook"
-
on package.json file, replace:
"scripts": { ... "build": "ng build --prod --base-href ./", ... }
$ git c "build(script): update build script"
-
update .huskyrc.json file adding pre-push hook:
{ "hooks": { ... "pre-push": "npm run build" } }
$ git c "build(husky): add husky pre-push hook"
$ npm i -D pretty-quick@latest
$ git c "chore(pretty-quick): install package"
-
on .huskyrc.json file update pre-commit hook with:
{ "hooks": { "pre-commit": "pretty-quick --check --staged && ng-lint-staged", ... }
$ git c "chore(pretty-quick): update husky pre-commit hook"
$ npx prettier --write "**/*.{json,ts,html,js}"
$ git c "style: ensure prettier applies defined format to project files"
-
$ npm i -D commitizen@latest $ git c "chore(commitizen): install package"
-
$ npx commitizen init cz-conventional-changelog --save-dev --save-exact $ git c "chore(commitizen): initialize cz-conventional-changelog adapter settings"
-
on package.json file, add:
"scripts": { ... "commitizen": "exec < /dev/tty && git cz --hook || true", ... }
$ git c "chore(commitizen): add commitizen script"
-
on .huskyrc.json file add prepare-commit-msg hook with:
{ "hooks": { "prepare-commit-msg": "echo '👉 Control-C 👈 abort commitizen and continue with your commit message' && npm run commitizen || true", ... }
$ git c "chore(commitizen): add husky prepare-commit-msg hook with commitizen script"
-
Now you can choose to provide or use comitizen to assist you on building your commit message
$ npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter
$ git c "chore(karma): remove packages and dependencies"
-
update angular.json file:
{ ... projects: { template-app-angular: { architect: { test: { options: { "karmaConfig": "karma.conf.js" } } } } } ... }
$ git c "chore(karma): remove configuration reference"
$ rm ./karma.conf.js
$ git c "chore(karma): remove configuration file"
-
$ npm i -D jest@latest ts-jest@latest jest-preset-angular@latest @types/jest@latest $ git c "chore(jest): install packages"
-
create setup-jest.ts file with:
import 'jest-preset-angular';
$ git c "chore(jest): create setup-jest.ts file"
-
create jest.config.js file and add:
module.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], transformIgnorePatterns: ['node_modules/(?!@ngrx|ngx-socket-io)'], transform: { '^.+\\.(ts|js|html)$': 'ts-jest', }, testPathIgnorePatterns: [ '<rootDir>/node_modules/', '<rootDir>/dist/', '<rootDir>/cypress/', '<rootDir>/src/test.ts', ], };
$ git c "chore(jest): setup jest.config.js file"
-
remove this comment from tsconfig.json file:
/* To learn more about this file see: https://angular.io/config/tsconfig. */
-
remove this comment from tsconfig.app.json file:
/* To learn more about this file see: https://angular.io/config/tsconfig. */
-
remove this comment from tsconfig.spec.json file:
/* To learn more about this file see: https://angular.io/config/tsconfig. */
$ git c "chore(tsconfig): remove unnecessary comments on tsconfig files"
-
update tsconfig.json file, adding:
{ "compilerOptions": { ... "types": ["jest"], "esModuleInterop": true, "emitDecoratorMetadata": true
$ git c "chore(jest): setup tsconfig.json file"
-
update tsconfig.spec.json file:
{ "compilerOptions": { ... "types": ["jest", "node"], "esModuleInterop": true, "emitDecoratorMetadata": true }, ...
$ git c "chore(jest): setup tsconfig.spec.json file"
-
update angular.json file:
{ ... projects: { template-app-angular: { architect: { test: {} } } } ... }
$ git c "chore(jest): remove test target"
-
update tsconfig.spec.json file:
{ ... "files": [ "src/test.ts", ...
$ git c "chore(jest): remove src/test.ts reference on tsconfig.spec.json"
$ rm ./src/test.ts
$ git c "chore(jest): remove previous test configuration file"
-
on package.json file, add:
"scripts": { ... "test": "jest --passWithNoTests --silent --noStackTrace --runInBand", "test:verbose": "jest --passWithNoTests --runInBand", "test:staged": "npm test -- --findRelatedTests", ...
$ git c "chore(jest): add test scripts"
-
update .lintstagedrc file:
{ "lint-staged": { "src/**/*.ts": ["ng-lint-staged lint --fix --", "npm run test:staged"] } }
$ git c "chore(jest): setup staged files test on .lintstagedrc file"
-
create jest-unit-config.js file and add:
const config = require('./jest.config'); config.testMatch = ['**/*.spec.ts']; module.exports = config;
$ git c "chore(jest): setup configuration for unit tests"
-
create jest-integration-config.js file and add:
const config = require('./jest.config'); config.testMatch = ['**/*.test.ts']; module.exports = config;
$ git c "chore(jest): setup configuration for integration tests"
-
on package.json file, add:
"scripts": { ... "test:unit": "npm test -- --watch -c jest-unit-config.js", "test:integration": "npm test -- --watch -c jest-integration-config.js", ...
$ git c "chore(jest): add scripts for unit and integration tests"
-
$ npm i -D coveralls@latest $ git c "chore(coveralls): install package"
-
Reference: coveralls
-
add the following lines on jest.config.js file:
module.exports = { ..., collectCoverage: true, coverageDirectory: "coverage/template-app-angular" };
$ git c "chore(jest): add coverage settings"
-
on package.json file, add:
"scripts": { ... "test:ci": "npm test -- --coverage --watch=false --no-progress --browsers=ChromeHeadlessNoSandbox", "test:coveralls": "npm run test:ci && coveralls < coverage/template-app-angular/lcov.info", ...
$ git c "chore(jest): add test:ci and test:coveralls scripts"
-
update .huskyrc.json file:
{ "hooks": { ... "pre-push": "npm run test:ci && npm run build" } }
$ git c "chore(jest): add test:ci script on husky pre-push hook"
-
create .travis.yml file and add:
language: node_js node_js: - 12 addons: apt: sources: - google-chrome packages: - google-chrome-stable cache: directories: - ~/.npm - ~/.cache install: - npm install script: - npm run lint - npm run test:coveralls
$ git c "chore(travis): create building and testing file"
- Reference: TravisCI
$ npm uninstall @types/jasmine @types/jasminewd2 jasmine-core jasmine-spec-reporter
$ git c "chore(jasmine): remove packages"
-
$ npm i -D cypress@latest $ git c "chore(cypress): install package"
-
create cypress.json file and add:
{ "baseUrl": "http://localhost:4200", "video": false }
$ git c "chore(cypress): create configuration file"
- Reference: Cypress-Configuration
-
$ npm i -D concurrently@latest $ git c "chore(concurrently): install package"
-
on package.json file, update:
"scripts": { ... "cypress:e2e": "cypress open", "cypress:install": "cypress install -f", "cypress:run": "cypress run --record", "cypress:chrome": "cypress run -b chrome", "cypress:open": "concurrently \"ng serve\" \"cypress open\"" }, ...
$ git c "chore(cypress): add e2e scripts"
$ npm uninstall protractor
$ git c "chore(protractor): remove package"
-
update angular.json file:
{ ... projects: { template-app-angular: { architect: { e2e: {} } } } ... }
$ git c "chore(cypress): remove e2e target"
-
update angular.json file:
{ ... projects: { template-app-angular: { architect: { lint: { ... "options": { "tsConfig": [ ... "e2e/tsconfig.json" ... }
$ git c "chore(cypress): remove previous e2e file entry reference"
$ rm -rf ./e2e
$ git c "chore(cypress): remove e2e folder"
-
after Cypress UI loads, exit it
$ npm run cypress:e2e
-
remove cypress examples folder or move to another place
$ rm -rf ./cypress/integration/examples $ npx pretty-quick --fix $ git c "chore(cypress): initialize and generates payloads"
-
create cypress/tsconfig.json file and add:
{ "compilerOptions": { "allowJs": true, "baseUrl": "../node_modules", "types": ["cypress"], "noEmit": true }, "include": ["**/*.*"] }
$ git c "chore(cypress): enable intellisense"
- Reference: Cypress-IntelliSense
-
on src/app/app.component.html file locate:
<span>{{ title }} app is running!</span>
-
and add
data-cy="main-title"
attribute as:<span data-cy="main-title">{{ title }} app is running!</span>
$ git c "test(cypress): update sample angular component"
-
create cypress/integration/main-page.spec.js file and add:
const MAIN_TITLE = 'template-app-angular app is running!'; describe('Main Page UI', () => { it('Should return true when title component was correct', () => { cy.visit('/'); cy.contains(MAIN_TITLE).should('have.length', 1); }); it('Should return true when title component was correctly located', () => { cy.visit('/'); cy.get('[data-cy=main-title]') .contains(MAIN_TITLE) .should('have.length', 1); }); });
$ git c "test(cypress): create sample test file"
-
$ npm i -D http-server@latest $ git c "chore(http-server): install package"
-
on package.json file, add:
"scripts": { ..., "start:ci": "http-server ./dist/template-app-angular -a localhost -p 4200 -c-1" ...
$ git c "chore(cypress): add start:ci test script"
-
$ npm i -D npm-run-all@latest $ git c "chore(npm-run-all): install package"
-
on package.json file, add:
"scripts": { ..., "cypress:ci": "ng build --prod && run-p --race start:ci cypress:run" ...
-
on package.json file, update:
"scripts": { ..., "cypress:e2e": "npm run cypress:ci", ...
$ git c "chore(cypress): add test scripts"
-
update .huskyrc.json file:
{ "hooks": { ... "pre-push": "npm run test:ci && npm run cypress:e2e" } }
$ git c "chore(cypress): ensure husky pre-push hook calls cypress:ci script"
-
at script entry on .travis.yml file add:
- npm run cypress:ci
$ git c "chore(travis): ensure cypress:ci script runs"
-
replace src/main.ts file content with:
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic() .bootstrapModule(AppModule) .then((ref) => { if (window[`ngRef`]) { window[`ngRef`].destroy(); } window[`ngRef`] = ref; }) .catch((err) => console.error(err));
$ git c "refactor(project): ensure angular destroys itself on hot reloads"
-
$ npm i -D rimraf@latest $ git c "chore(rimraf): install package"
-
on package.json file, add:
"scripts": { ... "prebuild": "rimraf dist", ...
$ git c "build(script): ensure rimraf destroy the dist folder before building"
-
$ npm install -D npm-check@latest $ git c "chore(npm-check): install package"
-
on package.json file, add:
"scripts": { ... "check": "npm-check -s -u", ...
$ git c "chore(npm-check): add check script to ensure project packages to be updated"
-
Optional
$ npm run check $ git c "chore(zone.js): upgrade version from 0.10.3 to 0.11.1"
-
Optional
$ npm run check $ git c "chore(types/node): upgrade version from 12.12.62 to 14.11.2"
-
Optional
$ npm run check $ git c "chore(ts-node): upgrade version from 8.3.0 to 9.0.0"
-
Create a new project after logging in to the Cypress Test Runner Setup
$ npx cypress open # Login # Click on the run tab # Conect to dashboard # Setup project (Project name, organization, project visibility) # Copy projectId and CYPRESS_RECORD_KEY # Exit
-
Ensure if automatically added the projectId on cypress.json file and commit:
{ ... "projectId": <<YOUR ProjectId>> ... }
$ git c "chore(cypress): setup projectId"
-
create .env file and add:
CYPRESS_RECORD_KEY=<<ENTER YOUR CYPRESS_RECORD_KEY>>
-
$ npm install -D env-cmd@latest $ git c "chore(env-cmd): install package"
-
on package.json file, update:
"scripts": { ..., "cypress:e2e": "env-cmd npm run cypress:ci", ...
$ git c "chore(cypress): enable record key to be visible when cypress:e2e test script runs"
87. Create GIT Repo on GitHub
- do not push on it yet
88. Assign Repo to cypress.io
89. Assign Repo to Coveralls
90. Assign Repo to TravisCI
91. Add CYPRESS_RECORD_KEY to TravisCI project environment variables
-
on package.json file, add:
{ ... "badges": [ { "description": "Travis-CI - Build Status", "href": "https://travis-ci.org/luizhp/template-app-angular.svg?branch=main", "url": "https://travis-ci.org/luizhp/template-app-angular" }, { "description": "Coveralls - Coverage Status", "href": "https://coveralls.io/repos/github/luizhp/template-app-angular/badge.svg?branch=main", "url": "https://coveralls.io/github/luizhp/template-app-angular?branch=main" }, { "description": "snyk.io - Known Vulnerabilities", "href": "https://snyk.io/test/github/luizhp/template-app-angular/badge.svg?targetFile=package.json", "url": "https://snyk.io/test/github/luizhp/template-app-angular?targetFile=package.json" }, { "description": "cypress.io", "href": "https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/oaq3oo/main&style=flat&logo=cypress", "url": "https://dashboard.cypress.io/projects/oaq3oo/runs" }, { "description": "Prettier Code Style", "href": "https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square", "url": "https://github.com/prettier/prettier/" }, { "description": "Commitizen friendly", "href": "https://img.shields.io/badge/commitizen-friendly-brightgreen.svg", "url": "https://commitizen.github.io/cz-cli/" }, { "description": "GPLv3 License", "href": "https://img.shields.io/badge/License-GPL%20v3-yellow.svg", "url": "https://opensource.org/licenses/" }, { "description": "Open Source", "href": "https://badges.frapsoft.com/os/v1/open-source.svg?v=103", "url": "https://opensource.org/" } ], ... }
$ git c "chore(project): ensure all badges are declared"
-
$ npm i -D standard-version $ git c "chore(standard-version): install package"
-
on package.json file, add:
{ ... "standard-version": { "changelogHeader": "# Template Angular TDD App\n\nAll notable changes to this project will be documented here.\n\n" }
$ git c "chore(standard-version): setup changelog header output"
-
on package.json file, add:
"scripts": { ... "release": "HUSKY_SKIP_HOOKS=1 standard-version", ... }
$ git c "chore(standard-version): add release script"
-
on package.json file, update:
"version": "1.0.0",
$ npm run release -- --first-release
$ git add ./package.json
$ git commit --amend --no-edit
100. Assign Repo to snyk.io
Contributions are always welcome! 👊
You can reach me out at Twitter @luizhp
Give a ⭐️ if this project helped you!
Copyright © 2020 .luizhp
This project is GPL v3 licensed.