Protractor: تجنب انتظار $ timeout () s؟

تم إنشاؤها على ١٦ أكتوبر ٢٠١٣  ·  59تعليقات  ·  مصدر: angular/protractor

في تطبيقنا ، نعرض رسائل "منبثقة" لمستخدمنا عند النقر على أزرار معينة. لا تظهر هذه الرسائل المنبثقة إلا لمدة 20 ثانية تقريبًا (وبعد ذلك يزيلها $ timeout).

تكمن المشكلة في أن منقلة يبدو أنها تنتظر حتى تكتمل مهلة $ قبلها .findElement () و .expect () s الأشياء. ومع ذلك ، عندما تكون مهلة $ _timed out_ ، تختفي الرسالة ولا يتم العثور على العنصر.

أي اقتراح حول كيفية تجاوز / حل هذا؟ (نحن بحاجة إلى تأكيد عرض الرسالة "المنبثقة" الصحيحة للمستخدم)

شكر

question

التعليق الأكثر فائدة

هل يخطط فريق Angular لإعادة فتح هذه المشكلة لأن المزيد والمزيد من الأشخاص يواجهون هذه المشكلة. إنه ليس احترافيًا فقط ادعي أنه لا توجد مشكلة لأنه يمكنك استبدال $ timeout بفاصل $ لأنه لا يجب كتابة الكود لتناسب الاختبارات - يجب كتابة الاختبارات لاختبار الكود.

ال 59 كومينتر

يمكنك استخدام ptor.ignoreSynchronization ، ولكن هذا قد يسبب عدم استقرار في مكان آخر في الاختبار. بدلاً من ذلك ، في Angular 1.2rc3 ، هناك الآن خدمة interval ، والتي لن تنتظرها منقلة (انظر https://github.com/angular/angular.js/commit/2b5ce84fca7b41fca24707e163ec6af84bc12e83). يمكنك ضبط فترة زمنية تتكرر مرة واحدة.

مرحبًا drhumlen ، كان لدينا نفس المشكلة ونخلص إلى أن
آمل أن يساعد ذلك.

$interval فعل الحيلة لنا.

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

إنه يعمل الآن بشكل رائع. ولكن يجب أن نكون واعين للغاية ونتأكد من إزالة النافذة المنبثقة بطريقة أخرى بعد كل اختبار (في حالتنا ، انقر فوق الزر "x"):

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

mackwic : أفترض أنه من الممكن اختباره من خلال اختبار الوحدة للعديد من التطبيقات ، ولكن في حالتنا ، يتم إنشاء رسائل الخطأ بواسطة الواجهة الخلفية ، لذلك يتعين علينا اختبارها في e2e.

juliemr شكرا

يبدو من الغريب أن المنقلة تنتظر $timeout s. في معظم الأوقات سيتعين على المستخدم العمل ضد هذا؟

كما واجهت هذه المشكلة وحلها بـ $interval . مع القليل من التحريف ، يمكنك استخدامه تمامًا مثل $timeout .

أردت اختبار طريقة الحفظ والتحقق من عرض إشعار النجاح بعد الحفظ. تم إخفاء هذا الإشعار بواسطة خدمة timeout $. كانت المنقلة تنتظر مهلة $ وتتحقق مما إذا كان الإخطار مرئيًا بعد أن أصبح مخفيًا بالفعل.

قبل:

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

بعد:

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

أليس هذا يعتبر قضية صحيحة؟ أنا فقط واجهت هذا بنفسي. لا أرى حقًا أن استخدام $interval بدلاً من $timeout هو حل ، بل هو حل بديل.

لا يمكنني أيضًا تشغيل هذا ، حتى إذا قمت بالتغيير إلى $interval من $timeout .

لدي نخب يختفي بعد انتهاء الوقت. هذا هو الكود الذي أستخدمه لاختباره:

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

الترميز ذي الصلة هنا (اليشم)

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

الفشل هو أن toastMessage = $('toast-message') لا يطابق أي عناصر. هل فشل هذا لأنه تم استدعاؤه في البداية ، عندما لا يكون .toast-message موجودًا؟

هل تم حل هذه المشكلة حتى الآن؟ لأن استخدام الفاصل الزمني بدلاً من المهلة هو الاختراق أو الحل أكثر من الحل.

أواجه نفس المشكلة و browser.ignoreSynchronization = true ؛ لا يساعد. يمكنني استبدال الكود بـالفاصل الزمني $ لكن اختبارات e2e يجب أن تختبر الكود الحقيقي وليس الكود المعتمد لها.

@ vytautas-pranskunas- يبدو أن هناك مشكلة مختلفة بالنسبة لك إذا كان ignoreSynchronization لا يعمل. إذا كان بإمكانك تقديم مثال قابل للتكرار ، فافتح مشكلة جديدة.

لقد اكتشفت أن ignoreSynchronization لا يعمل:
لدي خدمة مسؤولة عن إظهار رسائل الخطأ. بمجرد أن تظل رسالة العرض على الشاشة لمدة خمس ثوانٍ بعد أن تتلاشى. يتم التحكم في هذه العملية بواسطة $ timeout.

حصلت على سيناريوهين - في الأول ignoreSynchronization يعمل بشكل جيد ، والثاني - لا

1) أعلم أن الرسائل يجب أن تظهر على الفور بعد نقر المستخدم على الزر وأنني أقوم بتنفيذ المهمة expec(message).tobe(...) في هذه الحالة ignoreSynchronization .

