guinness 0.0.1
guinness: ^0.0.1 copied to clipboard
A port of the Jasmine testing framework.
Guinness #
This is a port of the Jasmine library to Dart. It is inspired by the AngularDart implementation of Jasmine.
Example #
The library can be used as follows:
import 'package:guinness/guinness.dart';
main(){
describe("guinness", (){
it("has various built-in matchers", (){
expect(2).toEqual(2);
expect([1,2]).toContain(2);
expect(2).toBe(2);
expect(()=> throw "BOOM").toThrow();
expect(()=> throw "BOOM").toThrow("BOOM");
expect(false).toBeFalsy();
expect(null).toBeFalsy();
expect(true).toBeTruthy();
expect("any object").toBeTruthy();
expect("any object").toBeDefined();
expect(null).toBeNull();
expect("not null").toBeNotNull();
expect(2).not.toEqual(1);
expect([1,2]).not.toContain(3);
expect([1,2]).not.toBe([1,2]);
expect((){}).not.toThrow();
expect(null).not.toBeDefined();
expect(new DocumentFragment.html("<div>some html</div>"))
.toHaveHtml("<div>some html</div>");
expect(new DocumentFragment.html("<div>some text</div>"))
.toHaveText("some text");
expect(new DivElement()..classes.add('abc'))
.toHaveClass("abc");
expect(new DivElement()..attributes['attr'] = 'value')
.toHaveAttribute("attr");
expect(new DocumentFragment.html("<div>some html</div>"))
.not.toHaveHtml("<div>some other html</div>");
expect(new DocumentFragment.html("<div>some text</div>"))
.not.toHaveText("some other text");
expect(new DivElement()..classes.add('abc'))
.not.toHaveClass("def");
expect(new DivElement()..attributes['attr'] = 'value')
.not.toHaveAttribute("other-attr");
});
describe("spy", (){
it("supports spy functions", (){
final s = guinness.createSpy("my spy");
expect(s).not.toHaveBeenCalled();
s(1);
expect(s).toHaveBeenCalled();
expect(s).toHaveBeenCalledOnce();
expect(s).toHaveBeenCalledWith(1);
expect(s).toHaveBeenCalledOnceWith(1);
expect(s).not.toHaveBeenCalledWith(2);
s(2);
expect((){
expect(s).toHaveBeenCalledOnce();
}).toThrow();
expect((){
expect(s).toHaveBeenCalledOnceWith(1);
}).toThrow();
});
});
describe("beforeEach", (){
var res = [];
beforeEach((){ res.add("outer"); });
describe("nested describe", (){
beforeEach((){ res.add("inner"); });
it("run callbacks in order", (){
expect(res).toEqual(["outer", "inner"]);
});
});
});
describe("afterEach", (){
var res = [];
afterEach((){ res.add("outer"); });
describe("nested describe", (){
afterEach((){ res.add("inner"); });
it("will run afterEach after this test", (){});
it("runs callbacks in reverse order", (){
expect(res).toEqual(["inner", "outer"]);
});
});
});
xdescribe("won't run", (){
it("won't run", (){
throw "Won't Run!";
});
});
xit("won't run", (){
throw "Won't Run!";
});
//also supports ddescribe, and iit
});
}
Status #
There are a few things that are still not supported (e.g., handling named parameters in expectations).
Implementation Details #
Key Ideas #
The main idea is to treat the Jasmine syntax as a domain specific language. Therefore, the implementation clearly separates such things as: syntax, semantic model, and execution model. Let's quickly look at the benefits this approach provices:
The semantic model is separate from the syntax.
The semantic model consists of It, Describe, Suite, BeforeEach, and AfterEach objects. You can create and analyse them without using the context-dependent nested Jasmine syntax.
The parsing of specs is separate from the execution of specs.
The library builds a tree of the It, Describe, Suite, BeforeEach, and AfterEach objects first. And after that, as a separate step, executes them. It enables all sorts of preprocessing (e.g., filtering, reordering).
Pluggable backends.
Since the library is a DSL, there can be multiple backend libraries actually executing the specs. By default, the library comes with the unittest backend.