Ejemplo n.º 1
0
 describe('operators', () => {
   var ops: any /** TODO #9100 */;
   var aObj: any /** TODO #9100 */, bObj: any /** TODO #9100 */;
   beforeEach(() => {
     ops = expressions['operators'];
     aObj = new Object();
     bObj = new Object();
   });
   it('should support ==', () => {
     expect(ops['=='](aObj, aObj)).toBe(true);
     expect(ops['=='](aObj, bObj)).toBe(false);
     expect(ops['=='](1, 1)).toBe(true);
     expect(ops['=='](0, 1)).toBe(false);
     expect(ops['==']('a', 'a')).toBe(true);
     expect(ops['==']('a', 'b')).toBe(false);
   });
   it('should support !=', () => {
     expect(ops['!='](aObj, aObj)).toBe(false);
     expect(ops['!='](aObj, bObj)).toBe(true);
     expect(ops['!='](1, 1)).toBe(false);
     expect(ops['!='](0, 1)).toBe(true);
     expect(ops['!=']('a', 'a')).toBe(false);
     expect(ops['!=']('a', 'b')).toBe(true);
   });
   it('should support ===', () => {
     expect(ops['==='](aObj, aObj)).toBe(true);
     expect(ops['==='](aObj, bObj)).toBe(false);
     expect(ops['==='](1, 1)).toBe(true);
     expect(ops['==='](0, 1)).toBe(false);
   });
   it('should support !==', () => {
     expect(ops['!=='](aObj, aObj)).toBe(false);
     expect(ops['!=='](aObj, bObj)).toBe(true);
     expect(ops['!=='](1, 1)).toBe(false);
     expect(ops['!=='](0, 1)).toBe(true);
   });
   it('should support -', () => { expect(ops['-'](3, 2)).toEqual(1); });
   it('should support +', () => { expect(ops['+'](1, 2)).toEqual(3); });
   it('should support /', () => { expect(ops['/'](6, 2)).toEqual(3); });
   it('should support *', () => { expect(ops['*'](2, 3)).toEqual(6); });
   it('should support %', () => { expect(ops['%'](3, 2)).toEqual(1); });
   it('should support &&', () => {
     expect(ops['&&'](true, true)).toBe(true);
     expect(ops['&&'](true, false)).toBe(false);
   });
   it('should support ||', () => {
     expect(ops['||'](true, false)).toBe(true);
     expect(ops['||'](false, false)).toBe(false);
   });
   it('should support <', () => {
     expect(ops['<'](1, 2)).toBe(true);
     expect(ops['<'](1, 1)).toBe(false);
   });
   it('should support <=', () => {
     expect(ops['<='](1, 2)).toBe(true);
     expect(ops['<='](1, 1)).toBe(true);
   });
   it('should support >', () => {
     expect(ops['>'](2, 1)).toBe(true);
     expect(ops['>'](1, 1)).toBe(false);
   });
   it('should support >=', () => {
     expect(ops['>='](2, 1)).toBe(true);
     expect(ops['>='](1, 1)).toBe(true);
   });
 });
