describe("Locals", () => {
            it('should read a value from locals', () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));

              expect(executeWatch('key', 'key', null, locals))
                .toEqual(['key=value']);
            });

            it('should invoke a function from local', () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", () => "value"]]));

              expect(executeWatch('key', 'key()', null, locals))
                .toEqual(['key=value']);
            });

            it('should handle nested locals', () => {
              var nested = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));
              var locals = new Locals(nested, MapWrapper.create());

              expect(executeWatch('key', 'key', null, locals))
                .toEqual(['key=value']);
            });

            it("should fall back to a regular field read when the locals map" +
              "does not have the requested field", () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));

              expect(executeWatch('name', 'name', new Person("Jim"), locals))
                .toEqual(['name=Jim']);
            });
          });
        describe("hydration", () => {
          it("should be able to rehydrate a change detector", () => {
            var c  = createChangeDetector("memo", "name");
            var cd = c["changeDetector"];

            cd.hydrate("some context", null);
            expect(cd.hydrated()).toBe(true);

            cd.dehydrate();
            expect(cd.hydrated()).toBe(false);

            cd.hydrate("other context", null);
            expect(cd.hydrated()).toBe(true);
          });

          it("should destroy all active pipes during dehyration", () => {
            var pipe = new OncePipe();
            var registry = new FakePipeRegistry('pipe', () => pipe);
            var c  = createChangeDetector("memo", "name | pipe", new Person('bob'), null, registry);
            var cd = c["changeDetector"];

            cd.detectChanges();

            cd.dehydrate();

            expect(pipe.destroyCalled).toBe(true);
          });
        });
          describe("handle children", () => {
            var parent, child;

            beforeEach(() => {
              var protoParent = createProtoChangeDetector();
              parent = protoParent.instantiate(null, [], null);

              var protoChild = createProtoChangeDetector();
              child = protoChild.instantiate(null, [], null);
            });

            it("should add children", () => {
              parent.addChild(child);

              expect(parent.children.length).toEqual(1);
              expect(parent.children[0]).toBe(child);
            });

            it("should remove children", () => {
              parent.addChild(child);
              parent.removeChild(child);

              expect(parent.children).toEqual([]);
            });
          });
          describe("keyed access", () => {
            it("should support accessing a list item", () => {
              expect(executeWatch('array[0]', '["foo", "bar"][0]')).toEqual(['array[0]=foo']);
            });

            it("should support accessing a map item", () => {
              expect(executeWatch('map[foo]', '{"foo": "bar"}["foo"]')).toEqual(['map[foo]=bar']);
            });
          });
        describe("pipes", () => {
          it("should support pipes", () => {
            var registry = new FakePipeRegistry('pipe', () => new CountingPipe());
            var ctx = new Person("Megatron");

            var c  = createChangeDetector("memo", "name | pipe", ctx, null, registry);
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.detectChanges();

            expect(dispatcher.log).toEqual(['memo=Megatron state:0']);

            dispatcher.clear();
            cd.detectChanges();

            expect(dispatcher.log).toEqual(['memo=Megatron state:1']);
          });

          it("should lookup pipes in the registry when the context is not supported", () => {
            var registry = new FakePipeRegistry('pipe', () => new OncePipe());
            var ctx = new Person("Megatron");

            var c  = createChangeDetector("memo", "name | pipe", ctx, null, registry);
            var cd = c["changeDetector"];

            cd.detectChanges();

            expect(registry.numberOfLookups).toEqual(1);

            ctx.name = "Optimus Prime";
            cd.detectChanges();

            expect(registry.numberOfLookups).toEqual(2);
          });

          it("should invoke onDestroy on a pipe before switching to another one", () => {
            var pipe = new OncePipe();
            var registry = new FakePipeRegistry('pipe', () => pipe);
            var ctx = new Person("Megatron");

            var c  = createChangeDetector("memo", "name | pipe", ctx, null, registry);
            var cd = c["changeDetector"];

            cd.detectChanges();
            ctx.name = "Optimus Prime";
            cd.detectChanges();

            expect(pipe.destroyCalled).toEqual(true);
          });
        });
  describe('RuntimeComponentUrlMapper', () => {
    it('should return the registered URL', () => {
      var url = 'http://path/to/component';
      var mapper = new RuntimeComponentUrlMapper();
      mapper.setComponentUrl(SomeComponent, url);
      expect(mapper.getUrl(SomeComponent)).toEqual(url);
    });

    it('should fallback to ComponentUrlMapper', () => {
      var mapper = new ComponentUrlMapper();
      var runtimeMapper = new RuntimeComponentUrlMapper();
      expect(runtimeMapper.getUrl(SomeComponent)).toEqual(mapper.getUrl(SomeComponent));
    });
  });
        describe("markPathToRootAsCheckOnce", () => {
          function changeDetector(mode, parent) {
            var cd = createProtoChangeDetector().instantiate(null, [], null);
            cd.mode = mode;
            if (isPresent(parent)) parent.addChild(cd);
            return cd;
          }

          it("should mark all checked detectors as CHECK_ONCE " +
            "until reaching a detached one", () => {

            var root = changeDetector(CHECK_ALWAYS, null);
            var disabled = changeDetector(DETACHED, root);
            var parent = changeDetector(CHECKED, disabled);
            var checkAlwaysChild = changeDetector(CHECK_ALWAYS, parent);
            var checkOnceChild = changeDetector(CHECK_ONCE, checkAlwaysChild);
            var checkedChild = changeDetector(CHECKED, checkOnceChild);

            checkedChild.markPathToRootAsCheckOnce();

            expect(root.mode).toEqual(CHECK_ALWAYS);
            expect(disabled.mode).toEqual(DETACHED);
            expect(parent.mode).toEqual(CHECK_ONCE);
            expect(checkAlwaysChild.mode).toEqual(CHECK_ALWAYS);
            expect(checkOnceChild.mode).toEqual(CHECK_ONCE);
            expect(checkedChild.mode).toEqual(CHECK_ONCE);
          });
        });
            describe("group changes", () => {
              it("should notify the dispatcher when a group of records changes", () => {
                var pcd = createProtoChangeDetector();

                var dispatcher = new TestDispatcher();
                var cd = pcd.instantiate(dispatcher, [
                  new BindingRecord(ast("1 + 2"), "memo", "1"),
                  new BindingRecord(ast("10 + 20"), "memo", "1"),
                  new BindingRecord(ast("100 + 200"), "memo", "2")
                ], null);

                cd.detectChanges();

                expect(dispatcher.loggedValues).toEqual([[3, 30], [300]]);
              });

              it("should notify the dispatcher before switching to the next group", () => {
                var pcd = createProtoChangeDetector();
                var dispatcher = new TestDispatcher();
                var cd = pcd.instantiate(dispatcher, [
                  new BindingRecord(ast("a()"), "a", "1"),
                  new BindingRecord(ast("b()"), "b", "2"),
                  new BindingRecord(ast("c()"), "c", "2")
                ], null);

                var tr = new TestRecord();
                tr.a = () => {
                  dispatcher.logValue('InvokeA');
                  return 'a'
                };
                tr.b = () => {
                  dispatcher.logValue('InvokeB');
                  return 'b'
                };
                tr.c = () => {
                  dispatcher.logValue('InvokeC');
                  return 'c'
                };
                cd.hydrate(tr, null);

                cd.detectChanges();

                expect(dispatcher.loggedValues).toEqual(['InvokeA', ['a'], 'InvokeB', 'InvokeC', ['b', 'c']]);
              });
            });
  describe('regression slope validator', () => {
    var validator;

    function createValidator({size, metric}) {
      validator = new Injector([
        RegressionSlopeValidator.BINDINGS,
        bind(RegressionSlopeValidator.METRIC).toValue(metric),
        bind(RegressionSlopeValidator.SAMPLE_SIZE).toValue(size)
      ]).get(RegressionSlopeValidator);
    }

    it('should return sampleSize and metric as description', () => {
      createValidator({size: 2, metric: 'script'});
      expect(validator.describe()).toEqual({
        'sampleSize': 2,
        'regressionSlopeMetric': 'script'
      });
    });

    it('should return null while the completeSample is smaller than the given size', () => {
      createValidator({size: 2, metric: 'script'});
      expect(validator.validate([])).toBe(null);
      expect(validator.validate([mv(0,0,{})])).toBe(null);
    });

    it('should return null while the regression slope is < 0', () => {
      createValidator({size: 2, metric: 'script'});
      expect(validator.validate([mv(0,0,{'script':2}), mv(1,1,{'script':1})])).toBe(null);
    });

    it('should return the last sampleSize runs when the regression slope is ==0', () => {
      createValidator({size: 2, metric: 'script'});
      var sample = [mv(0,0,{'script':1}), mv(1,1,{'script':1}), mv(2,2,{'script':1})];
      expect(validator.validate(ListWrapper.slice(sample,0,2))).toEqual(ListWrapper.slice(sample,0,2));
      expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample,1,3));
    });

    it('should return the last sampleSize runs when the regression slope is >0', () => {
      createValidator({size: 2, metric: 'script'});
      var sample = [mv(0,0,{'script':1}), mv(1,1,{'script':2}), mv(2,2,{'script':3})];
      expect(validator.validate(ListWrapper.slice(sample,0,2))).toEqual(ListWrapper.slice(sample,0,2));
      expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample,1,3));
    });

  });