2) أعلم أن الرسالة يمكن أن تظهر بعد أي مقدار من الوقت (يعتمد على وقت استجابة الخادم) ويجب تنفيذ منطقتي الإضافية فقط بعد ظهورها ، لذا في هذه الحالة يجب أن أستخدم browser.wait(by.(....).isPresent(), n) هنا ignoreSynchronization توقف عن العمل وكان التدفق متابعًا (سأعرض إخراج browser.wait console.log أثناء الانتظار)

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

لذلك كما ترون ، لا ترى العنصر حاضرًا أبدًا لأن الانتظار يتجمد عند الاتصال بـ timeout $

ليس لدي حقًا الكثير من الوقت لأجعله قابلاً للتكرار في plunker ولكن إذا حاولت ذلك فسيكون رائعًا لأن هذا السيناريو يجب أن يكون شائعًا جدًا.

ثناك

لا يعد تسجيل الدخول مفيدًا جدًا بدون سياق الكود الذي أنشأه. هل يمكنك مشاركة ذلك؟

لا يمكنني مشاركة الكود الخاص بي بسبب الخصوصية ولكن يمكنني إظهار بعض الشفرات الزائفة للحصول على فكرة
(عدم كتابة كود html بسبب وجود زر وتكرار ng لعرض الرسائل)

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;
    }

وجزء المنقلة

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 على هذا العنصر أبدًا لأنه أثناء وجود العنصر ، لا يؤدي المتصفح browse.wait إلى تشغيل عمليات التحقق.

هل هناك أي تقدم أو أفكار حول هذا؟

لماذا لا يمكن تعيين "browser.ignoreSynchronization = false؛" مباشرة بعد browser.wait ()؟

رمز بلدي

        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

التعرض للعض من نفس المشكلة. تعد وحدة toast التي نستخدمها مكونًا عامًا لـ npm ، لذلك لا يمكننا تغييرها بسهولة لاستخدام الفاصل الزمني $. كما أنني أخفق في معرفة سبب انتظار المنقلة لواحد دون الآخر. من الناحية المثالية ، سيكون هذا قابلاً للتكوين من تلقاء نفسه ، لذلك لا يؤثر على فترات انتظار المزامنة الأخرى.

لدينا هذه المشكلة في angular-ui / bootstrap # 3982 وقررنا عدم تبديلها بالفاصل الزمني $ لذلك نأتي إلى هنا لمعرفة ما إذا كان هناك أي شيء يمكن القيام به لإصلاح المشكلة.

شكرا جزيلا.

لقد مررت بهذه المشكلة هذا الأسبوع باستخدام مكون إخطار نخب.

استخدام $interval بدلاً من $timeout ليس حلاً مقبولاً. و browser.ignoreSynchronization = true لا يعمل معي أيضًا.

أي أفكار أو أفكار؟

هل يخطط فريق Angular لإعادة فتح هذه المشكلة لأن المزيد والمزيد من الأشخاص يواجهون هذه المشكلة. إنه ليس احترافيًا فقط ادعي أنه لا توجد مشكلة لأنه يمكنك استبدال $ timeout بفاصل $ لأنه لا يجب كتابة الكود لتناسب الاختبارات - يجب كتابة الاختبارات لاختبار الكود.

