Protractor: 앱이 ngUpgrade둜 λΆ€νŠΈμŠ€νŠΈλž©λ  λ•Œ 각도기가 μ‹€νŒ¨ν•¨

에 λ§Œλ“  2017λ…„ 05μ›” 16일  Β·  51μ½”λ©˜νŠΈ  Β·  좜처: angular/protractor

μ €λŠ” 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 블둝이 μžˆμŠ΅λ‹ˆλ‹€. μ΄μƒν•˜κ²Œλ„ μ—¬μ „νžˆ νŽ˜μ΄μ§€λ₯Ό μ—΄κ³  μ‚¬μš©μž 이름 ν•„λ“œμ— ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ§€λ§Œ 더 이상 μ§„ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” μ‹œλ„ν–ˆμ§€λ§Œ μ„±κ³΅ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.

  • λ‚΄ 각도기 ꡬ성 νŒŒμΌμ— "rootElement: 'body'" μΆ”κ°€
  • λ‚΄ 각도기 ꡬ성 νŒŒμΌμ— "ng12Hybrid: true" μΆ”κ°€ - μžλ™ κ°μ§€ν•˜λ―€λ‘œ 더 이상 ν•„μš”ν•˜μ§€ μ•Šλ‹€λŠ” λ©”μ‹œμ§€κ°€ λ‚˜νƒ€λ‚©λ‹ˆλ‹€.
  • allScriptsTimeout 섀정을 11000μ—μ„œ 60000으둜 늘리면 μ—¬μ „νžˆ μ‹œκ°„μ΄ μ΄ˆκ³Όλ©λ‹ˆλ‹€.
  • waitForAngularEnabled 섀정을 λ•λ‹ˆλ‹€. 이것은 둜그인 ν•„λ“œμ˜ 문제λ₯Ό ν•΄κ²°ν•˜μ§€λ§Œ λ‚΄ http λͺ¨μ˜κ°€ μž‘λ™ν•˜μ§€ μ•Šκ³  ν…ŒμŠ€νŠΈκ°€ μ‹€νŒ¨ν•©λ‹ˆλ‹€.

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

μ•ˆλ…• - μš°λ¦¬λŠ” μœ„μ˜ 문제λ₯Ό μ²˜λ¦¬ν•˜λŠ” 데 도움이 될 수 μžˆλ„λ‘ 각도기가 κΈ°λ‹€λ¦¬λŠ” μž‘μ—…μ„ ꡬ성할 수 μžˆλ„λ‘ λ³€κ²½ μž‘μ—…μ„ 진행 μ€‘μž…λ‹ˆλ‹€. 이것은 Zone.js 및 Angular와 κ΄€λ ¨λœ κ΄‘λ²”μœ„ν•œ 변경이며 νŠΉμ • ETAκ°€ μ—†μŠ΅λ‹ˆλ‹€(λͺ‡ μ£Ό 정도 μ†Œμš”λ  μ˜ˆμ •). μ—¬κΈ°μ—μ„œ 진행 상황을 μ—…λ°μ΄νŠΈν•©λ‹ˆλ‹€.

λͺ¨λ“  51 λŒ“κΈ€

이 μ—…κ·Έλ ˆμ΄λ“œ μ½”λ“œλ₯Ό λ‹€μŒκ³Ό 같이 λž˜ν•‘ν•˜μ—¬ μœ μ‚¬ν•œ λ¬Έμ œκ°€ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

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) μ•±μž…λ‹ˆλ‹€.

  • κ°€μž₯ λ°”κΉ₯μͺ½ νŽ˜μ΄μ§€(CharactersPage)λŠ” AngularJS(1.6)μ—μ„œ μ œκ³΅ν•©λ‹ˆλ‹€.
  • 이 νŽ˜μ΄μ§€μ—λŠ” λ‹€μš΄κ·Έλ ˆμ΄λ“œλœ Angular(4) ꡬ성 μš”μ†ŒμΈ CharacterListComponentκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • CharacterListComponentλŠ” λ‹€λ₯Έ Angular 4 ꡬ성 μš”μ†ŒμΈ CharacterDetail ꡬ성 μš”μ†Œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