Esempio n. 10
0
    describe('elements with template attribute', () => {

      it('should replace the element with an empty <template> element', () => {
        var rootElement = el('<div><span template=""></span></div>');
        var originalChild = rootElement.childNodes[0];
        var results = createPipeline().process(rootElement);
        expect(results[0].element).toBe(rootElement);
        expect(DOM.getOuterHTML(results[0].element)).toEqual('<div><template></template></div>');
        expect(DOM.getOuterHTML(results[2].element)).toEqual('<span template=""></span>')
        expect(results[2].element).toBe(originalChild);
      });

      it('should mark the element as viewRoot', () => {
        var rootElement = el('<div><div template></div></div>');
        var results = createPipeline().process(rootElement);
        expect(results[2].isViewRoot).toBe(true);
      });

      it('should work with top-level template node', () => {
        var rootElement = DOM.createTemplate('<div template>x</div>');
        var originalChild = DOM.content(rootElement).childNodes[0];
        var results = createPipeline().process(rootElement);

        expect(results[0].element).toBe(rootElement);
        expect(results[0].isViewRoot).toBe(true);
        expect(results[2].isViewRoot).toBe(true);
        expect(DOM.getOuterHTML(results[0].element)).toEqual('<template><template></template></template>');
        expect(results[2].element).toBe(originalChild);
      });

      it('should add property bindings from the template attribute', () => {
        var rootElement = el('<div><div template="prop:expr"></div></div>');
        var results = createPipeline().process(rootElement);
        expect(MapWrapper.get(results[1].propertyBindings, 'prop').source).toEqual('expr');
      });

      it('should add variable mappings from the template attribute', () => {
        var rootElement = el('<div><div template="var varName=mapName"></div></div>');
        var results = createPipeline().process(rootElement);
        expect(results[1].variableBindings).toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
      });

      it('should add entries without value as attribute to the element', () => {
        var rootElement = el('<div><div template="varname"></div></div>');
        var results = createPipeline().process(rootElement);
        expect(results[1].attrs()).toEqual(MapWrapper.createFromStringMap({'varname': ''}));
        expect(results[1].propertyBindings).toBe(null);
        expect(results[1].variableBindings).toBe(null);
      });

      it('should iterate properly after a template dom modification', () => {
        var rootElement = el('<div><div template></div><after></after></div>');
        var results = createPipeline().process(rootElement);
        // 1 root + 2 initial + 1 generated template elements
        expect(results.length).toEqual(4);
      });

    });
Esempio n. 11
0
    describe('<template> elements', () => {

      it('should move the content into a new <template> element and mark that as viewRoot', () => {
        var rootElement = el('<div><template if="true">a</template></div>');
        var results = createPipeline().process(rootElement);

        expect(DOM.getOuterHTML(results[1].element)).toEqual('<template if="true"></template>');
        expect(results[1].isViewRoot).toBe(false);
        expect(DOM.getOuterHTML(results[2].element)).toEqual('<template>a</template>');
        expect(results[2].isViewRoot).toBe(true);
      });

      it('should not wrap a root <template> element', () => {
        var rootElement = el('<div></div>');
        var results = createPipeline().process(rootElement);
        expect(results.length).toBe(1);
        expect(DOM.getOuterHTML(rootElement)).toEqual('<div></div>');
      });

    });
Esempio n. 12
0
        describe("mode", () => {
          it("should not check a detached change detector", () => {
            var c = createChangeDetector('name', 'a', new TestData("value"));
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.mode = DETACHED;
            cd.detectChanges();

            expect(dispatcher.log).toEqual([]);
          });

          it("should not check a checked change detector", () => {
            var c = createChangeDetector('name', 'a', new TestData("value"));
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.mode = CHECKED;
            cd.detectChanges();

            expect(dispatcher.log).toEqual([]);
          });

          it("should change CHECK_ONCE to CHECKED", () => {
            var cd = createProtoChangeDetector().instantiate(null, [], null);
            cd.mode = CHECK_ONCE;

            cd.detectChanges();

            expect(cd.mode).toEqual(CHECKED);
          });

          it("should not change the CHECK_ALWAYS", () => {
            var cd = createProtoChangeDetector().instantiate(null, [], null);
            cd.mode = CHECK_ALWAYS;

            cd.detectChanges();

            expect(cd.mode).toEqual(CHECK_ALWAYS);
          });
        });
 ['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'].forEach( (recordType) => {
   it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
     createExtension([
       durationRecord(recordType, 0, 1)
     ]).readPerfLog().then( (events) => {
       expect(events).toEqual([
         normEvents.start('render', 0),
         normEvents.end('render', 1),
       ]);
       async.done();
     });
   }));
 });
Esempio n. 14
0
 xdescribe('static class fields', function() {
   it('should fail when setting wrong type value', function() {
     expect(function() {
       WithFields.id = true;
     }).toThrowError(IS_DARTIUM ?
       // Dart
       "type 'bool' is not a subtype of type 'num' of 'id'" :
       // JavaScript
       // TODO(vojta): Better error, it's not first argument, it's setting a field.
       'Invalid arguments given!\n' +
       '  - 1st argument has to be an instance of number, got true'
     );
   });
 });
  describe('TextInterpolationParser', () => {
    function createPipeline(ignoreBindings = false) {
      return new CompilePipeline([
        new MockStep((parent, current, control) => { current.ignoreBindings = ignoreBindings; }),
        new IgnoreChildrenStep(),
        new TextInterpolationParser(new Parser(new Lexer()))
      ]);
    }

    it('should not look for text interpolation when ignoreBindings is true', () => {
      var results = createPipeline(true).process(el('<div>{{expr1}}<span></span>{{expr2}}</div>'));
      expect(results[0].textNodeBindings).toBe(null);
    });

    it('should find text interpolation in normal elements', () => {
      var results = createPipeline().process(el('<div>{{expr1}}<span></span>{{expr2}}</div>'));
      var bindings = results[0].textNodeBindings;
      expect(MapWrapper.get(bindings, 0).source).toEqual("{{expr1}}");
      expect(MapWrapper.get(bindings, 2).source).toEqual("{{expr2}}");
    });

    it('should find text interpolation in template elements', () => {
      var results = createPipeline().process(el('<template>{{expr1}}<span></span>{{expr2}}</template>'));
      var bindings = results[0].textNodeBindings;
      expect(MapWrapper.get(bindings, 0).source).toEqual("{{expr1}}");
      expect(MapWrapper.get(bindings, 2).source).toEqual("{{expr2}}");
    });

    it('should allow multiple expressions', () => {
      var results = createPipeline().process(el('<div>{{expr1}}{{expr2}}</div>'));
      var bindings = results[0].textNodeBindings;
      expect(MapWrapper.get(bindings, 0).source).toEqual("{{expr1}}{{expr2}}");
    });

    it('should not interpolate when compileChildren is false', () => {
      var results = createPipeline().process(el('<div>{{included}}<span ignore-children>{{excluded}}</span></div>'));
      var bindings = results[0].textNodeBindings;
      expect(MapWrapper.get(bindings, 0).source).toEqual("{{included}}");
      expect(results[1].textNodeBindings).toBe(null);
    });

    it('should allow fixed text before, in between and after expressions', () => {
      var results = createPipeline().process(el('<div>a{{expr1}}b{{expr2}}c</div>'));
      var bindings = results[0].textNodeBindings;
      expect(MapWrapper.get(bindings, 0).source).toEqual("a{{expr1}}b{{expr2}}c");
    });

    it('should escape quotes in fixed parts', () => {
      var results = createPipeline().process(el("<div>'\"a{{expr1}}</div>"));
      expect(MapWrapper.get(results[0].textNodeBindings, 0).source).toEqual("'\"a{{expr1}}");
    });
  });
Esempio n. 16
0
  describe('title service', () => {
    var initialTitle = DOM.getTitle();
    var titleService = new Title();

    afterEach(() => {
      DOM.setTitle(initialTitle);
    });

    it('should allow reading initial title', () => {
      expect(titleService.getTitle()).toEqual(initialTitle);
    });

    it('should set a title on the injected document', () => {
      titleService.setTitle('test title');
      expect(DOM.getTitle()).toEqual('test title');
      expect(titleService.getTitle()).toEqual('test title');
    });

    it('should reset title to empty string if title not provided', () => {
      titleService.setTitle(null);
      expect(DOM.getTitle()).toEqual('');
    });

  });
Esempio n. 17
0
    xdescribe('class fields', function() {
      it('should fail when setting wrong type value', function() {
        var wf = new WithFields();

        expect(function() {
          wf.name = true;
        }).toThrowError(IS_DARTIUM ?
          // Dart
          "type 'bool' is not a subtype of type 'String' of 'value'" :
          // JavaScript
          // TODO(vojta): Better error, it's not first argument, it's setting a field.
          'Invalid arguments given!\n' +
          '  - 1st argument has to be an instance of string, got true'
        );
      });
    });
Esempio n. 18
0
  describe('types', function() {
    it('should work', function() {
      // TODO(vojta): test this better.
      var f = new Foo(1, 2);
      assert(f.sum() == 3);
      assert(f instanceof Foo);

      f.typedVariables();
    });

    xdescribe('class fields', function() {
      it('should fail when setting wrong type value', function() {
        var wf = new WithFields();

        expect(function() {
          wf.name = true;
        }).toThrowError(IS_DARTIUM ?
          // Dart
          "type 'bool' is not a subtype of type 'String' of 'value'" :
          // JavaScript
          // TODO(vojta): Better error, it's not first argument, it's setting a field.
          'Invalid arguments given!\n' +
          '  - 1st argument has to be an instance of string, got true'
        );
      });
    });

    xdescribe('static class fields', function() {
      it('should fail when setting wrong type value', function() {
        expect(function() {
          WithFields.id = true;
        }).toThrowError(IS_DARTIUM ?
          // Dart
          "type 'bool' is not a subtype of type 'num' of 'id'" :
          // JavaScript
          // TODO(vojta): Better error, it's not first argument, it's setting a field.
          'Invalid arguments given!\n' +
          '  - 1st argument has to be an instance of number, got true'
        );
      });
    });
  });
