Protractor: Hindari menunggu $ timeout () s?

Dibuat pada 16 Okt 2013  ·  59Komentar  ·  Sumber: angular/protractor

Di aplikasi kami, kami menampilkan pesan "popup" kepada pengguna kami ketika tombol tertentu diklik. Pesan popup ini hanya terlihat selama sekitar 20 detik (setelah itu $ timeout menghapusnya).

Masalahnya adalah bahwa Protractor tampaknya menunggu sampai $ timeout selesai sebelum itu .findElement () dan .expect () hal. Namun, ketika $ timeout adalah _timed out_, pesan tersebut hilang, dan elemen tidak ditemukan.

Ada saran tentang cara melewati / mengatasi ini? (Kami _perlu_ untuk menegaskan bahwa pesan "munculan" yang benar ditampilkan kepada pengguna)

Terima kasih

question

Komentar yang paling membantu

Apakah tim Angular berencana untuk membuka kembali masalah ini karena semakin banyak orang yang mengalami ini. Ini bukan profesional hanya berpura-pura bahwa tidak ada masalah karena Anda dapat mengganti $ timeout dengan $ interval karena kode tidak boleh ditulis agar sesuai dengan tes - tes harus ditulis untuk kode tes.

Semua 59 komentar

Anda dapat menggunakan ptor.ignoreSynchronization , tetapi ini mungkin menyebabkan kelemahan di tempat lain dalam pengujian Anda. Atau, di Angular 1.2rc3, sekarang ada layanan interval , yang tidak akan ditunggu oleh Protractor (lihat https://github.com/angular/angular.js/commit/2b5ce84fca7b41fca24707e163ec6af84bc12e83). Anda dapat mengatur interval yang akan berulang 1 kali.

Hai @drhumlen , kami memiliki masalah yang sama dan kami menyimpulkan bahwa munculan pasti sesuatu yang harus pergi ke pengujian unit. Jadi, kami mengejek sistem notifikasi kami dan berharap bahwa tiruan tersebut telah dipanggil (akhirnya dengan beberapa informasi penting). Kami juga menguji unit notifikasi untuk memastikan tidak ada yang rusak.
Semoga bantuan itu.

$interval melakukan trik untuk kami.

  $interval(function() {
    // ...
  }, duration, 1);

Sekarang bekerja dengan baik. Tetapi kita harus sangat berhati-hati dan memastikan bahwa popup dihapus dengan cara lain setelah setiap pengujian (dalam kasus kita, mengklik tombol "x"):

  afterEach(function() {
    removeLogMessagesFromDOM();
  });

@mackwic : Saya kira itu mungkin untuk mengujinya dengan tes unit untuk banyak aplikasi, tetapi dalam kasus kami, pesan kesalahan dihasilkan oleh backend, jadi kami harus mengujinya di e2e.

Terima kasih @juliemr

Tampaknya aneh bahwa Busur derajat menunggu $timeout s. Sebagian besar waktu pengguna harus bekerja melawan ini?

Juga menghadapi masalah ini dan menyelesaikannya dengan $interval . Dengan sedikit perubahan, Anda dapat menggunakannya seperti $timeout .

Saya ingin menguji metode penyimpanan dan memverifikasi bahwa pemberitahuan sukses ditampilkan setelah penyimpanan. Notifikasi ini disembunyikan oleh layanan $ timeout. Busur derajat sedang menunggu $ timeout dan memeriksa apakah pemberitahuan terlihat setelah itu sudah disembunyikan.

Sebelum:

$timeout(function() {
    //hide notification
}, 3000);

Setelah:

var intervalCanceller = $interval(function() {
    //hide notification
    $interval.cancel(intervalCanceller);
}, 3000);

Apakah ini tidak dianggap sebagai masalah yang valid? Saya baru saja mengalami ini sendiri. Saya tidak benar-benar melihat bahwa menggunakan $interval daripada $timeout adalah solusi, lebih merupakan solusi.

Saya juga tidak bisa menjalankan ini, bahkan jika saya mengubah ke $interval dari $timeout .

Saya memiliki roti panggang yang menghilang setelah waktu tunggu. Ini adalah kode yang saya gunakan untuk mengujinya:

username = element(select.model("user.username"))
password = element(select.model("user.password"))
loginButton = $('button[type=\'submit\']')
toast = $('.toaster')
# Check the toaster isn't displayed initially
expect(toast.isDisplayed()).toBe(false)  # This passes
username.sendKeys("redders")
password.sendKeys("wrongpassword")
loginButton.click()
toastMessage = $('toast-message')
# Check the toaster is now displayed
expect(toast.isDisplayed()).toBe(true)   # This passes
expect(toastMessage.getText()).toBe("Invalid password")  # This fails

Markup yang relevan ada di sini (giok)

.toaster(ng-show="messages.length")
  .toast-message(ng-repeat="message in messages") {{message.body}}

Kegagalannya adalah toastMessage = $('toast-message') tidak cocok dengan elemen apapun. Apakah ini gagal karena dipanggil di awal, ketika .toast-message tidak ada?

Apakah masalah ini sudah diperbaiki? Karena menggunakan interval daripada timeout adalah hack atau workarounf lebih dari solusi.

Saya menghadapi masalah yang sama dan browser.ignoreSynchronization = true; tidak membantu. Saya dapat mengganti kode menjadi $ interval tetapi tes e2e harus menguji kode sebenarnya bukan kode yang diadopsi untuk mereka.

@ vytautas-pranskunas- sepertinya ada masalah yang berbeda untuk Anda jika ignoreSynchronization tidak berfungsi. Jika Anda dapat memberikan contoh yang dapat direproduksi, buka masalah baru.

Saya menemukan ketika ignoreSynchronization berfungsi:
Saya memiliki layanan yang bertanggung jawab untuk menampilkan pesan kesalahan. Setelah pesan acara tetap di layar selama lima detik setelah menghilang. Proses ini dikontrol oleh $ timeout.

Saya punya dua skenario - di ignoreSynchronization berfungsi dengan baik, di kedua - tidak

1) Saya tahu bahwa pesan akan segera muncul setelah pengguna mengklik tombol dan saya melakukan expec(message).tobe(...) dalam hal ini ignoreSynchronization melakukan pekerjaan.

