anchor.diff:      invocations.add('created');
     }
   
  +  void attached() {
  +    invocations.add('attached');
  +  }
  +
     void enteredView() {
  -    invocations.add('entered');
  +    // Deprecated name. Should never be called since we override "attached".
  +    invocations.add('enteredView');
  +  }
  +
  +  void detached() {
  +    invocations.add('detached');
     }
   
     void leftView() {
  -    invocations.add('left');
  +    // Deprecated name. Should never be called since we override "detached".
  +    invocations.add('leftView');
     }
   
     void attributeChanged(String name, String oldValue, String newValue) {
  
positive.code:     test('Entered document with a view', () {
        document.body.append(a);
        customElementsTakeRecords();
        expect(invocations, ['entered'],
            reason: 'entered callback should be invoked when entering a document '
            'with a view');
      });
  
      test('Left document with a view', () {
        a.remove();
        customElementsTakeRecords();
        expect(invocations, ['left'],
            reason: 'left callback should be invoked when leaving a document '
            'with a view');
      });
  
  
negative.code:       upgradeCustomElements(div);
  
        expect(invocations, ['created'],
            reason: 'the attached callback should not be invoked when inserted '
            'into a disconnected subtree');
      });
  
      test('Leaves a disconnected subtree of DOM', () {
        div.innerHtml = '';
        expect(invocations, [],
            reason: 'the detached callback should not be invoked when removed from a '
            'disconnected subtree');
      });
  
  