Esempio n. 19
0
        describe(`${name} change detection`, () => {
          it('should do simple watching', () => {
            var person = new Person("misko");
            var c = createChangeDetector('name', 'name', person);
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.detectChanges();
            expect(dispatcher.log).toEqual(['name=misko']);
            dispatcher.clear();

            cd.detectChanges();
            expect(dispatcher.log).toEqual([]);
            dispatcher.clear();

            person.name = "Misko";
            cd.detectChanges();
            expect(dispatcher.log).toEqual(['name=Misko']);
          });

          it('should report all changes on the first run including uninitialized values', () => {
            expect(executeWatch('value', 'value', new Uninitialized())).toEqual(['value=null']);
          });

          it('should report all changes on the first run including null values', () => {
            var td = new TestData(null);
            expect(executeWatch('a', 'a', td)).toEqual(['a=null']);
          });

          it("should support literals", () => {
            expect(executeWatch('const', '10')).toEqual(['const=10']);
            expect(executeWatch('const', '"str"')).toEqual(['const=str']);
            expect(executeWatch('const', '"a\n\nb"')).toEqual(['const=a\n\nb']);
          });

          it('simple chained property access', () => {
            var address = new Address('Grenoble');
            var person = new Person('Victor', address);

            expect(executeWatch('address.city', 'address.city', person))
              .toEqual(['address.city=Grenoble']);
          });

          it("should support method calls", () => {
            var person = new Person('Victor');
            expect(executeWatch('m', 'sayHi("Jim")', person)).toEqual(['m=Hi, Jim']);
          });

          it("should support function calls", () => {
            var td = new TestData(() => (a) => a);
            expect(executeWatch('value', 'a()(99)', td)).toEqual(['value=99']);
          });

          it("should support chained method calls", () => {
            var person = new Person('Victor');
            var td = new TestData(person);
            expect(executeWatch('m', 'a.sayHi("Jim")', td)).toEqual(['m=Hi, Jim']);
          });

          it("should support literal array", () => {
            var c = createChangeDetector('array', '[1,2]');
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues).toEqual([[[1, 2]]]);

            c = createChangeDetector('array', '[1,a]', new TestData(2));
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues).toEqual([[[1, 2]]]);
          });

          it("should support literal maps", () => {
            var c = createChangeDetector('map', '{z:1}');
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues[0][0]['z']).toEqual(1);

            c = createChangeDetector('map', '{z:a}', new TestData(1));
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues[0][0]['z']).toEqual(1);
          });

          it("should support binary operations", () => {
            expect(executeWatch('exp', '10 + 2')).toEqual(['exp=12']);
            expect(executeWatch('exp', '10 - 2')).toEqual(['exp=8']);

            expect(executeWatch('exp', '10 * 2')).toEqual(['exp=20']);
            expect(executeWatch('exp', '10 / 2')).toEqual([`exp=${5.0}`]); //dart exp=5.0, js exp=5
            expect(executeWatch('exp', '11 % 2')).toEqual(['exp=1']);

            expect(executeWatch('exp', '1 == 1')).toEqual(['exp=true']);
            expect(executeWatch('exp', '1 != 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '1 < 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 < 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '2 > 1')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 < 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '1 <= 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 <= 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 <= 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '2 >= 1')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 >= 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '1 >= 2')).toEqual(['exp=false']);

            expect(executeWatch('exp', 'true && true')).toEqual(['exp=true']);
            expect(executeWatch('exp', 'true && false')).toEqual(['exp=false']);

            expect(executeWatch('exp', 'true || false')).toEqual(['exp=true']);
            expect(executeWatch('exp', 'false || false')).toEqual(['exp=false']);
          });

          it("should support negate", () => {
            expect(executeWatch('exp', '!true')).toEqual(['exp=false']);
            expect(executeWatch('exp', '!!true')).toEqual(['exp=true']);
          });

          it("should support conditionals", () => {
            expect(executeWatch('m', '1 < 2 ? 1 : 2')).toEqual(['m=1']);
            expect(executeWatch('m', '1 > 2 ? 1 : 2')).toEqual(['m=2']);
          });

          describe("keyed access", () => {
            it("should support accessing a list item", () => {
              expect(executeWatch('array[0]', '["foo", "bar"][0]')).toEqual(['array[0]=foo']);
            });

            it("should support accessing a map item", () => {
              expect(executeWatch('map[foo]', '{"foo": "bar"}["foo"]')).toEqual(['map[foo]=bar']);
            });
          });

          it("should support interpolation", () => {
            var parser = new Parser(new Lexer());
            var pcd = createProtoChangeDetector();
            var ast = parser.parseInterpolation("B{{a}}A", "location");

            var dispatcher = new TestDispatcher();
            var cd = pcd.instantiate(dispatcher, [new BindingRecord(ast, "memo", "memo")], null);
            cd.hydrate(new TestData("value"), null);

            cd.detectChanges();

            expect(dispatcher.log).toEqual(["memo=BvalueA"]);
          });
 
          describe("change notification", () => {
            describe("simple checks", () => {
              it("should pass a change record to the dispatcher", () => {
                var person = new Person('bob');
                var c = createChangeDetector('name', 'name', person);
                var cd = c["changeDetector"];
                var dispatcher = c["dispatcher"];

                cd.detectChanges();

                var changeRecord = dispatcher.changeRecords[0][0];

                expect(changeRecord.bindingMemento).toEqual('name');
                expect(changeRecord.change.currentValue).toEqual('bob');
                expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
              });
            });

            describe("pipes", () => {
              it("should pass a change record to the dispatcher", () => {
                var registry = new FakePipeRegistry('pipe', () => new CountingPipe());

                var person = new Person('bob');
                var c = createChangeDetector('name', 'name | pipe', person, null, registry);
                var cd = c["changeDetector"];
                var dispatcher = c["dispatcher"];

                cd.detectChanges();

                var changeRecord = dispatcher.changeRecords[0][0];

                expect(changeRecord.bindingMemento).toEqual('name');
                expect(changeRecord.change.currentValue).toEqual('bob state:0');
                expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
              });
            });

            describe("group changes", () => {
              it("should notify the dispatcher when a group of records changes", () => {
                var pcd = createProtoChangeDetector();

                var dispatcher = new TestDispatcher();
                var cd = pcd.instantiate(dispatcher, [
                  new BindingRecord(ast("1 + 2"), "memo", "1"),
                  new BindingRecord(ast("10 + 20"), "memo", "1"),
                  new BindingRecord(ast("100 + 200"), "memo", "2")
                ], null);

                cd.detectChanges();

                expect(dispatcher.loggedValues).toEqual([[3, 30], [300]]);
              });

              it("should notify the dispatcher before switching to the next group", () => {
                var pcd = createProtoChangeDetector();
                var dispatcher = new TestDispatcher();
                var cd = pcd.instantiate(dispatcher, [
                  new BindingRecord(ast("a()"), "a", "1"),
                  new BindingRecord(ast("b()"), "b", "2"),
                  new BindingRecord(ast("c()"), "c", "2")
                ], null);

                var tr = new TestRecord();
                tr.a = () => {
                  dispatcher.logValue('InvokeA');
                  return 'a'
                };
                tr.b = () => {
                  dispatcher.logValue('InvokeB');
                  return 'b'
                };
                tr.c = () => {
                  dispatcher.logValue('InvokeC');
                  return 'c'
                };
                cd.hydrate(tr, null);

                cd.detectChanges();

                expect(dispatcher.loggedValues).toEqual(['InvokeA', ['a'], 'InvokeB', 'InvokeC', ['b', 'c']]);
              });
            });
          });
          
          describe("enforce no new changes", () => {
            it("should throw when a record gets changed after it has been checked", () => {
              var pcd = createProtoChangeDetector();
              pcd.addAst(ast("a"), "a", 1);

              var dispatcher = new TestDispatcher();
              var cd = pcd.instantiate(dispatcher, [
                new BindingRecord(ast("a"), "a", 1)
              ], null);
              cd.hydrate(new TestData('value'), null);

              expect(() => {
                cd.checkNoChanges();
              }).toThrowError(new RegExp("Expression 'a in location' has changed after it was checked"));
            });
          });

          //TODO vsavkin: implement it
          describe("error handling", () => {
            xit("should wrap exceptions into ChangeDetectionError", () => {
              var pcd = createProtoChangeDetector();
              var cd = pcd.instantiate(new TestDispatcher(), [
                new BindingRecord(ast("invalidProp", "someComponent"), "a", 1)
              ], null);
              cd.hydrate(null, null);

              try {
                cd.detectChanges();

                throw new BaseException("fail");
              } catch (e) {
                expect(e).toBeAnInstanceOf(ChangeDetectionError);
                expect(e.location).toEqual("invalidProp in someComponent");
              }
            });
          });

          describe("Locals", () => {
            it('should read a value from locals', () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));

              expect(executeWatch('key', 'key', null, locals))
                .toEqual(['key=value']);
            });

            it('should invoke a function from local', () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", () => "value"]]));

              expect(executeWatch('key', 'key()', null, locals))
                .toEqual(['key=value']);
            });

            it('should handle nested locals', () => {
              var nested = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));
              var locals = new Locals(nested, MapWrapper.create());

              expect(executeWatch('key', 'key', null, locals))
                .toEqual(['key=value']);
            });

            it("should fall back to a regular field read when the locals map" +
              "does not have the requested field", () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));

              expect(executeWatch('name', 'name', new Person("Jim"), locals))
                .toEqual(['name=Jim']);
            });
          });

          describe("handle children", () => {
            var parent, child;

            beforeEach(() => {
              var protoParent = createProtoChangeDetector();
              parent = protoParent.instantiate(null, [], null);

              var protoChild = createProtoChangeDetector();
              child = protoChild.instantiate(null, [], null);
            });

            it("should add children", () => {
              parent.addChild(child);

              expect(parent.children.length).toEqual(1);
              expect(parent.children[0]).toBe(child);
            });

            it("should remove children", () => {
              parent.addChild(child);
              parent.removeChild(child);

              expect(parent.children).toEqual([]);
            });
          });
        });