+1 نحن بحاجة إلى إصلاح أيضًا.

متفق عليه. يجب إصلاح الاختبار. +1

+1 ، واجهت أيضًا هذه المشكلة. ربما يجب أن تكون هناك طريقة لإخبار أنه لا ينبغي انتظار مهلات المنقلة.

ignoreSynchronisation لا يعمل بالنسبة لي ، وأعتقد أنه يتجاهل الكثير من الأشياء. نحتاج إلى طريقة لتجاهل مزامنة المهلات ، أو أن يكون لدينا واجهة برمجة تطبيقات أكثر تعقيدًا مثل browser.waitForTimeouts(); .

+1. بحاجة الى حل. لماذا يجب علينا استخدام الحلول القبيحة مع الفاصل الزمني.

+1

+1 ، العثور على صعوبة بالغة في التعامل مع الاختبارات غير المستقرة .. بحاجة إلى إصلاح لهذا

+1 يتفق مع @ vytautas-pranskunas- لا ينبغي أن نكون مطالبين بتغيير الكود الذي نريد اختباره فقط لجعل الاختبار نفسه يعمل ....

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

أعتقد أن العديد من الأشخاص ربما يستخدمون browser.ignoreSynchronization = true بطريقة خاطئة. من فضلك صححني إذا كنت مخطئا ، ولكن لي إذا كتبت:

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

ثم لن يعمل: هذا لا يزال جافا سكريبت خالص وسيتم قراءة الأسطر الثلاثة بشكل متزامن. لذا بحلول الوقت الذي يعد فيه getText و expect بالحل ، سيتم إعادة تشغيل المزامنة بالفعل. يمكنك التغلب على ذلك من خلال انتظار المنقلة لحل الوعد الأخير وإعادة المزامنة مرة أخرى على رد الاتصال على then .

قد تكون إحدى الطرق التي يمكن أن يساعد بها فريق منقلة الأشخاص هي توفير الوصول إلى الأساليب التي تؤثر فقط على المزامنة عند تنفيذ الوعود المؤقتة. على سبيل المثال:

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

على أي حال ، واجهت أيضًا العديد من المشكلات بسبب انتظار المنقلة لانتهاء مهلة $: في التطبيقات الكبيرة ، هناك الكثير من الآثار الجانبية ، سواء كانت بعض تلميحات الأدوات أو النماذج أو الرسوم المتحركة ، وما إلى ذلك ، فقد قررنا تعطيل المزامنة مع browser.ignoreSynchronization = true; عالميًا

+1 باستخدام الفاصل الزمني دولار هو اختراق وليس حلاً

+1 سبب لي هذا الخطأ الكثير من البؤس. من فضلك ، لنبدأ حوارًا حول كيفية إصلاح هذا. لدي عشرات من الوحدات الزاويّة bower و npm التي تستخدم $ timeout ، في مئات (!) من الأماكن ، بالإضافة إلى استخدامها 45 مرة في الكود الخاص بي. يعد تغيير الكود الخاص بي أمرًا ممكنًا (ومعقولًا) ، ومع ذلك ، فإن تغيير رمز الجهة الخارجية أمر غير وارد تمامًا من الناحية اللوجستية: الاتصال بمقدمي الخدمات الأولية ومحاولة تحفيزهم أو إنشاء وحدات زاويّة لطرف ثالث محليًا والحفاظ على تدفق التصحيح المتوازي هو سيناريو مرعب غير مقبول ، عندما يكون الخطأ في منقلة ومهلة $ ، وليس وحدات خارجية.

من فضلك دعنا نعمل معا على هذا.

+1

يتسبب هذا الخطأ في حدوث مشكلات لإجراء اختبار e2e للسيناريو النموذجي أدناه ،

1) املأ الحقول وأرسل نموذجًا ما ، والذي سيبث أحداثًا متعددة مثل
* رابط رسالة الحالة ، والذي يتم إرفاقه بـ $ timeout ويكون مرئيًا لبضع ثوانٍ فقط
* يتم إضافة رسالة جديدة إلى قائمة الرسائل في عنصر واجهة مستخدم مختلف
2) بعد ذلك ، عند النقر فوق ارتباط رسالة الحالة ، يجب أن تفتح الرسالة كما تظهر مع التفاصيل

