2016-06-20 21 views
17

Vấn đề:Một trong những chuỗi trong mảng để phù hợp với một biểu

tôi có một loạt các lời hứa đó đã được giải quyết để một mảng các chuỗi. Bây giờ bài kiểm tra nên vượt qua nếu ít nhất một trong các chuỗi khớp với cụm từ thông dụng.

Hiện nay, tôi giải quyết nó bằng chuỗi nối đơn giản:

protractor.promise.all([text1, text2, text3]).then(function (values) { 
    expect(values[0] + values[1] + values[2]).toMatch(/expression/); 
}); 

Rõ ràng, này không quy mô cũng và không phải là đặc biệt có thể đọc được.

Các Câu hỏi:

là có thể giải quyết nó bằng cách sử dụng hoa nhài khớp tùy chỉnh, hoặc jasmine.any() hoặc custom asymmetric equality tester?

+0

Tại sao bạn sẽ không chỉ cần sử dụng một biến ('x = false;') và 'values.map (function (v) {x = v.match (/ expression /) || x; }); 'và sau đó chỉ có' ​​mong đợi (x) .toBe (true); '? –

+4

Có gì sai với 'mong đợi (values.some (function (i) {return /expression/.match(i);}). ToBe (true);'? – haim770

+0

Có vẻ như một matcher tùy chỉnh có thể là con đường để đi: http : //jasmine.github.io/2.0/custom_matcher.html –

Trả lời

6

Bạn chỉ có thể sử dụng map để có được một danh sách các boolean và sau đó khẳng định kết quả với toContain(true):

var all = protractor.promise.all; 
var map = protractor.promise.map; 

expect(map(all([text1, text2, text3]), RegExp.prototype.test, /expression/)).toContain(true); 

Bạn cũng có thể sử dụng một khớp tùy chỉnh:

expect(all([text1, text2, text3])).toContainPattern(/expression/); 

Và các khớp tùy chỉnh khai báo trong beforeEach:

beforeEach(function() { 
    jasmine.addMatchers({ 
    toContainPattern: function() { 
     return { 
     compare: function(actual, regex) { 
      return { 
      pass: actual.some(RegExp.prototype.test, regex), 
      message: "Expected [" + actual + "] to have one or more match with " + regex 
      }; 
     } 
     }; 
    } 
    }); 
}); 
+0

Chỉ cần ra khỏi tò mò: những gì là những lợi thế của 'all', mà nhìn tôi như nó là tương đương với' map' trên 'values.reduce()'? Tôi biết nó không thực sự quan trọng, nhưng theo trực giác, tôi muốn nói 'reduce' có nhiều khả năng hoạt động tốt hơn trên các tập dữ liệu lớn, đặc biệt nếu bạn ngừng kết hợp sau khi tìm thấy kết quả hợp lệ đầu tiên (cf câu trả lời cập nhật của tôi). Dù sao, 1 bởi vì câu trả lời của bạn phù hợp hơn với OP muốn một cách tiếp cận giống như hoa nhài hơn –

+0

@Elias Van Ootegem, 'all' không giống với' map'. 'all' giải quyết một tập hợp các lời hứa, trong khi' map' giải quyết một lời hứa duy nhất. Sử dụng 'map' trên' reduce' sẽ không có bất kỳ tác động hiệu suất nào vì tất cả các chi phí là lấy ra văn bản cho mỗi phần tử, đó là một cuộc gọi tới trình duyệt cho mỗi phần tử. Và nếu nó là của bất kỳ mối quan tâm, sau đó 'Array.some()' với '/expression/.test (item)' sẽ là thích hợp hơn và ít tốn kém hơn so với 'Array.reduce' với' item.match (/ expression /) '. –

+0

Có, nhưng '[] .reduce' (theo cách tiếp cận thứ hai trong câu trả lời của tôi) cho phép bạn bỏ qua cuộc gọi' match' khi một kết quả trùng khớp đã được tìm thấy, vì vậy sẽ có từ 1 đến n cuộc gọi khớp, trong khi 'map' và 'all' dường như xử lý tất cả các giá trị mảng, hoặc tôi thiếu một cái gì đó? –

7

Như đã nói trong các ý kiến, mặc dù tôi ban đầu sử dụng map, giảm sẽ cho phép bạn làm những gì bạn cần, và ở đẳng cấp này ít nhất có ý nghĩa hơn rất nhiều:

protractor.promise.all([text1, text2, text3]).then(function (values) { 
    expect(
     values.reduce(function(p, v) { 
      return v.match(/expression/) || p; 
     }, false) 
    ).toBe(true); 
}); 

Hoặc viết những điều tương tự , nhưng sử dụng ES6 mũi tên chức năng:

protractor.promise.all([text1, text2, text3]).then(function(values) { 
    exptect(
     values.reduce((p, v) => v.match(/expression/) || p, false) 
    ).toBe(true); 
}); 

Cả hai làm điều tương tự, các giảm callback sẽ mặc định là false, cho đến khi biểu thức v.match để đánh giá đúng.
Tôi giả định này là hiển nhiên đối với hầu hết mọi người, nhưng tôi nghĩ rằng tôi muốn cung cấp cả cú pháp và một số giải thích để tham khảo trong tương lai


Có lẽ giải pháp này có thể được tối ưu hóa hơn một chút, để ngăn chặn phù hợp mô hình một khi trận đấu đơn đã được tìm thấy:

protractor.promise.all([text1, text2, text3]).then(function (values) { 
    expect(
     values.reduce(function(p, v) { 
      return p || !!v.match(/expression/); 
     }, false) 
    ).toBe(true); 
}); 

Tất cả tôi đã làm là sử dụng giá trị giảm hiện nay như mặc định (một lần mà đã được thiết lập là true, không có điểm trong thử nghiệm bất kỳ chuỗi giá trị khác). Để đảm bảo v.match đánh giá thành boolean thay vì mảng, tôi chỉ sử dụng !!v.match(). Đó là một phần là tùy chọn mặc dù. Trong ES6, điều tương tự như thế này:

protractor.promise.all([text1, text2, text3]).then(function(values) { 
    exptect(
     values.reduce((p, v) => p || !!v.match(/expression/), false) 
    ).toBe(true); 
}); 

Điều này có thể thực hiện tốt hơn với các tập dữ liệu lớn (xem xét match cuộc gọi chấm dứt một khi trận đấu đầu tiên được tìm thấy, như trái ngược với v.match được gọi mỗi lần).

6

Nếu công trình này,

protractor.promise.all([text1, text2, text3]).then(function (values) { 
    expect(values[0] + values[1] + values[2]).toMatch(/expression/); 
}); 

Tôi nghĩ bạn có thể viết những dòng này như sau;

protractor.promise.all([text1, text2, text3]).then(function (values) { 
    expect(values.join('')).toMatch(/expression/); 
}); 

Và có thể mở rộng. :)

+0

Có thể có một số vấn đề với cách tiếp cận này. Nếu 'values' trông như thế này, ví dụ:' ['foo', 'bar', 123, 'car'] 'và biểu thức là'/foobar/', nối tất cả các giá trị vào một chuỗi lớn, kết quả chuỗi sẽ khớp/chứa '/ foobar /', nhưng không có giá trị riêng lẻ thực tế nào. Điều đó sẽ không được mong muốn IMO –

4

Nếu những [text1, text2, text3] là văn bản từ ElementFinder .getText() thì bạn cũng có thể thử với Điều kiện mong đợi (Bạn biết rằng tôi là người hâm mộ lớn của EC phải không :)).

describe('test', function() { 

    it('test', function() { 
     var EC = protractor.ExpectedConditions; 
     browser.get('http://www.protractortest.org/testapp/ng1/#/form'); 

     var textToContain = 'Check'; //Notice, that this is not 'equals', this is 'contains' 
     var elementTextToCheck1 = EC.textToBePresentInElement($('#checkboxes h4'), textToContain); // Here it will be true : Checkboxes 
     var elementTextToCheck2 = EC.textToBePresentInElement($('#animals h4'), textToContain); //false 
     var elementTextToCheck3 = EC.textToBePresentInElement($('#transformedtext h4'), textToContain); //false 

     var oneElementShouldContainText = EC.or(elementTextToCheck1, elementTextToCheck2, elementTextToCheck3); 

     expect(oneElementShouldContainText()).toBeTruthy(`At least one element should contain "${textToContain}"`); 
    }) 
}); 

Đối với các yếu tố đơn giản: http://www.protractortest.org/#/api?view=ExpectedConditions.prototype.textToBePresentInElement

Đối textArea, đầu vào: http://www.protractortest.org/#/api?view=ExpectedConditions.prototype.textToBePresentInElementValue

Thông báo, rằng unfortunatelly .textToBePresentInElement chỉ làm việc với đơn ElementFinder, ArrayElementFinder không được hỗ trợ. Nhưng trong trường hợp đó, bạn có thể tạo một cái gì đó với .filter() và khẳng định rằng danh sách trả về trống.

Các vấn đề liên quan