2) Saya tahu bahwa pesan dapat muncul setelah beberapa waktu (tergantung pada waktu respons server) dan logika saya selanjutnya harus dijalankan hanya setelah muncul jadi dalam kasus ini saya harus menggunakan browser.wait(by.(....).isPresent(), n) sini ignoreSynchronization berhenti bekerja dan alirannya mengikuti (saya akan menampilkan keluaran browser.wait console.log sambil menunggu)

waits
waits
waits (element appears)
browser waits freezes for 5 seconds
after element disappears it continue
wait
wait
wait

Jadi seperti yang Anda lihat, ia tidak pernah melihat elemen hadir karena menunggu membeku saat berhubungan dengan $ timeout

Saya benar-benar tidak punya banyak waktu untuk membuatnya dapat direproduksi di plunker tetapi jika Anda mencobanya akan lebih bagus karena skenario ini seharusnya cukup umum.

Terima kasih

Anda log sebenarnya tidak terlalu membantu tanpa konteks kode yang membuatnya. Bisakah Anda membagikan itu?

Saya tidak dapat membagikan kode saya karena privasi tetapi saya dapat menunjukkan beberapa kode palsu untuk mendapatkan ide
(tidak menulis kode html karena ada tombol dan ng-repeat untuk menampilkan pesan)

constructor(){
$scope.$on('globalMessageAdded', () => {
            $scope.globalMessages = this.getMessages();
        });
}

callServer(){
//interval here acts like server delay
   $interval(()=> {
     $rootScope.messages.push('test messages');
      this.$rootScope.$broadcast('globalMessageAdded');
   }, 3000, 1);
}

getMessages = () => {
        var newMessages = <ISpaGlobalMessage[]>[];
        _.forEach(this.$rootScope.globalMessages, item => {
            newMessages.push(item);
//because of this timeout browser.wait stops waitng for 5 seconds
            this.$timeout(() => {
                this.remove(item);
                this.$rootScope.$broadcast('globalMessageRemoved');
            }, 5000);
        });

        return newMessages;
    }

dan bagian busur derajat

element('button').click();
browser.ignoreSynchronization = true; //tried with and without it
browser.wait(() => element(by.css('.alert-success')).isPresent(), 10000000);
browser.ignoreSynchronization = false;

other code that should be executed after successful message

browser.wait tidak pernah menemukan elemen itu karena saat elemen ada, browse.wait tidak memicu pemeriksaan.

Apakah ada kemajuan atau pemikiran tentang ini?

Mengapa "browser.ignoreSynchronization = false;" tidak dapat disetel segera setelah browser.wait ()?

Kode Saya

        var el = element(by.css('.popup-title.ng-binding'));
        browser.ignoreSynchronization = true; 
        browser.wait(function (){
            return el.isPresent();
        }, 10000);
        var popupMsg = el.getText();
        expect(popupMsg).toEqual('something...');
        browser.ignoreSynchronization = false; // not work, if take out this statement, it works again

Digigit oleh masalah yang sama. Modul toast yang kami gunakan adalah komponen umum untuk npm, jadi kami tidak dapat dengan mudah mengubahnya untuk menggunakan $ interval. Saya juga gagal untuk melihat mengapa busur derajat harus menunggu yang satu dan bukan yang lain. Idealnya ini akan dapat dikonfigurasi sendiri, sehingga tidak mempengaruhi menunggu sinkronisasi lainnya.

Kami memiliki masalah ini di angular-ui / bootstrap # 3982 dan kami memutuskan untuk tidak menukarnya ke $ interval jadi kami datang ke sini untuk melihat apakah ada yang dapat dilakukan untuk memperbaiki masalah tersebut.

Terima kasih banyak.

Saya mengalami masalah ini minggu ini menggunakan komponen pemberitahuan bersulang.

Menggunakan $interval daripada $timeout bukanlah solusi yang masuk akal. Dan browser.ignoreSynchronization = true juga tidak bekerja untuk saya.

Ada pemikiran atau ide?

Apakah tim Angular berencana untuk membuka kembali masalah ini karena semakin banyak orang yang mengalami ini. Ini bukan profesional hanya berpura-pura bahwa tidak ada masalah karena Anda dapat mengganti $ timeout dengan $ interval karena kode tidak boleh ditulis agar sesuai dengan tes - tes harus ditulis untuk kode tes.

+1 Kami juga membutuhkan perbaikan.

Sepakat. Tes harus diperbaiki. +1

+1, juga mengalami masalah ini. Mungkin harus ada cara untuk memberi tahu batas waktu busur derajat yang tidak boleh ditunggu.

ignoreSynchronisation tidak berfungsi untuk saya, saya pikir itu mengabaikan terlalu banyak hal. Kami membutuhkan cara untuk mengabaikan sinkronisasi batas waktu, atau memiliki API yang lebih canggih seperti browser.waitForTimeouts(); .

+1. butuh perbaikan. mengapa kita harus menggunakan solusi buruk dengan interval.

+1

+1, merasa sangat sulit untuk menangani tes bersisik .. perlu perbaikan untuk ini

+1 setuju dengan @ vytautas-pranskunas- kita tidak perlu mengubah kode yang ingin kita uji hanya untuk membuat pengujian itu sendiri berfungsi ....

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

Saya pikir banyak orang mungkin menggunakan browser.ignoreSynchronization = true dengan cara yang salah. Tolong koreksi saya jika saya salah, tetapi bagi saya jika Anda menulis:

browser.ignoreSynchronization = true;
expect( elem.getText() ).toEqual( "foo" );
browser.ignoreSynchronization = false;

Maka itu tidak akan berhasil: ini masih JavaScript murni dan tiga baris akan dibaca secara bersamaan. Jadi pada saat janji getText dan expect selesai, sinkronisasi sudah dihidupkan kembali. Anda dapat mengatasinya dengan menunggu busur derajat menyelesaikan janji terakhir dan mengaktifkan kembali sinkronisasi pada then callback.

Salah satu cara Tim Busur Derajat untuk membantu orang mungkin dengan menyediakan akses ke metode yang hanya mempengaruhi sinkronisasi ketika buffer janji selesai. Misalnya:

browser.setIgnoreSynchronization( true );
expect( elem.getText() ).toEqual( "foo" );
browser.setIgnoreSynchronization( false );

Bagaimanapun, saya juga mengalami banyak masalah karena Busur derajat menunggu $ timeout: dalam aplikasi besar ada terlalu banyak efek samping, baik itu beberapa tooltips, modals, animasi, dll. Kami memutuskan untuk menonaktifkan sinkronisasi secara global dengan browser.ignoreSynchronization = true; dan tulis tes seperti cara pengguna menguji produk: tunggu sampai elemen terlihat jika Anda ingin mengkliknya, dll. Tulis sendiri beberapa metode pembantu dan itu akan menjadi sangat mudah. Ini bekerja cukup baik untuk kami, dan membuat pengujian berjalan jauh lebih cepat.

+1 menggunakan $ interval adalah retasan, bukan solusi

+1 bug ini telah membuat saya begitu menderita. Mari kita mulai dialog tentang cara memperbaikinya. Saya memiliki beberapa lusin modul sudut bower dan npm yang menggunakan $ timeout, di ratusan (!) Tempat, serta saya menggunakannya 45 kali dalam kode saya. Mengubah kode saya dapat dilakukan (dan masuk akal), namun, mengubah kode pihak ketiga sama sekali tidak mungkin dilakukan secara logistik: menghubungi dan mencoba untuk memotivasi penyedia hulu atau secara lokal membagi modul sudut pihak ketiga secara lokal dan mempertahankan aliran patch paralel adalah skenario mimpi buruk yang tidak dapat diterima, saat bug ada pada Protractor dan $ timeout, bukan modul luar.

Mari bekerja sama dalam hal ini.

+1

Bug ini membuat masalah untuk melakukan tes e2e untuk skenario contoh di bawah ini,

1) Isi kolom dan kirimkan beberapa formulir, yang akan menyiarkan beberapa acara seperti
* Tautan pesan status, yang dilampirkan dengan $ timeout dan terlihat hanya beberapa detik
* pesan baru ditambahkan ke daftar pesan di widget berbeda
2) Selanjutnya ketika Anda mengklik tautan pesan status, maka itu akan membuka pesan sebagai pop up dengan detail

Jadi saat kami mencoba mengotomatiskan skenario, kami dapat mengirimkan formulir. Tetapi ketika kita mencoba untuk mengklik tautan pesan status, kita perlu memiliki browser.ignoreSynchronization = true; karena tautan dilampirkan ke $ timeout.

Tautan dapat diklik, tetapi pesan yang dibuka sebagai munculan tidak berfungsi.

Ketika saya memeriksa Stackoverflow dan beberapa jawaban Google, saya mengetahui bahwa itu karena $ timeout. Jadi saya memeriksa dengan menghapus $ timeout untuk elemen, sekarang berfungsi dengan baik.

Jadi permintaan saya adalah setiap kali kami tidak dapat memiliki elemen tanpa $ timeout. Jadi harap pertimbangkan skenario di atas dan miliki fitur baru di mana busur derajat dapat mengabaikan menunggu $ batas waktu.

Menghadapi masalah yang sama, harus menggunakan window.setTimeout dan window.clearTimeout untuk menghindarinya. Cara yang tidak terlalu bersudut dan dapat mengganggu intisari, tetapi $ interval dan mengabaikan sinkronisasi bukanlah solusi

Menghadapi masalah yang persis sama, akankah ada orang dari tim busur derajat yang menanggapi ini?

+1

Ini membuat saya gila (Busur derajat noob di sini) sampai saya tiba di solusi kotor seperti di bawah ini:

beforeEach(function () { browser.ignoreSynchronization = true; });
afterEach(function () { browser.restart(); });

Bekerja dengan baik dan tidak terlalu lambat pada browser tanpa kepala.

+1

Juga mengalami masalah di sini. Pengujian saya berjalan lancar sampai mengunjungi halaman yang membuat beberapa permintaan API & membuka beberapa WebSockets. Pada saat itu, Busur derajat habis, setiap saat. Saya belum menemukan solusi yang baik.

Saya ingin tahu @floribon tentang metode pembantu yang Anda sarankan jika Anda menonaktifkan browser.ignoreSynchronization = true; secara global. Saat ini saya menggunakan objek halaman, yang cenderung terlihat seperti:

describe('something', function() {
  it('should do....', function() {
    var fooPage = new FooPage();
    fooPage.visit();
    var barPage = fooPage.clickCreate();  // does some API call, then redirects to barPage
    // at this point, enough things are happening that it is impossible to interact with barPage.
    // Protractor locks up.
    // barPage makes other API call & opens WebSocket
    barPage.clickBaz();  // nope.  will timeout every time.
  });
});