Ejemplo n.º 2
0
  describe('MessageBus', () => {
    var bus: MessageBus;

    beforeEach(() => { bus = createConnectedMessageBus(); });

    it('should pass messages in the same channel from sink to source',
       inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
         const CHANNEL = 'CHANNEL 1';
         const MESSAGE = 'Test message';
         bus.initChannel(CHANNEL, false);

         var fromEmitter = bus.from(CHANNEL);
         fromEmitter.subscribe({
           next: (message: any) => {
             expect(message).toEqual(MESSAGE);
             async.done();
           }
         });
         var toEmitter = bus.to(CHANNEL);
         toEmitter.emit(MESSAGE);
       }));

    it('should broadcast', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
         const CHANNEL = 'CHANNEL 1';
         const MESSAGE = 'TESTING';
         const NUM_LISTENERS = 2;
         bus.initChannel(CHANNEL, false);

         var callCount = 0;
         var emitHandler = (message: any) => {
           expect(message).toEqual(MESSAGE);
           callCount++;
           if (callCount == NUM_LISTENERS) {
             async.done();
           }
         };

         for (var i = 0; i < NUM_LISTENERS; i++) {
           var emitter = bus.from(CHANNEL);
           emitter.subscribe({next: emitHandler});
         }

         var toEmitter = bus.to(CHANNEL);
         toEmitter.emit(MESSAGE);
       }));

    it('should keep channels independent',
       inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
         const CHANNEL_ONE = 'CHANNEL 1';
         const CHANNEL_TWO = 'CHANNEL 2';
         const MESSAGE_ONE = 'This is a message on CHANNEL 1';
         const MESSAGE_TWO = 'This is a message on CHANNEL 2';
         var callCount = 0;
         bus.initChannel(CHANNEL_ONE, false);
         bus.initChannel(CHANNEL_TWO, false);

         var firstFromEmitter = bus.from(CHANNEL_ONE);
         firstFromEmitter.subscribe({
           next: (message: any) => {
             expect(message).toEqual(MESSAGE_ONE);
             callCount++;
             if (callCount == 2) {
               async.done();
             }
           }
         });
         var secondFromEmitter = bus.from(CHANNEL_TWO);
         secondFromEmitter.subscribe({
           next: (message: any) => {
             expect(message).toEqual(MESSAGE_TWO);
             callCount++;
             if (callCount == 2) {
               async.done();
             }
           }
         });

         var firstToEmitter = bus.to(CHANNEL_ONE);
         firstToEmitter.emit(MESSAGE_ONE);

         var secondToEmitter = bus.to(CHANNEL_TWO);
         secondToEmitter.emit(MESSAGE_TWO);
       }));
  });
  describe('CompileMetadataResolver', () => {
    beforeEach(() => { configureCompiler({providers: TEST_COMPILER_PROVIDERS}); });

    describe('getMetadata', () => {
      it('should read metadata',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           var meta = resolver.getDirectiveMetadata(ComponentWithEverything);
           expect(meta.selector).toEqual('someSelector');
           expect(meta.exportAs).toEqual('someExportAs');
           expect(meta.isComponent).toBe(true);
           expect(meta.type.runtime).toBe(ComponentWithEverything);
           expect(meta.type.name).toEqual(stringify(ComponentWithEverything));
           expect(meta.lifecycleHooks).toEqual(LIFECYCLE_HOOKS_VALUES);
           expect(meta.changeDetection).toBe(ChangeDetectionStrategy.Default);
           expect(meta.inputs).toEqual({'someProp': 'someProp'});
           expect(meta.outputs).toEqual({'someEvent': 'someEvent'});
           expect(meta.hostListeners).toEqual({'someHostListener': 'someHostListenerExpr'});
           expect(meta.hostProperties).toEqual({'someHostProp': 'someHostPropExpr'});
           expect(meta.hostAttributes).toEqual({'someHostAttr': 'someHostAttrValue'});
           expect(meta.template.encapsulation).toBe(ViewEncapsulation.Emulated);
           expect(meta.template.styles).toEqual(['someStyle']);
           expect(meta.template.styleUrls).toEqual(['someStyleUrl']);
           expect(meta.template.template).toEqual('someTemplate');
           expect(meta.template.templateUrl).toEqual('someTemplateUrl');
           expect(meta.template.interpolation).toEqual(['{{', '}}']);
         }));

      it('should use the moduleUrl from the reflector if none is given',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           var value: string =
               resolver.getDirectiveMetadata(ComponentWithoutModuleId).type.moduleUrl;
           var expectedEndValue =
               IS_DART ? 'test/compiler/metadata_resolver_spec.dart' : './ComponentWithoutModuleId';
           expect(value.endsWith(expectedEndValue)).toBe(true);
         }));

      it('should throw when metadata is incorrectly typed',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           expect(() => resolver.getDirectiveMetadata(MalformedStylesComponent))
               .toThrowError(`Expected 'styles' to be an array of strings.`);
         }));

      it('should throw with descriptive error message when provider token can not be resolved',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           expect(() => resolver.getDirectiveMetadata(MyBrokenComp1))
               .toThrowError(`Can't resolve all parameters for MyBrokenComp1: (?).`);
         }));

      it('should throw with descriptive error message when a param token of a dependency is undefined',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           expect(() => resolver.getDirectiveMetadata(MyBrokenComp2))
               .toThrowError(`Can't resolve all parameters for NonAnnotatedService: (?).`);
         }));

      it('should throw with descriptive error message when one of providers is not present',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           expect(() => resolver.getDirectiveMetadata(MyBrokenComp3))
               .toThrowError(
                   `One or more of providers for "MyBrokenComp3" were not defined: [?, SimpleService, ?].`);
         }));

      it('should throw with descriptive error message when one of viewProviders is not present',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           expect(() => resolver.getDirectiveMetadata(MyBrokenComp4))
               .toThrowError(
                   `One or more of viewProviders for "MyBrokenComp4" were not defined: [?, SimpleService, ?].`);
         }));

      it('should throw an error when the interpolation config has invalid symbols',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           expect(() => resolver.getDirectiveMetadata(ComponentWithInvalidInterpolation1))
               .toThrowError(`[' ', ' '] contains unusable interpolation symbol.`);
           expect(() => resolver.getDirectiveMetadata(ComponentWithInvalidInterpolation2))
               .toThrowError(`['{', '}'] contains unusable interpolation symbol.`);
           expect(() => resolver.getDirectiveMetadata(ComponentWithInvalidInterpolation3))
               .toThrowError(`['<%', '%>'] contains unusable interpolation symbol.`);
           expect(() => resolver.getDirectiveMetadata(ComponentWithInvalidInterpolation4))
               .toThrowError(`['&#', '}}'] contains unusable interpolation symbol.`);
           expect(() => resolver.getDirectiveMetadata(ComponentWithInvalidInterpolation5))
               .toThrowError(`['&lbrace;', '}}'] contains unusable interpolation symbol.`);
         }));
    });

    describe('getViewDirectivesMetadata', () => {

      it('should return the directive metadatas',
         inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
           expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
               .toContain(resolver.getDirectiveMetadata(SomeDirective));
         }));

      describe('platform directives', () => {
        beforeEach(() => {
          configureCompiler({
            providers: [{
              provide: CompilerConfig,
              useValue:
                  new CompilerConfig({genDebugInfo: true, platformDirectives: [ADirective]})
            }]
          });
        });

        it('should include platform directives when available',
           inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
             expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
                 .toContain(resolver.getDirectiveMetadata(ADirective));
             expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
                 .toContain(resolver.getDirectiveMetadata(SomeDirective));
           }));
      });
    });

  });
Ejemplo n.º 4
0
    describe('disable() & enable()', () => {
      let a: FormArray;
      let c: FormControl;
      let c2: FormControl;

      beforeEach(() => {
        c = new FormControl(null);
        c2 = new FormControl(null);
        a = new FormArray([c, c2]);
      });

      it('should mark the array as disabled', () => {
        expect(a.disabled).toBe(false);
        expect(a.valid).toBe(true);

        a.disable();
        expect(a.disabled).toBe(true);
        expect(a.valid).toBe(false);

        a.enable();
        expect(a.disabled).toBe(false);
        expect(a.valid).toBe(true);
      });

      it('should set the array status as disabled', () => {
        expect(a.status).toBe('VALID');

        a.disable();
        expect(a.status).toBe('DISABLED');

        a.enable();
        expect(a.status).toBe('VALID');
      });

      it('should mark children of the array as disabled', () => {
        expect(c.disabled).toBe(false);
        expect(c2.disabled).toBe(false);

        a.disable();
        expect(c.disabled).toBe(true);
        expect(c2.disabled).toBe(true);

        a.enable();
        expect(c.disabled).toBe(false);
        expect(c2.disabled).toBe(false);
      });

      it('should ignore disabled controls in validation', () => {
        const g = new FormGroup({
          nested: new FormArray([new FormControl(null, Validators.required)]),
          two: new FormControl('two')
        });
        expect(g.valid).toBe(false);

        g.get('nested').disable();
        expect(g.valid).toBe(true);

        g.get('nested').enable();
        expect(g.valid).toBe(false);
      });

      it('should ignore disabled controls when serializing value', () => {
        const g = new FormGroup(
            {nested: new FormArray([new FormControl('one')]), two: new FormControl('two')});
        expect(g.value).toEqual({'nested': ['one'], 'two': 'two'});

        g.get('nested').disable();
        expect(g.value).toEqual({'two': 'two'});

        g.get('nested').enable();
        expect(g.value).toEqual({'nested': ['one'], 'two': 'two'});
      });

      it('should ignore disabled controls when determining dirtiness', () => {
        const g = new FormGroup({nested: a, two: new FormControl('two')});
        g.get(['nested', 0]).markAsDirty();
        expect(g.dirty).toBe(true);

        g.get('nested').disable();
        expect(g.get('nested').dirty).toBe(true);
        expect(g.dirty).toEqual(false);

        g.get('nested').enable();
        expect(g.dirty).toEqual(true);
      });

      it('should ignore disabled controls when determining touched state', () => {
        const g = new FormGroup({nested: a, two: new FormControl('two')});
        g.get(['nested', 0]).markAsTouched();
        expect(g.touched).toBe(true);

        g.get('nested').disable();
        expect(g.get('nested').touched).toBe(true);
        expect(g.touched).toEqual(false);

        g.get('nested').enable();
        expect(g.touched).toEqual(true);
      });

      it('should keep empty, disabled arrays disabled when updating validity', () => {
        const arr = new FormArray([]);
        expect(arr.status).toEqual('VALID');

        arr.disable();
        expect(arr.status).toEqual('DISABLED');

        arr.updateValueAndValidity();
        expect(arr.status).toEqual('DISABLED');

        arr.push(new FormControl({value: '', disabled: true}));
        expect(arr.status).toEqual('DISABLED');

        arr.push(new FormControl());
        expect(arr.status).toEqual('VALID');
      });

      it('should re-enable empty, disabled arrays', () => {
        const arr = new FormArray([]);
        arr.disable();
        expect(arr.status).toEqual('DISABLED');

        arr.enable();
        expect(arr.status).toEqual('VALID');
      });

      it('should not run validators on disabled controls', () => {
        const validator = jasmine.createSpy('validator');
        const arr = new FormArray([new FormControl()], validator);
        expect(validator.calls.count()).toEqual(1);

        arr.disable();
        expect(validator.calls.count()).toEqual(1);

        arr.setValue(['value']);
        expect(validator.calls.count()).toEqual(1);

        arr.enable();
        expect(validator.calls.count()).toEqual(2);
      });

      describe('disabled errors', () => {
        it('should clear out array errors when disabled', () => {
          const arr = new FormArray([new FormControl()], () => ({'expected': true}));
          expect(arr.errors).toEqual({'expected': true});

          arr.disable();
          expect(arr.errors).toEqual(null);

          arr.enable();
          expect(arr.errors).toEqual({'expected': true});
        });

        it('should re-populate array errors when enabled from a child', () => {
          const arr = new FormArray([new FormControl()], () => ({'expected': true}));
          arr.disable();
          expect(arr.errors).toEqual(null);

          arr.push(new FormControl());
          expect(arr.errors).toEqual({'expected': true});
        });

        it('should clear out async array errors when disabled', fakeAsync(() => {
             const arr = new FormArray([new FormControl()], null, asyncValidator('expected'));
             tick();
             expect(arr.errors).toEqual({'async': true});

             arr.disable();
             expect(arr.errors).toEqual(null);

             arr.enable();
             tick();
             expect(arr.errors).toEqual({'async': true});
           }));

        it('should re-populate async array errors when enabled from a child', fakeAsync(() => {
             const arr = new FormArray([new FormControl()], null, asyncValidator('expected'));
             tick();
             expect(arr.errors).toEqual({'async': true});

             arr.disable();
             expect(arr.errors).toEqual(null);

             arr.push(new FormControl());
             tick();
             expect(arr.errors).toEqual({'async': true});
           }));
      });

      describe('disabled events', () => {
        let logger: string[];
        let c: FormControl;
        let a: FormArray;
        let form: FormGroup;

        beforeEach(() => {
          logger = [];
          c = new FormControl('', Validators.required);
          a = new FormArray([c]);
          form = new FormGroup({a: a});
        });

        it('should emit value change events in the right order', () => {
          c.valueChanges.subscribe(() => logger.push('control'));
          a.valueChanges.subscribe(() => logger.push('array'));
          form.valueChanges.subscribe(() => logger.push('form'));

          a.disable();
          expect(logger).toEqual(['control', 'array', 'form']);
        });

        it('should emit status change events in the right order', () => {
          c.statusChanges.subscribe(() => logger.push('control'));
          a.statusChanges.subscribe(() => logger.push('array'));
          form.statusChanges.subscribe(() => logger.push('form'));

          a.disable();
          expect(logger).toEqual(['control', 'array', 'form']);
        });

      });

      describe('setControl()', () => {
        let c: FormControl;
        let a: FormArray;

        beforeEach(() => {
          c = new FormControl('one');
          a = new FormArray([c]);
        });

        it('should replace existing control with new control', () => {
          const c2 = new FormControl('new!', Validators.minLength(10));
          a.setControl(0, c2);

          expect(a.controls[0]).toEqual(c2);
          expect(a.value).toEqual(['new!']);
          expect(a.valid).toBe(false);
        });

        it('should add control if control did not exist before', () => {
          const c2 = new FormControl('new!', Validators.minLength(10));
          a.setControl(1, c2);

          expect(a.controls[1]).toEqual(c2);
          expect(a.value).toEqual(['one', 'new!']);
          expect(a.valid).toBe(false);
        });

        it('should remove control if new control is null', () => {
          a.setControl(0, null);
          expect(a.controls[0]).not.toBeDefined();
          expect(a.value).toEqual([]);
        });

        it('should only emit value change event once', () => {
          const logger: string[] = [];
          const c2 = new FormControl('new!');
          a.valueChanges.subscribe(() => logger.push('change!'));
          a.setControl(0, c2);
          expect(logger).toEqual(['change!']);
        });

      });

    });
