From 1808d9f2dcef31fedfd6f342550b95f19fadae5d Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Wed, 25 Jan 2017 16:24:55 -0800 Subject: [PATCH] Refactor test setup * Use shared global type definitions * Fix non-relative pathing for imports * Integrate test double library sinon as a global * Rework expect to make it a global * Integrate mocha-gherkin across all packages * Rewrite loopback black-box test using mocha-gherkin syntax * Remove unused .eslintignore in package loopback * Simply bootstrapping tests * Fix Application constructor and start methods --- .vscode/launch.json | 21 ++++++++ .vscode/settings.json | 3 ++ .vscode/tasks.json | 48 +++++++++++++++++++ package.json | 4 ++ packages/juggler/package.json | 5 +- packages/juggler/test/black-box/smoke.ts | 8 ++-- packages/juggler/test/white-box/smoke.ts | 8 ++-- packages/loopback/.eslintignore | 2 - packages/loopback/.travis.yml | 3 +- packages/loopback/index.ts | 5 ++ packages/loopback/lib/application.ts | 26 +++++++--- packages/loopback/loopback.ts | 1 - packages/loopback/package.json | 4 +- .../loopback/test/black-box/bootstrapping.ts | 25 ++++++++++ .../test/black-box/bootstrapping/features.md | 6 --- .../test/black-box/bootstrapping/index.ts | 17 ------- packages/loopback/test/support/client.ts | 6 +-- packages/loopback/test/support/container.ts | 6 --- packages/loopback/test/support/expect.ts | 7 --- packages/loopback/test/support/scenarios.ts | 8 ---- packages/loopback/test/support/support.d.ts | 1 - packages/loopback/test/support/util.ts | 18 +++---- .../loopback/test/white-box/application.ts | 20 ++++++++ packages/loopback/test/white-box/smoke.ts | 7 --- packages/remoting/package.json | 5 +- packages/remoting/test/black-box/smoke.ts | 8 ++-- packages/remoting/test/white-box/smoke.ts | 8 ++-- test/expect.ts | 3 +- test/gherkin.ts | 18 +++++++ test/global-types.d.ts | 8 ++++ test/mocha.opts.black-box | 9 ++-- test/mocha.opts.white-box | 7 ++- test/sinon.ts | 1 + test/{ts-nodify.js => ts-node.js} | 0 tsconfig.json | 14 ++++-- 35 files changed, 224 insertions(+), 116 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json delete mode 100644 packages/loopback/.eslintignore create mode 100644 packages/loopback/index.ts delete mode 100644 packages/loopback/loopback.ts create mode 100644 packages/loopback/test/black-box/bootstrapping.ts delete mode 100644 packages/loopback/test/black-box/bootstrapping/features.md delete mode 100644 packages/loopback/test/black-box/bootstrapping/index.ts delete mode 100644 packages/loopback/test/support/container.ts delete mode 100644 packages/loopback/test/support/expect.ts delete mode 100644 packages/loopback/test/support/scenarios.ts delete mode 100644 packages/loopback/test/support/support.d.ts create mode 100644 packages/loopback/test/white-box/application.ts delete mode 100644 packages/loopback/test/white-box/smoke.ts create mode 100644 test/gherkin.ts create mode 100644 test/global-types.d.ts create mode 100644 test/sinon.ts rename test/{ts-nodify.js => ts-node.js} (100%) diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000000..22ce6df06eed --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceRoot}/app.js", + "cwd": "${workspaceRoot}" + }, + { + "type": "node", + "request": "attach", + "name": "Attach to Process", + "port": 5858 + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..c7c1623bc4e6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "./node_modules/typescript/lib" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000000..f5e64488a7f5 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,48 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "lerna", + "isShellCommand": true, + "echo command": true, + "showOutput": "always", + "suppressTaskName": true, + "tasks": [ + // Installing dependencies + { + "taskName": "Install dependencies", + "args": ["exec", "npm", "install"] + }, + { + "taskName": "Install loopback dependencies", + "args": ["exec", "npm", "install", "--scope", "loopback"] + }, + { + "taskName": "Install juggler dependencies", + "args": ["exec", "npm", "install", "--scope", "@loopback/juggler"] + }, + { + "taskName": "Install remoting dependencies", + "args": ["exec", "npm", "install", "--scope", "@loopback/remoting"] + }, + // Running tests + { + // run all tests for every package + "taskName": "test", // DO NOT CHANGE (used for vscode ctrl+shift+t keybinding) + "args": ["run", "test"], + "isTestCommand": true + }, + { + "taskName": "Run loopback tests", + "args": ["run", "test", "--scope", "loopback"] + }, + { + "taskName": "Run juggler tests", + "args": ["run", "test", "--scope", "@loopback/juggler"] + }, + { + "taskName": "Run remoting tests", + "args": ["run", "test", "--scope", "@loopback/remoting"] + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 2078ed304f2c..e532fc1edfe7 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,16 @@ { "license": "MIT", "devDependencies": { + "@types/mocha": "^2.2.38", + "@types/node": "^7.0.4", "chai": "^3.5.0", "dirty-chai": "^1.2.2", "lerna": "^2.0.0-beta.32", "request": "^2.79.0", "request-promise": "^4.1.1", + "sinon": "^1.17.7", "ts-node": "^2.0.0", + "tsconfig-paths": "^2.1.0", "typescript": "^2.1.5" }, "dependencies": { diff --git a/packages/juggler/package.json b/packages/juggler/package.json index a561b628c4ef..5c86c1191319 100644 --- a/packages/juggler/package.json +++ b/packages/juggler/package.json @@ -5,12 +5,13 @@ "main": "index.js", "scripts": { "black-box": "mocha --opts ../../test/mocha.opts.black-box", - "test": "npm run black-box && npm run white-box", + "test": "npm run white-box && npm run black-box", "white-box": "mocha --opts ../../test/mocha.opts.white-box" }, "author": "IBM", "license": "MIT", "devDependencies": { - "mocha": "^3.2.0" + "mocha": "^3.2.0", + "mocha-gherkin": "^0.2.0" } } diff --git a/packages/juggler/test/black-box/smoke.ts b/packages/juggler/test/black-box/smoke.ts index f6186d3c4cce..7fd3f6d83f14 100644 --- a/packages/juggler/test/black-box/smoke.ts +++ b/packages/juggler/test/black-box/smoke.ts @@ -1,7 +1,5 @@ -import {expect} from '../../../../test/expect'; - -suite('black-box smoke test', () => { - test('passes', () => { +describe('white-box smoke test', () => { + it('passes', () => { expect(true).to.be.true(); }); -}); +}); \ No newline at end of file diff --git a/packages/juggler/test/white-box/smoke.ts b/packages/juggler/test/white-box/smoke.ts index e80379f22bea..33b3a107cdcc 100644 --- a/packages/juggler/test/white-box/smoke.ts +++ b/packages/juggler/test/white-box/smoke.ts @@ -1,7 +1,5 @@ -import {expect} from '../../../../test/expect'; - -describe('white-box smoke test', () => { - it('passes', () => { +suite('white-box smoke test', () => { + test('passes', () => { expect(true).to.be.true(); }); -}); +}); \ No newline at end of file diff --git a/packages/loopback/.eslintignore b/packages/loopback/.eslintignore deleted file mode 100644 index 009af5438f17..000000000000 --- a/packages/loopback/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -coverage diff --git a/packages/loopback/.travis.yml b/packages/loopback/.travis.yml index 01bff6f247fc..fa5016567131 100644 --- a/packages/loopback/.travis.yml +++ b/packages/loopback/.travis.yml @@ -3,5 +3,4 @@ language: node_js node_js: - "4" - "6" - - "7" - + - "7" \ No newline at end of file diff --git a/packages/loopback/index.ts b/packages/loopback/index.ts new file mode 100644 index 000000000000..f171ba262305 --- /dev/null +++ b/packages/loopback/index.ts @@ -0,0 +1,5 @@ +export { + Application, + AppConfig, + AppState +} from './lib/application'; \ No newline at end of file diff --git a/packages/loopback/lib/application.ts b/packages/loopback/lib/application.ts index 12164037a798..706c391a5db6 100644 --- a/packages/loopback/lib/application.ts +++ b/packages/loopback/lib/application.ts @@ -1,23 +1,35 @@ import http = require('http'); - import bluebird = require('bluebird'); export interface AppConfig { port : number; } +export enum AppState { + cold, + starting, + listening, + crashed, + stopped +} + export class Application { - constructor(public config : AppConfig) { + // get runtime to enforce AppConfig as AppConfig + constructor(public config?: AppConfig) { if (config === undefined) { this.config = {port: 3000}; } } - public start() : Promise { - let server = http.createServer((req, res) => { + + public state: AppState = AppState.cold; + + async start() { + this.state = AppState.starting; + const server = http.createServer((req, res) => { res.end(); }); - let listen = bluebird.promisify(server.listen, {context: server}); - - return listen(this.config.port); + const listen = bluebird.promisify(server.listen, {context: server}); + await listen(this.config.port); + this.state = AppState.listening; } } \ No newline at end of file diff --git a/packages/loopback/loopback.ts b/packages/loopback/loopback.ts deleted file mode 100644 index 2e2b1417f7da..000000000000 --- a/packages/loopback/loopback.ts +++ /dev/null @@ -1 +0,0 @@ -export { Application, AppConfig } from './lib/application'; \ No newline at end of file diff --git a/packages/loopback/package.json b/packages/loopback/package.json index d97b403a1099..e945d8684218 100644 --- a/packages/loopback/package.json +++ b/packages/loopback/package.json @@ -11,7 +11,7 @@ "author": "IBM", "license": "MIT", "devDependencies": { - "@types/mocha": "^2.2.38", - "mocha": "^3.2.0" + "mocha": "^3.2.0", + "mocha-gherkin": "^0.2.0" } } diff --git a/packages/loopback/test/black-box/bootstrapping.ts b/packages/loopback/test/black-box/bootstrapping.ts new file mode 100644 index 000000000000..affe80a9fa67 --- /dev/null +++ b/packages/loopback/test/black-box/bootstrapping.ts @@ -0,0 +1,25 @@ +import * as util from 'loopback/test/support/util'; + +Feature('Bootstrapping', + 'In order to serve up my API', + 'As a user', + 'I want to start the app', () => { + Scenario('with default configs', () => { + let app; + let client; + + Given('an app', () => { + app = util.createApp(); + }); + And('a client', () => { + client = util.createClient(app); + }); + When('the app is started (on port 3000 by default)', async () => { + await app.start(); + }); + Then('the app responds with HTTP 200 when a request is sent to GET /', async () => { + const result = await client.get('/') + expect(result.statusCode).to.equal(200); + }); + }); +}); \ No newline at end of file diff --git a/packages/loopback/test/black-box/bootstrapping/features.md b/packages/loopback/test/black-box/bootstrapping/features.md deleted file mode 100644 index fccb843ab3af..000000000000 --- a/packages/loopback/test/black-box/bootstrapping/features.md +++ /dev/null @@ -1,6 +0,0 @@ -As a user I want to start the app - - Scenario: using default configs - Given a newly scaffolded app - When I run it - Then it starts on port 3000 diff --git a/packages/loopback/test/black-box/bootstrapping/index.ts b/packages/loopback/test/black-box/bootstrapping/index.ts deleted file mode 100644 index b5c3c6b99b63..000000000000 --- a/packages/loopback/test/black-box/bootstrapping/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -scenarios('User starting app', (util, expect) => { - context('Given an app using default configs', () => { - let app; - let client; - - before(async () => { - app = util.createApp(); - client = util.createClient(app); - await app.start(); - }); - - it('will start the app on port 3000', async () => { - let result = await client.get('/') - expect(result.status).to.equal(200); - }); - }); -}); diff --git a/packages/loopback/test/support/client.ts b/packages/loopback/test/support/client.ts index 567560e9068f..a19fc8e922a3 100644 --- a/packages/loopback/test/support/client.ts +++ b/packages/loopback/test/support/client.ts @@ -1,10 +1,10 @@ -import { Application, AppConfig } from '../../loopback'; +import { Application, AppConfig } from 'loopback'; import bluebird = require('bluebird'); import request = require('request-promise'); export class Client { constructor(public app : Application) { - + } public get(path : string) : Promise{ @@ -17,7 +17,7 @@ export class Client { return request(options) .then((response) => { return { - status: response.statusCode + statusCode: response.statusCode }; }); } diff --git a/packages/loopback/test/support/container.ts b/packages/loopback/test/support/container.ts deleted file mode 100644 index bc42b00064de..000000000000 --- a/packages/loopback/test/support/container.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Container } from 'inversify'; -import 'reflect-metadata'; - -const container = new Container(); - -export default container; diff --git a/packages/loopback/test/support/expect.ts b/packages/loopback/test/support/expect.ts deleted file mode 100644 index fac4f4b92960..000000000000 --- a/packages/loopback/test/support/expect.ts +++ /dev/null @@ -1,7 +0,0 @@ -import chai = require('chai'); -import dirtyChai = require('dirty-chai'); - -chai.use(dirtyChai); -const expect = chai.expect; - -export default expect; \ No newline at end of file diff --git a/packages/loopback/test/support/scenarios.ts b/packages/loopback/test/support/scenarios.ts deleted file mode 100644 index ec2b3599f24d..000000000000 --- a/packages/loopback/test/support/scenarios.ts +++ /dev/null @@ -1,8 +0,0 @@ -import expect from './expect'; -import util from './util'; - -global['scenarios'] = function(description : string, cb) { - describe(description, () => { - cb(util, expect); - }); -}; diff --git a/packages/loopback/test/support/support.d.ts b/packages/loopback/test/support/support.d.ts deleted file mode 100644 index fbe3c8459cf7..000000000000 --- a/packages/loopback/test/support/support.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare var scenarios : Function; \ No newline at end of file diff --git a/packages/loopback/test/support/util.ts b/packages/loopback/test/support/util.ts index 5c5e37a954db..430fd3e62e6f 100644 --- a/packages/loopback/test/support/util.ts +++ b/packages/loopback/test/support/util.ts @@ -1,16 +1,10 @@ -import { Application, AppConfig } from '../../loopback'; +import { Application, AppConfig } from 'loopback'; import { Client } from './client'; - -class Util { - public createApp(config: AppConfig) : Application { - return new Application(config); - } - public createClient(app : Application) { - return new Client(app); - } +export function createApp(config?: AppConfig) : Application { + return new Application(config); } - - -export default new Util; \ No newline at end of file +export function createClient(app : Application) { + return new Client(app); +} \ No newline at end of file diff --git a/packages/loopback/test/white-box/application.ts b/packages/loopback/test/white-box/application.ts new file mode 100644 index 000000000000..42fefa2cb241 --- /dev/null +++ b/packages/loopback/test/white-box/application.ts @@ -0,0 +1,20 @@ +import {Application, AppState} from 'loopback'; + +suite('Application', () => { + suite('constructor(config?: AppConfig)', () => { + test('without config arg', () => { + const app = new Application(); + expect(app.config).to.be.an('object'); + expect(app.config.port).to.eql(3000); + }); + }) + + suite('start()', () => { + test('when state is cold', async () => { + const app = new Application(); + expect(app.state).to.equal(AppState.cold); + await app.start(); + expect(app.state).to.equal(AppState.listening); + }); + }); +}); \ No newline at end of file diff --git a/packages/loopback/test/white-box/smoke.ts b/packages/loopback/test/white-box/smoke.ts deleted file mode 100644 index f6186d3c4cce..000000000000 --- a/packages/loopback/test/white-box/smoke.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {expect} from '../../../../test/expect'; - -suite('black-box smoke test', () => { - test('passes', () => { - expect(true).to.be.true(); - }); -}); diff --git a/packages/remoting/package.json b/packages/remoting/package.json index 8c691292e11a..191bbdf44983 100644 --- a/packages/remoting/package.json +++ b/packages/remoting/package.json @@ -5,12 +5,13 @@ "main": "index.js", "scripts": { "black-box": "mocha --opts ../../test/mocha.opts.black-box", - "test": "npm run black-box && npm run white-box", + "test": "npm run white-box && npm run black-box", "white-box": "mocha --opts ../../test/mocha.opts.white-box" }, "author": "IBM", "license": "MIT", "devDependencies": { - "mocha": "^3.2.0" + "mocha": "^3.2.0", + "mocha-gherkin": "^0.2.0" } } diff --git a/packages/remoting/test/black-box/smoke.ts b/packages/remoting/test/black-box/smoke.ts index f6186d3c4cce..63f4950e6df6 100644 --- a/packages/remoting/test/black-box/smoke.ts +++ b/packages/remoting/test/black-box/smoke.ts @@ -1,7 +1,5 @@ -import {expect} from '../../../../test/expect'; - -suite('black-box smoke test', () => { - test('passes', () => { +describe('black-box smoke test', () => { + it('passes', () => { expect(true).to.be.true(); }); -}); +}); \ No newline at end of file diff --git a/packages/remoting/test/white-box/smoke.ts b/packages/remoting/test/white-box/smoke.ts index e80379f22bea..33b3a107cdcc 100644 --- a/packages/remoting/test/white-box/smoke.ts +++ b/packages/remoting/test/white-box/smoke.ts @@ -1,7 +1,5 @@ -import {expect} from '../../../../test/expect'; - -describe('white-box smoke test', () => { - it('passes', () => { +suite('white-box smoke test', () => { + test('passes', () => { expect(true).to.be.true(); }); -}); +}); \ No newline at end of file diff --git a/test/expect.ts b/test/expect.ts index 61bcc15b4484..d1a3e0965476 100644 --- a/test/expect.ts +++ b/test/expect.ts @@ -2,5 +2,6 @@ import chai = require('chai'); import dirtyChai = require('dirty-chai'); chai.use(dirtyChai); +const expect = chai.expect; -export const expect = chai.expect; +global['expect'] = expect; \ No newline at end of file diff --git a/test/gherkin.ts b/test/gherkin.ts new file mode 100644 index 000000000000..174fe575259c --- /dev/null +++ b/test/gherkin.ts @@ -0,0 +1,18 @@ +global['AsA'] = function(description : string, cb) { + describe(description, cb); +}; +global['Scenario'] = function(description : string, cb) { + context(description, cb); +}; +global['Given'] = function(description : string, cb) { + before(description, cb || function() {}); +}; +global['And'] = function(description : string, cb) { + before(description, cb || function() {}); +}; +global['When'] = function(description : string, cb) { + before(description, cb || function() {}); +}; +global['Then'] = function(description : string, cb) { + it(description, cb); +}; \ No newline at end of file diff --git a/test/global-types.d.ts b/test/global-types.d.ts new file mode 100644 index 000000000000..15fa4199f68b --- /dev/null +++ b/test/global-types.d.ts @@ -0,0 +1,8 @@ +declare var expect : Function; +declare var Feature : Function; +declare var Scenario : any; +declare var Given : any; +declare var And : any; +declare var When : any; +declare var Then : any; +declare var sinon : any; \ No newline at end of file diff --git a/test/mocha.opts.black-box b/test/mocha.opts.black-box index 74bdcd6054ff..17488e2f8fdd 100644 --- a/test/mocha.opts.black-box +++ b/test/mocha.opts.black-box @@ -1,4 +1,7 @@ ---require ../../test/ts-nodify.js ---require test/support/scenarios.ts ---ui bdd +--require ../../test/ts-node.js +--compilers ts:tsconfig-paths/register +--require ../../test/gherkin.ts +--require ../../test/expect.ts +--require ../../test/sinon.ts +--ui mocha-gherkin --reporter mocha-gherkin/build/spec test/black-box/**/*.ts diff --git a/test/mocha.opts.white-box b/test/mocha.opts.white-box index d630e9925e24..e0b4d194a527 100644 --- a/test/mocha.opts.white-box +++ b/test/mocha.opts.white-box @@ -1,4 +1,7 @@ ---require ../../test/ts-nodify.js ---require test/support/scenarios.ts +--require ../../test/ts-node.js +--compilers ts:tsconfig-paths/register +--require ../../test/gherkin.ts +--require ../../test/expect.ts +--require ../../test/sinon.ts --ui tdd test/white-box/**/*.ts diff --git a/test/sinon.ts b/test/sinon.ts new file mode 100644 index 000000000000..b4a0ccab35e1 --- /dev/null +++ b/test/sinon.ts @@ -0,0 +1 @@ +global['sinon'] = require('sinon'); diff --git a/test/ts-nodify.js b/test/ts-node.js similarity index 100% rename from test/ts-nodify.js rename to test/ts-node.js diff --git a/tsconfig.json b/tsconfig.json index 3d85ea4cab3c..4c9483ae526a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,20 @@ { "compilerOptions": { - "target": "es5", + "baseUrl": ".", + "paths": { + "*": ["packages/*"] + }, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, "lib": ["es6", "dom"], - "types": ["reflect-metadata"], "module": "commonjs", "moduleResolution": "node", - "experimentalDecorators": true, - "emitDecoratorMetadata": true + "target": "es5" }, "include": [ "examples/**/*.ts", - "packages/**/*.ts" + "packages/**/*.ts", + "test/global-types.d.ts" ], "exclude": [ "node_modules"