Esempio n. 20
0
  describe('CssSelector.parse', () => {
    it('should detect element names', () => {
      var cssSelector = CssSelector.parse('sometag')[0];
      expect(cssSelector.element).toEqual('sometag');
      expect(cssSelector.toString()).toEqual('sometag');
    });

    it('should detect class names', () => {
      var cssSelector = CssSelector.parse('.someClass')[0];
      expect(cssSelector.classNames).toEqual(['someclass']);

      expect(cssSelector.toString()).toEqual('.someclass');
    });

    it('should detect attr names', () => {
      var cssSelector = CssSelector.parse('[attrname]')[0];
      expect(cssSelector.attrs).toEqual(['attrname', '']);

      expect(cssSelector.toString()).toEqual('[attrname]');
    });

    it('should detect attr values', () => {
      var cssSelector = CssSelector.parse('[attrname=attrvalue]')[0];
      expect(cssSelector.attrs).toEqual(['attrname', 'attrvalue']);
      expect(cssSelector.toString()).toEqual('[attrname=attrvalue]');
    });

    it('should detect multiple parts', () => {
      var cssSelector = CssSelector.parse('sometag[attrname=attrvalue].someclass')[0];
      expect(cssSelector.element).toEqual('sometag');
      expect(cssSelector.attrs).toEqual(['attrname', 'attrvalue']);
      expect(cssSelector.classNames).toEqual(['someclass']);

      expect(cssSelector.toString()).toEqual('sometag.someclass[attrname=attrvalue]');
    });

    it('should detect :not', () => {
      var cssSelector = CssSelector.parse('sometag:not([attrname=attrvalue].someclass)')[0];
      expect(cssSelector.element).toEqual('sometag');
      expect(cssSelector.attrs.length).toEqual(0);
      expect(cssSelector.classNames.length).toEqual(0);

      var notSelector = cssSelector.notSelector;
      expect(notSelector.element).toEqual(null);
      expect(notSelector.attrs).toEqual(['attrname', 'attrvalue']);
      expect(notSelector.classNames).toEqual(['someclass']);

      expect(cssSelector.toString()).toEqual('sometag:not(.someclass[attrname=attrvalue])');
    });

    it('should detect :not without truthy', () => {
      var cssSelector = CssSelector.parse(':not([attrname=attrvalue].someclass)')[0];
      expect(cssSelector.element).toEqual("*");

      var notSelector = cssSelector.notSelector;
      expect(notSelector.attrs).toEqual(['attrname', 'attrvalue']);
      expect(notSelector.classNames).toEqual(['someclass']);

      expect(cssSelector.toString()).toEqual('*:not(.someclass[attrname=attrvalue])');
    });

    it('should throw when nested :not', () => {
      expect(() => {
        CssSelector.parse('sometag:not(:not([attrname=attrvalue].someclass))')[0];
      }).toThrowError('Nesting :not is not allowed in a selector');
    });

    it('should detect lists of selectors', () => {
      var cssSelectors = CssSelector.parse('.someclass,[attrname=attrvalue], sometag');
      expect(cssSelectors.length).toEqual(3);

      expect(cssSelectors[0].classNames).toEqual(['someclass']);
      expect(cssSelectors[1].attrs).toEqual(['attrname', 'attrvalue']);
      expect(cssSelectors[2].element).toEqual('sometag');
    });

    it('should detect lists of selectors with :not', () => {
      var cssSelectors = CssSelector.parse('input[type=text], :not(textarea), textbox:not(.special)');
      expect(cssSelectors.length).toEqual(3);

      expect(cssSelectors[0].element).toEqual('input');
      expect(cssSelectors[0].attrs).toEqual(['type', 'text']);

      expect(cssSelectors[1].element).toEqual('*');
      expect(cssSelectors[1].notSelector.element).toEqual('textarea');

      expect(cssSelectors[2].element).toEqual('textbox');
      expect(cssSelectors[2].notSelector.classNames).toEqual(['special']);
    });
  });
Esempio n. 21
0
  describe('SelectorMatcher', () => {
    var matcher, matched, selectableCollector, s1, s2, s3, s4;

    function reset() {
      matched = ListWrapper.create();
    }

    beforeEach(() => {
      reset();
      s1 = s2 = s3 = s4 = null;
      selectableCollector = (selector, context) => {
        ListWrapper.push(matched, selector);
        ListWrapper.push(matched, context);
      }
      matcher = new SelectorMatcher();
    });

    it('should select by element name case insensitive', () => {
      matcher.addSelectables(s1 = CssSelector.parse('someTag'), 1);

      expect(matcher.match(CssSelector.parse('SOMEOTHERTAG')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('SOMETAG')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1]);
    });

    it('should select by class name case insensitive', () => {
      matcher.addSelectables(s1 = CssSelector.parse('.someClass'), 1);
      matcher.addSelectables(s2 = CssSelector.parse('.someClass.class2'), 2);

      expect(matcher.match(CssSelector.parse('.SOMEOTHERCLASS')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('.SOMECLASS')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1]);

      reset();
      expect(matcher.match(CssSelector.parse('.someClass.class2')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1,s2[0],2]);
    });

    it('should select by attr name case insensitive independent of the value', () => {
      matcher.addSelectables(s1 = CssSelector.parse('[someAttr]'), 1);
      matcher.addSelectables(s2 = CssSelector.parse('[someAttr][someAttr2]'), 2);

      expect(matcher.match(CssSelector.parse('[SOMEOTHERATTR]')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('[SOMEATTR]')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1]);

      reset();
      expect(matcher.match(CssSelector.parse('[SOMEATTR=someValue]')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1]);

      reset();
      expect(matcher.match(CssSelector.parse('[someAttr][someAttr2]')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1,s2[0],2]);
    });

    it('should select by attr name only once if the value is from the DOM', () => {
      matcher.addSelectables(s1 = CssSelector.parse('[some-decor]'), 1);

      var elementSelector = new CssSelector();
      var element = el('<div attr></div>');
      var empty = DOM.getAttribute(element, 'attr');
      elementSelector.addAttribute('some-decor', empty);
      matcher.match(elementSelector, selectableCollector);
      expect(matched).toEqual([s1[0],1]);
    });

    it('should select by attr name and value case insensitive', () => {
      matcher.addSelectables(s1 = CssSelector.parse('[someAttr=someValue]'), 1);

      expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEOTHERATTR]')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEVALUE]')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1]);
    });

    it('should select by element name, class name and attribute name with value', () => {
      matcher.addSelectables(s1 = CssSelector.parse('someTag.someClass[someAttr=someValue]'), 1);

      expect(matcher.match(CssSelector.parse('someOtherTag.someOtherClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('someTag.someOtherClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('someTag.someClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr]')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);

      expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr=someValue]')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1]);
    });

    it('should select independent of the order in the css selector', () => {
      matcher.addSelectables(s1 = CssSelector.parse('[someAttr].someClass'), 1);
      matcher.addSelectables(s2 = CssSelector.parse('.someClass[someAttr]'), 2);
      matcher.addSelectables(s3 = CssSelector.parse('.class1.class2'), 3);
      matcher.addSelectables(s4 = CssSelector.parse('.class2.class1'), 4);

      expect(matcher.match(CssSelector.parse('[someAttr].someClass')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1,s2[0],2]);

      reset();
      expect(matcher.match(CssSelector.parse('.someClass[someAttr]')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1,s2[0],2]);

      reset();
      expect(matcher.match(CssSelector.parse('.class1.class2')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s3[0],3,s4[0],4]);

      reset();
      expect(matcher.match(CssSelector.parse('.class2.class1')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s4[0],4,s3[0],3]);
    });

    it('should not select with a matching :not selector', () => {
      matcher.addSelectables(CssSelector.parse('p:not(.someClass)'), 1);
      matcher.addSelectables(CssSelector.parse('p:not([someAttr])'), 2);
      matcher.addSelectables(CssSelector.parse(':not(.someClass)'), 3);
      matcher.addSelectables(CssSelector.parse(':not(p)'), 4);
      matcher.addSelectables(CssSelector.parse(':not(p[someAttr])'), 5);

      expect(matcher.match(CssSelector.parse('p.someClass[someAttr]')[0], selectableCollector)).toEqual(false);
      expect(matched).toEqual([]);
    });

    it('should select with a non matching :not selector', () => {
      matcher.addSelectables(s1 = CssSelector.parse('p:not(.someClass)'), 1);
      matcher.addSelectables(s2 = CssSelector.parse('p:not(.someOtherClass[someAttr])'), 2);
      matcher.addSelectables(s3 = CssSelector.parse(':not(.someClass)'), 3);
      matcher.addSelectables(s4 = CssSelector.parse(':not(.someOtherClass[someAttr])'), 4);

      expect(matcher.match(CssSelector.parse('p[someOtherAttr].someOtherClass')[0], selectableCollector)).toEqual(true);
      expect(matched).toEqual([s1[0],1,s2[0],2,s3[0],3,s4[0],4]);
    });

    it('should select with one match in a list', () => {
       matcher.addSelectables(s1 = CssSelector.parse('input[type=text], textbox'), 1);

       expect(matcher.match(CssSelector.parse('textbox')[0], selectableCollector)).toEqual(true);
       expect(matched).toEqual([s1[1],1]);

       reset();
       expect(matcher.match(CssSelector.parse('input[type=text]')[0], selectableCollector)).toEqual(true);
       expect(matched).toEqual([s1[0],1]);
    });

    it('should not select twice with two matches in a list', () => {
       matcher.addSelectables(s1 = CssSelector.parse('input, .someClass'), 1);

       expect(matcher.match(CssSelector.parse('input.someclass')[0], selectableCollector)).toEqual(true);
       expect(matched.length).toEqual(2);
       expect(matched).toEqual([s1[0],1]);
    });
  });
Esempio n. 22
0
  describe('runner', () => {
    var injector;
    var runner;

    function createRunner(defaultBindings = null) {
      if (isBlank(defaultBindings)) {
        defaultBindings = [];
      }
      runner = new Runner([
        defaultBindings,
        bind(Sampler).toFactory(
          (_injector) => {
            injector = _injector;
            return new MockSampler();
          }, [Injector]
        ),
        bind(Metric).toFactory( () => new MockMetric(), []),
        bind(Validator).toFactory( () => new MockValidator(), []),
        bind(WebDriverAdapter).toFactory( () => new MockWebDriverAdapter(), [])
      ]);
      return runner;
    }

    it('should set SampleDescription.id', inject([AsyncTestCompleter], (async) => {
      createRunner().sample({id: 'someId'})
        .then( (_) => injector.asyncGet(SampleDescription) )
        .then( (desc) => {
          expect(desc.id).toBe('someId');
          async.done();
        });
    }));

    it('should merge SampleDescription.description', inject([AsyncTestCompleter], (async) => {
      createRunner([
        bind(Options.DEFAULT_DESCRIPTION).toValue({'a': 1})
      ]).sample({id: 'someId', bindings: [
        bind(Options.SAMPLE_DESCRIPTION).toValue({'b': 2})
      ]}).then( (_) => injector.asyncGet(SampleDescription) )
         .then( (desc) => {

        expect(desc.description).toEqual({
          'forceGc': false,
          'userAgent': 'someUserAgent',
          'a': 1,
          'b': 2,
          'v': 11
        });
        async.done();
      });
    }));

    it('should fill SampleDescription.metrics from the Metric', inject([AsyncTestCompleter], (async) => {
      createRunner().sample({id: 'someId'})
        .then( (_) => injector.asyncGet(SampleDescription) )
        .then( (desc) => {

        expect(desc.metrics).toEqual({ 'm1': 'some metric' });
        async.done();
      });
    }));

    it('should bind Options.EXECUTE', inject([AsyncTestCompleter], (async) => {
      var execute = () => {};
      createRunner().sample({id: 'someId', execute: execute}).then( (_) => {
        expect(injector.get(Options.EXECUTE)).toEqual(execute);
        async.done();
      });
    }));

    it('should bind Options.PREPARE', inject([AsyncTestCompleter], (async) => {
      var prepare = () => {};
      createRunner().sample({id: 'someId', prepare: prepare}).then( (_) => {
        expect(injector.get(Options.PREPARE)).toEqual(prepare);
        async.done();
      });
    }));

    it('should bind Options.MICRO_ITERATIONS', inject([AsyncTestCompleter], (async) => {
      createRunner().sample({id: 'someId', microIterations: 23}).then( (_) => {
        expect(injector.get(Options.MICRO_ITERATIONS)).toEqual(23);
        async.done();
      });
    }));

    it('should overwrite bindings per sample call', inject([AsyncTestCompleter], (async) => {
      createRunner([
        bind(Options.DEFAULT_DESCRIPTION).toValue({'a': 1}),
      ]).sample({id: 'someId', bindings: [
        bind(Options.DEFAULT_DESCRIPTION).toValue({'a': 2}),
      ]}).then( (_) => injector.asyncGet(SampleDescription) )
         .then( (desc) => {

        expect(injector.get(SampleDescription).description['a']).toBe(2);
        async.done();
      });

    }));

  });
Esempio n. 23
0
          describe("enforce no new changes", () => {
            it("should throw when a record gets changed after it has been checked", () => {
              var pcd = createProtoChangeDetector();
              pcd.addAst(ast("a"), "a", 1);

              var dispatcher = new TestDispatcher();
              var cd = pcd.instantiate(dispatcher, [
                new BindingRecord(ast("a"), "a", 1)
              ], null);
              cd.hydrate(new TestData('value'), null);

              expect(() => {
                cd.checkNoChanges();
              }).toThrowError(new RegExp("Expression 'a in location' has changed after it was checked"));
            });
          });
Esempio n. 24
0
            describe("pipes", () => {
              it("should pass a change record to the dispatcher", () => {
                var registry = new FakePipeRegistry('pipe', () => new CountingPipe());

                var person = new Person('bob');
                var c = createChangeDetector('name', 'name | pipe', person, null, registry);
                var cd = c["changeDetector"];
                var dispatcher = c["dispatcher"];

                cd.detectChanges();

                var changeRecord = dispatcher.changeRecords[0][0];

                expect(changeRecord.bindingMemento).toEqual('name');
                expect(changeRecord.change.currentValue).toEqual('bob state:0');
                expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
              });
            });
  describe('ios driver extension', () => {
    var log;
    var extension;

    var normEvents = new TraceEventFactory('timeline', 'pid0');

    function createExtension(perfRecords = null) {
      if (isBlank(perfRecords)) {
        perfRecords = [];
      }
      log = [];
      extension = new Injector([
        IOsDriverExtension.BINDINGS,
        bind(WebDriverAdapter).toValue(new MockDriverAdapter(log, perfRecords))
      ]).get(IOsDriverExtension);
      return extension;
    }

    it('should throw on forcing gc', () => {
      expect( () => createExtension().gc() ).toThrowError('Force GC is not supported on iOS');
    });

    it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => {
      createExtension().timeBegin('someName').then( (_) => {
        expect(log).toEqual([['executeScript', `console.time('someName');`]]);
        async.done();
      });
    }));

    it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => {
      createExtension().timeEnd('someName').then( (_) => {
        expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
        async.done();
      });
    }));

    it('should mark the timeline via console.time() and console.timeEnd()', inject([AsyncTestCompleter], (async) => {
      createExtension().timeEnd('name1', 'name2').then( (_) => {
        expect(log).toEqual([['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
        async.done();
      });
    }));

    describe('readPerfLog', () => {

      it('should execute a dummy script before reading them', inject([AsyncTestCompleter], (async) => {
        // TODO(tbosch): This seems to be a bug in ChromeDriver:
        // Sometimes it does not report the newest events of the performance log
        // to the WebDriver client unless a script is executed...
        createExtension([]).readPerfLog().then( (_) => {
          expect(log).toEqual([ [ 'executeScript', '1+1' ], [ 'logs', 'performance' ] ]);
          async.done();
        });
      }));

      it('should report FunctionCall records as "script"', inject([AsyncTestCompleter], (async) => {
        createExtension([
          durationRecord('FunctionCall', 1, 5)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.start('script', 1),
            normEvents.end('script', 5)
          ]);
          async.done();
        });
      }));

      it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
        createExtension([
          internalScriptRecord(1, 5)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([]);
          async.done();
        });
      }));

      it('should report begin time', inject([AsyncTestCompleter], (async) => {
        createExtension([
          timeBeginRecord('someName', 12)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.markStart('someName', 12)
          ]);
          async.done();
        });
      }));

      it('should report end timestamps', inject([AsyncTestCompleter], (async) => {
        createExtension([
          timeEndRecord('someName', 12)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.markEnd('someName', 12)
          ]);
          async.done();
        });
      }));

      ['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'].forEach( (recordType) => {
        it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
          createExtension([
            durationRecord(recordType, 0, 1)
          ]).readPerfLog().then( (events) => {
            expect(events).toEqual([
              normEvents.start('render', 0),
              normEvents.end('render', 1),
            ]);
            async.done();
          });
        }));
      });


      it('should walk children', inject([AsyncTestCompleter], (async) => {
        createExtension([
          durationRecord('FunctionCall', 1, 5, [
            timeBeginRecord('someName', 2)
          ])
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.start('script', 1),
            normEvents.markStart('someName', 2),
            normEvents.end('script', 5)
          ]);
          async.done();
        });
      }));

      it('should match safari browsers', () => {
        expect(createExtension().supports({
          'browserName': 'safari'
        })).toBe(true);

        expect(createExtension().supports({
          'browserName': 'Safari'
        })).toBe(true);
      });

    });

  });
