5. • 마술 같은 2-way binding
• HTML 표준을 기반으로 기능 확장
• 체계적인 컴포넌트 구성, Web Component로 가는 길
• Front-end 전체를 커버하는 프레임워크
• Google 에서 관리, 개선
• 풍부한 사용자 삽질 경험
Angular를 쓰는 이유
5
24. describe('homeCtrl.test', () => {
it('module import', () => {
expect(true).to.be.true;
});
});
λ karma start
(node:7564) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new
Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:53:45.852:INFO [framework.browserify]: bundle built
18 11 2016 02:53:45.941:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:53:45.941:INFO [launcher]: Launching browser Chrome with unlimited concurrency
18 11 2016 02:53:45.952:INFO [launcher]: Starting browser Chrome
18 11 2016 02:53:47.283:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket
/#AjAqCwTlrwmVmV_sAAAA with id 16857313
Chrome 54.0.2840 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.005 secs / 0.001 secs)
BDD 시작
24
25. λ karma start
(node:12196) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably
`Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:19:10.237:INFO [framework.browserify]: bundle built
18 11 2016 02:19:10.343:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:19:10.343:INFO [launcher]: Launching browser Chrome with unlimited concurrency
18 11 2016 02:19:10.353:INFO [launcher]: Starting browser Chrome
18 11 2016 02:19:11.676:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#sBpP4RL0XFZAwPtxAAAA with id 52822107
Chrome 54.0.2840 (Windows 10 0.0.0) ERROR
Uncaught SyntaxError: Unexpected token import
at test/homeCtrl.test.js:1
import HomeCtrl from '../view/homeCtrl';
describe('homeCtrl.test', () => {
it('module import', () => {
console.log(HomeCtrl);
expect(true).to.be.true;
expect(HomeCtrl).to.be.ok;
});
});
λ karma start
(node:11580) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably
`Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:31:24.248:INFO [framework.browserify]: bundle built
18 11 2016 02:31:24.339:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:31:24.339:INFO [launcher]: Launching browser Chrome with unlimited concurrency
18 11 2016 02:31:24.349:INFO [launcher]: Starting browser Chrome
18 11 2016 02:31:25.657:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#pvpyGrXqq2TZPTgmAAAA with id 30236974
LOG: class HomeCtrl { ... }
Chrome 54.0.2840 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.007 secs / 0.002 secs)
babel : node6
λ karma start
(node:13196) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably
`Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:58:38.638:INFO [framework.browserify]: bundle built
18 11 2016 02:58:38.728:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:58:38.729:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
18 11 2016 02:58:38.738:INFO [launcher]: Starting browser PhantomJS
18 11 2016 02:58:40.301:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket /#JeRwavdozVZCC8HJAAAA with id 75347319
LOG: function HomeCtrl(MyService) { ... }
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 1 of 1 SUCCESS (0.008 secs / 0.001 secs)
babel : es2015
ES6가 돌지 않는다…
+
25
26. var $httpBackend;
beforeEach(function () {
module('angular1es5');
inject(function (_$httpBackend_) {
$httpBackend = _$httpBackend_;
});
});
module 선언, injection 불가
ES6ES5
const $injector, $httpBackend;
beforeEach(() => {
$injector = angular.injector(['angular1es6']);
$httpBackend = $injector.get('$httpBackend');
});
Object is not a constructor (evaluating 'module('angular1es6')')
r:/temp/test/homeCtrl.test.js:15:9 <-
R:/temp/3871fde1c6cf6c302eeae7add18a3b02.browserify:22:9
26
let ngApp = angular.module('angular1es6', ['ngMock']);
27. ngMock vs. ngMockE2E
The ngMock module provides support to inject
and mock Angular services into unit tests. In
addition, ngMock also extends various core ng
services such that they can be inspected and
controlled in a synchronous manner within test
code.
The ngMockE2E is an angular module which
contains mocks suitable for end-to-end testing.
Currently there is only one mock present in this
module - the e2e $httpBackend mock.
ngMock ngMockE2E
Fake HTTP backend implementation suitable for end-to-
end testing or backend-less development of applications
that use the $http service.
Fake HTTP backend implementation suitable for unit
testing applications that use the $http service.
.when()
.expect()
.flush()
.verifyNoOutstandingExpectation()
.verifyNoOutstandingRequest()
.resetExpectations()
.when()
ngMockE2E에는 $location 없음 27
28. Promise + http.flush()
Chrome 54.0.2840 (Windows 10 0.0.0) homeCtrl.test http test ok FAILED
Error: No pending request to flush !
at Function.$httpBackend.flush (node_modules/angular-mocks/angular-mocks.js:1799:34)
at r:/temp/test/homeCtrl.test.js:36:17
promise 함수로 부르면 동작 안함
flush() 타이밍 달라짐
flush는 Util에서 수행
const $injector = angular.injector(['angular1es6']);
const $httpBackend = $injector.get('$httpBackend');
const $http = $injector.get('$http');
beforeEach(() => {
$httpBackend.expectGET('/test')
.respond(['this', 'is', 'GET', 'test', 'data']);
});
it('ok', () => {
return new Promise(resolve => {
$http.get('/test').then(result => {
console.log('get().then()');
console.log(result);
console.log(result.data);
resolve(true);
});
$httpBackend.flush();
});
});
동작하는 코드
static post (uri, param, config) {
// use new promise for flush()
return new Promise((resolve, reject) => {
this.http.post(uri, param, config)
.then(result => {
resolve(result);
}, error => {
console.error(error);
reject(false);
});
if (this.httpBackend && this.httpBackend.flush) {
this.httpBackend.flush();
}
});
}
it('ok', () => {
return new Promise(resolve => {
Promise.resolve()
.then(() => {
$http.get('/test').then(result => {
console.log('get().then()');
console.log(result);
console.log(result.data);
resolve(true);
});
});
$httpBackend.flush();
});
});
28
const $httpBackend = $injector.get('$httpBackend');
const $http = $injector.get('$http');
ClientUtil.http = $http;
ClientUtil.httpBackend = $httpBackend;
29. 여러 test 파일 동시 실행
const $injector = angular.injector(['angular1es6']);
const $httpBackend = $injector.get('$httpBackend');
const $http = $injector.get('$http');
Chrome 54.0.2840 (Windows 10 0.0.0) SignInCtrl test logic submit() with ajax error response
response error test FAILED
AssertionError: expected [Error: Unexpected request: POST /api/user/signIn
No more request expected] to be an instance of ERROR
Chrome 54.0.2840 (Windows 10 0.0.0) SignUpCtrl test logic submit() error response response
error test FAILED
AssertionError: expected [Error: [$rootScope:inprog] $digest already in progress
const ngApp = angular.module(appName, ['ngMock']);
var $injector = angular.injector(['MoneyBook']);
const $httpBackend = $injector.get('$httpBackend');
const $http = $injector.get('$http');
ClientUtil.http = $http;
ClientUtil.httpBackend = $httpBackend;
29
지속적인 성능 개선, 버그 수정
two-way binding is magic
체계적인 앱 프론트엔드 구성
사용자 삽질 경험 풍부, 웬만한 문제는 해결 가능
Angular 2는 아직..
http://www.ecma-international.org/ecma-262/6.0/
ECMAScript 2015
2015-6 발표
2016-6-20 개정
ECMAScript 2016, ES7
2016-6
Exponentiation operator **
Array.prototype.includes
transpiler들의 지원
babel
babelify
browserify
traceur
ES6에서 angular.js 포함 없음
webpack 쓸거니까
webpack bundling을 위해 html이 아니라 js에서 추가
import 들… 코드에서 직접 쓰지는 않더라도 의존성을 위해 추가해야 함(script src 대신)
ex) import ngRoute 없으면 angular module injection failed
html script 나열이 아니라서 webpack dependency를 찾아가는 것이 편하기도 함
webpack을 쓰니까 pug 를 require로 사용
controllerAs 없으면 스코프 접근 불가
모두 class로 export
filter, directive 등록에는 new 필요, 없으면 에러
service, controller 등록에는 안 필요
controller 대체, controllerAs 사용하지 않으면 접근 불가
$scope 대신 this 사용, private function 불가
angular.service 와 ES6 class static은 연관되지만… static 있으면 안돌아감. 없어야 prototype chain으로 연결됨
ngApp.service() 필요 없음, babel 때문에
생성자의 재발견
상속이면 super() 필요
ES5 directive의 return보다 보기 편함
controller 대체
$scope 대신 this 사용, private function 불가
after Angular 1.5
componen는 directiv와 사용방법이 다름
component 쓸때는 객체를 반환
directive는 클래스를 반환, new 선언
componen에서는 element, attr 등 접근 어려움
component는 Element만 사용 가능, 어차피 directive 필요
.directive()는 쓰자
어차피 표준, 가독성 엄청 향상
catch로 끝내지 않도록 주의, 콘솔이 안 이쁘잖아..
callback hell, pyramid of doom
template, style 로드 간편
서버와 공통 로직 그대로 사용(ex. validation)
BDD 작성 시작
헬 시작
참고 자료 찾기 어려움
Chrome에서는 돈다. PhantomJS에서는 돌지 않음
브라우저에서 ES6지원하지 않으면 karma 돌지 않음… ES6니까
node6, es2015 babel preset 필요
Chrome에서도 import는 안됨
import 없이 arrow function은 동작함
webpack → karma : bundling, 오류 찾기 힘들다
karma-browerify → karma-babelify → karma : O
import 구문이 아니라서 찾을 수 없음
browserify, babelify를 거치니까..
karma.conf.js에 angular 추가, 수동 injector 사용
http 이후 $location 테스트하면서 문제 발생
같은 파일이지만 angular.module dependency 선언에서 ngMock과 ngMockE2E로 갈림
동시에 사용 불가, ngMockE2E에는 $location이 없음
ngMock : fake response for unit test
ngMockE2E : fake response for end-to-end test
promise 쓰니까 http.flush() 타이밍 맞지 않음
유틸 객체에 프로퍼티로 지정
한 번에 돌리면 에러
http injection 문제, 전역에서 한 번만 지정
생성자 안에서 Promise 쓰는 경우 결과 확인 불가
함수 분리. Promise 완료를 기다릴 수 없음
Promise 안에서 클래스 프로퍼티 값을 바꾼 경우 한 cycle 늦게 view에 적용됨
$scope.$apply() 호출 필요
할 만 하다
어차피 ES6는 표준
가독성이 향상되는 코드가 많음
Angular usage in Google (etc : https://builtwith.angularjs.org/)
Double Click For Advertiser
YouTube for PS3
Google Cloud Developers Console
Google Cast