typescript - Protractor `element().getAttribute()` üzerinde `await` kullanmak hata veriyor: "'await' işleminin tipi geçerli bir promise olmalı..."


Bir Angular2 uygulaması için Protractor kullanarak davranış testleri yazıyorum ve async/await sözdizimine yeniyim. Bu sorun beni durma noktasına getirdi. Birisi, isLogoFooterPresent() metodunda neden Type of 'await' operand must either be a valid promise or must not contain a callable 'then' member. Typescript hatasını aldığımı ve bunu nasıl düzeltebileceğimi açıklayabilir mi?

Bir görüntünün genişliğini kontrol ederek görüntünün gösterilip gösterilmediğini doğrulamaya çalışan aşağıdaki basit Protractor spesifikasyonuna sahibim.

İşte e2e-spec.ts dosyamdan bir alıntı:

import { LoginPage, Layout } from '../page_objects';

describe('Login page', () => {
  it('Should have the logo in the footer', async () => {
    await LoginPage.navigateTo();
    await expect(Layout.isFooterLogoPresent).toBe(true);
  })
});

Ve işte söz konusu logo görüntüsüne erişimi olan benim Layout sayfa nesnemden bir kesit. Hata oluşturan await element(...).getAttribute(...) zincirine sahip satır.

import { browser, element, by } from 'protractor/globals';

export class Layout {
  static get isFooterLogoPresent() {
    return ( async () => { // <-- this wrapping is necessary to use async/await in getter method
      return await element(by.css('.content-footer img')).getAttribute('naturalWidth') > 0; // <-- PROBLEM HERE
    })
  }
}

Aşağıdaki söz vaadi tabanlı sözdizimi (çalışan) benim değiştirmeye çalıştığım şeydir:

  static get isFooterLogoPresent() {
    return element(by.css('.content-footer img')).getAttribute('naturalWidth') // naturalWidth attr is 0 if image is missing
      .then( imgWidth => imgWidth > 0 );
  }

Bu arada, Ben TypeScript 2.3.2 ve Protractor 5.2.0 kullanıyorum. Sahip olduğunuz her türlü bilgeliğe minnettarım. Teşekkürler!

Cevap #1

Protractor 5.2'nin henüz async/await sözdizimi için hazır olmadığı sonucuna varıyorum. Eğer biri bunu sağlam bir şekilde çalıştırmayı başarırsa, nasıl ve hangi sürümle yaptığını öğrenmek isterim. Şu anda, getAttribute() kaynak koduna inerseniz, bir ElementFinder nesnesi döndürüyor, bir Promise değil. Bu nesnenin üzerinde bir .then() yöntemi var, bu nedenle .then() zincirleyerek sonucu bir promise gibi kullanabilirsiniz, ancak TypeScript bunu haklı olarak uygun bir promise olarak tanımayacak, oysa ki await bunu bekliyor.

Şu anda, bu Protractor projesi için async/await kullanmayı bırakıyorum. Bunun yerine, asenkron davranışı tamamen promise'lerle yönetmeye dönüyorum.

Cevap #2

Sadece await için parantez ekle -

  import { browser, element, by } from 'protractor/globals';

  export class Layout {
    static get isFooterLogoPresent() {
      return ( async () => {
        return (await $('.content-footer img').getAttribute('naturalWidth')) > 0;
      })
    }
  }

Bu, karşılaştırma ifadesine değil, çözülmüş değere > 0 uygulanmasını sağlayacaktır

AMA! Burada bir hata var:

await expect(Layout.isFooterLogoPresent).toBe(true);

function isFooterLogoPresent hâlâ bir promise döndürüyor, bu yüzden promise nesnesinin doğru olduğunu doğruluyorsunuz, bu JS'de nesne karşılaştırmasının nasıl çalıştığına göre her zaman doğru olacaktır. Yanlış pozitif testi düzeltmek için bunu değiştirin:

await expect(await Layout.isFooterLogoPresent).toBe(true);

İlgili makaleler