Esempio n. 26
0
    describe('token', function() {
      it('should tokenize a simple identifier', function() {
        var tokens:List<int> = lex("j");
        expect(tokens.length).toEqual(1);
        expectIdentifierToken(tokens[0], 0, 'j');
      });

      it('should tokenize a dotted identifier', function() {
        var tokens:List<int> = lex("j.k");
        expect(tokens.length).toEqual(3);
        expectIdentifierToken(tokens[0], 0, 'j');
        expectCharacterToken (tokens[1], 1, '.');
        expectIdentifierToken(tokens[2], 2, 'k');
      });

      it('should tokenize an operator', function() {
        var tokens:List<int> = lex("j-k");
        expect(tokens.length).toEqual(3);
        expectOperatorToken(tokens[1], 1, '-');
      });

      it('should tokenize an indexed operator', function() {
        var tokens:List<int> = lex("j[k]");
        expect(tokens.length).toEqual(4);
        expectCharacterToken(tokens[1], 1, "[");
        expectCharacterToken(tokens[3], 3, "]");
      });

      it('should tokenize numbers', function() {
        var tokens:List<int> = lex("88");
        expect(tokens.length).toEqual(1);
        expectNumberToken(tokens[0], 0, 88);
      });

      it('should tokenize numbers within index ops', function() {
        expectNumberToken(lex("a[22]")[2], 2, 22);
      });

      it('should tokenize simple quoted strings', function() {
        expectStringToken(lex('"a"')[0], 0, "a");
      });

      it('should tokenize quoted strings with escaped quotes', function() {
        expectStringToken(lex('"a\\""')[0], 0, 'a"');
      });

      it('should tokenize a string', function() {
        var tokens:List<Token> = lex("j-a.bc[22]+1.3|f:'a\\\'c':\"d\\\"e\"");
        expectIdentifierToken(tokens[0], 0, 'j');
        expectOperatorToken(tokens[1], 1, '-');
        expectIdentifierToken(tokens[2], 2, 'a');
        expectCharacterToken(tokens[3], 3, '.');
        expectIdentifierToken(tokens[4], 4, 'bc');
        expectCharacterToken(tokens[5], 6, '[');
        expectNumberToken(tokens[6], 7, 22);
        expectCharacterToken(tokens[7], 9, ']');
        expectOperatorToken(tokens[8], 10, '+');
        expectNumberToken(tokens[9], 11, 1.3);
        expectOperatorToken(tokens[10], 14, '|');
        expectIdentifierToken(tokens[11], 15, 'f');
        expectCharacterToken(tokens[12], 16, ':');
        expectStringToken(tokens[13], 17, "a'c");
        expectCharacterToken(tokens[14], 23, ':');
        expectStringToken(tokens[15], 24, 'd"e');
      });

      it('should tokenize undefined', function() {
        var tokens:List<Token> = lex("undefined");
        expectKeywordToken(tokens[0], 0, "undefined");
        expect(tokens[0].isKeywordUndefined()).toBe(true);
      });

      it('should ignore whitespace', function() {
        var tokens:List<Token> = lex("a \t \n \r b");
        expectIdentifierToken(tokens[0], 0, 'a');
        expectIdentifierToken(tokens[1], 8, 'b');
      });

      it('should tokenize quoted string', function() {
        var str = "['\\'', \"\\\"\"]";
        var tokens:List<Token> = lex(str);
        expectStringToken(tokens[1], 1, "'");
        expectStringToken(tokens[3], 7, '"');
      });

      it('should tokenize escaped quoted string', function() {
        var str = '"\\"\\n\\f\\r\\t\\v\\u00A0"';
        var tokens:List<Token> = lex(str);
        expect(tokens.length).toEqual(1);
        expect(tokens[0].toString()).toEqual('"\n\f\r\t\v\u00A0');
      });

      it('should tokenize unicode', function() {
        var tokens:List<Token> = lex('"\\u00A0"');
        expect(tokens.length).toEqual(1);
        expect(tokens[0].toString()).toEqual('\u00a0');
      });

      it('should tokenize relation', function() {
        var tokens:List<Token> = lex("! == != < > <= >=");
        expectOperatorToken(tokens[0], 0, '!');
        expectOperatorToken(tokens[1], 2, '==');
        expectOperatorToken(tokens[2], 5, '!=');
        expectOperatorToken(tokens[3], 8, '<');
        expectOperatorToken(tokens[4], 10, '>');
        expectOperatorToken(tokens[5], 12, '<=');
        expectOperatorToken(tokens[6], 15, '>=');
      });

      it('should tokenize statements', function() {
        var tokens:List<Token> = lex("a;b;");
        expectIdentifierToken(tokens[0], 0, 'a');
        expectCharacterToken(tokens[1], 1, ';');
        expectIdentifierToken(tokens[2], 2, 'b');
        expectCharacterToken(tokens[3], 3, ';');
      });

      it('should tokenize function invocation', function() {
        var tokens:List<Token> = lex("a()");
        expectIdentifierToken(tokens[0], 0, 'a');
        expectCharacterToken(tokens[1], 1, '(');
        expectCharacterToken(tokens[2], 2, ')');
      });

      it('should tokenize simple method invocations', function() {
        var tokens:List<Token> = lex("a.method()");
        expectIdentifierToken(tokens[2], 2, 'method');
      });

      it('should tokenize method invocation', function() {
        var tokens:List<Token> = lex("a.b.c (d) - e.f()");
        expectIdentifierToken(tokens[0], 0, 'a');
        expectCharacterToken(tokens[1], 1, '.');
        expectIdentifierToken(tokens[2], 2, 'b');
        expectCharacterToken(tokens[3], 3, '.');
        expectIdentifierToken(tokens[4], 4, 'c');
        expectCharacterToken(tokens[5], 6, '(');
        expectIdentifierToken(tokens[6], 7, 'd');
        expectCharacterToken(tokens[7], 8, ')');
        expectOperatorToken(tokens[8], 10, '-');
        expectIdentifierToken(tokens[9], 12, 'e');
        expectCharacterToken(tokens[10], 13, '.');
        expectIdentifierToken(tokens[11], 14, 'f');
        expectCharacterToken(tokens[12], 15, '(');
        expectCharacterToken(tokens[13], 16, ')');
      });

      it('should tokenize number', function() {
        var tokens:List<Token> = lex("0.5");
        expectNumberToken(tokens[0], 0, 0.5);
      });

      // NOTE(deboer): NOT A LEXER TEST
      //    it('should tokenize negative number', function() {
      //      var tokens:List<Token> = lex("-0.5");
      //      expectNumberToken(tokens[0], 0, -0.5);
      //    });

      it('should tokenize number with exponent', function() {
        var tokens:List<Token> = lex("0.5E-10");
        expect(tokens.length).toEqual(1);
        expectNumberToken(tokens[0], 0, 0.5E-10);
        tokens = lex("0.5E+10");
        expectNumberToken(tokens[0], 0, 0.5E+10);
      });

      it('should throws exception for invalid exponent', function() {
        expect(function() {
          lex("0.5E-");
        }).toThrowError('Lexer Error: Invalid exponent at column 4 in expression [0.5E-]');

        expect(function() {
          lex("0.5E-A");
        }).toThrowError('Lexer Error: Invalid exponent at column 4 in expression [0.5E-A]');
      });

      it('should tokenize number starting with a dot', function() {
        var tokens:List<Token> = lex(".5");
        expectNumberToken(tokens[0], 0, 0.5);
      });

      it('should throw error on invalid unicode', function() {
        expect(function() {
          lex("'\\u1''bla'");
        }).toThrowError("Lexer Error: Invalid unicode escape [\\u1''b] at column 2 in expression ['\\u1''bla']");
      });

      it('should tokenize hash as operator', function() {
        var tokens:List<Token> = lex("#");
        expectOperatorToken(tokens[0], 0, '#');
      });

    });
Esempio n. 27
0
            describe("simple checks", () => {
              it("should pass a change record to the dispatcher", () => {
                var person = new Person('bob');
                var c = createChangeDetector('name', 'name', person);
                var cd = c["changeDetector"];
                var dispatcher = c["dispatcher"];

                cd.detectChanges();

                var changeRecord = dispatcher.changeRecords[0][0];

                expect(changeRecord.bindingMemento).toEqual('name');
                expect(changeRecord.change.currentValue).toEqual('bob');
                expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
              });
            });