@benjaminapetersen pembantu saya terlihat seperti ini:

btn1.click();         // Triggers many things and eventually displays page2
wait.forURL('page2'); // wait for page2 to be loaded before moving on
$('.btn1').click();   // this does some async job and eventually displays btn2
wait.forElement('.btn2');
$('.btn2').click();

Dengan misalnya wait.forElement kembali

browser.wait(() => elem.isPresent().then(p => p, () => {}), timeout, 'Not found');
// browser.wait(function() { return elem.isPresent().then(function(p) { return p;} , function() {}); }, timeout, 'Not found');

Idenya adalah untuk meniru perilaku pengguna yang sebenarnya: Saya mengklik sebuah elemen, saya menunggu sampai elemen lain terlihat, kemudian saya mengkliknya, dll. Dengan cara ini tidak perlu menunggu $ timeout, ini lebih cepat dan lebih aman.

Kuncinya di sini adalah mengabaikan kesalahan dari janji batin dan mencobanya beberapa kali lagi sampai batas waktu tercapai.

PS: Anda juga dapat menggunakan ExpectedConditions untuk itu tetapi saya punya beberapa masalah dengan mereka ketika angular akan membangun kembali simpul DOM (misalnya ng-if kondisi):

browser.wait(browser.ExpectedConditions.precenseOf(elem), timeout, 'Not found');

@floribon luar biasa, terima kasih!

@juliemr dapatkah kamu membantu saya, tolong saya untuk menangkap pesan kesalahan roti bakar di busur derajat. Tolong balas di id email saya anjali. [email protected]

@juliemr Menggunakan $ interval service untuk memanggil permintaan http yang berjalan lama tidak bekerja. Busur derajat masih mendapat batas waktu.
Ini kode sudut saya
ini. $ interval (() => ini. $ http.get(this.prefix (url), config), 0, 1)
busur derajat masih menunggu tugas $ http selesai.
Saya menggunakan busur derajat 5.x dan angualrjs 1.6x.
Bisakah kamu membantuku?

+1, sesuatu harus ditambahkan untuk menangani ini.

+1

+1

+1

+1

+1

+1

Spesifikasi ini berhasil untuk saya. Terima kasih banyak! dan tepuk tangan untuk @floribon sebagai petunjuk bahwa eksekusinya tidak sinkron.

    // screenshot-spec.js

    // a close button that appears on the md-toast template
    const closeToastButton = $('[data-automation="toast-close"]')
    const cond = protractor.ExpectedConditions
    function waitToastShow() {
        return browser.wait(cond.elementToBeClickable(closeToastButton), 5000)
    }
    function waitToastHide() {
        return browser.wait(cond.invisibilityOf(closeToastButton), 5000)
    }

    screenshot = name => browser.takeScreenshot().then(/* save fn */)

    describe('a suite ... ', () => {
        it('takes screenshots of an md-toast once shown and after hidden', function () {
            // ... actions that launch an md-toast using $mdToast.show({ ... })
            browser.ignoreSynchronization = true
            waitToastShow().then(() => {
                screenshot('toast-showing.png')
                waitToastHide().then(() => {
                    screenshot('toast-hidden.png')
                    browser.ignoreSynchronization = false;
                })
            })
        });
    }

guys bagaimana saya dapat menambahkan waktu tunggu untuk kasus uji tertentu
`
it ('1-harus masuk dengan kode registrasi dikirim ke email', fungsi (selesai) {

// setTimeout(function () {
            flow.execute(browser.params.getLastEmail)
                .then(function (email) {
                    expect(email.subject)
                        .toEqual('[email protected] submitted feedback');
                    expect(email.headers.to)
                        .toEqual('[email protected]');
                    expect(email.html.includes('User feedback details: accountId: 12345, related To: dashboard, description: ' + D.feedbackMsg + ''))
                        .toEqual(true);
                    console.log(email.html);
                    // done();
                });


    });`
Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

vishalshivnath picture vishalshivnath  ·  3Komentar

koshkarov picture koshkarov  ·  3Komentar

davidkarlsen picture davidkarlsen  ·  3Komentar

gamecheck80 picture gamecheck80  ·  3Komentar

mvolkmann picture mvolkmann  ·  3Komentar