λ§ˆμŠ€ν„° 브랜치 λŠ” μž‘λ™ν•˜λŠ” μ•±κ³Ό 문제 없이 ν†΅κ³Όν•˜λŠ” 단일 각도기 ν…ŒμŠ€νŠΈλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.

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

  • UibAlertController
  • UibCarouselController
  • UibDatepickerPopupController
  • UibTypeaheadController
  • UibTooltip

UI 선택

  • UI선택
  • uiSelectMultiple
  • uiSelectSingle
  • UISelectSort
  • uisOpenClose

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μ˜€μŠ΅λ‹ˆλ‹€. λ˜λŠ” 계속 진행할 수 μžˆλ„λ‘ 이 문제λ₯Ό λ‹«μœΌμ‹­μ‹œμ˜€.

ν˜„μž¬ κ³ λ €ν•˜κ³  μžˆλŠ” 뗏λͺ©μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • λͺ¨λ“  angular-ui-bootstrap / ui-select λ₯Ό κ΅μ²΄ν•˜μ‹­μ‹œμ˜€ . 이것은 λ‚˜μ—κ²Œ μ€‘μš”ν•©λ‹ˆλ‹€. μ–΄μ¨Œλ“  μˆ˜ν–‰ν•΄μ•Ό ν•˜μ§€λ§Œ λ‚΄ κ΄€μ‹¬μ‚¬λŠ” λ‹€λ₯Έ 것이 λ‚˜νƒ€λ‚  것이고 κ·Έ μž‘μ—… 후에도 μ—¬μ „νžˆ AngularJS에 고정될 κ²ƒμ΄λΌλŠ” κ²ƒμž…λ‹ˆλ‹€. ν•™μŠ΅ν•œ λ‚΄μš©: 타사 ꡬ성 μš”μ†Œλ₯Ό 자체 ꡬ성 μš”μ†Œλ‘œ λž˜ν•‘ν•©λ‹ˆλ‹€.
  • @vladotesanovic이 μ œμ•ˆν•œ λͺ¨λ“  ν…ŒμŠ€νŠΈμ— λŒ€ν•΄ waitForAngularEnabled(false) μž…λ‹ˆλ‹€ . λ‚˜λŠ” 전체 앱에 λŒ€ν•΄ 이것에 λŒ€ν•΄ νšŒμ˜μ μ΄μ§€λ§Œ ν…ŒμŠ€νŠΈν•˜μ§€λŠ” μ•Šμ•˜μŠ΅λ‹ˆλ‹€. λ‚˜λŠ” ν˜„μž¬ ν•œ 가지 μƒν™©μ—μ„œλ§Œ waitForAngularEnabled λ₯Ό μ‚¬μš©ν•˜κ³  있으며 맀우 νŠΉμ •ν•œ κ²½μš°μ—λ§Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
  • 전체 앱을 AngularJS/
  • Angular λŒ€μ‹  Vue λ˜λŠ” React둜 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ν•˜μ‹­μ‹œμ˜€ . 특히 λ‘˜ λ‹€ AngularJ와 곡쑴할 수 μžˆλ‹€λŠ” 점을 κ³ λ €ν•˜λ©΄ λͺ©λ‘μ—μ„œ κ°€μž₯ λ†’μŠ΅λ‹ˆλ‹€.
  • Puppeteer둜 μ΄λ™ν•˜κ³  λͺ¨λ“  각도기 ν…ŒμŠ€νŠΈ
  • λ˜λŠ” #4290μ—μ„œ μˆ˜μ •ν•˜λ©΄ ngUpgrade μ‚¬μš©μ„ μ‹œμž‘ν•˜λŠ” 데 ν•„μš”ν•œ λͺ‡ μ€„μ˜ 주석을 μ œκ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. :)

우리 νŒ€μ€ λ³΅μž‘ν•œ μ‘μš© ν”„λ‘œκ·Έλž¨μ„ μ—…κ·Έλ ˆμ΄λ“œν•˜λŠ” 쀑이며 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)
            };
}
이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