Esempio n. 28
0
      }, (createProtoChangeDetector, name) => {

        if (name == "JIT" && IS_DARTIUM) return;

        function ast(exp:string, location:string = 'location') {
          var parser = new Parser(new Lexer());
          return parser.parseBinding(exp, location);
        }

        function convertLocalsToVariableBindings(locals) {
          var variableBindings = [];
          var loc = locals;
          while(isPresent(loc)) {
            MapWrapper.forEach(loc.current, (v, k) => ListWrapper.push(variableBindings, k));
            loc = loc.parent;
          }
          return variableBindings;
        }

        function createChangeDetector(memo:string, exp:string, context = null, locals = null, registry = null) {
          var pcd = createProtoChangeDetector(registry);
          var dispatcher = new TestDispatcher();

          var variableBindings = convertLocalsToVariableBindings(locals);
          var cd = pcd.instantiate(dispatcher, [new BindingRecord(ast(exp), memo, memo)], variableBindings);
          cd.hydrate(context, locals);

          return {"changeDetector" : cd, "dispatcher" : dispatcher};
        }

        function executeWatch(memo:string, exp:string, context = null, locals = null) {
          var res = createChangeDetector(memo, exp, context, locals);
          res["changeDetector"].detectChanges();
          return res["dispatcher"].log;
        }

        describe(`${name} change detection`, () => {
          it('should do simple watching', () => {
            var person = new Person("misko");
            var c = createChangeDetector('name', 'name', person);
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.detectChanges();
            expect(dispatcher.log).toEqual(['name=misko']);
            dispatcher.clear();

            cd.detectChanges();
            expect(dispatcher.log).toEqual([]);
            dispatcher.clear();

            person.name = "Misko";
            cd.detectChanges();
            expect(dispatcher.log).toEqual(['name=Misko']);
          });

          it('should report all changes on the first run including uninitialized values', () => {
            expect(executeWatch('value', 'value', new Uninitialized())).toEqual(['value=null']);
          });

          it('should report all changes on the first run including null values', () => {
            var td = new TestData(null);
            expect(executeWatch('a', 'a', td)).toEqual(['a=null']);
          });

          it("should support literals", () => {
            expect(executeWatch('const', '10')).toEqual(['const=10']);
            expect(executeWatch('const', '"str"')).toEqual(['const=str']);
            expect(executeWatch('const', '"a\n\nb"')).toEqual(['const=a\n\nb']);
          });

          it('simple chained property access', () => {
            var address = new Address('Grenoble');
            var person = new Person('Victor', address);

            expect(executeWatch('address.city', 'address.city', person))
              .toEqual(['address.city=Grenoble']);
          });

          it("should support method calls", () => {
            var person = new Person('Victor');
            expect(executeWatch('m', 'sayHi("Jim")', person)).toEqual(['m=Hi, Jim']);
          });

          it("should support function calls", () => {
            var td = new TestData(() => (a) => a);
            expect(executeWatch('value', 'a()(99)', td)).toEqual(['value=99']);
          });

          it("should support chained method calls", () => {
            var person = new Person('Victor');
            var td = new TestData(person);
            expect(executeWatch('m', 'a.sayHi("Jim")', td)).toEqual(['m=Hi, Jim']);
          });

          it("should support literal array", () => {
            var c = createChangeDetector('array', '[1,2]');
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues).toEqual([[[1, 2]]]);

            c = createChangeDetector('array', '[1,a]', new TestData(2));
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues).toEqual([[[1, 2]]]);
          });

          it("should support literal maps", () => {
            var c = createChangeDetector('map', '{z:1}');
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues[0][0]['z']).toEqual(1);

            c = createChangeDetector('map', '{z:a}', new TestData(1));
            c["changeDetector"].detectChanges();
            expect(c["dispatcher"].loggedValues[0][0]['z']).toEqual(1);
          });

          it("should support binary operations", () => {
            expect(executeWatch('exp', '10 + 2')).toEqual(['exp=12']);
            expect(executeWatch('exp', '10 - 2')).toEqual(['exp=8']);

            expect(executeWatch('exp', '10 * 2')).toEqual(['exp=20']);
            expect(executeWatch('exp', '10 / 2')).toEqual([`exp=${5.0}`]); //dart exp=5.0, js exp=5
            expect(executeWatch('exp', '11 % 2')).toEqual(['exp=1']);

            expect(executeWatch('exp', '1 == 1')).toEqual(['exp=true']);
            expect(executeWatch('exp', '1 != 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '1 < 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 < 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '2 > 1')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 < 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '1 <= 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 <= 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 <= 1')).toEqual(['exp=false']);

            expect(executeWatch('exp', '2 >= 1')).toEqual(['exp=true']);
            expect(executeWatch('exp', '2 >= 2')).toEqual(['exp=true']);
            expect(executeWatch('exp', '1 >= 2')).toEqual(['exp=false']);

            expect(executeWatch('exp', 'true && true')).toEqual(['exp=true']);
            expect(executeWatch('exp', 'true && false')).toEqual(['exp=false']);

            expect(executeWatch('exp', 'true || false')).toEqual(['exp=true']);
            expect(executeWatch('exp', 'false || false')).toEqual(['exp=false']);
          });

          it("should support negate", () => {
            expect(executeWatch('exp', '!true')).toEqual(['exp=false']);
            expect(executeWatch('exp', '!!true')).toEqual(['exp=true']);
          });

          it("should support conditionals", () => {
            expect(executeWatch('m', '1 < 2 ? 1 : 2')).toEqual(['m=1']);
            expect(executeWatch('m', '1 > 2 ? 1 : 2')).toEqual(['m=2']);
          });

          describe("keyed access", () => {
            it("should support accessing a list item", () => {
              expect(executeWatch('array[0]', '["foo", "bar"][0]')).toEqual(['array[0]=foo']);
            });

            it("should support accessing a map item", () => {
              expect(executeWatch('map[foo]', '{"foo": "bar"}["foo"]')).toEqual(['map[foo]=bar']);
            });
          });

          it("should support interpolation", () => {
            var parser = new Parser(new Lexer());
            var pcd = createProtoChangeDetector();
            var ast = parser.parseInterpolation("B{{a}}A", "location");

            var dispatcher = new TestDispatcher();
            var cd = pcd.instantiate(dispatcher, [new BindingRecord(ast, "memo", "memo")], null);
            cd.hydrate(new TestData("value"), null);

            cd.detectChanges();

            expect(dispatcher.log).toEqual(["memo=BvalueA"]);
          });
 
          describe("change notification", () => {
            describe("simple checks", () => {
              it("should pass a change record to the dispatcher", () => {
                var person = new Person('bob');
                var c = createChangeDetector('name', 'name', person);
                var cd = c["changeDetector"];
                var dispatcher = c["dispatcher"];

                cd.detectChanges();

                var changeRecord = dispatcher.changeRecords[0][0];

                expect(changeRecord.bindingMemento).toEqual('name');
                expect(changeRecord.change.currentValue).toEqual('bob');
                expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
              });
            });

            describe("pipes", () => {
              it("should pass a change record to the dispatcher", () => {
                var registry = new FakePipeRegistry('pipe', () => new CountingPipe());

                var person = new Person('bob');
                var c = createChangeDetector('name', 'name | pipe', person, null, registry);
                var cd = c["changeDetector"];
                var dispatcher = c["dispatcher"];

                cd.detectChanges();

                var changeRecord = dispatcher.changeRecords[0][0];

                expect(changeRecord.bindingMemento).toEqual('name');
                expect(changeRecord.change.currentValue).toEqual('bob state:0');
                expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
              });
            });

            describe("group changes", () => {
              it("should notify the dispatcher when a group of records changes", () => {
                var pcd = createProtoChangeDetector();

                var dispatcher = new TestDispatcher();
                var cd = pcd.instantiate(dispatcher, [
                  new BindingRecord(ast("1 + 2"), "memo", "1"),
                  new BindingRecord(ast("10 + 20"), "memo", "1"),
                  new BindingRecord(ast("100 + 200"), "memo", "2")
                ], null);

                cd.detectChanges();

                expect(dispatcher.loggedValues).toEqual([[3, 30], [300]]);
              });

              it("should notify the dispatcher before switching to the next group", () => {
                var pcd = createProtoChangeDetector();
                var dispatcher = new TestDispatcher();
                var cd = pcd.instantiate(dispatcher, [
                  new BindingRecord(ast("a()"), "a", "1"),
                  new BindingRecord(ast("b()"), "b", "2"),
                  new BindingRecord(ast("c()"), "c", "2")
                ], null);

                var tr = new TestRecord();
                tr.a = () => {
                  dispatcher.logValue('InvokeA');
                  return 'a'
                };
                tr.b = () => {
                  dispatcher.logValue('InvokeB');
                  return 'b'
                };
                tr.c = () => {
                  dispatcher.logValue('InvokeC');
                  return 'c'
                };
                cd.hydrate(tr, null);

                cd.detectChanges();

                expect(dispatcher.loggedValues).toEqual(['InvokeA', ['a'], 'InvokeB', 'InvokeC', ['b', 'c']]);
              });
            });
          });
          
          describe("enforce no new changes", () => {
            it("should throw when a record gets changed after it has been checked", () => {
              var pcd = createProtoChangeDetector();
              pcd.addAst(ast("a"), "a", 1);

              var dispatcher = new TestDispatcher();
              var cd = pcd.instantiate(dispatcher, [
                new BindingRecord(ast("a"), "a", 1)
              ], null);
              cd.hydrate(new TestData('value'), null);

              expect(() => {
                cd.checkNoChanges();
              }).toThrowError(new RegExp("Expression 'a in location' has changed after it was checked"));
            });
          });

          //TODO vsavkin: implement it
          describe("error handling", () => {
            xit("should wrap exceptions into ChangeDetectionError", () => {
              var pcd = createProtoChangeDetector();
              var cd = pcd.instantiate(new TestDispatcher(), [
                new BindingRecord(ast("invalidProp", "someComponent"), "a", 1)
              ], null);
              cd.hydrate(null, null);

              try {
                cd.detectChanges();

                throw new BaseException("fail");
              } catch (e) {
                expect(e).toBeAnInstanceOf(ChangeDetectionError);
                expect(e.location).toEqual("invalidProp in someComponent");
              }
            });
          });

          describe("Locals", () => {
            it('should read a value from locals', () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));

              expect(executeWatch('key', 'key', null, locals))
                .toEqual(['key=value']);
            });

            it('should invoke a function from local', () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", () => "value"]]));

              expect(executeWatch('key', 'key()', null, locals))
                .toEqual(['key=value']);
            });

            it('should handle nested locals', () => {
              var nested = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));
              var locals = new Locals(nested, MapWrapper.create());

              expect(executeWatch('key', 'key', null, locals))
                .toEqual(['key=value']);
            });

            it("should fall back to a regular field read when the locals map" +
              "does not have the requested field", () => {
              var locals = new Locals(null,
                MapWrapper.createFromPairs([["key", "value"]]));

              expect(executeWatch('name', 'name', new Person("Jim"), locals))
                .toEqual(['name=Jim']);
            });
          });

          describe("handle children", () => {
            var parent, child;

            beforeEach(() => {
              var protoParent = createProtoChangeDetector();
              parent = protoParent.instantiate(null, [], null);

              var protoChild = createProtoChangeDetector();
              child = protoChild.instantiate(null, [], null);
            });

            it("should add children", () => {
              parent.addChild(child);

              expect(parent.children.length).toEqual(1);
              expect(parent.children[0]).toBe(child);
            });

            it("should remove children", () => {
              parent.addChild(child);
              parent.removeChild(child);

              expect(parent.children).toEqual([]);
            });
          });
        });

        describe("mode", () => {
          it("should not check a detached change detector", () => {
            var c = createChangeDetector('name', 'a', new TestData("value"));
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.mode = DETACHED;
            cd.detectChanges();

            expect(dispatcher.log).toEqual([]);
          });

          it("should not check a checked change detector", () => {
            var c = createChangeDetector('name', 'a', new TestData("value"));
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.mode = CHECKED;
            cd.detectChanges();

            expect(dispatcher.log).toEqual([]);
          });

          it("should change CHECK_ONCE to CHECKED", () => {
            var cd = createProtoChangeDetector().instantiate(null, [], null);
            cd.mode = CHECK_ONCE;

            cd.detectChanges();

            expect(cd.mode).toEqual(CHECKED);
          });

          it("should not change the CHECK_ALWAYS", () => {
            var cd = createProtoChangeDetector().instantiate(null, [], null);
            cd.mode = CHECK_ALWAYS;

            cd.detectChanges();

            expect(cd.mode).toEqual(CHECK_ALWAYS);
          });
        });

        describe("markPathToRootAsCheckOnce", () => {
          function changeDetector(mode, parent) {
            var cd = createProtoChangeDetector().instantiate(null, [], null);
            cd.mode = mode;
            if (isPresent(parent)) parent.addChild(cd);
            return cd;
          }

          it("should mark all checked detectors as CHECK_ONCE " +
            "until reaching a detached one", () => {

            var root = changeDetector(CHECK_ALWAYS, null);
            var disabled = changeDetector(DETACHED, root);
            var parent = changeDetector(CHECKED, disabled);
            var checkAlwaysChild = changeDetector(CHECK_ALWAYS, parent);
            var checkOnceChild = changeDetector(CHECK_ONCE, checkAlwaysChild);
            var checkedChild = changeDetector(CHECKED, checkOnceChild);

            checkedChild.markPathToRootAsCheckOnce();

            expect(root.mode).toEqual(CHECK_ALWAYS);
            expect(disabled.mode).toEqual(DETACHED);
            expect(parent.mode).toEqual(CHECK_ONCE);
            expect(checkAlwaysChild.mode).toEqual(CHECK_ALWAYS);
            expect(checkOnceChild.mode).toEqual(CHECK_ONCE);
            expect(checkedChild.mode).toEqual(CHECK_ONCE);
          });
        });

        describe("hydration", () => {
          it("should be able to rehydrate a change detector", () => {
            var c  = createChangeDetector("memo", "name");
            var cd = c["changeDetector"];

            cd.hydrate("some context", null);
            expect(cd.hydrated()).toBe(true);

            cd.dehydrate();
            expect(cd.hydrated()).toBe(false);

            cd.hydrate("other context", null);
            expect(cd.hydrated()).toBe(true);
          });

          it("should destroy all active pipes during dehyration", () => {
            var pipe = new OncePipe();
            var registry = new FakePipeRegistry('pipe', () => pipe);
            var c  = createChangeDetector("memo", "name | pipe", new Person('bob'), null, registry);
            var cd = c["changeDetector"];

            cd.detectChanges();

            cd.dehydrate();

            expect(pipe.destroyCalled).toBe(true);
          });
        });

        describe("pipes", () => {
          it("should support pipes", () => {
            var registry = new FakePipeRegistry('pipe', () => new CountingPipe());
            var ctx = new Person("Megatron");

            var c  = createChangeDetector("memo", "name | pipe", ctx, null, registry);
            var cd = c["changeDetector"];
            var dispatcher = c["dispatcher"];

            cd.detectChanges();

            expect(dispatcher.log).toEqual(['memo=Megatron state:0']);

            dispatcher.clear();
            cd.detectChanges();

            expect(dispatcher.log).toEqual(['memo=Megatron state:1']);
          });

          it("should lookup pipes in the registry when the context is not supported", () => {
            var registry = new FakePipeRegistry('pipe', () => new OncePipe());
            var ctx = new Person("Megatron");

            var c  = createChangeDetector("memo", "name | pipe", ctx, null, registry);
            var cd = c["changeDetector"];

            cd.detectChanges();

            expect(registry.numberOfLookups).toEqual(1);

            ctx.name = "Optimus Prime";
            cd.detectChanges();

            expect(registry.numberOfLookups).toEqual(2);
          });

          it("should invoke onDestroy on a pipe before switching to another one", () => {
            var pipe = new OncePipe();
            var registry = new FakePipeRegistry('pipe', () => pipe);
            var ctx = new Person("Megatron");

            var c  = createChangeDetector("memo", "name | pipe", ctx, null, registry);
            var cd = c["changeDetector"];

            cd.detectChanges();
            ctx.name = "Optimus Prime";
            cd.detectChanges();

            expect(pipe.destroyCalled).toEqual(true);
          });
        });

        it("should do nothing when returns NO_CHANGE", () => {
          var registry = new FakePipeRegistry('pipe', () => new IdentityPipe())
          var ctx = new Person("Megatron");

          var c  = createChangeDetector("memo", "name | pipe", ctx, null, registry);
          var cd = c["changeDetector"];
          var dispatcher = c["dispatcher"];

          cd.detectChanges();
          cd.detectChanges();

          expect(dispatcher.log).toEqual(['memo=Megatron']);

          ctx.name = "Optimus Prime";
          dispatcher.clear();
          cd.detectChanges();

          expect(dispatcher.log).toEqual(['memo=Optimus Prime']);
        });
      });
    describe('readPerfLog', () => {

      it('should execute a dummy script before reading them', inject([AsyncTestCompleter], (async) => {
        // TODO(tbosch): This seems to be a bug in ChromeDriver:
        // Sometimes it does not report the newest events of the performance log
        // to the WebDriver client unless a script is executed...
        createExtension([]).readPerfLog().then( (_) => {
          expect(log).toEqual([ [ 'executeScript', '1+1' ], [ 'logs', 'performance' ] ]);
          async.done();
        });
      }));

      it('should report FunctionCall records as "script"', inject([AsyncTestCompleter], (async) => {
        createExtension([
          durationRecord('FunctionCall', 1, 5)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.start('script', 1),
            normEvents.end('script', 5)
          ]);
          async.done();
        });
      }));

      it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
        createExtension([
          internalScriptRecord(1, 5)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([]);
          async.done();
        });
      }));

      it('should report begin time', inject([AsyncTestCompleter], (async) => {
        createExtension([
          timeBeginRecord('someName', 12)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.markStart('someName', 12)
          ]);
          async.done();
        });
      }));

      it('should report end timestamps', inject([AsyncTestCompleter], (async) => {
        createExtension([
          timeEndRecord('someName', 12)
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.markEnd('someName', 12)
          ]);
          async.done();
        });
      }));

      ['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'].forEach( (recordType) => {
        it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
          createExtension([
            durationRecord(recordType, 0, 1)
          ]).readPerfLog().then( (events) => {
            expect(events).toEqual([
              normEvents.start('render', 0),
              normEvents.end('render', 1),
            ]);
            async.done();
          });
        }));
      });


      it('should walk children', inject([AsyncTestCompleter], (async) => {
        createExtension([
          durationRecord('FunctionCall', 1, 5, [
            timeBeginRecord('someName', 2)
          ])
        ]).readPerfLog().then( (events) => {
          expect(events).toEqual([
            normEvents.start('script', 1),
            normEvents.markStart('someName', 2),
            normEvents.end('script', 5)
          ]);
          async.done();
        });
      }));

      it('should match safari browsers', () => {
        expect(createExtension().supports({
          'browserName': 'safari'
        })).toBe(true);

        expect(createExtension().supports({
          'browserName': 'Safari'
        })).toBe(true);
      });

    });
