with(JSSpec2) { story("Fullstack DSL for BDD") as_a("spec writer") i_want("to write specs in fullstack DSL") so_that("the specs can be read and understood as easily as possible") scenario("High level APIs should be defined") given("JSSpec2 instance", {v: JSSpec2}) when("loaded", function() {}) then("BDD vocabulary should be defined as functions", function() { value_of(this.v.story).should_be_function() value_of(this.v.as_a).should_be_function() value_of(this.v.i_want).should_be_function() value_of(this.v.so_that).should_be_function() value_of(this.v.scenario).should_be_function() value_of(this.v.given).should_be_function() value_of(this.v.when).should_be_function() value_of(this.v.then).should_be_function() value_of(this.v.and).should_be_function() }) scenario("executing STEP") given("defined 'given' has two arguments - number1 and number2", function() { this.context = {} this.given = new JSSpec2.Step( "two numbers are {number1} and {number2}", {number1: "12", number2: "34"}, this.context, function(args) {this.args = args;} ) }) when("'given' runs", function() { this.given.run(); }) then("the arguments should be bound", function() { value_of(this.context.args.number1).should_be("12"); value_of(this.context.args.number2).should_be("34"); }) story("Expectation APIs") scenario("Boolean expectation") given("boolean expectations are in test mode", function() { this.true_1 = new JSSpec2.Expectation(true); this.true_1.set_mode("test") this.true_2 = new JSSpec2.Expectation(true); this.true_2.set_mode("test") this.false_1 = new JSSpec2.Expectation(false); this.false_1.set_mode("test") this.false_2 = new JSSpec2.Expectation(false); this.false_2.set_mode("test") }) when("runner performs various tests", function() { this.true_1.should_be(true) this.true_2.should_be_true() this.false_1.should_be(false) this.false_2.should_be_false() }) then("the tests should be performed correctly", function() { value_of(this.true_1.is_passed()).should_be_true() value_of(this.true_2.is_passed()).should_be_true() value_of(this.false_1.is_passed()).should_be_true() value_of(this.false_2.is_passed()).should_be_true() }) scenario("Type expectation") given("type expectations are in test mode", function() { this.function_type = new JSSpec2.Expectation(function() {}); this.function_type.set_mode("test") this.string_type = new JSSpec2.Expectation("Hello"); this.string_type.set_mode("test") this.boolean_type = new JSSpec2.Expectation(true); this.boolean_type.set_mode("test") this.number_type = new JSSpec2.Expectation(1); this.number_type.set_mode("test") this.array_type = new JSSpec2.Expectation([1,2,3]); this.array_type.set_mode("test") this.date_type = new JSSpec2.Expectation(new Date()); this.date_type.set_mode("test") this.regex_type = new JSSpec2.Expectation(/Hello/); this.regex_type.set_mode("test") this.object_type = new JSSpec2.Expectation({a:1}); this.object_type.set_mode("test") }) when("runner performs various tests", function() { this.function_type.should_be_function() this.string_type.should_be_string() this.boolean_type.should_be_boolean() this.number_type.should_be_number() this.array_type.should_be_array() this.date_type.should_be_date() this.regex_type.should_be_regexp() this.object_type.should_be_object() }) then("the tests should be performed correctly", function() { value_of(this.function_type.is_passed()).should_be_true() value_of(this.string_type.is_passed()).should_be_true() value_of(this.boolean_type.is_passed()).should_be_true() value_of(this.number_type.is_passed()).should_be_true() value_of(this.array_type.is_passed()).should_be_true() value_of(this.date_type.is_passed()).should_be_true() value_of(this.regex_type.is_passed()).should_be_true() value_of(this.object_type.is_passed()).should_be_true() }) scenario("") // ----------------------------------------------------------------------- story("Temporary specs for bootstrap") scenario("plain text loader") given("plain text loader", {loader: new JSSpec2.PlainTextLoader()}) when("loader interpretes story title", function() { this.loader.interprete( "Story: transfer to cash account\n" + " As a savings account holder\n" + " I want to transfer money from my savings account\n" + " So that I can get cash easily from an ATM\n" + " \n" + " Scenario: savings account is in credit\n" + " Given my savings account balance is 100\n" /* + " And my cash account balance is 10\n" + " When I transfer 20\n" + " Then my savings account balance should be 80\n" + " And my cash account balance should be 30\n" + " \n" + " Scenario: savings account is overdrawn\n" + " Given my savings account balance is -20\n" + " And my cash account balance is 10\n" + " When I transfer 20\n" + " Then my savings account balance should be -20\n" + " And my cash account balance should be 10\n"/**/ ); this.story = this.loader.get_story(); }) then("story instance should be created", function() { var story = this.story; value_of(story.get_title()).should_be("transfer to cash account"); value_of(story.get_role()).should_be("savings account holder"); value_of(story.get_feature()).should_be("to transfer money from my savings account"); value_of(story.get_benefit()).should_be("I can get cash easily from an ATM"); value_of(story.get_scenarios().length).should_be(1); var scenario = story.get_scenarios()[0]; }) scenario("polymorphic 'Scenario.add_given' - object") given("empty scenario", {scenario: new JSSpec2.Scenario("scenario 1")}) when("'addGiven' is called with an object", function() { this.scenario.add_given("two numbers", {a:1, b:2}) this.scenario.run() }) then("contents of the object should be copied into context", function() { value_of(this.scenario.context.a).should_be(1) value_of(this.scenario.context.b).should_be(2) }) scenario("polymorphic 'Scenario.add_given' - function") given("empty scenario", {scenario: new JSSpec2.Scenario("scenario 1")}) when("'addGiven' is called with an object", function() { this.scenario.add_given("two numbers", function() { this.a = 1 this.b = 2 }) this.scenario.run() }) then("contents of the object should be copied into context", function() { value_of(this.scenario.context.a).should_be(1) value_of(this.scenario.context.b).should_be(2) }) scenario("scenario.add_event") given("empty scenario", {scenario: new JSSpec2.Scenario("scenario 1")}) when("'addEvent' is called with a event function", function() { this.scenario.add_event("event 1", function() { this.a = 1 }) this.scenario.run() }) then("the function should be executed", function() { value_of(this.scenario.context.a).should_be(1) }) scenario("polymorphic 'Scenario.add_outcome' - object") given("empty scenario", {scenario: new JSSpec2.Scenario("scenario 1")}) when("'addOutcome' is called with an object", function() { this.scenario.add_given("given 1", {a:1}) this.scenario.add_outcome("outcome 1", {a:1}) this.scenario.run() }) then("object matching should be performed", function() { value_of(this.scenario.is_passed()).should_be_true() }) scenario("polymorphic 'Scenario.add_outcome' - function") given("empty scenario", {scenario: new JSSpec2.Scenario("scenario 1")}) when("'addOutcome' is called with a function", function() { this.scenario.add_outcome("outcome 1", function() { this.a = 1 }) this.scenario.run() }) then("the function should be executed", function() { value_of(this.scenario.context.a).should_be(1) }) scenario("scenario execution") given("plain scenario", function() { this.scenario = new JSSpec2.Scenario("scenario 1") this.scenario.add_given( "given 1", function() { this.log = [] this.log.push("given") this.a = 1 }, function() { this.log.push("cleanup") this.d = 4 } ) this.scenario.add_event("when 1", function() { this.log.push("when") this.b = 2 }) this.scenario.add_outcome("then 1", function() { this.log.push("then") this.c = 3 }) }) when("the scenario runned", function() { this.scenario.run() }) then("'given', 'when' and 'then' should be executed in exact order", function() { value_of(this.scenario.context.log.join(",")).should_be("given,when,then,cleanup") }) and("context should be preserved", function() { value_of(this.scenario.context.a).should_be(1) value_of(this.scenario.context.b).should_be(2) value_of(this.scenario.context.c).should_be(3) value_of(this.scenario.context.d).should_be(4) }) and("the scenario should be passed", function() { value_of(this.scenario.is_passed()).should_be_true() }) } runner.run()