لذلك عندما نحاول أتمتة السيناريو ، يمكننا إرسال النموذج. ولكن عندما نحاول النقر فوق ارتباط رسالة الحالة ، نحتاج إلى أن يكون لدينا browser.ignoreSynchronization = true؛ لأن الارتباط مرفق بـ $ timeout.

الارتباط قابل للنقر عليه ، ولكن لا تعمل الرسالة التي تفتح كنافذة منبثقة.

عندما قمت بتسجيل الدخول في Stackoverflow وبعض إجابات Google ، عرفت أنه بسبب مهلة $. لذلك راجعت بإزالة $ timeout للعنصر ، والآن يعمل بشكل صحيح.

لذلك طلبي في كل مرة لا يمكننا فيها الحصول على عنصر بدون مهلة $. لذا يرجى النظر في السيناريو أعلاه والحصول على ميزة جديدة حيث يمكن للمنقلة تجاهل انتظار مهلة دولار.

واجهت نفس المشكلة ، كان لا بد من استخدام window.setTimeout و window.clearTimeout لتجنب ذلك. ليست طريقة زاويّة للغاية وقد تتداخل مع الملخص ، لكن الفاصل الزمني $ وتجاهل المزامنة ليس حلاً

تواجه نفس المشكلة بالضبط ، هل سيستجيب أي شخص من فريق المنقلة لهذا؟

+1

كان هذا يقودني إلى الجنون (منقلة noob هنا) حتى وصلت إلى حل قذر على النحو التالي:

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

يعمل بشكل جيد ولا يكون بطيئًا جدًا على متصفح مقطوعة الرأس.

+1

تواجه أيضًا مشكلة هنا. كانت اختباراتي تسير بسلاسة حتى زيارة صفحة تقدم بعض طلبات API وتفتح بعض WebSockets. عند هذه النقطة ، تنتهي مهلة المنقلة في كل مرة. لم أتوصل إلى حل جيد.

أشعر بالفضول تجاهfloribon حول طرق المساعدة المقترحة إذا قمت بإيقاف browser.ignoreSynchronization = true; عالميًا أستخدم حاليًا كائنات الصفحة ، والتي تميل إلى الشكل:

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 مساعدي يبدون

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();

مع عودة wait.forElement على سبيل المثال

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');

الفكرة هي محاكاة سلوك المستخدم الفعلي: أنقر على عنصر ، وأنتظر حتى يظهر عنصر آخر ، ثم أنقر عليه ، وما إلى ذلك. وبهذه الطريقة لا داعي لانتظار مهلة $ ، إنها أسرع وأكثر أمانًا.

المفتاح هنا هو تجاهل الأخطاء من الوعد الداخلي وإعطائه بضع محاولات أخرى حتى يتم الوصول إلى المهلة.

ملاحظة: يمكنك أيضًا استخدام ExpectedConditions لذلك ولكن كان لدي بعض المشاكل معهم عندما يعيد Angular بناء عقدة DOM (على سبيل المثال ng-if الظروف):

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

@ floribon رائع ، شكرًا!

@ juliemr ، هل يمكنك مساعدتي من فضلك [email protected]

juliemr لا يعمل استخدام خدمة الفاصل الزمني $ لاستدعاء طلبات http طويلة الأمد. المنقلة لا تزال تحصل على مهلة.
هذا هو الكود الخاص بي الزاوي
هذا الفاصل الزمني $ (() => هذا $ http.get(this.prefix (url)، config)، 0، 1)
المنقلة لا تزال تنتظر حتى تكتمل مهمة $ http.
أنا أستخدم المنقلة 5.x و angualrjs 1.6x.
هل يمكنك مساعدتي؟

+1 ، يجب إضافة شيء للتعامل مع هذا الأمر.

+1

+1

+1

+1

+1

+1

هذه المواصفات عملت معي شكرا جزيلا! وتهتف إلى

    // 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;
                })
            })
        });
    }

يا رفاق كيف يمكنني إضافة مهلة لحالة اختبار معينة
"
("1-يجب تسجيل الدخول باستخدام رمز التسجيل المرسل إلى بريد إلكتروني" ، الوظيفة (تم) {

// 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();
                });


    });`
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات