2016-06-20 29 views
17

problem:Jeden z ciągów w tablicy, aby dopasować wyrazem

Mam tablicę obietnic który rozdziela się na tablicy ciągów. Teraz test powinien przejść, jeśli przynajmniej jeden z ciągów pasuje do wyrażenia regularnego.

Obecnie mogę rozwiązać to za pomocą prostych operacji konkatenacji:

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

Oczywiście, nie skaluje się dobrze i nie jest szczególnie czytelny.

Pytanie:

Czy jest możliwe, aby rozwiązać go za pomocą niestandardowego jaśmin dopasowywania lub jasmine.any() lub custom asymmetric equality tester?

+0

Dlaczego nie wystarczy użyć zmiennej ('x = false;') i 'values.map (function (obj) {x = v.match (/ wyrażenie /) || x; }); 'a następnie po prostu mieć' expected (x) .toBe (true); '? –

+4

Co jest nie tak z 'expect (values.some (function (i) {return /expression/.match(i);)). ToBe (true);'? – haim770

+0

Wygląda na to, że niestandardowy szablon matcher może być rozwiązaniem: http : //jasmine.github.io/2.0/custom_matcher.html –

Odpowiedz

6

mógłby po prostu użyć map aby uzyskać listę boolean a następnie dochodzić wynik z toContain(true):

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

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

Można również użyć niestandardowego dopasowywania:

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

A zwyczaj dopasowujący zadeklarowane w 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

Po prostu z ciekawości: jakie są zalety "all", które wygląda na to, że jest odpowiednikiem 'map' ponad' values.reduce() '? Wiem, że to naprawdę nie ma znaczenia, ale intuicyjnie, powiedziałbym, że 'zmniejszyć' jest bardziej prawdopodobne, że będzie działało lepiej na dużych zbiorach danych, szczególnie jeśli przestaniesz dopasowywać po pierwszym prawidłowym dopasowaniu (cf moja zaktualizowana odpowiedź). W każdym razie +1, ponieważ twoja odpowiedź jest bardziej zgodna z PO, który chce bardziej jaśminowego podejścia. –

+0

@ Elias Van Ootegem, 'all' to nie to samo co' map'. 'all' rozwiązuje zbiór obietnic, podczas gdy' map' rozwiązuje pojedynczą obietnicę. Użycie 'map' zamiast' reduce' nie będzie miało żadnego wpływu na wydajność, ponieważ cały koszt polega na pobieraniu tekstu dla każdego elementu, który jest jednym wywołaniem przeglądarki dla każdego elementu. A gdyby było to niepokojące, to 'Array.some()' z '/expression/.test (item)' byłoby bardziej odpowiednie i tańsze niż 'Array.reduce' z' item.match (/ expression /) '. –

+0

Tak, ale '[] .reduce' (jak przy drugim podejściu w mojej odpowiedzi) pozwala pominąć wywołanie' match' po znalezieniu pozytywnego dopasowania, więc będzie od 1 do n połączeń, podczas gdy 'map' i "wszystko" wydaje się przetwarzać wszystkie wartości tablicowe, czy też czegoś mi brakuje? –

7

Jak powiedział w komentarzach, choć początkowo używać map, zmniejszyć pozwoli Ci zrobić to, czego potrzebujesz, w tym kasty przynajmniej sprawia dużo więcej sensu:

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

lub pisząc to samo , ale przy użyciu strzałek ES6 funkcje:

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

Oba zrobić to samo, callback zmniejszyć domyślnie false, dopóki wyrażenie v.match wartość true.
Jestem zakładając, jest to oczywiste dla większości ludzi, ale pomyślałem, że zapewniają zarówno składni i wyjaśnień na przyszłość


Może to rozwiązanie może być zoptymalizowany nieco więcej, aby zatrzymać dopasowanie wzór po jednym meczu stwierdzono:

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

Wszystko zrobiłem było użyć bieżącej wartości redukcji jako domyślne (kiedyś, że został ustawiony na true, to nie ma sensu testowania dowolny inny ciąg znaków). Aby upewnić się, że v.match jest wartością boolowską zamiast tablicą, użyłem tylko !!v.match(). Ta część jest opcjonalna. W ES6, samo wygląda następująco:

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

To może lepiej z dużymi zbiorami danych (z uwzględnieniem połączeń match zatrzymać raz pierwszy mecz został znaleziony, w przeciwieństwie do v.match miano za każdym razem).

6

Jeśli to działa,

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

myślę, że można napisać to w następujący sposób;

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

Jest skalowalny. :)

+0

Mogą wystąpić pewne problemy z tym podejściem. Jeśli "wartości" wyglądają tak, na przykład: '['foo', 'bar', 123, 'car']' a wyrażenie to '/ foobar /', łącząc wszystkie wartości w jeden duży ciąg, wynikowe Łańcuch będzie pasował/zawiera '/ foobar /', ale żadna z rzeczywistych wartości nie będzie. To byłoby niepożądane IMO –

4

Jeśli te [text1, text2, text3] są tekstami z ElementFinder .getText(), to możesz także wypróbować z Oczekiwanymi warunkami (Wiesz, że jestem wielkim fanem EC, prawda? :)).

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}"`); 
    }) 
}); 

przypadku prostych elementów: http://www.protractortest.org/#/api?view=ExpectedConditions.prototype.textToBePresentInElement

Dla textarea, wejścia: http://www.protractortest.org/#/api?view=ExpectedConditions.prototype.textToBePresentInElementValue

odnotować, że niestety .textToBePresentInElement działa tylko z pojedynczego ElementFinder, ArrayElementFinder nie jest obsługiwany. Ale w takim przypadku możesz zrobić coś z .filter() i stwierdzić, że zwrócona lista jest pusta.