diff options
| author | Elliott Sprehn | 2010-10-18 14:02:18 -0700 | 
|---|---|---|
| committer | Elliott Sprehn | 2010-10-19 00:45:38 -0700 | 
| commit | e7e894a2e36e042be6d62af56b0f3126f4e4fc77 (patch) | |
| tree | 5b9c8b94bf3e3935a3acd6a3c0ecb142c82f4b17 /test | |
| parent | a1fa23397f12e0b52838530a993f14491ad50869 (diff) | |
| download | angular.js-e7e894a2e36e042be6d62af56b0f3126f4e4fc77.tar.bz2 | |
Significantly clean up the way the scenario DSL works and implement many more DSL statements.
- "this" always means the current chain scope inside a DSL
- addFutureAction callbacks now take ($window, $document, done)
- $document has a special method elements() that uses the currently selected nodes in the document as defined by using() statements.
- $document.elements() allows placeholder insertion into selectors to make them more readable.
  ex. $document.elements('input[name="$1"]', myVar) will substitute the value of myVar for $1 in the selector. Subsequent arguments are $2 and so on.
- $document.elements() results have a special method trigger(event) which should be used to events. This method implements some hacks to make sure browser UI controls update and the correct angular events fire.
- futures now allow custom formatting. By default any chain that results in a future can use toJson() or fromJson() to convert the future value to and from json. A custom parser can be provided with parsedWith(fn) where fn is a callback(value) that must return the parsed result.
Note: The entire widgets.html UI is now able to be controlled and asserted through DSL statements!!! Victory! :)
Diffstat (limited to 'test')
| -rw-r--r-- | test/scenario/ApplicationSpec.js | 13 | ||||
| -rw-r--r-- | test/scenario/FutureSpec.js | 38 | ||||
| -rw-r--r-- | test/scenario/SpecRunnerSpec.js | 17 | ||||
| -rw-r--r-- | test/scenario/dslSpec.js (renamed from test/scenario/DSLSpec.js) | 196 | 
4 files changed, 210 insertions, 54 deletions
diff --git a/test/scenario/ApplicationSpec.js b/test/scenario/ApplicationSpec.js index 706fbc36..2fb9881f 100644 --- a/test/scenario/ApplicationSpec.js +++ b/test/scenario/ApplicationSpec.js @@ -18,20 +18,21 @@ describe('angular.scenario.Application', function() {        testDocument = $document;      });      app.navigateTo('http://www.google.com/'); -    app.executeAction(function($document, $window) { +    app.executeAction(function($window, $document) {        expect($window).not.toEqual(testWindow);        expect($document).not.toEqual(testDocument);      });    }); -  it('should execute callback on $window of frame', function() { +  it('should execute callback with correct arguments', function() {      var testWindow = {document: {}};      app.getWindow = function() {         return testWindow;       }; -    app.executeAction(function($document, $window) { -      expect(this).toEqual($window); -      expect(this).toEqual(testWindow); +    app.executeAction(function($window, $document) { +      expect(this).toEqual(app); +      expect($document).toEqual(_jQuery($window.document)); +      expect($window).toEqual(testWindow);      });    }); @@ -52,7 +53,7 @@ describe('angular.scenario.Application', function() {    it('should call onload handler when frame loads', function() {      var called; -    app.getFrame = function() {  +    app.getFrame = function() {        // Mock a little jQuery        var result = {          remove: function() {  diff --git a/test/scenario/FutureSpec.js b/test/scenario/FutureSpec.js index ae475779..1e6af7a1 100644 --- a/test/scenario/FutureSpec.js +++ b/test/scenario/FutureSpec.js @@ -1,13 +1,14 @@  describe('angular.scenario.Future', function() {    var future; -  it('should set the name and behavior', function() { +  it('should set the sane defaults', function() {      var behavior = function() {};      var future = new angular.scenario.Future('test name', behavior);      expect(future.name).toEqual('test name');      expect(future.behavior).toEqual(behavior);      expect(future.value).toBeUndefined();      expect(future.fulfilled).toBeFalsy(); +    expect(future.parser).toEqual(angular.identity);    });    it('should be fulfilled after execution and done callback', function() { @@ -35,4 +36,39 @@ describe('angular.scenario.Future', function() {      future.execute(angular.noop);      expect(future.value).toEqual(10);    }); +   +  it('should parse json with fromJson', function() { +    var future = new angular.scenario.Future('test name', function(done) { +      done(null, "{test: 'foo'}"); +    }); +    future.fromJson().execute(angular.noop); +    expect(future.value).toEqual({test: 'foo'}); +  }); +   +  it('should convert to json with toJson', function() { +    var future = new angular.scenario.Future('test name', function(done) { +      done(null, {test: 'foo'}); +    }); +    future.toJson().execute(angular.noop); +    expect(future.value).toEqual('{"test":"foo"}'); +  }); +   +  it('should convert with custom parser', function() { +    var future = new angular.scenario.Future('test name', function(done) { +      done(null, 'foo'); +    }); +    future.parsedWith(function(value) { +      return value.toUpperCase(); +    }).execute(angular.noop); +    expect(future.value).toEqual('FOO'); +  }); +   +  it('should pass error if parser fails', function() { +    var future = new angular.scenario.Future('test name', function(done) { +      done(null, '{'); +    }); +    future.fromJson().execute(function(error, result) { +      expect(error).toBeDefined(); +    }); +  });    }); diff --git a/test/scenario/SpecRunnerSpec.js b/test/scenario/SpecRunnerSpec.js index 0926c3f8..e62bb392 100644 --- a/test/scenario/SpecRunnerSpec.js +++ b/test/scenario/SpecRunnerSpec.js @@ -42,7 +42,7 @@ function ApplicationMock($window) {  }  ApplicationMock.prototype = {    executeAction: function(callback) { -    callback.call(this.$window); +    callback.call(this.$window, _jQuery(this.$window.document), this.$window);    }  }; @@ -59,15 +59,15 @@ describe('angular.scenario.SpecRunner', function() {    it('should bind futures to the spec', function() {      runner.addFuture('test future', function(done) { -      this.application.value = 10; +      this.value = 10;        done();      });      runner.futures[0].execute(angular.noop); -    expect(runner.application.value).toEqual(10); +    expect(runner.value).toEqual(10);    });    it('should pass done to future action behavior', function() { -    runner.addFutureAction('test future', function(done) { +    runner.addFutureAction('test future', function($window, $document, done) {        expect(angular.isFunction(done)).toBeTruthy();        done(10, 20);      }); @@ -77,15 +77,6 @@ describe('angular.scenario.SpecRunner', function() {      });    }); -  it('should pass execute future action on the $window', function() { -    runner.addFutureAction('test future', function(done) { -      this.test = 'test value'; -      done(); -    }); -    runner.futures[0].execute(angular.noop); -    expect($window.test).toEqual('test value'); -  }); -    it('should execute spec function and notify UI', function() {      var finished = false;      var ui = new UIMock(); diff --git a/test/scenario/DSLSpec.js b/test/scenario/dslSpec.js index b144a3ce..a30fe165 100644 --- a/test/scenario/DSLSpec.js +++ b/test/scenario/dslSpec.js @@ -12,11 +12,20 @@ AngularMock.prototype.reset = function() {  AngularMock.prototype.element = function(node) {    this.log.push('element(' + node.nodeName.toLowerCase() + ')'); -  return this; -}; - -AngularMock.prototype.trigger = function(value) { -  this.log.push('element().trigger(' + value + ')'); +  var mock = this; +  return { +    selector: '', +    attr: function(name, value) { +      mock.log.push('attr(' + name + (angular.isDefined(value) ? ',' + value : '') + ')'); +      return _jQuery.fn.attr.apply(_jQuery(node), arguments);  +    }, +    trigger: function(type) { +      mock.log.push('element().trigger(' + type + ')'); +      //TODO(esprehn): See the HACK!! in the SpecRunner. This avoids +      // triggering the second part of the hack in tests +      delete this.selector; +    } +  };  };  AngularMock.prototype.$browser = function() { @@ -53,6 +62,12 @@ describe("angular.scenario.dsl", function() {          $root.futureResult = result;        });      }; +    $root.dsl = {}; +    angular.foreach(angular.scenario.dsl, function(fn, name) { +      $root.dsl[name] = function() { +        return fn.call($root).apply($root, arguments); +      }; +    });      $root.application = new angular.scenario.Application($window.document);      $root.application.getWindow = function() {        return $window; @@ -75,7 +90,7 @@ describe("angular.scenario.dsl", function() {      });      it('should pause for specified seconds', function() { -      angular.scenario.dsl.pause.call($root).call($root, 10); +      $root.dsl.pause(10);        expect($root.timerValue).toEqual(10000);        expect($root.futureResult).toEqual(10000);      }); @@ -84,11 +99,11 @@ describe("angular.scenario.dsl", function() {    describe('Expect', function() {      it('should chain and execute matcher', function() {        var future = {value: 10}; -      var result = angular.scenario.dsl.expect.call($root).call($root, future); +      var result = $root.dsl.expect(future);        result.toEqual(10);        expect($root.futureError).toBeUndefined();        expect($root.futureResult).toBeUndefined(); -      result = angular.scenario.dsl.expect.call($root).call($root, future); +      result = $root.dsl.expect(future);        result.toEqual(20);        expect($root.futureError).toBeDefined();      }); @@ -96,27 +111,27 @@ describe("angular.scenario.dsl", function() {    describe('NavigateTo', function() {      it('should allow a string url', function() { -      angular.scenario.dsl.navigateTo.call($root).call($root, 'http://myurl'); +      $root.dsl.navigateTo('http://myurl');        expect($window.location).toEqual('http://myurl');        expect($root.futureResult).toEqual('http://myurl');      });      it('should allow a future url', function() {        var future = {name: 'future name', value: 'http://myurl'}; -      angular.scenario.dsl.navigateTo.call($root).call($root, future); +      $root.dsl.navigateTo(future);        expect($window.location).toEqual('http://myurl');        expect($root.futureResult).toEqual('http://myurl');      });      it('should complete if angular is missing from app frame', function() {        delete $window.angular; -      angular.scenario.dsl.navigateTo.call($root).call($root, 'http://myurl'); +      $root.dsl.navigateTo('http://myurl');        expect($window.location).toEqual('http://myurl');        expect($root.futureResult).toEqual('http://myurl');      });      it('should wait for angular notify when no requests pending', function() { -      angular.scenario.dsl.navigateTo.call($root).call($root, 'url'); +      $root.dsl.navigateTo('url');        expect($window.angular.log).toContain('$brower.poll()');        expect($window.angular.log).          toContain('$brower.notifyWhenNoOutstandingRequests()'); @@ -143,24 +158,141 @@ describe("angular.scenario.dsl", function() {          remove();      }); +    describe('Select', function() { +      it('should select single option', function() { +        doc.append( +          '<select name="test">' + +          '  <option>A</option>' + +          '  <option selected>B</option>' + +          '</select>' +        ); +        $root.dsl.select('test').option('A'); +        expect(_jQuery('[name="test"]').val()).toEqual('A'); +      }); + +      it('should select multiple options', function() { +        doc.append( +          '<select name="test" multiple>' + +          '  <option>A</option>' + +          '  <option selected>B</option>' + +          '  <option>C</option>' + +          '</select>' +        ); +        $root.dsl.select('test').options('A', 'B'); +        expect(_jQuery('[name="test"]').val()).toEqual(['A','B']); +      }); +       +      it('should fail to select multiple options on non-multiple select', function() { +        doc.append('<select name="test"></select>'); +        $root.dsl.select('test').options('A', 'B'); +        expect($root.futureError).toMatch(/did not match/); +      }); +    }); + +    describe('Element', function() { +      it('should execute click', function() { +        var clicked; +        doc.append('<a href=""></a>'); +        doc.find('a').click(function() { +          clicked = true; +        }); +        $root.dsl.element('a').click(); +      }); +       +      it('should get attribute', function() { +        doc.append('<div id="test" class="foo"></div>'); +        $root.dsl.element('#test').attr('class'); +        expect($root.futureResult).toEqual('foo'); +      }); + +      it('should set attribute', function() { +        doc.append('<div id="test" class="foo"></div>'); +        $root.dsl.element('#test').attr('class', 'bam'); +        expect(doc.find('div').attr('class')).toEqual('bam'); +      }); +       +      it('should get val', function() { +        doc.append('<input value="bar">'); +        $root.dsl.element('input').val(); +        expect($root.futureResult).toEqual('bar'); +      }); +       +      it('should set val', function() { +        doc.append('<input value="bar">'); +        $root.dsl.element('input').val('baz'); +        expect(doc.find('input').val()).toEqual('baz'); +      }); + +    }); + +    describe('Repeater', function() { +      var chain; +      beforeEach(function() { +        doc.append( +          '<ul>' + +          '  <li ng:repeat-index="0"><span ng:bind="name">misko</span><span ng:bind="gender">male</span></li>' + +          '  <li ng:repeat-index="1"><span ng:bind="name">felisa</span><span ng:bind="gender">female</span></li>' + +          '</ul>' +        ); +        chain = $root.dsl.repeater('ul li'); +      }); + +      it('should get the row count', function() { +        chain.count(); +        expect($root.futureResult).toEqual(2); +      }); + +      it('should get a row of bindings', function() { +        chain.row(1); +        expect($root.futureResult).toEqual(['felisa', 'female']); +      }); + +      it('should get a column of bindings', function() { +        chain.column('gender'); +        expect($root.futureResult).toEqual(['male', 'female']); +      }); +    }); +      describe('Binding', function() {        it('should select binding by name', function() {          doc.append('<span ng:bind="foo.bar">some value</span>'); -        angular.scenario.dsl.binding.call($root).call($root, 'foo.bar'); +        $root.dsl.binding('foo.bar');          expect($root.futureResult).toEqual('some value');        }); +       +      it('should select binding in template by name', function() { +        doc.append('<pre ng:bind-template="foo {{bar}} baz">foo some baz</pre>'); +        $root.dsl.binding('bar'); +        expect($root.futureResult).toEqual('foo some baz'); +      });        it('should return error if no binding exists', function() { -        angular.scenario.dsl.binding.call($root).call($root, 'foo.bar'); -        expect($root.futureError).toMatch(/does not exist/); +        $root.dsl.binding('foo.bar'); +        expect($root.futureError).toMatch(/did not match/); +      }); +    }); +     +    describe('Using', function() { +      it('should prefix selector in $document.elements()', function() { +        var chain; +        doc.append( +          '<div id="test1"><input name="test.input" value="something"></div>' + +          '<div id="test2"><input name="test.input" value="something"></div>' +        ); +        chain = $root.dsl.using('div#test2'); +        chain.input('test.input').enter('foo'); +        expect($window.angular.log).toContain('element(input)'); +        expect($window.angular.log).toContain('element().trigger(change)'); +        var inputs = _jQuery('input[name="test.input"]'); +        expect(inputs.first().val()).toEqual('something'); +        expect(inputs.last().val()).toEqual('foo');        });      });      describe('Input', function() {        it('should change value in text input', function() {          doc.append('<input name="test.input" value="something">'); -        var chain = angular.scenario.dsl.input. -          call($root).call($root, 'test.input'); +        var chain = $root.dsl.input('test.input');          chain.enter('foo');          expect($window.angular.log).toContain('element(input)');          expect($window.angular.log).toContain('element().trigger(change)'); @@ -168,18 +300,16 @@ describe("angular.scenario.dsl", function() {        });        it('should return error if no input exists', function() { -        var chain = angular.scenario.dsl.input. -          call($root).call($root, 'test.input'); +        var chain = $root.dsl.input('test.input');          chain.enter('foo'); -        expect($root.futureError).toMatch(/does not exist/); +        expect($root.futureError).toMatch(/did not match/);        });        it('should toggle checkbox state', function() {          doc.append('<input type="checkbox" name="test.input" checked>');          expect(_jQuery('input[name="test.input"]').            attr('checked')).toBeTruthy(); -        var chain = angular.scenario.dsl.input. -          call($root).call($root, 'test.input'); +        var chain = $root.dsl.input('test.input');          chain.check();          expect($window.angular.log).toContain('element(input)');          expect($window.angular.log).toContain('element().trigger(click)'); @@ -193,25 +323,24 @@ describe("angular.scenario.dsl", function() {            attr('checked')).toBeTruthy();        }); -      it('should return error if checkbox does not exist', function() { -        var chain = angular.scenario.dsl.input. -          call($root).call($root, 'test.input'); +      it('should return error if checkbox did not match', function() { +        var chain = $root.dsl.input('test.input');          chain.check(); -        expect($root.futureError).toMatch(/does not exist/); +        expect($root.futureError).toMatch(/did not match/);        });        it('should select option from radio group', function() {          doc.append(            '<input type="radio" name="0@test.input" value="foo">' + -          '<input type="radio" name="0@test.input" value="bar" checked="checked">'); +          '<input type="radio" name="0@test.input" value="bar" checked="checked">' +        );          // HACK! We don't know why this is sometimes false on chrome          _jQuery('input[name="0@test.input"][value="bar"]').attr('checked', true);          expect(_jQuery('input[name="0@test.input"][value="bar"]').            attr('checked')).toBeTruthy();          expect(_jQuery('input[name="0@test.input"][value="foo"]').            attr('checked')).toBeFalsy(); -        var chain = angular.scenario.dsl.input. -          call($root).call($root, 'test.input'); +        var chain = $root.dsl.input('test.input');          chain.select('foo');          expect($window.angular.log).toContain('element(input)');          expect($window.angular.log).toContain('element().trigger(click)'); @@ -221,13 +350,12 @@ describe("angular.scenario.dsl", function() {            attr('checked')).toBeTruthy();        }); -      it('should return error if radio button does not exist', function() { -        var chain = angular.scenario.dsl.input. -          call($root).call($root, 'test.input'); +      it('should return error if radio button did not match', function() { +        var chain = $root.dsl.input('test.input');          chain.select('foo'); -        expect($root.futureError).toMatch(/does not exist/); +        expect($root.futureError).toMatch(/did not match/);        });      }); +        }); -  });  | 
