text: 'use strict';
  
  var tape = require('tape');
  var wrtc = require('..');
  
  var getUserMedia = wrtc.getUserMedia;
  var MediaStream = wrtc.MediaStream;
  var RTCPeerConnection = wrtc.RTCPeerConnection;
  var RTCSessionDescription = wrtc.RTCSessionDescription;
  
  var sdp = [
    'v=0',
    'o=- 0 1 IN IP4 0.0.0.0',
    's=-',
    't=0 0',
    'a=group:BUNDLE audio video',
    'a=msid-semantic:WMS *',
    'a=ice-ufrag:0000',
    'a=ice-pwd:0000000000000000000000',
    'a=fingerprint:sha-256 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00',
    'm=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 101',
    'c=IN IP4 0.0.0.0',
    'a=mid:audio',
    'a=sendrecv',
    'a=rtpmap:109 opus/48000/2',
    'a=rtpmap:9 G722/8000/1',
    'a=rtpmap:0 PCMU/8000',
    'a=rtpmap:8 PCMA/8000',
    'a=rtpmap:101 PCMA/16000',
    'a=rtcp-mux',
    'a=ssrc:1 cname:0',
    'a=ssrc:1 msid:stream 123',
    'm=video 9 UDP/TLS/RTP/SAVPF 120 121 126 97',
    'c=IN IP4 0.0.0.0',
    'a=mid:video',
    'a=sendrecv',
    'a=rtpmap:120 VP8/90000',
    'a=rtpmap:121 VP9/90000',
    'a=rtpmap:126 H264/90000',
    'a=rtpmap:97 H264/180000',
    'a=rtcp-mux',
    'a=ssrc:2 cname:0',
    'a=ssrc:2 msid:stream 456'
  ].join('\r\n') + '\r\n';
  
  tape('new MediaStream()', function(t) {
    var stream = new MediaStream();
    t.equal(stream.getTracks().length, 0, 'the MediaStream does not contain any MediaStreamTracks');
    t.end();
  });
  
  tape('new MediaStream(stream)', function(t) {
    return getRemoteMediaStream().then(function(stream1) {
      var stream2 = new MediaStream(stream1);
      t.notEqual(stream2.id, stream1.id, 'the MediaStream .ids do not match');
      t.ok(stream2.getTracks().every(function(track, i) {
        return track === stream1.getTracks()[i];
      }) && stream1.getTracks().every(function(track, i) {
        return track === stream2.getTracks()[i];
      }), 'the MediaStreams\' MediaStreamTracks are the same');
      t.end();
    });
  });
  
  tape('new MediaStream(tracks)', function(t) {
    return getRemoteMediaStream().then(function(stream1) {
      var tracks = stream1.getTracks();
      var stream2 = new MediaStream(tracks);
      t.ok(stream2.getTracks().every(function(track, i) {
        return track === tracks[i];
      }) && tracks.every(function(track, i) {
        return track === stream2.getTracks()[i];
      }), 'the MediaStream\'s MediaStreamTracks match tracks');
      t.end();
    });
  });
  
  tape('new MediaStream(mediaStreamInit)', function(t) {
    var stream = new MediaStream({ id: 'testStreamId' });
    t.equal(stream.getTracks().length, 0, 'the MediaStream does not contain any MediaStreamTracks');
    t.equal(stream.id, 'testStreamId', 'the MediaStream has the id we assigned to it');
    t.end();
  });
  
  tape('.clone', function(t) {
    return getRemoteMediaStream().then(function(stream1) {
      var stream2 = stream1.clone();
      var stream3 = stream2.clone();
      // NOTE(mroberts): Weirdly, cloned video MediaStreamTracks have .readyState
      // "live"; we'll .stop them, at least until that bug is fixed.
      // stream2.getVideoTracks().forEach(function(track) {
      stream2.getTracks().forEach(function(track) {
        track.stop();
      });
      // stream3.getVideoTracks().forEach(function(track) {
      stream3.getTracks().forEach(function(track) {
        track.stop();
      });
      t.ok(
        stream1.id !== stream2.id &&
        stream2.id !== stream3.id &&
        stream3.id !== stream1.id,
        'the cloned MediaStreams have different IDs');
      t.ok(
        stream1.getTracks().length === stream2.getTracks().length &&
        stream1.getTracks().length === stream3.getTracks().length,
        'the cloned MediaStreams contain the same number of MediaStreamTracks');
      t.ok(stream1.getTracks().every(function(track, i) {
        return track.kind === stream2.getTracks()[i].kind &&
          track.kind === stream3.getTracks()[i].kind;
      }), 'the cloned MediaStreams contain the same kinds of MediaStreamTracks');
      t.ok(stream1.getTracks().every(function(track, i) {
        return track.id !== stream2.getTracks()[i].id &&
          track.id !== stream3.getTracks()[i].id;
      }), 'the cloned MediaStreams\'s MediaStreamTracks do not have the same .ids');
      t.end();
    });
  });
  
  tape.skip('.clone and .stop', function(t) {
    getUserMedia({ audio: true }).then(function(stream1) {
      var track1 = stream1.getTracks()[0];
  
      t.ok(stream1.active, 'stream1 is active');
      t.equal(track1.readyState, 'live', 'track1 is live');
  
      var stream2 = stream1.clone();
      var track2 = stream2.getTracks()[0];
  
      t.ok(stream2.active, 'stream2 is active');
      t.equal(track2.readyState, 'live', 'track2 is live');
      t.notEqual(stream1, stream2, 'stream1 and stream2 are different');
      t.notEqual(track1, track2, 'track1 and track2 are different');
  
      track1.stop();
  
      t.ok(!stream1.active, 'stream1 is inactive');
      t.ok(stream2.active, 'stream2 is active');
      t.equal(track1.readyState, 'ended', 'track1 is ended');
      t.equal(track2.readyState, 'live', 'track2 is live');
  
      track2.stop();
  
      t.ok(!stream2.active, 'stream2 is inactive');
      t.equal(track2.readyState, 'ended', 'track2 is ended');
  
      t.end();
    });
  });
  
  tape('.removeTrack and .addTrack on remote MediaStream', function(t) {
    return getRemoteMediaStream().then(function(stream) {
      var tracks = stream.getTracks();
      tracks.forEach(function(track) {
        stream.removeTrack(track);
      });
      t.equal(stream.getTracks().length, 0, 'all MediaStreamTracks are removed');
      tracks.forEach(function(track) {
        stream.addTrack(track);
      });
      t.equal(stream.getTracks().length, tracks.length, 'all MediaStreamTracks are added back');
      t.ok(stream.getTracks().every(function(track, i) {
        return track === tracks[i];
      }), 'all MediaStreamTracks added back are the same (and in the same order)');
      t.end();
    });
  });
  
  function testSettingEnabled(t, stream) {
    const tracks = stream.getTracks();
  
    tracks.forEach(track => { track.enabled = false; });
    t.ok(tracks.every(track => !track.enabled),
      'enabled can initially be set to false on all MediaStreamTracks');
  
    tracks.forEach(track => { track.enabled = true; });
    t.ok(tracks.every(track => track.enabled),
      'enabled can then be set to true on all MediaStreamTracks');
  
    tracks.forEach(track => track.stop());
    t.ok(tracks.every(track => track.enabled),
      'enabled remains true for all MediaStreamTracks after stopping');
  
    tracks.forEach(track => { track.enabled = false; });
    t.ok(tracks.every(track => !track.enabled),
      'enabled can still be set on stopped MediaStreamTracks');
  
    t.end();
  }
  
  tape('.enabled on local MediaStreamTrack', t => {
    getLocalMediaStream().then(stream => testSettingEnabled(t, stream));
  });
  
  tape('.enabled on remote MediaStreamTrack', t => {
    getRemoteMediaStream().then(stream => testSettingEnabled(t, stream));
  });
  
  function getRemoteMediaStream() {
    var pc = new RTCPeerConnection();
    var offer = new RTCSessionDescription({ type: 'offer', sdp: sdp });
    var trackEventPromise = new Promise(function(resolve) {
      pc.ontrack = resolve;
    });
    return pc.setRemoteDescription(offer).then(function() {
      return trackEventPromise;
    }).then(function(trackEvent) {
      pc.close();
      return trackEvent.streams[0];
    });
  }
  
  function getLocalMediaStream() {
    return getUserMedia({ audio: true, video: true });
  }
  