Ejemplo n.º 5
0
  t.describe('HTML sanitizer', () => {
    let originalLog: (msg: any) => any = null;
    let logMsgs: string[];

    t.beforeEach(() => {
      logMsgs = [];
      originalLog = getDOM().log;  // Monkey patch DOM.log.
      getDOM().log = (msg) => logMsgs.push(msg);
    });
    t.afterEach(() => { getDOM().log = originalLog; });

    t.it('serializes nested structures', () => {
      t.expect(sanitizeHtml('<div alt="x"><p>a</p>b<b>c<a alt="more">d</a></b>e</div>'))
          .toEqual('<div alt="x"><p>a</p>b<b>c<a alt="more">d</a></b>e</div>');
      t.expect(logMsgs).toEqual([]);
    });
    t.it('serializes self closing elements', () => {
      t.expect(sanitizeHtml('<p>Hello <br> World</p>')).toEqual('<p>Hello <br> World</p>');
    });
    t.it('supports namespaced elements', () => {
      t.expect(sanitizeHtml('a<my:hr/><my:div>b</my:div>c')).toEqual('abc');
    });
    t.it('supports namespaced attributes', () => {
      t.expect(sanitizeHtml('<a xlink:href="something">t</a>'))
          .toEqual('<a xlink:href="something">t</a>');
      t.expect(sanitizeHtml('<a xlink:evil="something">t</a>')).toEqual('<a>t</a>');
      t.expect(sanitizeHtml('<a xlink:href="javascript:foo()">t</a>'))
          .toEqual('<a xlink:href="unsafe:javascript:foo()">t</a>');
    });

    t.it('supports sanitizing plain text', () => {
      t.expect(sanitizeHtml('Hello, World')).toEqual('Hello, World');
    });
    t.it('ignores non-element, non-attribute nodes', () => {
      t.expect(sanitizeHtml('<!-- comments? -->no.')).toEqual('no.');
      t.expect(sanitizeHtml('<?pi nodes?>no.')).toEqual('no.');
      t.expect(logMsgs.join('\n')).toMatch(/sanitizing HTML stripped some content/);
    });
    t.it('escapes entities', () => {
      t.expect(sanitizeHtml('<p>Hello &lt; World</p>')).toEqual('<p>Hello &lt; World</p>');
      t.expect(sanitizeHtml('<p>Hello < World</p>')).toEqual('<p>Hello &lt; World</p>');
      t.expect(sanitizeHtml('<p alt="% &amp; &quot; !">Hello</p>'))
          .toEqual('<p alt="% &amp; &#34; !">Hello</p>');  // NB: quote encoded as ASCII &#34;.
    });
    t.describe('should strip dangerous elements', () => {
      let dangerousTags = [
        'frameset', 'form', 'param', 'object', 'embed', 'textarea', 'input', 'button', 'option',
        'select', 'script', 'style', 'link', 'base', 'basefont'
      ];

      for (let tag of dangerousTags) {
        t.it(
            `${tag}`, () => { t.expect(sanitizeHtml(`<${tag}>evil!</${tag}>`)).toEqual('evil!'); });
      }
      t.it(`swallows frame entirely`, () => {
        t.expect(sanitizeHtml(`<frame>evil!</frame>`)).not.toContain('<frame>');
      });
    });
    t.describe('should strip dangerous attributes', () => {
      let dangerousAttrs = ['id', 'name', 'style'];

      for (let attr of dangerousAttrs) {
        t.it(`${attr}`, () => {
          t.expect(sanitizeHtml(`<a ${attr}="x">evil!</a>`)).toEqual('<a>evil!</a>');
        });
      }
    });

    if (browserDetection.isWebkit) {
      t.it('should prevent mXSS attacks', function() {
        t.expect(sanitizeHtml('<a href="&#x3000;javascript:alert(1)">CLICKME</a>'))
            .toEqual('<a href="unsafe:javascript:alert(1)">CLICKME</a>');
      });
    }
  });
    describe('trackBy function by id', function() {
      var differ: any /** TODO #9100 */;

      var trackByItemId = (index: number, item: any): any => item.id;

      var buildItemList =
          (list: string[]) => { return list.map((val) => { return new ItemWithId(val); }); };

      beforeEach(() => { differ = new DefaultIterableDiffer(trackByItemId); });

      it('should treat the collection as dirty if identity changes', () => {
        differ.diff(buildItemList(['a']));
        expect(differ.diff(buildItemList(['a']))).toBe(differ);
      });

      it('should treat seen records as identity changes, not additions', () => {
        let l = buildItemList(['a', 'b', 'c']);
        differ.check(l);
        expect(differ.toString()).toEqual(iterableChangesAsString({
          collection: [`{id: a}[null->0]`, `{id: b}[null->1]`, `{id: c}[null->2]`],
          additions: [`{id: a}[null->0]`, `{id: b}[null->1]`, `{id: c}[null->2]`]
        }));

        l = buildItemList(['a', 'b', 'c']);
        differ.check(l);
        expect(differ.toString()).toEqual(iterableChangesAsString({
          collection: [`{id: a}`, `{id: b}`, `{id: c}`],
          identityChanges: [`{id: a}`, `{id: b}`, `{id: c}`],
          previous: [`{id: a}`, `{id: b}`, `{id: c}`]
        }));
      });

      it('should have updated properties in identity change collection', () => {
        let l = [new ComplexItem('a', 'blue'), new ComplexItem('b', 'yellow')];
        differ.check(l);

        l = [new ComplexItem('a', 'orange'), new ComplexItem('b', 'red')];
        differ.check(l);
        expect(differ.toString()).toEqual(iterableChangesAsString({
          collection: [`{id: a, color: orange}`, `{id: b, color: red}`],
          identityChanges: [`{id: a, color: orange}`, `{id: b, color: red}`],
          previous: [`{id: a, color: orange}`, `{id: b, color: red}`]
        }));
      });

      it('should track moves normally', () => {
        let l = buildItemList(['a', 'b', 'c']);
        differ.check(l);

        l = buildItemList(['b', 'a', 'c']);
        differ.check(l);
        expect(differ.toString()).toEqual(iterableChangesAsString({
          collection: ['{id: b}[1->0]', '{id: a}[0->1]', '{id: c}'],
          identityChanges: ['{id: b}[1->0]', '{id: a}[0->1]', '{id: c}'],
          previous: ['{id: a}[0->1]', '{id: b}[1->0]', '{id: c}'],
          moves: ['{id: b}[1->0]', '{id: a}[0->1]']
        }));

      });

      it('should track duplicate reinsertion normally', () => {
        let l = buildItemList(['a', 'a']);
        differ.check(l);

        l = buildItemList(['b', 'a', 'a']);
        differ.check(l);
        expect(differ.toString()).toEqual(iterableChangesAsString({
          collection: ['{id: b}[null->0]', '{id: a}[0->1]', '{id: a}[1->2]'],
          identityChanges: ['{id: a}[0->1]', '{id: a}[1->2]'],
          previous: ['{id: a}[0->1]', '{id: a}[1->2]'],
          moves: ['{id: a}[0->1]', '{id: a}[1->2]'],
          additions: ['{id: b}[null->0]']
        }));

      });

      it('should track removals normally', () => {
        let l = buildItemList(['a', 'b', 'c']);
        differ.check(l);

        ListWrapper.removeAt(l, 2);
        differ.check(l);
        expect(differ.toString()).toEqual(iterableChangesAsString({
          collection: ['{id: a}', '{id: b}'],
          previous: ['{id: a}', '{id: b}', '{id: c}[2->null]'],
          removals: ['{id: c}[2->null]']
        }));
      });
    });
Ejemplo n.º 7
0
    describe('reset()', () => {
      let c: FormControl, c2: FormControl, a: FormArray;

      beforeEach(() => {
        c = new FormControl('initial value');
        c2 = new FormControl('');
        a = new FormArray([c, c2]);
      });

      it('should set its own value if value passed', () => {
        a.setValue(['new value', 'new value']);

        a.reset(['initial value', '']);
        expect(a.value).toEqual(['initial value', '']);
      });

      it('should not update the parent when explicitly specified', () => {
        const form = new FormGroup({'a': a});
        a.reset(['one', 'two'], {onlySelf: true});

        expect(form.value).toEqual({a: ['initial value', '']});
      });

      it('should set its own value if boxed value passed', () => {
        a.setValue(['new value', 'new value']);

        a.reset([{value: 'initial value', disabled: false}, '']);
        expect(a.value).toEqual(['initial value', '']);
      });

      it('should clear its own value if no value passed', () => {
        a.setValue(['new value', 'new value']);

        a.reset();
        expect(a.value).toEqual([null, null]);
      });

      it('should set the value of each of its child controls if value passed', () => {
        a.setValue(['new value', 'new value']);

        a.reset(['initial value', '']);
        expect(c.value).toBe('initial value');
        expect(c2.value).toBe('');
      });

      it('should clear the value of each of its child controls if no value', () => {
        a.setValue(['new value', 'new value']);

        a.reset();
        expect(c.value).toBe(null);
        expect(c2.value).toBe(null);
      });

      it('should set the value of its parent if value passed', () => {
        const form = new FormGroup({'a': a});
        a.setValue(['new value', 'new value']);

        a.reset(['initial value', '']);
        expect(form.value).toEqual({'a': ['initial value', '']});
      });

      it('should clear the value of its parent if no value passed', () => {
        const form = new FormGroup({'a': a});
        a.setValue(['new value', 'new value']);

        a.reset();
        expect(form.value).toEqual({'a': [null, null]});
      });

      it('should mark itself as pristine', () => {
        a.markAsDirty();
        expect(a.pristine).toBe(false);

        a.reset();
        expect(a.pristine).toBe(true);
      });

      it('should mark all child controls as pristine', () => {
        c.markAsDirty();
        c2.markAsDirty();
        expect(c.pristine).toBe(false);
        expect(c2.pristine).toBe(false);

        a.reset();
        expect(c.pristine).toBe(true);
        expect(c2.pristine).toBe(true);
      });

      it('should mark the parent as pristine if all siblings pristine', () => {
        const c3 = new FormControl('');
        const form = new FormGroup({'a': a, 'c3': c3});

        a.markAsDirty();
        expect(form.pristine).toBe(false);

        a.reset();
        expect(form.pristine).toBe(true);
      });

      it('should not mark the parent pristine if any dirty siblings', () => {
        const c3 = new FormControl('');
        const form = new FormGroup({'a': a, 'c3': c3});

        a.markAsDirty();
        c3.markAsDirty();
        expect(form.pristine).toBe(false);

        a.reset();
        expect(form.pristine).toBe(false);
      });

      it('should mark itself as untouched', () => {
        a.markAsTouched();
        expect(a.untouched).toBe(false);

        a.reset();
        expect(a.untouched).toBe(true);
      });

      it('should mark all child controls as untouched', () => {
        c.markAsTouched();
        c2.markAsTouched();
        expect(c.untouched).toBe(false);
        expect(c2.untouched).toBe(false);

        a.reset();
        expect(c.untouched).toBe(true);
        expect(c2.untouched).toBe(true);
      });

      it('should mark the parent untouched if all siblings untouched', () => {
        const c3 = new FormControl('');
        const form = new FormGroup({'a': a, 'c3': c3});

        a.markAsTouched();
        expect(form.untouched).toBe(false);

        a.reset();
        expect(form.untouched).toBe(true);
      });

      it('should not mark the parent untouched if any touched siblings', () => {
        const c3 = new FormControl('');
        const form = new FormGroup({'a': a, 'c3': c3});

        a.markAsTouched();
        c3.markAsTouched();
        expect(form.untouched).toBe(false);

        a.reset();
        expect(form.untouched).toBe(false);
      });

      it('should retain previous disabled state', () => {
        a.disable();
        a.reset();

        expect(a.disabled).toBe(true);
      });

      it('should set child disabled state if boxed value passed', () => {
        a.disable();
        a.reset([{value: '', disabled: false}, '']);

        expect(c.disabled).toBe(false);
        expect(a.disabled).toBe(false);
      });


      describe('reset() events', () => {
        let form: FormGroup, c3: FormControl, logger: any[];

        beforeEach(() => {
          c3 = new FormControl('');
          form = new FormGroup({'a': a, 'c3': c3});
          logger = [];
        });

        it('should emit one valueChange event per reset control', () => {
          form.valueChanges.subscribe(() => logger.push('form'));
          a.valueChanges.subscribe(() => logger.push('array'));
          c.valueChanges.subscribe(() => logger.push('control1'));
          c2.valueChanges.subscribe(() => logger.push('control2'));
          c3.valueChanges.subscribe(() => logger.push('control3'));

          a.reset();
          expect(logger).toEqual(['control1', 'control2', 'array', 'form']);
        });

        it('should not fire an event when explicitly specified', fakeAsync(() => {
             form.valueChanges.subscribe((value) => { throw 'Should not happen'; });
             a.valueChanges.subscribe((value) => { throw 'Should not happen'; });
             c.valueChanges.subscribe((value) => { throw 'Should not happen'; });
             c2.valueChanges.subscribe((value) => { throw 'Should not happen'; });
             c3.valueChanges.subscribe((value) => { throw 'Should not happen'; });

             a.reset([], {emitEvent: false});
             tick();
           }));

        it('should emit one statusChange event per reset control', () => {
          form.statusChanges.subscribe(() => logger.push('form'));
          a.statusChanges.subscribe(() => logger.push('array'));
          c.statusChanges.subscribe(() => logger.push('control1'));
          c2.statusChanges.subscribe(() => logger.push('control2'));
          c3.statusChanges.subscribe(() => logger.push('control3'));

          a.reset();
          expect(logger).toEqual(['control1', 'control2', 'array', 'form']);
        });
      });
    });
    describe('DefaultKeyValueDiffer', function() {
      var differ: any /** TODO #9100 */;
      var m: Map<any, any>;

      beforeEach(() => {
        differ = new DefaultKeyValueDiffer();
        m = new Map();
      });

      afterEach(() => { differ = null; });

      it('should detect additions', () => {
        differ.check(m);

        m.set('a', 1);
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString({map: ['a[null->1]'], additions: ['a[null->1]']}));

        m.set('b', 2);
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString(
                {map: ['a', 'b[null->2]'], previous: ['a'], additions: ['b[null->2]']}));
      });

      it('should handle changing key/values correctly', () => {
        m.set(1, 10);
        m.set(2, 20);
        differ.check(m);

        m.set(2, 10);
        m.set(1, 20);
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString({
              map: ['1[10->20]', '2[20->10]'],
              previous: ['1[10->20]', '2[20->10]'],
              changes: ['1[10->20]', '2[20->10]']
            }));
      });

      it('should expose previous and current value', () => {
        var previous: any /** TODO #9100 */, current: any /** TODO #9100 */;

        m.set(1, 10);
        differ.check(m);

        m.set(1, 20);
        differ.check(m);

        differ.forEachChangedItem((record: any /** TODO #9100 */) => {
          previous = record.previousValue;
          current = record.currentValue;
        });

        expect(previous).toEqual(10);
        expect(current).toEqual(20);
      });

      it('should do basic map watching', () => {
        differ.check(m);

        m.set('a', 'A');
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString({map: ['a[null->A]'], additions: ['a[null->A]']}));

        m.set('b', 'B');
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString(
                {map: ['a', 'b[null->B]'], previous: ['a'], additions: ['b[null->B]']}));

        m.set('b', 'BB');
        m.set('d', 'D');
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString({
              map: ['a', 'b[B->BB]', 'd[null->D]'],
              previous: ['a', 'b[B->BB]'],
              additions: ['d[null->D]'],
              changes: ['b[B->BB]']
            }));

        m.delete('b');
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString(
                {map: ['a', 'd'], previous: ['a', 'b[BB->null]', 'd'], removals: ['b[BB->null]']}));

        m.clear();
        differ.check(m);
        expect(differ.toString())
            .toEqual(kvChangesAsString(
                {previous: ['a[A->null]', 'd[D->null]'], removals: ['a[A->null]', 'd[D->null]']}));
      });

      it('should test string by value rather than by reference (DART)', () => {
        m.set('foo', 'bar');
        differ.check(m);

        var f = 'f';
        var oo = 'oo';
        var b = 'b';
        var ar = 'ar';

        m.set(f + oo, b + ar);
        differ.check(m);

        expect(differ.toString()).toEqual(kvChangesAsString({map: ['foo'], previous: ['foo']}));
      });

      it('should not see a NaN value as a change (JS)', () => {
        m.set('foo', NumberWrapper.NaN);
        differ.check(m);

        differ.check(m);
        expect(differ.toString()).toEqual(kvChangesAsString({map: ['foo'], previous: ['foo']}));
      });

      // JS specific tests (JS Objects)
      if (isJsObject({})) {
        describe('JsObject changes', () => {
          it('should support JS Object', () => {
            var f = new DefaultKeyValueDifferFactory();
            expect(f.supports({})).toBeTruthy();
            expect(f.supports("not supported")).toBeFalsy();
            expect(f.supports(0)).toBeFalsy();
            expect(f.supports(null)).toBeFalsy();
          });

          it('should do basic object watching', () => {
            let m = {};
            differ.check(m);

            (m as any /** TODO #9100 */)['a'] = 'A';
            differ.check(m);
            expect(differ.toString())
                .toEqual(kvChangesAsString({map: ['a[null->A]'], additions: ['a[null->A]']}));

            (m as any /** TODO #9100 */)['b'] = 'B';
            differ.check(m);
            expect(differ.toString())
                .toEqual(kvChangesAsString(
                    {map: ['a', 'b[null->B]'], previous: ['a'], additions: ['b[null->B]']}));

            (m as any /** TODO #9100 */)['b'] = 'BB';
            (m as any /** TODO #9100 */)['d'] = 'D';
            differ.check(m);
            expect(differ.toString())
                .toEqual(kvChangesAsString({
                  map: ['a', 'b[B->BB]', 'd[null->D]'],
                  previous: ['a', 'b[B->BB]'],
                  additions: ['d[null->D]'],
                  changes: ['b[B->BB]']
                }));

            m = {};
            (m as any /** TODO #9100 */)['a'] = 'A';
            (m as any /** TODO #9100 */)['d'] = 'D';
            differ.check(m);
            expect(differ.toString())
                .toEqual(kvChangesAsString({
                  map: ['a', 'd'],
                  previous: ['a', 'b[BB->null]', 'd'],
                  removals: ['b[BB->null]']
                }));

            m = {};
            differ.check(m);
            expect(differ.toString())
                .toEqual(kvChangesAsString({
                  previous: ['a[A->null]', 'd[D->null]'],
                  removals: ['a[A->null]', 'd[D->null]']
                }));
          });
        });

        describe('diff', () => {
          it('should return self when there is a change', () => {
            m.set('a', 'A');
            expect(differ.diff(m)).toBe(differ);
          });

          it('should return null when there is no change', () => {
            m.set('a', 'A');
            differ.diff(m);
            expect(differ.diff(m)).toEqual(null);
          });

          it('should treat null as an empty list', () => {
            m.set('a', 'A');
            differ.diff(m);
            expect(differ.diff(null).toString())
                .toEqual(kvChangesAsString({previous: ['a[A->null]'], removals: ['a[A->null]']}));
          });

          it('should throw when given an invalid collection', () => {
            expect(() => differ.diff("invalid")).toThrowErrorWith("Error trying to diff 'invalid'");
          });
        });
      }
    });
Ejemplo n.º 9
0
  describe('DatePipe', () => {
    var date: Date;
    var pipe: DatePipe;

    // TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
    // In some old versions of Chrome in Android emulators, time formatting returns dates in the
    // timezone of the VM host,
    // instead of the device timezone. Same symptoms as
    // https://bugs.chromium.org/p/chromium/issues/detail?id=406382
    // This happens locally and in SauceLabs, so some checks are disabled to avoid failures.
    // Tracking issue: https://github.com/angular/angular/issues/11187

    beforeEach(() => {
      date = new Date(2015, 5, 15, 9, 3, 1);
      pipe = new DatePipe('en-US');
    });

    it('should be marked as pure',
       () => { expect(new PipeResolver().resolve(DatePipe).pure).toEqual(true); });

    describe('supports', () => {
      it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
      it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
      it('should support numeric strings',
         () => { expect(() => pipe.transform('123456789')).not.toThrow(); });

      it('should support decimal strings',
         () => { expect(() => pipe.transform('123456789.11')).not.toThrow(); });

      it('should support ISO string',
         () => { expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow(); });

      it('should not support other objects', () => {
        expect(() => pipe.transform({})).toThrow();
        expect(() => pipe.transform('')).toThrow();
      });
    });

    describe('transform', () => {
      it('should format each component correctly', () => {
        expect(pipe.transform(date, 'y')).toEqual('2015');
        expect(pipe.transform(date, 'yy')).toEqual('15');
        expect(pipe.transform(date, 'M')).toEqual('6');
        expect(pipe.transform(date, 'MM')).toEqual('06');
        expect(pipe.transform(date, 'MMM')).toEqual('Jun');
        expect(pipe.transform(date, 'MMMM')).toEqual('June');
        expect(pipe.transform(date, 'd')).toEqual('15');
        expect(pipe.transform(date, 'EEE')).toEqual('Mon');
        expect(pipe.transform(date, 'EEEE')).toEqual('Monday');
        if (!browserDetection.isOldChrome) {
          expect(pipe.transform(date, 'h')).toEqual('9');
          expect(pipe.transform(date, 'hh')).toEqual('09');
          expect(pipe.transform(date, 'j')).toEqual('9 AM');
        }
        // IE and Edge can't format a date to minutes and seconds without hours
        if (!browserDetection.isEdge && !browserDetection.isIE ||
            !browserDetection.supportsNativeIntlApi) {
          if (!browserDetection.isOldChrome) {
            expect(pipe.transform(date, 'HH')).toEqual('09');
          }

          expect(pipe.transform(date, 'E')).toEqual('M');
          expect(pipe.transform(date, 'L')).toEqual('J');
          expect(pipe.transform(date, 'm')).toEqual('3');
          expect(pipe.transform(date, 's')).toEqual('1');
          expect(pipe.transform(date, 'mm')).toEqual('03');
          expect(pipe.transform(date, 'ss')).toEqual('01');
        }
        expect(pipe.transform(date, 'Z')).toBeDefined();
      });

      it('should format common multi component patterns', () => {
        expect(pipe.transform(date, 'EEE, M/d/y')).toEqual('Mon, 6/15/2015');
        expect(pipe.transform(date, 'EEE, M/d')).toEqual('Mon, 6/15');
        expect(pipe.transform(date, 'MMM d')).toEqual('Jun 15');
        expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015');
        expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
        expect(pipe.transform(date, 'yMEEEd')).toEqual('20156Mon15');
        expect(pipe.transform(date, 'MEEEd')).toEqual('6Mon15');
        expect(pipe.transform(date, 'MMMd')).toEqual('Jun15');
        expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
        // IE and Edge can't format a date to minutes and seconds without hours
        if (!browserDetection.isEdge && !browserDetection.isIE ||
            !browserDetection.supportsNativeIntlApi) {
          expect(pipe.transform(date, 'ms')).toEqual('31');
        }
        if (!browserDetection.isOldChrome) {
          expect(pipe.transform(date, 'jm')).toEqual('9:03 AM');
        }
      });

      it('should format with pattern aliases', () => {
        if (!browserDetection.isOldChrome) {
          // IE and Edge do not add a coma after the year in these 2 cases
          if ((browserDetection.isEdge || browserDetection.isIE) &&
              browserDetection.supportsNativeIntlApi) {
            expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015 9:03:01 AM');
            expect(pipe.transform(date, 'short')).toEqual('6/15/2015 9:03 AM');
          } else {
            expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:03:01 AM');
            expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:03 AM');
          }
        }
        expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
        expect(pipe.transform(date, 'fullDate')).toEqual('Monday, June 15, 2015');
        expect(pipe.transform(date, 'longDate')).toEqual('June 15, 2015');
        expect(pipe.transform(date, 'mediumDate')).toEqual('Jun 15, 2015');
        expect(pipe.transform(date, 'shortDate')).toEqual('6/15/2015');
        if (!browserDetection.isOldChrome) {
          expect(pipe.transform(date, 'mediumTime')).toEqual('9:03:01 AM');
          expect(pipe.transform(date, 'shortTime')).toEqual('9:03 AM');
        }
      });

      it('should remove bidi control characters',
         () => { expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10); });
    });
  });