Esempio n. 30
0
    describe('elements with *directive_name attribute', () => {

      it('should replace the element with an empty <template> element', () => {
        var rootElement = el('<div><span *if></span></div>');
        var originalChild = rootElement.childNodes[0];
        var results = createPipeline().process(rootElement);
        expect(results[0].element).toBe(rootElement);
        expect(DOM.getOuterHTML(results[0].element)).toEqual('<div><template if=""></template></div>');
        expect(DOM.getOuterHTML(results[2].element)).toEqual('<span *if=""></span>')
        expect(results[2].element).toBe(originalChild);
      });

      it('should mark the element as viewRoot', () => {
        var rootElement = el('<div><div *foo="bar"></div></div>');
        var results = createPipeline().process(rootElement);
        expect(results[2].isViewRoot).toBe(true);
      });

      it('should work with top-level template node', () => {
        var rootElement = DOM.createTemplate('<div *foo>x</div>');
        var originalChild = DOM.content(rootElement).childNodes[0];
        var results = createPipeline().process(rootElement);

        expect(results[0].element).toBe(rootElement);
        expect(results[0].isViewRoot).toBe(true);
        expect(results[2].isViewRoot).toBe(true);
        expect(DOM.getOuterHTML(results[0].element)).toEqual('<template><template foo=""></template></template>');
        expect(results[2].element).toBe(originalChild);
      });

      it('should add property bindings from the template attribute', () => {
        var rootElement = el('<div><div *prop="expr"></div></div>');
        var results = createPipeline().process(rootElement);
        expect(MapWrapper.get(results[1].propertyBindings, 'prop').source).toEqual('expr');
      });

      it('should add variable mappings from the template attribute', () => {
        var rootElement = el('<div><div *foreach="var varName=mapName"></div></div>');
        var results = createPipeline().process(rootElement);
        expect(results[1].variableBindings).toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
      });

      it('should add entries without value as attribute to the element', () => {
        var rootElement = el('<div><div *varname></div></div>');
        var results = createPipeline().process(rootElement);
        expect(results[1].attrs()).toEqual(MapWrapper.createFromStringMap({'varname': ''}));
        expect(results[1].propertyBindings).toBe(null);
        expect(results[1].variableBindings).toBe(null);
      });

      it('should iterate properly after a template dom modification', () => {
        var rootElement = el('<div><div *foo></div><after></after></div>');
        var results = createPipeline().process(rootElement);
        // 1 root + 2 initial + 1 generated template elements
        expect(results.length).toEqual(4);
      });

      it('should not allow multiple template directives on the same element', () => {
        expect( () => {
          var rootElement = el('<div><div *foo *bar="blah"></div></div>');
          createPipeline().process(rootElement);
        }).toThrowError('Only one template directive per element is allowed: foo and bar cannot be used simultaneously in <div *foo *bar="blah">');
      });

      it('should not allow template and star directives on the same element', () => {
        expect( () => {
          var rootElement = el('<div><div *foo template="bar"></div></div>');
          createPipeline().process(rootElement);
        }).toThrowError('Only one template directive per element is allowed: bar and foo cannot be used simultaneously in <div *foo template="bar">');
      });

    });