├── .editorconfig
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── appveyor.yml
├── custom-typings
└── chai-subset.d.ts
├── package.json
├── src
├── greeter.ts
└── index.ts
├── test
├── greeter.spec.ts
└── setup.ts
├── tsconfig.json
├── webpack.config.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | insert_final_newline = true
5 | charset = utf-8
6 | trim_trailing_whitespace = true
7 | indent_style = space
8 |
9 | [*.{js,jsx,ts,tsx}]
10 | indent_size = 4
11 |
12 | [*.json]
13 | indent_size = 2
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | node_modules
28 |
29 | # Optional npm cache directory
30 | .npm
31 |
32 | # Optional REPL history
33 | .node_repl_history
34 |
35 | # TypeScript target
36 | dist
37 |
38 | # Visual Studio Code local project settings
39 | .vscode
40 |
41 | .idea
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: required
3 | language: node_js
4 |
5 | node_js:
6 | - "9"
7 | - "8"
8 |
9 | os:
10 | - linux
11 |
12 |
13 | before_install:
14 | - sudo sysctl fs.inotify.max_user_watches=524288
15 | - yarn global add greenkeeper-lockfile@1
16 |
17 | before_script:
18 | - greenkeeper-lockfile-update
19 |
20 | after_script:
21 | - greenkeeper-lockfile-upload
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Wix.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # typescript-boilerplate
2 |
3 | [](https://greenkeeper.io/)
4 | [](https://travis-ci.org/wix/typescript-boilerplate)
5 |
6 | Generic project boilerplate for isomorphic TypeScript
7 |
8 | ### project features
9 | - Typescript in strict mode (the only way to roll!)
10 | - Customised 3rd parrty typings in `./custom_typings` folder
11 | - Fully automated tests that run both in node and browser using mocha + chai
12 | - Test tools set-up phase that is loaded prior to any test being run
13 | - Automatically discoverable tests (by glob pattern defined in package.json)
14 | - Dev server for live updates in browser and transpiled files
15 | - Least opinionated setup: no run time dependencies and minimal configuration
16 |
17 | ## developer documentation
18 | how to build and test:
19 | - clone the repository
20 | - in the cloned folder, run `npm install`
21 | - run `npm test` to build and test the code in both nodejs and browser
22 |
23 | how to debug (browser):
24 | - run `npm start` to run a development server
25 | - open `http://localhost:8080/test.bundle` to run live tests that will update while you change the source code
26 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | nodejs_version: "8"
3 |
4 | # Install scripts. (runs after repo cloning)
5 |
6 | install:
7 | # Get the latest stable version of Node.js or io.js
8 | - ps: Install-Product node $env:nodejs_version
9 | # install modules
10 | - yarn
11 |
12 | # Post-install test scripts.
13 | test_script:
14 | # Output useful info for debugging.
15 | - node --version
16 | - yarn --version
17 | # run tests
18 | - yarn test
19 |
20 | # Don't actually build.
21 | build: off
22 |
23 | cache:
24 | - "%LOCALAPPDATA%\\Yarn"
25 |
--------------------------------------------------------------------------------
/custom-typings/chai-subset.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for chai-subset 1.0.0
2 | // Project: https://github.com/e-conomic/chai-subset
3 | // Definitions by: Sam Noedel , Andrew Brown
4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5 |
6 | ///
7 |
8 | declare namespace Chai {
9 | interface Assertion {
10 | containSubset(obj: object): Assertion;
11 | }
12 | }
13 |
14 | declare module "chai-subset" {
15 | function chaiSubset(chai: any, utils: any): void;
16 | namespace chaiSubset {}
17 | export = chaiSubset;
18 | }
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typescript-boilerplate",
3 | "version": "0.0.1",
4 | "description": "Generic project boilerplate for TypeScript",
5 | "author": "Amir Arad (amira@wix.com)",
6 | "license": "MIT",
7 | "bugs": {
8 | "url": "https://github.com/wix/typescript-boilerplate/issues"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git@github.com:wix/typescript-boilerplate.git"
13 | },
14 | "files": [
15 | "dist/src"
16 | ],
17 | "testGlob": "./dist/test/**/*.spec.js?(x)",
18 | "homepage": "https://github.com/wix/typescript-boilerplate#readme",
19 | "keywords": [
20 | "typescript",
21 | "tdd"
22 | ],
23 | "main": "dist/src/index.js",
24 | "browser": "dist/src/index.js",
25 | "scripts": {
26 | "build": "tsc -d",
27 | "bundle": "webpack --progress",
28 | "reset": "rimraf node_modules dist && yarn install && yarn test",
29 | "test": "run-s test:node test:browser:run",
30 | "test:node": "mocha --require ts-node/register/transpile-only --require test/setup.ts --require source-map-support/register test/*.spec.ts",
31 | "test:browser:run": "run-p -r start test:browser:run2",
32 | "test:browser:run2": "run-s start:wait test:browser",
33 | "test:browser": "cross-var mocha-headless-chrome $HL_CHROME_PARAMS -t 30000 -f http://localhost:8080/test.bundle",
34 | "start": "tsc-watch --onFirstSuccess \"webpack-dev-server --no-info\"",
35 | "start:wait": "wait-on -t 30000 http://localhost:8080/test.bundle"
36 | },
37 | "devDependencies": {
38 | "@types/chai": "~4.1.2",
39 | "@types/mocha": "~5.2.0",
40 | "@types/sinon": "~5.0.1",
41 | "@types/sinon-chai": "~3.2.0",
42 | "chai": "~4.1.0",
43 | "chai-subset": "~1.6.0",
44 | "cross-var": "^1.1.0",
45 | "glob": "~7.1.2",
46 | "mocha": "~5.2.0",
47 | "mocha-env-reporter": "~3.0.0",
48 | "mocha-headless-chrome": "^2.0.0",
49 | "mocha-loader": "~1.1.1",
50 | "npm-run-all": "^4.1.2",
51 | "rimraf": "~2.6.1",
52 | "sinon": "~6.0.1",
53 | "sinon-chai": "~3.2.0",
54 | "source-map-support": "~0.5.0",
55 | "ts-node": "^7.0.0",
56 | "tsc-watch-2": "^0.0.2",
57 | "tslib": "~1.9.0",
58 | "typescript": "~2.9.1",
59 | "wait-on": "^2.1.0",
60 | "webpack": "~4.12.0",
61 | "webpack-cli": "^3.0.3",
62 | "webpack-dev-server": "~3.1.1"
63 | },
64 | "peerDependencies": {
65 | "tslib": "~1.7.1"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/greeter.ts:
--------------------------------------------------------------------------------
1 |
2 | export function hello(name:string){
3 | return "Hello "+name;
4 | }
5 |
6 | export function helloObj(name:string, greet:(a:string)=>string){
7 | return {name, greet:greet(name)};
8 | }
9 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export * from './greeter';
3 |
--------------------------------------------------------------------------------
/test/greeter.spec.ts:
--------------------------------------------------------------------------------
1 | import {hello, helloObj} from "../src/greeter";
2 | import {expect} from 'chai';
3 | import * as sinon from 'sinon';
4 |
5 |
6 | const NAME = 'Joe';
7 | const PLACEHOLDER = 'placeholder';
8 |
9 |
10 | describe('greeter', () => {
11 | // simple unit test
12 | it('greets', ()=>{
13 | expect(hello(NAME).toLowerCase()).to.equal('hello joe');
14 | });
15 |
16 | //more complex unit test
17 | it('produces object', ()=>{
18 | const mySpy = sinon.spy(()=>PLACEHOLDER);
19 | const result = helloObj(NAME, mySpy);
20 |
21 | expect(mySpy).to.have.callCount(1);
22 | expect(mySpy).to.have.been.calledWith(NAME);
23 | expect(result).to.containSubset({greet:PLACEHOLDER});
24 | });
25 |
26 | // integration test
27 | it('object works with provided greeter', ()=>{
28 | expect(helloObj(NAME, hello)).to.containSubset({greet:'Hello Joe'});
29 | });
30 |
31 | });
32 |
--------------------------------------------------------------------------------
/test/setup.ts:
--------------------------------------------------------------------------------
1 | import * as chai from 'chai';
2 | import * as sinonChai from 'sinon-chai';
3 | import * as chaiSubset from 'chai-subset';
4 |
5 | chai.use(sinonChai);
6 | chai.use(chaiSubset);
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": [
4 | "es2015"
5 | ],
6 | "module": "commonjs",
7 | "target": "es5",
8 | "strict": true,
9 | "importHelpers": true,
10 | "noImplicitReturns": true,
11 | "strictNullChecks": true,
12 | "sourceMap": true,
13 | "outDir": "dist",
14 | "typeRoots": [
15 | "./node_modules/@types",
16 | "./custom-typings"
17 | ]
18 | },
19 | "exclude": [
20 | "node_modules",
21 | "dist"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const glob = require("glob");
3 | const {testGlob} = require('./package.json');
4 | const testFiles = glob.sync(testGlob);
5 |
6 | const distPath = path.join(__dirname, 'dist');
7 |
8 | const testsSetup = [path.join(__dirname, 'dist', 'test', 'setup.js')];
9 | module.exports = {
10 | mode: 'development',
11 | devtool: 'eval',
12 | entry: {
13 | test: testsSetup.concat(testFiles.map(fileName => `mocha-loader!${fileName}`))
14 | },
15 | output: {
16 | path: distPath,
17 | filename: '[name].bundle.js',
18 | libraryTarget: 'umd',
19 | pathinfo: true
20 | },
21 | devServer: {
22 | contentBase: distPath,
23 | inline: true,
24 | hot: false
25 | },
26 | module: {
27 | noParse: [/\.min\.js$/, /\.bundle\.js$/]
28 | }
29 | };
30 |
--------------------------------------------------------------------------------