anchor.diff:  
     Element makeListElement() =>
       new Element.html('<ul class="foo bar baz">'
  -        '<li class="quux qux"><li class="meta">'
  -        '<li class="classy lassy"><li class="qux lassy"></ul>');
  +        '<li class="quux qux">'
  +        '<li class="meta">'
  +        '<li class="classy lassy">'
  +        '<li class="qux lassy">'
  +        '</ul>');
   
     Set<String> makeClassSet() => makeElementWithClasses().classes;
   
     Set<String> extractClasses(Element el) {
       final match = new RegExp('class="([^"]+)"').firstMatch(el.outerHtml);
       return new LinkedHashSet.from(match[1].split(' '));
  +  }
  +
  +  /// Returns a canonical string for Set<String> and lists of Element's classes.
  +  String view(var e) {
  +    if (e is Set) return '${e.toList()..sort()}';
  +    if (e is Element) return view(e.classes);
  +    if (e is Iterable) return '${e.map(view).toList()}';
  +    throw new ArgumentError('Cannot make canonical view string for: $e}');
     }
   
     test('affects the "class" attribute', () {
  
positive.code:     var added = elements.classes.add('lassie');
      expect(added, isNull);
  
      expect(elements.classes,
          unorderedEquals(['lassie', 'qux', 'quux', 'meta', 'classy', 'lassy']));
      for (Element e in elements) {
        expect(e.classes, anyOf(unorderedEquals(['quux', 'qux', 'lassie']),
            unorderedEquals(['meta', 'lassie']),
            unorderedEquals(['classy', 'lassy', 'lassie']),
            unorderedEquals(['qux', 'lassy', 'lassie'])));
      }
      document.documentElement.children.remove(listElement);
    });
  
    test('listRemove', () {
      var elements = listElementSetup();
      expect(elements.classes.remove('lassi'), isFalse);
      expect(elements.classes,
          unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy']));
      for (Element e in elements) {
        expect(e.classes, anyOf(unorderedEquals(['quux', 'qux']),
            unorderedEquals(['meta']), unorderedEquals(['classy', 'lassy']),
            unorderedEquals(['qux', 'lassy'])));
      }
  
      expect(elements.classes.remove('qux'), isTrue);
      expect(elements.classes,
          unorderedEquals(['quux', 'meta', 'classy', 'lassy']));
      for (Element e in elements) {
        expect(e.classes, anyOf(unorderedEquals(['quux']),
            unorderedEquals(['meta']), unorderedEquals(['classy', 'lassy']),
            unorderedEquals(['lassy'])));
      }
      document.documentElement.children.remove(listElement);
    });
  
    test('listToggle', () {
      var elements = listElementSetup();
      elements.classes.toggle('qux');
      expect(elements.classes,
          unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy']));
      for (Element e in elements) {
        expect(e.classes, anyOf(unorderedEquals(['quux']),
            unorderedEquals(['meta', 'qux']), unorderedEquals(['classy', 'lassy',
            'qux']), unorderedEquals(['lassy'])));
      }
      document.documentElement.children.remove(listElement);
    });
  
    test('listAddAll', () {
      var elements = listElementSetup();
      elements.classes.addAll(['qux', 'lassi', 'sassy']);
      expect(elements.classes,
          unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy', 'sassy',
          'lassi']));
      for (Element e in elements) {
        expect(e.classes, anyOf(
            unorderedEquals(['quux', 'qux', 'lassi', 'sassy']),
            unorderedEquals(['meta', 'qux', 'lassi', 'sassy']),
            unorderedEquals(['classy', 'lassy', 'qux', 'lassi','sassy']),
            unorderedEquals(['lassy', 'qux', 'lassi', 'sassy'])));
      }
      document.documentElement.children.remove(listElement);
    });
  
    test('listRemoveAll', () {
      var elements = listElementSetup();
      elements.classes.removeAll(['qux', 'lassy', 'meta']);
      expect(elements.classes,
          unorderedEquals(['quux','classy']));
      for (Element e in elements) {
        expect(e.classes, anyOf(unorderedEquals(['quux']),
            unorderedEquals([]), unorderedEquals(['classy'])));
      }
      document.documentElement.children.remove(listElement);
    });
  
    test('listToggleAll', () {
      var elements = listElementSetup();
      elements.classes.toggleAll(['qux', 'meta', 'mornin']);
      expect(elements.classes,
          unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy', 'mornin']));
      for (Element e in elements) {
        expect(e.classes, anyOf(unorderedEquals(['quux', 'meta', 'mornin']),
            unorderedEquals(['qux', 'mornin']),
            unorderedEquals(['classy', 'lassy', 'qux', 'mornin', 'meta']),
            unorderedEquals(['lassy', 'mornin', 'meta'])));
      }
      document.documentElement.children.remove(listElement);
    });
  
    test('listContainsAll', () {
      var elements = listElementSetup();
      expect(elements.classes.containsAll(['qux', 'meta', 'mornin']), isFalse);
      expect(elements.classes.containsAll(['qux', 'lassy', 'classy']), isTrue);
      document.documentElement.children.remove(listElement);
    });
  }
  
negative.code:     expect(classes, orderedEquals(['qux','bar', 'foo']));
    });
  
    test('retainAll', () {
      final classes = makeClassSet();
      classes.retainAll(['bar', 'baz', 'qux']);
      expect(classes, orderedEquals(['bar', 'baz']));
    });
  
    test('removeWhere', () {
      final classes = makeClassSet();
      classes.removeWhere((s) => s.startsWith('b'));
      expect(classes, orderedEquals(['foo']));
    });
  
    test('retainWhere', () {
      final classes = makeClassSet();
      classes.retainWhere((s) => s.startsWith('b'));
      expect(classes, orderedEquals(['bar', 'baz']));
    });
  
    test('containsAll', () {
      final classes = makeClassSet();
      expect(classes.containsAll(['foo', 'baz']), isTrue);
      expect(classes.containsAll(['foo', 'qux']), isFalse);
      expect(classes.containsAll(['foo', 'baz'].toSet()), isTrue);
      expect(classes.containsAll(['foo', 'qux'].toSet()), isFalse);
    });
  