μ λ AngularJS(1.6) μ±μ Angular(4)λ‘ λ§μ΄κ·Έλ μ΄μ νλ μμ μ νκ³ μμΌλ©° μ΄μ NgUpgradeλ‘ λΆνΈμ€νΈλ©λ νμ΄λΈλ¦¬λ μ ν리μΌμ΄μ μ΄ μμ΅λλ€. μ΄κ²μ λ΄ κ°λκΈ° ν μ€νΈλ₯Ό μμ ν λ§μΉ κ² κ°μ΅λλ€.
μ΄κ²μ΄ μ κ° μλͺ»νκ³ μλ κ²μ΄λΌλ©΄ μ©μν΄ μ£Όμμμ€. νμ§λ§ μ΄κ²μ΄ μλνμ§ μλ μ΄μ μ λν λ΅μ μ°Ύμ μ μμ΅λλ€.
λ΄κ° μ»λ μ€λ₯λ λ€μκ³Ό κ°μ΅λλ€.
μ€ν¨: 11μ΄ νμ λΉλκΈ° Angular μμ μ΄ μλ£λ λκΉμ§ λκΈ°νλ λμ μκ°μ΄ μ΄κ³Όλμμ΅λλ€. νμ¬ νμ΄μ§κ° Angular μ ν리μΌμ΄μ μ΄ μλκΈ° λλ¬ΈμΌ μ μμ΅λλ€. μμΈν λ΄μ©μ FAQλ₯Ό μ°Έμ‘°νμΈμ. https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting -for-angular
λ‘μΌμ΄ν°κ° μλ μμλ₯Ό κΈ°λ€λ¦¬λ λμ - λ‘μΌμ΄ν°: By(css μ νκΈ°, .toggle-summary-button)
μμ© νλ‘κ·Έλ¨μ΄ μ λλ‘ μ€νλλ κ² κ°μΌλ©° AngularJSμ Angular κ΅¬μ± μμκ° λͺ¨λ μμλλ‘ μλν©λλ€. λΆνΈμ€νΈλ© νλ‘μΈμ€μμ λ³κ²½ν μ¬νμ λ€μκ³Ό κ°μ΅λλ€.
1 HTML νκ·Έμμ ng-app μ κ±°:
<html lang="en" *ng-app="myapp">
2 AppModules(@NgModule) λ±μ μΆκ°νμ΅λλ€.
3 NgUpgradeλ₯Ό μ¬μ©νμ¬ μ± λΆνΈμ€νΈλ©:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { UpgradeModule } from '@angular/upgrade/static';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['myapp'], {strictDi: true});
});
μμ μ€λ₯λ₯Ό κΈ°λ°μΌλ‘ λ¬Έμ λ κ°λκΈ°κ° Angularλ₯Ό κΈ°λ€λ¦΄ λ μννλ λͺ¨λ μμ κ³Ό κ΄λ ¨λ κ²μΌλ‘ 보μ λλ€. λ‘κ·ΈμΈ νμ΄μ§λ₯Ό λ‘λνκ³ μΈλΆ μ 보λ₯Ό μ±μ°κ³ λ‘κ·ΈμΈνλ beforeEach λΈλ‘μ΄ μμ΅λλ€. μ΄μνκ²λ μ¬μ ν νμ΄μ§λ₯Ό μ΄κ³ μ¬μ©μ μ΄λ¦ νλμ ν μ€νΈλ₯Ό μ λ ₯νμ§λ§ λ μ΄μ μ§νλμ§ μμ΅λλ€.
λλ μλνμ§λ§ μ±κ³΅νμ§ λͺ»νμ΅λλ€.
μ΄ μ κ·Έλ μ΄λ μ½λλ₯Ό λ€μκ³Ό κ°μ΄ λννμ¬ μ μ¬ν λ¬Έμ κ° ν΄κ²°λμμ΅λλ€.
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { UpgradeModule } from '@angular/upgrade/static';
import { AppModule } from './app.module';
angular.element(document).ready(() => {
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['myapp'], {strictDi: true});
});
});
κ·Έλ¦¬κ³ κ΅¬μ±μμ λλ κ·Έ μ€ μ΄λ κ²λ μ¬μ©
//ng12Hybrid: true,
//useAllAngular2AppRoots: true,
//rootElement: 'body',
https://github.com/angular/protractor/issues/4234λ₯Ό μ΄ν΄λ³΄κ³ λμΌν λ¬Έμ κ° μλμ§ νμΈν μ μμ΅λκΉ? λν ngUpgradeμμ $interval
λ μ΄μ μ΄μ μ μμλ κ°λκΈ°λ₯Ό μ°¨λ¨νμ§λ§(https://github.com/angular/angular/issues/16349), μ λ κ·Έ μμ
μ νκ³ μμ΅λλ€.
@Evilweed - μ μν΄ μ£Όμ μ κ°μ¬ν©λλ€. λΆννλ ν΄κ²°λμ§ μλ κ² κ°μ΅λλ€.
@heathkit - μ 체 νλ‘μ νΈλ₯Ό κ²μνμ¬ νλμ μ₯κΈ° μ€ν $intervalμ μ°Ύμμ§λ§ μ κ±°ν νμλ λ¬Έμ κ° μ§μλ©λλ€. λν μ 체 μ±μμ $interval λλ $timeoutμ λͺ¨λ μ¬μ©λ²μ μ£Όμ μ²λ¦¬νμ§λ§ μ¬μ ν λμΌν μ€λ₯λ‘ μ€ν¨ν©λλ€. λΉλκΈ° λ¬Έμ μΈ κ²½μ° μ°¨λ¨ν μ μλ νλͺ©μ λλ²κ·Ένκ³ μ°Ύμ μ μλ λ°©λ²μ΄ μλμ§ μκ³ μμ΅λκΉ?
μ 체 μ€λ₯λ₯Ό κ²μν μ μμ΅λκΉ? μ€λ₯ λ©μμ§μ 보λ₯ μ€μΈ μμ μ΄ λ¬΄μμΈμ§ νμν΄μΌ νμ§λ§ μΌλΆκ° λλ½λμμ μ μμ΅λλ€. μλ₯Ό λ€μ΄, μ€λ₯λ μμ§ Angular μΈ‘μμ 보λ₯ μ€μΈ μμ μ νμνμ§ μμ΅λλ€. μ±μ Angular λΆλΆμμ μ€λ μ€νλλ λΉλκΈ° μμ μ΄ μλ κ²½μ° κ°λκΈ°λ₯Ό μ°¨λ¨νμ§ μλλ‘ Angular μμ μΈλΆμμ μμ μ μ€νν΄μΌ ν©λλ€. (https://github.com/angular/protractor/blob/master/docs/timeouts.md μ°Έμ‘°)
λ΅μ₯ν΄μ£Όμ μ λ€μ νλ² κ°μ¬λ립λλ€. μ€λ₯ μΈλΆ μ 보λ μλμ μμ΅λλ€. λͺ κ°μ§ μ°Έκ³ μ¬ν:
λ΄ ν
μ€νΈ νμΌμλ beforeAll
λΈλ‘μ΄ μμ΅λλ€. μ΄ λΈλ‘μ λ‘κ·ΈμΈμ μν΄ μ¬μ©μ μ΄λ¦κ³Ό μνΈ νλλ₯Ό μ±μ°λλ‘ λμ΄ μμ΅λλ€. μ¬μ©μ μ΄λ¦ νλλ₯Ό μ±κ³΅μ μΌλ‘ μ±μ°μ§λ§ waitForAngular
μμ μκ° μ΄κ³Όλκ³ μνΈ νλλ₯Ό μ±μ°μ§ μμ΅λλ€. μ΄κ²μ΄ μ€λ₯μ μ λ°λΆμΈ κ² κ°μ΅λλ€. νλ°λΆλ μ€μ μ€ν¨ν ν
μ€νΈμ
λλ€(λ‘κ·ΈμΈμ μ€ν¨νμ¬ μμκ° μ‘΄μ¬νμ§ μκΈ° λλ¬Έμ μλ―Έκ° μμ).
μ΄ μ€λ₯λ λ¬Έμ κ° HTTP νΈμΆμμ λΉλ‘―λ κ²μΌ μ μμμ μμνλ―λ‘ $interval λλ $timeoutμ΄ μλ μ μμ΅λλ€.
λλ νμ¬ Angularμ λν΄ λ³λ‘ κ°μ§κ³ μμ§ μμΌλ©°, κ±°μ λλΆλΆμ΄ μ¬μ ν AngularJSμ λλ€. κ·Έκ²μ λ‘κ·ΈμΈμ κ΄λ¦¬νμ§ μκΈ° λλ¬Έμ μλ‘μ΄ Angular κ΅¬μ± μμλ₯Ό νμνλ κ²λ§νΌ λ©λ¦¬ κ°μ§ μμ΅λλ€ (λ°λΌμ http νΈμΆμ΄ Angular 4 κ΅¬μ± μμμ κ΄λ ¨μ΄ μλμ§ μμ¬λ©λλ€)
Message:
Failed: Timed out waiting for asynchronous Angular tasks to finish after 11 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular
While waiting for element with locator - Locator: By(css selector, *[name="password"])
Stack:
ScriptTimeoutError: asynchronous script timeout: result was not received in 11 seconds
(Session info: chrome=58.0.3029.110)
(Driver info: chromedriver=2.29.461585,platform=Mac OS X 10.12.4 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 11.07 seconds
Build info: version: '3.4.0', revision: 'unknown', time: 'unknown'
System info: host: 'Matt.lan', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.12.4', java.version: '1.8.0_111'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{applicationCacheEnabled=false, rotatable=false, mobileEmulationEnabled=false, networkConnectionEnabled=false, chrome={chromedriverVersion=2.29.461585, takesHeapSnapshot=true, pageLoadStrategy=normal, databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false, version=58.0.3029.110, platform=MAC, browserConnectionEnabled=false, nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true, webStorageEnabled=true, browserName=chrome, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true, unexpectedAlertBehaviour=}]
Session ID: 40deafceb49b72b1c0188ad0895c1179
at Object.checkLegacyResponse (/Users/matt/web-app/node_modules/selenium-webdriver/lib/error.js:505:15)
at parseHttpResponse (/Users/matt/web-app/node_modules/selenium-webdriver/lib/http.js:509:13)
at doSend.then.response (/Users/matt/web-app/node_modules/selenium-webdriver/lib/http.js:440:13)
at process._tickCallback (internal/process/next_tick.js:109:7)
From: Task: Protractor.waitForAngular() - Locator: By(css selector, *[name="password"])
at thenableWebDriverProxy.schedule (/Users/matt/web-app/node_modules/selenium-webdriver/lib/webdriver.js:816:17)
at ProtractorBrowser.executeAsyncScript_ (/Users/matt/web-app/node_modules/protractor/lib/browser.ts:608:24)
at angularAppRoot.then (/Users/matt/web-app/node_modules/protractor/lib/browser.ts:642:23)
at ManagedPromise.invokeCallback_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:1366:14)
at TaskQueue.execute_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2970:14)
at TaskQueue.executeNext_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2953:27)
at asyncRun (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2813:27)
at /Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:676:7
at process._tickCallback (internal/process/next_tick.js:109:7)Error
at ElementArrayFinder.applyAction_ (/Users/matt/web-app/node_modules/protractor/lib/element.ts:482:23)
at ElementArrayFinder.(anonymous function).args [as sendKeys] (/Users/matt/web-app/node_modules/protractor/lib/element.ts:96:21)
at ElementFinder.(anonymous function).args [as sendKeys] (/Users/matt/web-app/node_modules/protractor/lib/element.ts:873:14)
at /Users/matt/web-app/e2e-tests/modules/authentication.js:83:38
at ManagedPromise.invokeCallback_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:1366:14)
at TaskQueue.execute_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2970:14)
at TaskQueue.executeNext_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2953:27)
at asyncRun (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2813:27)
at /Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:676:7
at process._tickCallback (internal/process/next_tick.js:109:7)
From: Task: Run beforeAll in control flow
at Object.<anonymous> (/Users/matt/web-app/node_modules/jasminewd2/index.js:94:19)
From asynchronous test:
Error
at Suite.<anonymous> (/Users/matt/web-app/e2e-tests/specs/home/asset.spec.js:28:3)
at Object.<anonymous> (/Users/matt/web-app/e2e-tests/specs/home/asset.spec.js:7:1)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
Message:
Failed: No element found using locator: By(css selector, .toggle-asset-summary-button)
Stack:
NoSuchElementError: No element found using locator: By(css selector, .toggle-asset-summary-button)
at elementArrayFinder.getWebElements.then (/Users/matt/web-app/node_modules/protractor/lib/element.ts:851:17)
at ManagedPromise.invokeCallback_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:1366:14)
at TaskQueue.execute_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2970:14)
at TaskQueue.executeNext_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2953:27)
at asyncRun (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2813:27)
at /Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:676:7
at process._tickCallback (internal/process/next_tick.js:109:7)Error
at ElementArrayFinder.applyAction_ (/Users/matt/web-app/node_modules/protractor/lib/element.ts:482:23)
at ElementArrayFinder.(anonymous function).args [as click] (/Users/matt/web-app/node_modules/protractor/lib/element.ts:96:21)
at ElementFinder.(anonymous function).args [as click] (/Users/matt/web-app/node_modules/protractor/lib/element.ts:873:14)
at Page.showAssetSummaryComponent (/Users/matt/web-app/e2e-tests/specs/home/page-object.js:289:31)
at Object.<anonymous> (/Users/matt/web-app/e2e-tests/specs/home/asset.spec.js:63:12)
at /Users/matt/web-app/node_modules/jasminewd2/index.js:112:25
at new ManagedPromise (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:1067:7)
at ControlFlow.promise (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2396:12)
at schedulerExecute (/Users/matt/web-app/node_modules/jasminewd2/index.js:95:18)
at TaskQueue.execute_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2970:14)
From: Task: Run fit("should open asset summary component") in control flow
at Object.<anonymous> (/Users/matt/web-app/node_modules/jasminewd2/index.js:94:19)
at /Users/matt/web-app/node_modules/jasminewd2/index.js:64:48
at ControlFlow.emit (/Users/matt/web-app/node_modules/selenium-webdriver/lib/events.js:62:21)
at ControlFlow.shutdown_ (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2565:10)
at shutdownTask_.MicroTask (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2490:53)
at MicroTask.asyncRun (/Users/matt/web-app/node_modules/selenium-webdriver/lib/promise.js:2619:9)
From asynchronous test:
Error
at Suite.<anonymous> (/Users/matt/web-app/e2e-tests/specs/home/asset.spec.js:62:5)
at Suite.<anonymous> (/Users/matt/web-app/e2e-tests/specs/home/asset.spec.js:60:3)
at Object.<anonymous> (/Users/matt/web-app/e2e-tests/specs/home/asset.spec.js:7:1)
μμ ν λκ°μ΅λλ€. μλ‘μ΄ 'λΉ λ₯Έ μμ' angular4 ꡬμ±κ³Ό λ§€μ° κΈ°λ³Έμ μΈ κ°λκΈ° ν μ€νΈκ° μμ΅λλ€. λͺ¨λ κ²μ΄ λΉ νμ΄λΈλ¦¬λ λͺ¨λμμ μ μλν©λλ€.
Failed: Timed out waiting for asynchronous Angular tasks to finish after 50 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular
While waiting for element with locator - Locator: By(css selector, #loginModal h4)
μ΄ λ¬Έμ κ° κ³μ νμλ©λλ€.
μ¬μ©: @angular/upgrade 4.2.2
ν
μ€νΈ κ°λ₯μ± APIλ₯Ό μμ μ μΌλ‘ μ μ§νκΈ° μν΄ @heathkit (https://github.com/angular/angular/pull/16836)μ μμ μ¬νμ΄ ν¬ν¨λμ΄ μμ§λ§ μ¬μ ν μλνμ§ μλ κ² κ°μ΅λλ€.
λκ΅°κ° λ¬Έμ λ₯Ό 보μ¬μ£Όλ 리ν¬μ§ν 리λ₯Ό 곡μ ν μ μλ€λ©΄ λ μμΈν μ΄ν΄λ³΄κ² μ΅λλ€.
νκΈ° ν λλ λ΄κ°λ³΄κ³ μλ μκ° μ΄κ³Όμ μμΈ μ€ νλλ₯Ό λ°κ²¬νμ΅λλ€ (λλ κ·Έ μ€ νλλ μ μΌν κ²μ΄ μλλΌκ³ μκ°ν©λλ€). λ΄κ° μ¬μ©νκ³ μλ μ’
μμ± μ€ νλκ° window.setTimeout()
λ₯Ό νΈμΆνμ¬ κ°λκΈ°κ° λκΈ°νλμ§ μλλ‘ νλ κ²μΌλ‘ λνλ¬μ΅λλ€(μ κ²½μ°μλ
κ° λͺ¨λ©νΈ .
λ΄ μ±μ΄ AngularJSλ§ μ€ν μ€μΌ λλ μ λλ‘ μ€νλμμ§λ§ νμ΄λΈλ¦¬λ μ±μΌλ‘ λΆνΈμ€νΈλ©ν λ μκ° μ΄κ³Ό λ¬Έμ κ° λ°μν©λλ€(μλ§λ μμμμ μ€νλλ λ°©μ λλ¬Έμ).
https://github.com/mattwilson1024/angular-hybrid μμ μμ 리ν¬μ§ν 리λ₯Ό λ§λ€μμ΅λλ€. λ€μ λΆλΆμΌλ‘ ꡬμ±λ νμ΄λΈλ¦¬λ(NgUpgrade) μ±μ λλ€.
λ§μ€ν° λΈλμΉ λ μλνλ μ±κ³Ό λ¬Έμ μμ΄ ν΅κ³Όνλ λ¨μΌ κ°λκΈ° ν μ€νΈλ₯Ό ν¬ν¨ν©λλ€.
angular-moment λΆκΈ° λ angular-moment
λΌμ΄λΈλ¬λ¦¬μ λν μ’
μμ±μ μΆκ°νκ³ am-time-ago
μ§μλ¬Έμ μ¬μ©νμ¬ μ²« λ²μ§Έ μνΌμλ μ΄ν λͺ λ
μ μΈμ§ 보μ¬μ£Όλ λ μ΄λΈμ νμ΄μ§μ μΆκ°ν©λλ€. μ± μ체λ μ μ€νλμ§λ§ κ°λκΈ° ν
μ€νΈλ μ΄μ λκΈ°νλμ§ μμ΅λλ€.
μ΄κ²μ΄ μΌμ΄λκ³ μλμ§ νμΈνκΈ° μν΄ λ€μκ³Ό κ°μ κ²°κ³Όμ ν¨κ» AngularJS 컨νΈλ‘€λ¬μ λ€μν μ’ λ₯μ μκ° μ΄κ³Όλ₯Ό μΆκ°νλ €κ³ μλνμ΅λλ€. μ΄κ²μ $intervalμ΄ μλνμ§λ§ $timeout, setInterval λλ setTimeoutμ΄ μλνμ§ μμμ νμΈνμ΅λλ€.
function sayHello() { console.log('Hello, world'); }
$interval(sayHello, 30000); // Succeeds (with Angular 4.2.0 and later - see https://github.com/angular/angular/pull/16836)
$timeout(sayHello, 30000); // Fails - Timed out waiting for asynchronous Angular tasks to finish after 11 seconds
setInterval(sayHello, 30000); // Fails - Timed out waiting for asynchronous Angular tasks to finish after 11 seconds
setTimeout(sayHello, 300000); // Fails - Timed out waiting for asynchronous Angular tasks to finish after 11 seconds
λ¬΄μ¨ μΌμ΄ μΌμ΄λκ³ μλμ§ μΆμ ν΄ λ³΄μμ§λ§ μ¬μ ν ν΄κ²°μ± μ΄ λ¬΄μμΈμ§ νμ ν μ μμ΅λλ€. μμ λ±μ μ½μ ν TypeScript ν΄λμ€κ° μλ AngularJS μΈκ·Έλ¨ΌνΈμμ μ΄ μμ μ μννλ λ°©λ²μ μ λͺ¨λ₯΄κ² μ§λ§ "Angular μμ μΈλΆ"μμ νΉμ μ½λλ₯Ό μ€νν΄μΌ ν μλ μλ€λ κ²μ μ΄ν΄ν©λλ€.
κ·ΈλΌμλ λΆκ΅¬νκ³ λ¬Έμ μ½λκ° νμ¬ λΌμ΄λΈλ¬λ¦¬ λ΄λΆμμ λ°μνλ κ²½μ°(angular-momentμ κ²½μ°μ κ°μ΄) - μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν μ κ·Ό λ°©μμ νμ΄λΈλ¦¬λ μ€μ ?
μμμ μ°½μ μ€μ λμ΄ μμΌλ―λ‘ NgZoneμ μ£Όμ ν νμκ° μμ΅λλ€. λ€μκ³Ό κ°μ΄ AngularJSμ Angular μμ μΈλΆμμ μ€νν μ μμ΅λλ€.
if (Zone && Zone.current.name === 'angular') {
let angularZone = Zone.current;
Zone.parent.run(() => {
$timeout(() => {
// Stuff here is run outside the Angular zone and will not be change detected
angularZone.run(() => {
// Inside the zone and will be change detected.
});
}, 500);
});
}
νμ¬ μ½λμμλ setTimeout λλ setIntervalμ μ¬μ©νλ©΄ κ°λκΈ° μμ μ±μ΄ μ°¨λ¨λκ³ μκ° μ΄κ³Όκ° λ°μν μ μμ΅λλ€. Protractorκ° μκ° μ΄κ³Όν λΉλκΈ° μμ μ΄ μ΄λμμ μλμ§ λ³΄μ¬μ€μΌλ‘μ¨ μ΄λ¬ν λ¬Έμ λ₯Ό λ μ½κ² λλ²κ·Έν μ μλλ‘ Angular λ° AngularJSμ μμ μΆμ μ μΆκ°νκ³ μμ΅λλ€. νμ€μ μΌλ‘, μ°λ¦¬κ° κ·Έκ²μ κ°λκΈ°λ‘ κ°μ Έμ¬ μ μκΈ°κΉμ§λ λͺ λ¬μ΄ 걸릴 κ²μ λλ€.
Angular-momentκ° μ§νλλ ν κ°μ₯ μ’μ λ°©λ²μ μμ νμλ κ²μ²λΌ μμμ μΈμνλλ‘ PRμ μ μΆνλ κ²μ
λλ€. κ·Έλ μ§ μμΌλ©΄ waitForAngular
μ νμ μΌλ‘ λκ³ browser.wait
λ° ExpectedConditionsλ₯Ό λμ μ¬μ©ν μ μμ΅λλ€. κΈ°λ€λ¦¬λ μμ
μ μ μ΄ν μ μλ λ³΄λ€ μ μ°ν waitForAngular APIλ₯Ό κ°λ° μ€μ΄μ§λ§ μμ§ λ©μμ΅λλ€.
μ°λ¦¬ μν©μμ ν
μ€νΈλ μΌλ°(Angular λκΈ°ν μμ΄) λ°©μμΌλ‘ μμ±ν μ μμ§λ§(EC λ±μ μ¬μ©νμ¬ browser.ignoreSynchronization = true
), "Error while waiting for Protractor to sync with the page: "Cannot read property '$$testability' of undefined"
browser.ignoreSynchronization = false;
λ₯Ό μ€μ νλ©΄ μ€ν¨ν©λλ€.
μ΄κ²μ κΈ°λ³Έμ μΌλ‘ μ 체 E2E μλν ν μ€νΈ μ νκ΅°μ 무ν¨νν©λλ€.
κ°λκΈ° 5.1.2λ₯Ό μ¬μ©νμ¬ ng12Hybrid: true
μ€μ νλ©΄ λ€μ λ©μμ§κ° νμλ©λλ€.
ng12Hybridλ₯Ό μ€μ νμ΅λλ€. κ°λκΈ° 4.1.0λΆν° κ°λκΈ°λ ngUpgrade μ±μ μ¬μ© μ€μΈμ§ μλμΌλ‘ μΆλ‘ ν μ μμΌλ©°(platformBrowserDynamic()μ νΈμΆνκΈ° μ μ ng1μ΄ λ‘λλ κ²½μ°) μ΄ νλκ·Έλ λλΆλΆμ μ¬μ©μμκ² λ μ΄μ νμνμ§ μμ΅λλ€.
λ°λΌμ λΆλͺ ν angular.io λ¬Έμλ μ¬κΈ°μμ ꡬμμ λλ€. https://angular.io/guide/upgrade#e2e -tests
κ°μ λ¬Έμμ μ λͺ ν λ§μ§λ§ λ¨μ΄:
E2E ν μ€νΈλ μ€μ λ‘ μ ν리μΌμ΄μ κ΅¬μ± μμμ λ΄λΆ ꡬ쑰μ κ΄λ ¨μ΄ μμ΅λλ€. μ΄λ λν μ κ·Έλ μ΄λνλ λμ νλ‘μ νΈλ₯Ό μλΉν μμ νλλΌλ E2E ν μ€νΈ μ νκ΅°μ μ½κ°μ μμ μΌλ‘ κ³μ ν΅κ³Όν΄μΌ ν¨μ μλ―Έν©λλ€. μ¬μ©μμ κ΄μ μμ μ ν리μΌμ΄μ μ΄ μλνλ λ°©μμ λ³κ²½νμ§ μμμ΅λλ€.
angular.ioμ λν κ·Έ μ§μ μ λΉμΆμ΄:
@heathkit μμ λ΄λΆ λ° μΈλΆ μ€νμ λν νμ κ°μ¬λ립λλ€. νμ§λ§ μμ§ν λ§ν΄μ μ°λ¦¬λ κΈ°μ‘΄ AngularJS μ½λλ₯Ό μλ κ·Έλλ‘ μ€ννλ μ루μ μ μ°Ύκ³ μμ΅λλ€. μμμ AngularJS λκΈ°νμ μμ‘΄νλ κ΄λ²μν Protractor μ νκ΅°μ΄ μμ΅λλ€. μ°λ¦¬μ λͺ©νλ ngUpgradeλ₯Ό μ¬μ©νμ¬ AngularJSλ₯Ό Angularλ‘ λ§μ΄κ·Έλ μ΄μ νλ κ²μ΄μ§λ§ νμ΄λΈλ¦¬λ μ κ·Έλ μ΄λ λͺ¨λμμ κΈ°μ‘΄ Protractor μ νκ΅°μ μ€νν μ μλ€λ μ΄ λ¬Έμ λ‘ μΈν΄ μ΄λμ ν°λΈκ° μ’μ λμμ΅λλ€. νλͺ ν μμ μ μ§κΈμ―€μ΄λ©΄ κ°μ₯ νμν μΌμ λλ€.
μ°λ¦¬κ° κ·Όλ³Έμ μΌλ‘ μλͺ»λ μΌμ νκ³ μλ€λ©΄ 무μμΈμ§ μκ³ μΆμ΅λλ€.
κ°μ λ¬Έμ μ μ§λ©΄! :0
μ¬κΈ°μμ λμΌν κ²μ λ³Ό μ μμ΅λλ€. AngularJS 1.6 -> Angular 4.2.4
λꡬλ μ§ ν΄κ²° λ°©λ²μ μκ³ μμ΅λκΉ? κ·Έκ²μ΄ μ무리 ν΄ μ μμ΅λκΉ? μ¦, 1.6μΌλ‘ λλλ¦¬μ§ μλ κ²μ λλ€.
@quinw68 - @heathkit μ μ΄ μ€λ λμ μ΄μ μλ΅μμ Angular 'Zone' μΈλΆμμ μ½λλ₯Ό μ€ννλ λ°©λ²μ μ μν©λλ€. μ΄κ²μ΄ μλνλλ‘ μ±μ μμ€ μ½λλ₯Ό λ³κ²½νλ κ²μ μλ―Ένλ©° μ§μμ μΆκ°νλ νμ¬ λΌμ΄λΈλ¬λ¦¬μ μμ‘΄ν μλ μμ΅λλ€. λ΄κ° νλ Έλ€λ©΄ μ λ₯Ό μμ νμμμ€.
λ΄κ° μκ³ μλ λ λ€λ₯Έ 'ν΄κ²° λ°©λ²'μ κΈ°μ‘΄ μ±μ λ μ΄μ AngularJS μ±μ΄ μλ κ²μ²λΌ μ·¨κΈνλ κ²μ λλ€. μ΄κ²μ λ³Έμ§μ μΌλ‘ λ μ΄μ Angularλ₯Ό κΈ°λ€λ¦¬μ§ μκ³ μνλ₯Ό 쿼리νκΈ° μ μ νμ΄μ§μ μμκ° μλμ§ λͺ μμ μΌλ‘ νμΈνλλ‘ κ°λκΈ° ν μ€νΈλ₯Ό λ³κ²½ν΄μΌ ν¨μ μλ―Έν©λλ€. μ±μ ν¬κΈ°μ λ°λΌ μ΄λ €μ΄ μμ μ΄ λ μ μμ΅λλ€.
λμμ΄ λκΈ°λ₯Ό λ°λλλ€.
λ΄κ° μ΄ λ¬Έμ λ₯Ό μ΄ν΄νλ ν μ΄κ²μ ngUpgrade κ΄λ ¨μ΄ μλλΌ Angular κ΄λ ¨μ
λλ€. λ΄ λ§μ, μμν Angular(2+) μ±μμλ κΈ΄ setTimeout
(μ§μ λλ νμ¬ λΌμ΄λΈλ¬λ¦¬λ₯Ό ν΅ν΄)κ° μμΌλ©΄ κ°λκΈ°κ° μκ° μ΄κ³Όλ©λλ€.
@heathkit , νμΈν΄ μ£Όμκ² μ΅λκΉ μλλ©΄ μ κ° λμΉ κ²μ΄ μμ΅λκΉ? ngUpgradeκ° κ°λκΈ°λ₯Ό λμ§κ±°λ μ΄λ€ μμΌλ‘λ μν©μ μ νμν€λμ?
@gkalpak μ΄κ²μ Angular κ΄λ ¨ λ¬Έμ μ λ
AngularJSμμ κ°λκΈ°λ $browser.defer()
μμλ λΉλκΈ° μμ
λ§ κΈ°λ€λ¦½λλ€. κΈ°λ³Έμ μΌλ‘ μ ν리μΌμ΄μ
μ½λμμ $timeout
λ° $http
νΈμΆ setTimeout
νΈμΆ(μ 3μ λΌμ΄λΈλ¬λ¦¬μμ μ μ¬μ μΌλ‘)μΌλ‘ μΈν΄ μκ° μ΄κ³ΌλκΈ° μμν©λλ€. λ°λΌμ λλΆλΆμ λ¬Έμ λ ngUpgradeκ° μλν λλ‘ μλνκ³ μμΌλ©° μ΄μ μ¬λλ€μ AngularJS μ± λ° Protractor ν
μ€νΈκ° κ°μκΈ° Angular(2+) μλ―Έ 체κ³μ μ’
μλλ€λ κ²μ
λλ€.
κ·Έλ λ€λ©΄ μμν Angular μ±μ κ²½μ° μ΄ λ¬Έμ λ₯Ό μ΄λ»κ² ν΄κ²°ν μ μμκΉμ? νμ¬ Angular λΌμ΄λΈλ¬λ¦¬κ° κΈ΄ setTimeout
νμ¬ κ°λκΈ°κ° μκ° μ΄κ³Όλλ κ²½μ° μ΄λ»κ² ν΄μΌ ν©λκΉ?
@vikerman λΉμ μ΄ κ³§ μλ‘μ΄ νμμ ꡬν΄μ μ΄ νμμ μ€νν μ μλλ‘ λμ
νμ¬ μ±μ΄ κΈ΄ μκ° μ νμ μ€μ νλ κ²½μ°μλ μ€μ λ‘ μ’μ λ΅λ³μ΄ μμ΅λλ€. νμ¬λ‘μλ waitForAngular
λκ³ ExpectedConditionsμ μμ‘΄νλ κ²μ΄ κ°λ₯νμ§λ§ μ΄μμ μ΄μ§λ μμ΅λλ€. λλ μ¬λλ€μ΄ ν
μ€νΈκ° κΈ°λ€λ¦¬λ 맀ν¬λ‘ μμ
μ λ μ μ μ΄ν μ μλλ‘ κ°λκΈ°μ κΈ°λ₯μ μΆκ°νλ μμ
μ νκ³ μμ§λ§ μμ§ λ©μμ΅λλ€.
@heathkit @vikerman μ΄κ²μ λν μ λ°μ΄νΈκ° μμ΅λκΉ?
λ΄κ° μμ νλ νλ‘μ νΈλ μ΄μ μ μ΄ λ¬Έμ κ° μμμ§λ§ λΈλΌμ°μ μ μν₯μ λ―ΈμΉμ§ μλλ‘ κ°λ μμ μΈλΆμμ μ€νλλλ‘ μ°μ ν΄λ§ κΈ°λ₯μ λννμ΅λλ€.
λ¨Όμ κ°λκΈ° ν/κΈ°κ³ μμκ² κ°μ¬λ립λλ€ . κ°λκΈ°λ μ½ 400κ°μ e2e κ°λκΈ° ν μ€νΈκ° ν¬ν¨λ 200κ° μ΄μμ μλΉμ€, μ§μλ¬Έ, κ΅¬μ± μμ, 컨νΈλ‘€λ¬μ ν¨κ» 3λ μ κ±Έμ³ μμ κ°μ 릴리μ€μ κ±Έμ³ λ΄ μ±μ΄ νλ‘λμ λ¬Έμ κ° κ±°μ μλ κΈ°λ°μ΄ λμμ΅λλ€.
μ΄κ²μ λ΄κ° Protractorμ μΌλ§λ μμ‘΄νλμ§ μκΈ°μμΌμ£Όλ μ’μ λ°©λ²μ΄μ§λ§ μ΄ λ¬Έμ λ ngUpgrade λ° λ³΄μ‘° μꡬ μ¬νμ λΆνΈμ€νΈλ©νλ λ° 2μ£Όλ₯Ό μ λ ν ν νΈλμμ Angular μ κ·Έλ μ΄λλ₯Ό μ€λ¨νμ΅λλ€. μλ£λμμ§λ§ μ΄μ e2e ν μ€νΈλ₯Ό μ€νν μ μμΌλ©° κ°μμ μΈ κ²½λ‘ μμ΄ λ°°ν¬κ° μ€μ§λ©λλ€(μμ§).
@mattwilson1024 μ νλ₯ν μ 보 λλΆμ $timeout
, setTimeout
, setInterval
μ΄ μ±μμ μ¬μ©λμ§ μλλ‘ νμ΅λλ€.
κ·Έλ¬λ angular-ui-bootstrap
(v.2.5.6) λ° ui-select
(v0.19.8) κ° $timeout
μ¬μ©νλ€λ κ²μ μμμ΅λλ€. λ λΌμ΄λΈλ¬λ¦¬λ₯Ό κ΄λ²μνκ² μ¬μ©ν©λλ€. angular-ui-bootstrap - 400k npm downloads/mo, ui-select 100k+/mo λ± λ§μ μ¬λλ€μ΄ μ΄μ μμ‘΄νλ κ² κ°μ΅λλ€.
angular-ui-bootstrap
λΆννκ²λ νΉλ³ν λλ¬Έμμ΄ λ¬Έμ μ $ κ°κ²©μΌλ‘ $ μ ν μκ°μ λ체νκΈ° μν΄ 2015 λ
λ¬Έμ λ₯Ό λ§λ€μμ§ λ§μ΄μλ€ μκΈ°λ‘ κ²°μ "μ΄ λ²κ·Έλ κ°λκΈ°μ κ³ μ λμ§ μ¬κΈ°λμ΄μΌνλ€.μ΄ λ«κΈ°." λν angular-ui-bootstrap
λ λ² ν λ²μ μΈ @ng-bootstrap/ng-bootstrapμ Angular λ²μ liuμμ λ μ΄μ μ
λ°μ΄νΈλ₯Ό μ 곡νμ§ μμ΅λλ€.
κ°λκΈ° μ ν¨μ±μ 보μ₯νμ§ μλ λ§μ΄ μ¬μ©λ κ°λ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ³΄κ³ λλμ΅λλ€. κ·Έ μ μμ λλ ν΄λΉ λΌμ΄λΈλ¬λ¦¬κ° μ€μ€λ‘ μμ ν΄μΌ νλ€λ @heathkitμ λμν©λλ€. νμ§λ§ Protractorκ° κ°μ
νμ¬ ν λ²μ λͺ¨λ κ²μ μνν μ μκΈ°λ₯Ό λ°λλλ€. μ’μ ν΄κ²° λ°©λ²μ‘°μ°¨λ ν©κΈμμ΄ λ κ²μ
λλ€. $timeout
μ’
μμ±μ λͺ¨λ νν€μΉ λκΉμ§ μ§κΈμ ngUpgradeλ₯Ό μ·¨μν΄μΌ νλ€λ μ¬μ€μ μ€λ§ν©λλ€. ngGradeλ₯Ό ν¬ν¨νκ³ κ°λ₯ν λ μ
κ·Έλ μ΄λ νλͺ©μ μ ννκΈ° μμνλ κ²λ³΄λ€ κ°λ₯ν©λλ€. ngUpgradeλ₯Ό μΆκ°νλ κ²κ³Ό ν¨κ» ν΄λΉ νμ¬ νλͺ©μμ μ
κ·Έλ μ΄λνκ±°λ λ§μ΄κ·Έλ μ΄μ
νλ λ° μ’
μμ±μ΄ μμ μ μμ΅λλ€. μ΄.
λ΄ μ±(μκ° μ΄κ³Όλ₯Ό μ λ°νλ νΉμ μμΈ, μμΌλ‘ λμκ°λ λ°©λ² λ±)μ λν΄ κ³μ μ°κ΅¬νκ³ μμΌλ©° λ€λ₯Έ μ¬λλ€μκ² μ μ©ν μ μλ λͺ¨λ κ²μ λ€μ λ³΄κ³ ν κ²μ λλ€.
$timeoutμ μ°Ύμ κ³³:
Angular-ui-bootstrap v2.5.6
UI μ ν
angular-resource $resource
λ $timeout
μ£Όμ
νκ³ μ¬μ©ν©λλ€.
κ°λ νν°( $window.setTimeout
)
μλ - μ°λ¦¬λ μμ λ¬Έμ λ₯Ό μ²λ¦¬νλ λ° λμμ΄ λ μ μλλ‘ κ°λκΈ°κ° κΈ°λ€λ¦¬λ μμ μ ꡬμ±ν μ μλλ‘ λ³κ²½ μμ μ μ§ν μ€μ λλ€. μ΄κ²μ Zone.js λ° Angularμ κ΄λ ¨λ κ΄λ²μν λ³κ²½μ΄λ©° νΉμ ETAκ° μμ΅λλ€(λͺ μ£Ό μ λ μμλ μμ ). μ¬κΈ°μμ μ§ν μν©μ μ λ°μ΄νΈν©λλ€.
λ΄ λΆνΈ μ€νΈλ© λ κ°μ λ¬Έμ κ° [email protected]μ μ NgUpgradeμ μμ© νλ‘κ·Έλ¨ [email protected]μ.
μμ μ견, νΉν @mattwilson1024 λ° @tonybranfort λλΆμ λ¬Έμ λ₯Ό λ μ μ΄ν΄ν μ μμμ΅λλ€.
μ κ²½μ°μλ μκ° μ΄κ³Όλλ μ½λ μ£Όμμ browser.ignoreSynchronization = true/false;
λ₯Ό μΆκ°νμ¬ ν΄κ²° λ°©λ²μ μ°Ύμμ΅λλ€.
μλ₯Ό λ€μ΄, λ΄ ν μ€νΈ μ€ νλλ λΌλμ€ λ²νΌ κ·Έλ£Ήμμ κ°λ¨ν μ νμ μννμΌλ©° μ¬λ°λ₯Έ μ΅μ μ΄ μ νλ κ²μΌλ‘ μμν©λλ€.
it('should be able to pick option', function () {
expect(myPage.optionSelected()).toBe(false);
myPage.pickOption('Option 1');
expect(myPage.anyOptionSelected()).toBe(true);
expect(myPage.getSelectedOption()).toBe('Option 1');
});
μ΄ μ½λλ₯Ό λλ²κ·Ένλ €κ³ ν λ λ§μ§λ§ λ¨κ³μμ μκ° μ΄κ³Όκ° λ°μνμμ λ°κ²¬νμ΅λλ€. κ·Όλ³Έμ μΈ λ¬Έμ λ $timeoutμ μ¬μ©νλ angular-ui-bootstrapμ ν΄λ¦½μ΄λΌκ³ κ°μ ν©λλ€. https://github.com/angular-ui/bootstrap/blob/master/src/tooltip/tooltip.js
κ·Έλ¬λ μ΄ ν μ€νΈμλ λΉλκΈ° νΈμΆμ΄ μμ΅λλ€. κ·Έλμ λ΄κ°νλ μΌμ μ²μμ ignoreSynchronizationμ μΆκ°νκ³ λ§μ§λ§μ μ¬μ€μ νλ κ²μ λλ€.
it('should be able to pick a font', function () {
browser.ignoreSynchronization = true; // tell protractor do not waitForAngular
expect(myPage.optionSelected()).toBe(false);
myPage.PickOption('Option 1');
expect(myPage.anyOptionSelected()).toBe(true);
expect(myPage.getSelectedOption()).toBe('Option 1');
browser.ignoreSynchronization = false; // reset the flag
});
μ΄κ²μ΄ κΆμ₯λλ λ°©λ²μΈμ§ μλλ©΄ ν μ€νΈλ₯Ό λ λΆμμ νκ² λ§λ€μ§ λͺ¨λ₯΄κ² μ΅λλ€. κ·Έλ¬λ λΉλκΈ° νΈμΆμ΄ νμνμ§ μμ§λ§ μ¬μ ν μκ° μ΄κ³Ό λ¬Έμ κ° μλ ν μ€νΈμ κ²½μ° μμ ν΄μΌ ν©λλ€.
μλ νμΈμ @vikerman - μ΄μ λν μ λ°μ΄νΈκ° μμ΅λκΉ? https://github.com/angular/protractor/issues/4290#issuecomment -337094393
λ΄ μ루μ :
μ΄ μ μ₯μμμ:
https://github.com/Innovic-io/protractor-angular-hybrid-app
μ¬κΈ°μμ μ±μ κΈ°λ€λ¦½λλ€.
https://github.com/Innovic-io/protractor-angular-hybrid-app/blob/master/src/models/angular.ts#L9
@vikerman μ΄μ λν μ λ°μ΄νΈκ° μμ΅λκΉ?
λ΄ μμ© νλ‘κ·Έλ¨μμ μκ° μ΄κ³Όλ₯Ό μ κ±°ν μ μλλ‘ μ΄λ¬ν μ₯κΈ° μ€ν μκ° μ΄κ³Όλ₯Ό μ°Ύλ λ°©λ²μ λν μ’μ μ‘°μΈμ΄ μμ΅λκΉ?
From : κ°λκΈ° λ¬Έμ #4290μ μν΄ μ’μ΄λ AngularJS μ¬μ Castaway(s?)
λ°λμ¬λ : @vikerman @juliemr
μ΄μ΄! μ΄ λ¬Έμ μ λν μ λ°μ΄νΈλ₯Ό λ°μ μ μμ΅λκΉ? 10μ 16μΌμ λ§μ§λ§ μ λ°μ΄νΈλ "μ£Ό λ¨μ"μ ETAμμ΅λλ€. λλ κ³μ μ§νν μ μλλ‘ μ΄ λ¬Έμ λ₯Ό λ«μΌμμμ€.
νμ¬ κ³ λ €νκ³ μλ λλͺ©μ λ€μκ³Ό κ°μ΅λλ€.
waitForAngularEnabled(false)
μ
λλ€ . λλ μ 체 μ±μ λν΄ μ΄κ²μ λν΄ νμμ μ΄μ§λ§ ν
μ€νΈνμ§λ μμμ΅λλ€. λλ νμ¬ ν κ°μ§ μν©μμλ§ waitForAngularEnabled
λ₯Ό μ¬μ©νκ³ μμΌλ©° λ§€μ° νΉμ ν κ²½μ°μλ§ μ¬μ©ν©λλ€.μ°λ¦¬ νμ 볡μ‘ν μμ© νλ‘κ·Έλ¨μ μ κ·Έλ μ΄λνλ μ€μ΄λ©° NgUpgradeλ‘ λΆνΈμ€νΈλ©ν λ κ°λκΈ° ν μ€νΈκ° μ€ν¨ν©λλ€. μ΄μ μλͺ»λ κΈμ μΈ λͺ¨λ μ€ν¨ν ν μ€νΈλ₯Ό μ²λ¦¬ν μ μκΈ° λλ¬Έμ λ³κ²½ μ¬νμ λλλ €μΌ νμ΅λλ€.
μ΄ λ¬Έμ μ λν΄ μ°λ¦¬λ μ΄λμ μμ΅λκΉ? Angular μ κ·Έλ μ΄λ κ³νμ μ μ§ν μ μλλ‘ λ€λ₯Έ ν μ€νΈ νλ μμν¬λ‘ μ΄λν΄μΌ νλμ§ κ±±μ λ©λλ€.
@tonybranfort : λΉμ κ³Ό λκ°μ λ°°μμ... μ°λ¦¬λ ui-select
λ° angular-ui-bootstrap
μ ν¬κ² μμ‘΄ν©λλ€. μ΄κ²μ΄ μ°λ¦¬μ μ
κ·Έλ μ΄λλ₯Ό λ°©ν΄νλ μ£Όμ μμΈμ
λλ€. νμ§λ§ μ΄ λ¬Έμ λ₯Ό μ£Όλνμ κ² κ°μΌλ κ³μ μ
λ°μ΄νΈν΄ μ£ΌμΈμ! π
μ°λ¦¬λ κ°μ λ¬Έμ λ₯Ό κ²ͺκ³ μμ΅λλ€. κ°λκΈ°μμ λκ΅°κ° μ°λ¦¬μκ² μ΄κ²μ λν΄ μ λ°μ΄νΈν μ μμ΅λκΉ?
μ°λ¦¬λ Angular V1μμ μ±μ μ κ·Έλ μ΄λνλ μ€μ΄λ©° μ΄ μμΈμ΄ V1μΌλ‘ λμκ°μ μ§κΈκΉμ§ Angular V5λ‘μ μ κ·Έλ μ΄λλ₯Ό μν΄ μνν λͺ¨λ μμ μ λ²λ¦¬λ κ²μ μ«μ΄ν©λλ€.
μ¬κΈ°μ λ ν νλ₯Ό λμ§κ³ μ°λ¦¬λ μ±μ Angularλ‘ μ
κ·Έλ μ΄λνλ κ³Όμ μ μμΌλ©° νμ¬ waitForAngularEnabled(false)
μ λ¨νΈμ μΈ μ ν리μΌμ΄μ
μ μ¬μ©νμ¬ μ 체 μ νκ΅°μ λ ν° μνμ λΉ λ¨λ¦¬μ§ μκ³ ν΅κ³Όνλλ‘ νκ³ μμ΅λλ€. κ·Έλ¬λ λ§€μ° μ΄μμ μ΄μ§ μμΌλ―λ‘ λ λμ μ루μ
μ λμ΄ νκ°ν κ²μ
λλ€.
νΉν $interval μλΉμ€μ κ΄λ ¨νμ¬ μ΄ λ¬Έμ λ λ°μνμ΅λλ€. λλ‘λ κ°λκΈ°κ° κΈ°λ€λ¦¬κ³ μκ³ λλ‘λ κ·Έλ μ§ μμ΅λλ€. μμ§ ν¨ν΄μ μ°Ύμ§ λͺ»νμ΅λλ€.
κΈ΄ μκ° νΈμ§: λΆλͺ ν κ°κ²©μ΄ νΈμΆλλ μμ μ λ°λΌ λ€λ¦ λλ€(μμ λ΄ μ¬λΆ).
μλ νμΈμ @vikerman - κ°λκΈ°κ° κΈ°λ€λ¦¬λ μμ μ ꡬμ±ν μ μλ λ³κ²½ μ¬νμ λν μμμ΄ μμ΅λκΉ?
μ¬κΈ°μμλ κ°μ λ¬Έμ μ λλ€.
@vikerman μ λ°μ΄νΈλ ν΄κ²° λ°©λ²μ΄ μμ΅λκΉ?
μ°λ¦¬λ κ°μ λ¬Έμ μ μ§λ©΄ν΄ μμ΅λλ€. μ΄ λ¬Έμ μ λν΄ μ½κ°μ μ§μ μ΄ μλ€λ©΄ μ’μ κ²μ λλ€.
μ¬νκ²λ κ°μ λ¬Έμ κ° μμ΅λλ€. μ΄μ λν μ§μ μ΄ μμ΅λκΉ?
Protractorκ° μκ° μ΄κ³Όν λΉλκΈ° μμ μ΄ μ΄λμμ μλμ§ λ³΄μ¬μ€μΌλ‘μ¨ μ΄λ¬ν λ¬Έμ λ₯Ό λ μ½κ² λλ²κ·Έν μ μλλ‘ Angular λ° AngularJSμ μμ μΆμ μ μΆκ°νκ³ μμ΅λλ€.
@heathkit μ΄λ―Έ μ΄λκ°μμ μλ£λμλμ? μ°λ¦¬λ μ½λλ² μ΄μ€μμ ν΄λΉ μμΉλ₯Ό μλ³νλ λ° μ΄λ €μμ κ²ͺκ³ μμ΅λλ€.
λν κ°λκΈ°κ° μ νν 무μμ κΈ°λ€λ¦¬κ³ μλμ§ λ¬Έμλ₯Ό κ°μ§κ³ μλ κ²μ΄ μ’μ κ²μ
λλ€. μ΄κ²μ μ€λλ κ² κ°μ΅λλ€: https://www.protractortest.org/#/system -setup. $timeout
μ $interval
λ‘ λ°κΎΈλ κ²λ§ μΈκΈν©λλ€. setTimeout λλ setIntervalμ λν μ 보λ μμ΅λλ€.
μΌλΆ λ¬Έμλ http://www.protractortest.org/#/timeoutsμ μμ΅λλ€. κ·Έλ¬λ κ·Έλ€μ κ°μ§νλ λ°©λ²μ λν ννΈλ μμ΅λλ€ ...
μ΄κ²μ΄ "κ°ν νμ΄λΈλ¦¬λ + κ°λκΈ°" ν μ€νΈλ₯Ό μ€ννλ λ° λμμ΄ λ κ²μ΄λΌκ³ μκ°ν©λλ€. λμμ΄ λμμ΅λλ€. λ§ν¬ νμΈ: https://github.com/ui-router/angular-hybrid/issues/39#issuecomment -309057814
μ°λ¦¬λ μ΄ λ¬Έμ μ λ¬΄μ¨ μΌμ΄ μΌμ΄λκ³ μλμ§ μ΄ν΄νλ λ° μ½κ°μ μ§μ μ μ΄λ£¨μμ΅λλ€. μ°λ¦¬λ κ°μ κ²μ κ°μ§κ³ μλ κ² κ°μ΅λλ€. μ κ·Έλ μ΄λλ angularjs κ°μμ/λ€μ΄μ μ€νΈ μ¬μ΄ν΄μ μ½κ° λ€λ₯΄κ² μλνλ©° μΌλΆ 무ν λ€μ΄μ μ€νΈ μ¬μ΄ν΄ 루νλ₯Ό νμ±νν μ μμ΅λλ€. μ¬μ© μ€μΈ νμ¬μμ 1κ°λ₯Ό μ°Ύμκ³ λ€μ μ νμ μ‘°μ¬ μ€μ λλ€. κ·Έλ¬λ κΈ°λ³Έμ μΌλ‘ κ°μμλ κ°μ λμμ λ³κ²½νμ¬ κ°μμκ° νΈλ¦¬κ±°νλ λ±μ μμΈμ΄ λμμ΅λλ€. λμΌν λ¬Έμ κ° μλμ§ ν μ€νΈνλ €λ©΄ ν¬λ‘¬μμ κ°λ° λꡬλ₯Ό μ΄κ³ μ±λ₯μΌλ‘ μ΄λνμ¬ λͺ μ΄λ₯Ό κΈ°λ‘νκ³ NgZone ν΅νκ° λ§μ΄ λ°μνλμ§ νμΈνμμμ€. κ·Έλ λ€λ©΄ μ½λ μ΄λκ°μ 무ν λ€μ΄μ μ€νΈ μ£ΌκΈ°κ° μμ΅λλ€. νΈμΆμ μμΈν μ΄ν΄λ³΄λ©΄ νΈμΆμ μμΈμ μ°Ύλ λ° λμμ΄ λ μ μμ΅λλ€.
λν λ‘컬 zone.js νμΌμ μ½κ° μμ νκ³ μκ° μ΄κ³Ό/κ°κ²© μμ μ΄ ν¨μΉλλ μ½μ λ‘κ·Έλ₯Ό μΆκ°νμ¬ νΈμΆνλ νλͺ©μ νμΈν μ μμ΅λλ€. κ·Έλ κ² νλ μ¬μ΄ λ°©λ²:
try {
throw new Error("track");
} catch(err) {
console.debug(err);
}
νΈμ§: λͺ¨λ°μΌμμ μ½λ νμμ μ§μ νλ κ²μ΄ λ무 μ¬λ―Έμμ΅λλ€!
@vikerman μ΄κ²μ λν μ λ°μ΄νΈκ° μμ΅λκΉ? μ΄ λ¬Έμ κ° μΌλ§λ 빨리 μμ λ μ§μ λν μ견μ μ 곡ν μ μλ€λ©΄ μΌλ§λ μ’μκΉμ? κ°μ¬ ν΄μ.
λν λ‘컬 zone.js νμΌμ μ½κ° μμ νκ³ μκ° μ΄κ³Ό/κ°κ²© μμ μ΄ ν¨μΉλλ μ½μ λ‘κ·Έλ₯Ό μΆκ°νμ¬ νΈμΆνλ νλͺ©μ νμΈν μ μμ΅λλ€. κ·Έλ κ² νλ μ¬μ΄ λ°©λ²:
try { throw new Error("track"); } catch(err) { console.debug(err); }
νΈμ§: λͺ¨λ°μΌμμ μ½λ νμμ μ§μ νλ κ²μ΄ λ무 μ¬λ―Έμμ΅λλ€!
μκ° μ΄κ³Ό/κ°κ²©μ μΆμ νκΈ° μν΄ ν΄λΉ μ½λλ₯Ό μ΄λμ λ£κ² μ΅λκΉ?
@maurycyg patchTimer -> patchMethod ν¨μκ° νΈλ¦μ μνν΄μΌ ν©λλ€.
μ΄ μ€λ λλ 보기μ λ―Όλ§ν©λλ€. μ΄μ λν μ λ°μ΄νΈκ° μμ΅λκΉ?
$timeout
μ¬μ©νμ§ μλ μ μ¬μ μΈ ν΄κ²° λ°©λ²μ $interval
(νμ¬ λΌμ΄λΈλ¬λ¦¬μ κ²½μ°)λ‘ μ¬μ μνλ κ²μ
λλ€.
μλ μ½λλ μκ° μ΄κ³Ό λ¬Έμ λ₯Ό ν΄κ²°νμ΅λλ€(κ²½μ°μ λ°λΌ λΈλΌμ°μ νμΈ μΆκ°). μ κ²½μ°μλ μ§μ° μμ΄ $timeoutμ νΈμΆνλ angular-bootstrap κ΅¬μ± μμλ‘ μΈν΄ λ¬Έμ κ° λ°μνμ΅λλ€.
app.config(function($provide) {
function isUnderProtractor() {
var nav = window.navigator;
var lowercasedUserAgent = nav.userAgent;
return !lowercasedUserAgent || lowercasedUserAgent.contains('protractor');
}
if (isUnderE2ETest()) {
$provide.decorator('$timeout', ['$interval', '$delegate', function($interval, $delegate) {
var newTimeout = function(fn, delay, invokeApply, pass) {
if (!delay)
return $interval(fn, delay, 1, invokeApply, pass);
else
return $delegate(fn, delay, invokeApply, pass);
};
newTimeout.cancel = $delegate.cancel;
return newTimeout;
}]);
}
}
zone.js v0.8.9λΆν° μ΄λ¬ν λͺ¨λμ ν¨μΉλ‘ μΈν΄ λ°μνλ μ€λ²ν€λλ₯Ό μ€μ΄κΈ° μν΄ ν¨μΉν μΉ API λͺ¨λμ μ νν μ μμ΅λλ€.
https://github.com/angular/zone.js/blob/master/MODULE.md
μλ λ΄μ©μ΄ ν¬ν¨λ zone-flags.ts νμΌ μΆκ°
(window as any).__Zone_disable_timers = true;
zone.js μ΄μ μ polyfills.tsλ‘ κ°μ Έμ€κΈ°
import './zone-flags';
import 'zone.js/dist/zone'; // Included with Angular CLI.
ꡬμ νμ΄λ¨Έλ₯Ό λΉνμ±ννλ μμ μ루μ μ Obserables(μ: asyncValidators)λ₯Ό μλ§μΌλ‘ λ§λλ κ²μΌλ‘ λνλ¬μ΅λλ€. λ§μΉ¨λ΄ λλ₯Ό μν΄ μΌν μ루μ μ μμμ΄ ν¨μΉ setTimeoutμ λλ€.
platformBrowserDynamic().bootstrapModule(AppModule)
.then((moduleRef: NgModuleRef<AppModule>) => {
const ngZone: NgZone = moduleRef.injector.get(NgZone);
const originalSetTimeout = window.setTimeout;
(window as any).setTimeout = function setTimeout(fn, ms) {
return ngZone.runOutsideAngular(() => {
return originalSetTimeout(() => {
ngZone.run(fn);
}, ms);
});
};
})
μλ§λ λ¬Έμ λ κ°λκΈ° μμ²΄κ° μλλΌ μμ© νλ‘κ·Έλ¨ μ½λμ μμ΅λλ€.
λ€μ΄μ μ€νΈ μ£ΌκΈ°λ₯Ό μ¬μ©νμ¬ λ³κ²½ μ¬νμ μΆμ νλ Angular JSμμ Angular2+ λ§λ κ° μλ νμ΄λΈλ¦¬λ μ±μΌλ‘ μ ννλ©΄μ zone.jsλ₯Ό μ¬μ©νμ¬ λ³κ²½ μ¬νμ κ°μ§νλ©΄μ Protractorκ° μκ° μ΄κ³Όλ‘ λ¨μ΄μ§κΈ° μμνμ΅λλ€.
κ°λκΈ°λ μμ© νλ‘κ·Έλ¨μ΄ μμ μ μΈ κ²½μ°μλ§ λ€μ ν μ€νΈ μμ μ μμν©λλ€. νμ΄λΈλ¦¬λ μ±μ κ²½μ° μμ μ±μ΄λ μ ν리μΌμ΄μ μ Angular JS λΆλΆκ³Ό μ ν리μΌμ΄μ μ Angular2+ λΆλΆμ μμ μ±μ μλ―Έν©λλ€. λ λΆλΆ λͺ¨λ μμ μ μ΄μ΄μΌ ν©λλ€.
Angular JS μμ μ±μ $$testability.whenStable
ν΅ν΄ μ μλ©λλ€. Angular 2+μ μμ μ±μ window.getAngularTestability(...).whenStable
ν΅ν΄ κ²°μ λ©λλ€. κ°λκΈ° μ½λλ₯Ό λλ²κ·Ένκ³ μ§μ νμΈν μ μμ΅λλ€. μ΄λ κ² νλ €λ©΄ waitForAngular __\node_modules\protractor\built\clientsidescripts.js_ νμΌμ debugger;
λ¬Έμ μΆκ°νμμμ€.
Angular2+ μμμ μμ μ±μ΄ μ λ λ°μνμ§ μμμ μ μ μμ΅λλ€. μμ μ±μ μν΄ λͺ¨λ λ§μ΄ν¬λ‘ μμ
κ³Ό 맀ν¬λ‘ μμ
μ μλ£ν΄μΌ ν©λλ€.
μ΄μ μ°λ¦¬λ λ¬Έμ λ₯Ό μ΄ν΄ν©λλ€. μμ© νλ‘κ·Έλ¨μ Angular 2+ λΆλΆμ νμ λΆμμ νλ―λ‘ κ°λκΈ°λ μμ λκ³ μκ° μ΄κ³Όλ‘ λ¨μ΄μ§ λκΉμ§ 무기ν κΈ°λ€λ¦½λλ€. νμ΄λΈλ¦¬λ μ±μ κ²½μ° Angular JS μμ μ±μ λ³κ²½λμ΄μλ μ λλ©° κ°λκΈ° μκ° μ΄κ³Όμ μν₯μ λ―ΈμΉμ§ μμ΅λλ€. μ΄κ²μΌλ‘λΆν° μ°λ¦¬λ Angular2+ μμμ λΆμμ μ±μ μμ νλ κ²μ΄ νμνλ€λ κ²°λ‘ μ λ΄λ¦΄ μ μμ΅λλ€. κ·Έλ¬λ©΄ κ°λκΈ°κ° μμλλ‘ μλνκΈ° μμν κ²μ λλ€.
첫 λ²μ§Έ μμ μλ:
μκ°μ΄ κ±°μ μμκ³ λͺ¨λ κ²μ ν λ²μ μμ νκ³ μΆμκΈ° λλ¬Έμ Angular2+ μμμμ μμ
μΌμ μ μ‘λ μ½λλ₯Ό μμ±νμ΅λλ€.
$provide.decorator("$animateCss", ["$delegate", createDecorator]);
$provide.decorator("$http", ["$delegate", createDecorator]);
$provide.decorator("$timeout", ["$delegate", createDecorator]);
$provide.decorator("$interval", ["$delegate", createDecorator]);
$provide.decorator("$q", ["$delegate", createDecorator]);
$provide.decorator("$xhrFactory", ["$delegate", createDecorator]);
$provide.decorator("$templateRequest", ["$delegate", createDecorator]);
$provide.decorator("$httpBackend", ["$delegate", createDecorator]);
$provide.decorator("$animate", ["$delegate", createDecorator]);
$provide.decorator("$rootScope", ["$delegate", createDecorator]);
$provide.decorator("$templateCache", ["$delegate", createDecorator]);
$provide.decorator("$browser", ["$delegate", createDecorator]);
function runInRootZone(fn, ...args) {
if (window.Zone.current.parent) {
return window.Zone.current.parent.run(() => runInRootZone(fn, ...args));
}
return fn(...args);
}
function decorate(decorator, $delegate) {
const keys = Object.keys($delegate);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (angular.isFunction($delegate[key])) {
decorator[key] = createDecoratorForFunctionLikeService($delegate[key]);
} else {
if (decorator[key] !== $delegate[key]) {
decorator[key] = $delegate[key];
}
}
}
}
function createDecoratorForFunctionLikeService($delegate) {
function decorator(...args) {
return runInRootZone($delegate, ...args);
}
decorate(decorator, $delegate);
return decorator;
}
function createDecoratorForService($delegate) {
decorate($delegate, $delegate);
return $delegate;
}
function createDecorator($delegate) {
if (angular.isFunction($delegate)) {
return createDecoratorForFunctionLikeService($delegate);
}
return createDecoratorForService($delegate);
}
μ΄ μ κ·Ό λ°©μμ μ€ν κ°λ₯ν κ²μΌλ‘ μ μ¦λμμ§λ§ μκ°μ΄ 보μ¬μ£Όλ―μ΄ μ΄ μ κ·Ό λ°©μμλ κ³ μ ν λ¨μ μ΄ μμ΅λλ€. μ£Όλ κ²μ νμ΄λΈλ¦¬λ μ±μ νΉμ λΆλΆμ λν΄ μ΄λ€ μμ(λ£¨νΈ λλ κ°λ)μ΄ λ μ§ κ²°μ νλ κ²μ΄ λΆκ°λ₯νλ€λ κ²μ λλ€. μ μμ μΈ μλμ μν΄ Angular2+λ νμ Angular μμμ μμ΄μΌ νλ©° λ°μ½λ μ΄ν°λ Angular2+ κ΅¬μ± μμκ° λ£¨νΈ μμμ μλλ‘ ν μ μμ΅λλ€. ngUpgradeλ Angular μμμ΄ λλΆλΆμ μμ© νλ‘κ·Έλ¨μ ν¬κ΄ν¨μ μλ―Έν©λλ€.
μ΄λ₯Ό νΌνκΈ° μν΄ λ°μ½λ μ΄ν°λ₯Ό ν¬κΈ°νκ³ μλ λ¬Έμ λ‘ λμκ° μμΈμ λ μμΈν λΆμνμ¬ λ λ²μ§Έ μμ μλκ° μμμ΅λλ€.
μ΄μ μ΄λ€ μ½λκ° μμμ λΆμμ νκ² λ§λλμ§ μ΄ν΄ν΄μΌ ν©λλ€. μ΄λ₯Ό μν΄ zone.jsμλ _TaskTrackingZoneSpec_(_\node_modules\zone.js\dist\task-tracking.js_)κ³Ό κ°μ νΉμ μ νΈλ¦¬ν°κ° μμ΄ μμμ μλ μμ
κ³Ό μμ±λ μμΉλ₯Ό μΆμ ν μ μμ΅λλ€( creationLocation
). λν μ±μ Angular2+ λΆλΆ μμ λΆλΆμμ Angular μμ (window as any).a9Zone = (upgradeModule as any).ngZone._inner;
νκ³ μ΄ μ½λλ₯Ό μ΄λκ°μ μΆκ°ν©λλ€.
$rootScope.$watch(function () {
if (window.a9Zone) {
console.log("Angular2+ task count:", window.a9Zone._zoneDelegate._taskCounts);
// Optional.
window.getAllAngularTestabilities().forEach(_ => {
_.taskTrackingZone.macroTasks.forEach(t => {
console.log(t, t.creationLocation);
});
});
}
});
λ°λΌμ μμ© νλ‘κ·Έλ¨μμ λ§μ΄ν¬λ‘ μμ κ³Ό 맀ν¬λ‘ μμ μ΄ μ€λ«λμ μμμ μλ μμΉλ₯Ό μ°Ύμ΅λλ€(_microTasks.lenght! == 0 && macroTasks.lenght! == 0_).
κ·Έλ° λ€μ μ΄ μ½λλ₯Ό Angular μμμμ κ°μ ΈμμΌ ν©λλ€. μ΄λ κ² νλ €λ©΄ ngZone.runOutsideAngular
μ½λλ₯Ό λνν©λλ€. κ·Έλ¬λ λ§€μ° μ‘°μ¬μ€λ½κ² μννκ³ λ£¨νΈ μμμ΄ νμνμ§ μμ κ³³μ λνλμ§ μμλμ§ νμΈνμμμ€.
κ°λ μμμ΄ μμ λλ©΄ κ°λκΈ°κ° λ μ΄μ μκ° μ΄κ³Όλ‘ λ¨μ΄μ§μ§ μμ΅λλ€.
λμμ΄ λμκΈ°λ₯Ό λ°λλλ€.
μλ λ
Όλ¦¬λ‘ waitForAngular
ν¨μλ₯Ό μ¬μ μνμ¬ μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ μμ ν΄νΉμ μκ°ν΄ λμ΅λλ€.
onPrepare: function() {
var script = "var callback = arguments[arguments.length - 1];" +
"angular.element(document.querySelector(\"body\")).injector()"+
".get(\"$browser\").notifyWhenNoOutstandingRequests(callback)");
browser.waitForAngular = function() {
return browser.executeAsyncScript(script)
};
}
κ°μ₯ μ μ©ν λκΈ
μλ - μ°λ¦¬λ μμ λ¬Έμ λ₯Ό μ²λ¦¬νλ λ° λμμ΄ λ μ μλλ‘ κ°λκΈ°κ° κΈ°λ€λ¦¬λ μμ μ ꡬμ±ν μ μλλ‘ λ³κ²½ μμ μ μ§ν μ€μ λλ€. μ΄κ²μ Zone.js λ° Angularμ κ΄λ ¨λ κ΄λ²μν λ³κ²½μ΄λ©° νΉμ ETAκ° μμ΅λλ€(λͺ μ£Ό μ λ μμλ μμ ). μ¬κΈ°μμ μ§ν μν©μ μ λ°μ΄νΈν©λλ€.