test(matchers): add support for `toHaveCssStyle` matcher

This commit is contained in:
Matias Niemelä 2015-11-17 12:37:39 -08:00
parent e1d7bdcfe7
commit fad354904d
10 changed files with 94 additions and 2 deletions

View File

@ -4,6 +4,7 @@ import 'dart:html';
import 'package:angular2/platform/common_dom.dart' show setRootDomAdapter; import 'package:angular2/platform/common_dom.dart' show setRootDomAdapter;
import 'generic_browser_adapter.dart' show GenericBrowserDomAdapter; import 'generic_browser_adapter.dart' show GenericBrowserDomAdapter;
import 'package:angular2/src/facade/browser.dart'; import 'package:angular2/src/facade/browser.dart';
import 'package:angular2/src/facade/lang.dart' show isBlank, isPresent;
import 'dart:js' as js; import 'dart:js' as js;
// WARNING: Do not expose outside this class. Parsing HTML using this // WARNING: Do not expose outside this class. Parsing HTML using this
@ -335,6 +336,11 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
element.style.setProperty(stylename, stylevalue); element.style.setProperty(stylename, stylevalue);
} }
bool hasStyle(Element element, String stylename, [String stylevalue]) {
var value = this.getStyle(element, stylename);
return isPresent(stylevalue) ? value == stylevalue : value.length > 0;
}
void removeStyle(Element element, String stylename) { void removeStyle(Element element, String stylename) {
element.style.removeProperty(stylename); element.style.removeProperty(stylename);
} }

View File