Ejemplo n.º 10
0
  describe('navigation', () => {

    var tcb: TestComponentBuilder;
    var fixture: ComponentFixture<any>;
    var rtr: any /** TODO #9100 */;

    beforeEachProviders(() => TEST_ROUTER_PROVIDERS);

    beforeEach(inject([TestComponentBuilder, Router], (tcBuilder: any /** TODO #9100 */, router: any /** TODO #9100 */) => {
      tcb = tcBuilder;
      rtr = router;
      childCmpInstanceCount = 0;
      cmpInstanceCount = 0;
    }));

    it('should work in a simple case', inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/test', component: HelloCmp})]))
             .then((_) => rtr.navigateByUrl('/test'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('hello');
               async.done();
             });
       }));


    it('should navigate between components with different parameters',
       inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/user/:name', component: UserCmp})]))
             .then((_) => rtr.navigateByUrl('/user/brian'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('hello brian');
             })
             .then((_) => rtr.navigateByUrl('/user/igor'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('hello igor');
               async.done();
             });
       }));

    it('should navigate to child routes', inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb, 'outer { <router-outlet></router-outlet> }')
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/a/...', component: ParentCmp})]))
             .then((_) => rtr.navigateByUrl('/a/b'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }');
               async.done();
             });
       }));

    it('should navigate to child routes that capture an empty path',
       inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {

         compile(tcb, 'outer { <router-outlet></router-outlet> }')
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/a/...', component: ParentCmp})]))
             .then((_) => rtr.navigateByUrl('/a'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }');
               async.done();
             });
       }));

    it('should navigate to child routes when the root component has an empty path',
       inject([AsyncTestCompleter, Location], (async: any /** TODO #9100 */, location: any /** TODO #9100 */) => {
         compile(tcb, 'outer { <router-outlet></router-outlet> }')
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/...', component: ParentCmp})]))
             .then((_) => rtr.navigateByUrl('/b'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }');
               expect(location.urlChanges).toEqual(['/b']);
               async.done();
             });
       }));

    it('should navigate to child routes of async routes', inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb, 'outer { <router-outlet></router-outlet> }')
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new AsyncRoute({path: '/a/...', loader: parentLoader})]))
             .then((_) => rtr.navigateByUrl('/a/b'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }');
               async.done();
             });
       }));


    it('should replace state when normalized paths are equal',
       inject([AsyncTestCompleter, Location], (async: any /** TODO #9100 */, location: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => location.setInitialPath("/test/"))
             .then((_) => rtr.config([new Route({path: '/test', component: HelloCmp})]))
             .then((_) => rtr.navigateByUrl('/test'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('hello');
               expect(location.urlChanges).toEqual(['replace: /test']);
               async.done();
             });
       }));

    it('should reuse common parent components', inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/team/:id/...', component: TeamCmp})]))
             .then((_) => rtr.navigateByUrl('/team/angular/user/rado'))
             .then((_) => {
               fixture.detectChanges();
               expect(cmpInstanceCount).toBe(1);
               expect(fixture.debugElement.nativeElement).toHaveText('team angular { hello rado }');
             })
             .then((_) => rtr.navigateByUrl('/team/angular/user/victor'))
             .then((_) => {
               fixture.detectChanges();
               expect(cmpInstanceCount).toBe(1);
               expect(fixture.debugElement.nativeElement)
                   .toHaveText('team angular { hello victor }');
               async.done();
             });
       }));

    it('should not reuse children when parent components change',
       inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/team/:id/...', component: TeamCmp})]))
             .then((_) => rtr.navigateByUrl('/team/angular/user/rado'))
             .then((_) => {
               fixture.detectChanges();
               expect(cmpInstanceCount).toBe(1);
               expect(childCmpInstanceCount).toBe(1);
               expect(fixture.debugElement.nativeElement).toHaveText('team angular { hello rado }');
             })
             .then((_) => rtr.navigateByUrl('/team/dart/user/rado'))
             .then((_) => {
               fixture.detectChanges();
               expect(cmpInstanceCount).toBe(2);
               expect(childCmpInstanceCount).toBe(2);
               expect(fixture.debugElement.nativeElement).toHaveText('team dart { hello rado }');
               async.done();
             });
       }));

    it('should inject route data into component', inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([
               new Route({path: '/route-data', component: RouteDataCmp, data: {isAdmin: true}})
             ]))
             .then((_) => rtr.navigateByUrl('/route-data'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('true');
               async.done();
             });
       }));

    it('should inject route data into component with AsyncRoute',
       inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([
               new AsyncRoute(
                   {path: '/route-data', loader: asyncRouteDataCmp, data: {isAdmin: true}})
             ]))
             .then((_) => rtr.navigateByUrl('/route-data'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('true');
               async.done();
             });
       }));

    it('should inject empty object if the route has no data property',
       inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb)
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config(
                       [new Route({path: '/route-data-default', component: RouteDataCmp})]))
             .then((_) => rtr.navigateByUrl('/route-data-default'))
             .then((_) => {
               fixture.detectChanges();
               expect(fixture.debugElement.nativeElement).toHaveText('');
               async.done();
             });
       }));

    it('should fire an event for each activated component',
       inject([AsyncTestCompleter], (async: any /** TODO #9100 */) => {
         compile(tcb, '<router-outlet (activate)="activatedCmp = $event"></router-outlet>')
             .then((rtc) => {fixture = rtc})
             .then((_) => rtr.config([new Route({path: '/test', component: HelloCmp})]))
             .then((_) => rtr.navigateByUrl('/test'))
             .then((_) => {
               // Note: need a timeout so that all promises are flushed
               var completer = PromiseWrapper.completer();
               TimerWrapper.setTimeout(() => { completer.resolve(null); }, 0);
               return completer.promise;
             })
             .then((_) => {
               expect(fixture.componentInstance.activatedCmp).toBeAnInstanceOf(HelloCmp);
               async.done();
             });
       }));
  });