library testing.matchers; import 'dart:async'; import 'package:guinness2/guinness2.dart' as gns; import 'package:angular2/src/platform/dom/dom_adapter.dart' show DOM; import 'package:angular2/src/facade/lang.dart' show isString; Expect expect(actual, [matcher]) { final expect = new Expect(actual); if (matcher != null) expect.to(matcher); return expect; } const _u = const Object(); bool elementContainsStyle(element, styles) { var allPassed = true; if (isString(styles)) { allPassed = getDOM().hasStyle(element, styles); } else { styles.forEach((prop, style) { allPassed = allPassed && getDOM().hasStyle(element, prop, style); }); } return allPassed; } expectErrorMessage(actual, expectedMessage) { expect(actual.toString()).toContain(expectedMessage); } expectException(Function actual, expectedMessage) { try { actual(); } catch (e, s) { expectErrorMessage(e, expectedMessage); } } class Expect extends gns.Expect { Expect(actual) : super(actual); NotExpect get not => new NotExpect(actual); void toEqual(expected) => toHaveSameProps(expected); void toContainError(message) => expectErrorMessage(this.actual, message); void toThrowError([message = ""]) => toThrowWith(message: message); void toThrowErrorWith(message) => expectException(this.actual, message); void toBePromise() => gns.guinness.matchers.toBeTrue(actual is Future); void toHaveCssClass(className) => gns.guinness.matchers.toBeTrue(getDOM().hasClass(actual, className)); void toHaveCssStyle(styles) { gns.guinness.matchers.toBeTrue(elementContainsStyle(actual, styles)); } void toMatchPattern(pattern) => gns.guinness.matchers.toBeTrue(pattern.hasMatch(actual)); void toImplement(expected) => toBeA(expected); void toBeNaN() => gns.guinness.matchers.toBeTrue(double.NAN.compareTo(actual) == 0); void toHaveText(expected) => _expect(elementText(actual), expected); void toHaveBeenCalledWith([a = _u, b = _u, c = _u, d = _u, e = _u, f = _u]) => _expect(_argsMatch(actual, a, b, c, d, e, f), true, reason: 'method invoked with correct arguments'); Function get _expect => gns.guinness.matchers.expect; // TODO(tbosch): move this hack into Guinness _argsMatch(spyFn, [a0 = _u, a1 = _u, a2 = _u, a3 = _u, a4 = _u, a5 = _u]) { var calls = spyFn.calls; final toMatch = _takeDefined([a0, a1, a2, a3, a4, a5]); if (calls.isEmpty) { return false; } else { gns.SamePropsMatcher matcher = new gns.SamePropsMatcher(toMatch); for (var i = 0; i < calls.length; i++) { var call = calls[i]; // TODO: create a better error message, not just 'Expected: Actual: '. // For hacking this is good: // print(call.positionalArguments); if (matcher.matches(call.positionalArguments, null)) { return true; } } return false; } } List _takeDefined(List iter) => iter.takeWhile((_) => _ != _u).toList(); } class NotExpect extends gns.NotExpect { NotExpect(actual) : super(actual); void toEqual(expected) => toHaveSameProps(expected); void toBePromise() => gns.guinness.matchers.toBeFalse(actual is Future); void toHaveCssClass(className) => gns.guinness.matchers.toBeFalse(getDOM().hasClass(actual, className)); void toHaveCssStyle(styles) { gns.guinness.matchers.toBeFalse(elementContainsStyle(actual, styles)); } void toMatchPattern(pattern) => gns.guinness.matchers.toBeFalse(pattern.hasMatch(actual)); void toBeNull() => gns.guinness.matchers.toBeFalse(actual == null); Function get _expect => gns.guinness.matchers.expect; } String elementText(n) { hasNodes(n) { var children = getDOM().childNodes(n); return children != null && children.length > 0; } if (n is Iterable) { return n.map(elementText).join(""); } if (getDOM().isCommentNode(n)) { return ''; } if (getDOM().isElementNode(n) && getDOM().tagName(n) == 'CONTENT') { return elementText(getDOM().getDistributedNodes(n)); } if (getDOM().hasShadowRoot(n)) { return elementText(getDOM().childNodesAsList(getDOM().getShadowRoot(n))); } if (hasNodes(n)) { return elementText(getDOM().childNodesAsList(n)); } return getDOM().getText(n); }