@ -207,6 +207,10 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
} }
removeStyle(element, stylename: string) { element.style[stylename] = null; } removeStyle(element, stylename: string) { element.style[stylename] = null; }
getStyle(element, stylename: string): string { return element.style[stylename]; } getStyle(element, stylename: string): string { return element.style[stylename]; }
hasStyle(element, stylename: string, stylevalue: string = null): boolean {
var value = this.getStyle(element, stylename) || '';
return stylevalue ? value == stylevalue : value.length > 0;
}
tagName(element): string { return element.tagName; } tagName(element): string { return element.tagName; }
attributeMap(element): Map<string, string> { attributeMap(element): Map<string, string> {
var res = new Map<string, string>(); var res = new Map<string, string>();

View File

@ -89,6 +89,7 @@ export abstract class DomAdapter {
abstract setStyle(element, stylename: string, stylevalue: string); abstract setStyle(element, stylename: string, stylevalue: string);
abstract removeStyle(element, stylename: string); abstract removeStyle(element, stylename: string);
abstract getStyle(element, stylename: string): string; abstract getStyle(element, stylename: string): string;
abstract hasStyle(element, stylename: string, stylevalue?: string): boolean;
abstract tagName(element): string; abstract tagName(element): string;
abstract attributeMap(element): Map<string, string>; abstract attributeMap(element): Map<string, string>;
abstract hasAttribute(element, attribute: string): boolean; abstract hasAttribute(element, attribute: string): boolean;

View File

@ -6,6 +6,8 @@ import 'package:html/dom.dart';
import 'package:angular2/platform/common_dom.dart'; import 'package:angular2/platform/common_dom.dart';
import 'package:angular2/src/compiler/xhr.dart'; import 'package:angular2/src/compiler/xhr.dart';
import 'package:angular2/src/facade/lang.dart' show isBlank, isPresent;
const _attrToPropMap = const { const _attrToPropMap = const {
'innerHtml': 'innerHTML', 'innerHtml': 'innerHTML',
'readonly': 'readOnly', 'readonly': 'readOnly',
@ -265,6 +267,10 @@ abstract class AbstractHtml5LibAdapter implements DomAdapter {
throw 'not implemented'; throw 'not implemented';
} }
bool hasStyle(Element element, String styleName, [String styleValue]) {
throw 'not implemented';
}
removeStyle(element, String stylename) { removeStyle(element, String stylename) {
throw 'not implemented'; throw 'not implemented';
} }

View File

@ -371,6 +371,10 @@ export class Parse5DomAdapter extends DomAdapter {
hasClass(element, classname: string): boolean { hasClass(element, classname: string): boolean {
return ListWrapper.contains(this.classList(element), classname); return ListWrapper.contains(this.classList(element), classname);
} }
hasStyle(element, stylename: string, stylevalue: string = null): boolean {
var value = this.getStyle(element, stylename) || '';
return stylevalue ? value == stylevalue : value.length > 0;
}
/** @internal */ /** @internal */
_readStyleAttribute(element) { _readStyleAttribute(element) {
var styleMap = {}; var styleMap = {};

View File

@ -6,6 +6,8 @@ import 'package:guinness/guinness.dart' as gns;
import 'package:angular2/src/platform/dom/dom_adapter.dart' show DOM; import 'package:angular2/src/platform/dom/dom_adapter.dart' show DOM;
import 'package:angular2/src/facade/lang.dart' show isString;
Expect expect(actual, [matcher]) { Expect expect(actual, [matcher]) {
final expect = new Expect(actual); final expect = new Expect(actual);
if (matcher != null) expect.to(matcher); if (matcher != null) expect.to(matcher);
@ -14,6 +16,18 @@ Expect expect(actual, [matcher]) {
const _u = const Object(); const _u = const Object();
bool elementContainsStyle(element, styles) {
var allPassed = true;
if (isString(styles)) {
allPassed = DOM.hasStyle(element, styles);
} else {
styles.forEach((prop, style) {
allPassed = allPassed && DOM.hasStyle(element, prop, style);
});
}
return allPassed;
}
expectErrorMessage(actual, expectedMessage) { expectErrorMessage(actual, expectedMessage) {
expect(actual.toString()).toContain(expectedMessage); expect(actual.toString()).toContain(expectedMessage);
} }
@ -38,6 +52,9 @@ class Expect extends gns.Expect {
void toBePromise() => gns.guinness.matchers.toBeTrue(actual is Future); void toBePromise() => gns.guinness.matchers.toBeTrue(actual is Future);
void toHaveCssClass(className) => void toHaveCssClass(className) =>
gns.guinness.matchers.toBeTrue(DOM.hasClass(actual, className)); gns.guinness.matchers.toBeTrue(DOM.hasClass(actual, className));
void toHaveCssStyle(styles) {
gns.guinness.matchers.toBeTrue(elementContainsStyle(actual, styles));
}
void toImplement(expected) => toBeA(expected); void toImplement(expected) => toBeA(expected);
void toBeNaN() => void toBeNaN() =>
gns.guinness.matchers.toBeTrue(double.NAN.compareTo(actual) == 0); gns.guinness.matchers.toBeTrue(double.NAN.compareTo(actual) == 0);
@ -78,6 +95,9 @@ class NotExpect extends gns.NotExpect {
void toBePromise() => gns.guinness.matchers.toBeFalse(actual is Future); void toBePromise() => gns.guinness.matchers.toBeFalse(actual is Future);
void toHaveCssClass(className) => void toHaveCssClass(className) =>
gns.guinness.matchers.toBeFalse(DOM.hasClass(actual, className)); gns.guinness.matchers.toBeFalse(DOM.hasClass(actual, className));
void toHaveCssStyle(styles) {
gns.guinness.matchers.toBeFalse(elementContainsStyle(actual, styles));
}
void toBeNull() => gns.guinness.matchers.toBeFalse(actual == null); void toBeNull() => gns.guinness.matchers.toBeFalse(actual == null);
Function get _expect => gns.guinness.matchers.expect; Function get _expect => gns.guinness.matchers.expect;
} }

View File

@ -1,5 +1,6 @@
import {DOM} from 'angular2/src/platform/dom/dom_adapter'; import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {global} from 'angular2/src/facade/lang'; import {global, isString} from 'angular2/src/facade/lang';
import {StringMapWrapper} from 'angular2/src/facade/collection';
export interface NgMatchers extends jasmine.Matchers { export interface NgMatchers extends jasmine.Matchers {
@ -7,6 +8,7 @@ export interface NgMatchers extends jasmine.Matchers {
toBeAnInstanceOf(expected: any): boolean; toBeAnInstanceOf(expected: any): boolean;
toHaveText(expected: any): boolean; toHaveText(expected: any): boolean;
toHaveCssClass(expected: any): boolean; toHaveCssClass(expected: any): boolean;
toHaveCssStyle(expected: any): boolean;
toImplement(expected: any): boolean; toImplement(expected: any): boolean;
toContainError(expected: any): boolean; toContainError(expected: any): boolean;
toThrowErrorWith(expectedMessage: any): boolean; toThrowErrorWith(expectedMessage: any): boolean;
@ -105,6 +107,31 @@ _global.beforeEach(function() {
} }
}, },
toHaveCssStyle: function() {
return {
compare: function(actual, styles) {
var allPassed;
if (isString(styles)) {
allPassed = DOM.hasStyle(actual, styles);
} else {
allPassed = !StringMapWrapper.isEmpty(styles);
StringMapWrapper.forEach(styles, (style, prop) => {
allPassed = allPassed && DOM.hasStyle(actual, prop, style);
});
}
return {
pass: allPassed,
get message() {
var expectedValueStr = isString(styles) ? styles : JSON.stringify(styles);
return `Expected ${actual.outerHTML} ${!allPassed ? ' ' : 'not '}to contain the
CSS ${isString(styles) ? 'property' : 'styles'} "${expectedValueStr}"`;
}
};
}
};
},
toContainError: function() { toContainError: function() {
return { return {
compare: function(actual, expectedText) { compare: function(actual, expectedText) {

View File

@ -234,6 +234,7 @@ var NG_ALL = [
'BrowserDomAdapter.setGlobalVar():js', 'BrowserDomAdapter.setGlobalVar():js',
'BrowserDomAdapter.setInnerHTML():js', 'BrowserDomAdapter.setInnerHTML():js',
'BrowserDomAdapter.setProperty():js', 'BrowserDomAdapter.setProperty():js',
'BrowserDomAdapter.hasStyle():js',
'BrowserDomAdapter.setStyle():js', 'BrowserDomAdapter.setStyle():js',
'BrowserDomAdapter.setText():js', 'BrowserDomAdapter.setText():js',
'BrowserDomAdapter.setTitle():js', 'BrowserDomAdapter.setTitle():js',

View File

@ -109,6 +109,29 @@ export function main() {
expect(el).not.toHaveCssClass('fatias'); expect(el).not.toHaveCssClass('fatias');
}); });
}); });
describe('toHaveCssStyle', () => {
it('should assert that the CSS style is present', () => {
var el = document.createElement('div');
expect(el).not.toHaveCssStyle('width');
el.style.setProperty('width', '100px');
expect(el).toHaveCssStyle('width');
});
it('should assert that the styles are matched against the element', () => {
var el = document.createElement('div');
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
el.style.setProperty('width', '100px');
expect(el).toHaveCssStyle({width: '100px'});
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
el.style.setProperty('height', '555px');
expect(el).toHaveCssStyle({height: '555px'});
expect(el).toHaveCssStyle({width: '100px', height: '555px'});
});
});
}); });
describe('using the test injector with the inject helper', () => { describe('using the test injector with the inject helper', () => {