UNPKG

@sports-alliance/sports-lib

Version:

A Library to for importing / exporting and processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc

2,033 lines 161 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const index_1 = require("../index");
const data_heart_rate_1 = require("../data/data.heart-rate");
const data_longitude_degrees_1 = require("../data/data.longitude-degrees");
const data_latitude_degrees_1 = require("../data/data.latitude-degrees");
const data_distance_1 = require("../data/data.distance");
const data_speed_1 = require("../data/data.speed");
const data_cadence_1 = require("../data/data.cadence");
const data_power_1 = require("../data/data.power");
const data_altitude_1 = require("../data/data.altitude");
const activity_types_1 = require("../activities/activity.types");
const data_ascent_1 = require("../data/data.ascent");
const spec_utils_1 = require("./spec-utils");
const data_timer_time_1 = require("../data/data.timer-time");
const data_pause_1 = require("../data/data.pause");
const data_energy_1 = require("../data/data.energy");
const data_heart_rate_avg_1 = require("../data/data.heart-rate-avg");
const data_cadence_max_1 = require("../data/data.cadence-max");
const data_power_avg_1 = require("../data/data.power-avg");
const data_cadence_avg_1 = require("../data/data.cadence-avg");
const data_speed_avg_1 = require("../data/data.speed-avg");
const data_power_max_1 = require("../data/data.power-max");
const data_descent_1 = require("../data/data.descent");
const data_heart_rate_max_1 = require("../data/data.heart-rate-max");
const data_pool_length_1 = require("../data/data.pool-length");
const data_total_cycles_1 = require("../data/data-total-cycles");
const data_active_lengths_1 = require("../data/data-active-lengths");
const data_pace_avg_1 = require("../data/data.pace-avg");
const data_temperature_avg_1 = require("../data/data.temperature-avg");
const data_moving_time_1 = require("../data/data.moving-time");
const data_elapsed_time_1 = require("../data/data.elapsed-time");
const xmldom_1 = __importDefault(require("@xmldom/xmldom"));
const data_grade_adjusted_pace_avg_1 = require("../data/data.grade-adjusted-pace-avg");
const data_grade_adjusted_speed_1 = require("../data/data.grade-adjusted-speed");
const data_active_lap_1 = require("../data/data-active-lap");
const data_swolf_25m_1 = require("../data/data.swolf-25m");
const data_swolf_50m_1 = require("../data/data.swolf-50m");
const data_power_balance_left_1 = require("../data/data.power-balance-left");
const data_power_balance_right_1 = require("../data/data.power-balance-right");
const data_power_torque_effectiveness_left_1 = require("../data/data.power-torque-effectiveness-left");
const data_power_torque_effectiveness_right_1 = require("../data/data.power-torque-effectiveness-right");
const data_power_pedal_smoothness_right_1 = require("../data/data.power-pedal-smoothness-right");
const data_power_pedal_smoothness_left_1 = require("../data/data.power-pedal-smoothness-left");
const data_power_normalized_1 = require("../data/data.power-normalized");
const data_power_intensity_factor_1 = require("../data/data.power-intensity-factor");
const data_training_stress_score_1 = require("../data/data.training-stress-score");
const data_power_work_1 = require("../data/data.power-work");
const data_cycling_standing_time_1 = require("../data/data.cycling-standing-time");
const data_cycling_seated_time_1 = require("../data/data.cycling-seated-time");
const data_vertical_oscillation_avg_1 = require("../data/data.vertical-oscillation-avg");
const data_vertical_ratio_avg_1 = require("../data/data.vertical-ratio-avg");
const data_ground_contact_time_avg_1 = require("../data/data.ground-contact-time-avg");
const data_ground_contact_time_balance_left_1 = require("../data/data-ground-contact-time-balance-left");
const data_ground_contact_time_balance_right_1 = require("../data/data-ground-contact-time-balance-right");
const data_stance_time_balance_right_1 = require("../data/data-stance-time-balance-right");
const data_stance_time_balance_left_1 = require("../data/data-stance-time-balance-left");
const data_avg_stride_length_1 = require("../data/data.avg-stride-length");
const data_aerobic_training_effect_1 = require("../data/data-aerobic-training-effect");
const data_anaerobic_training_effect_1 = require("../data/data-anaerobic-training-effect");
const data_altitude_smooth_1 = require("../data/data.altitude-smooth");
const data_grade_1 = require("../data/data.grade");
const activity_parsing_options_1 = require("../activities/activity-parsing-options");
const helpers_1 = require("../events/utilities/helpers");
describe('FIT/TCX/GPX activity parsing compliance', () => {
    const domParser = new xmldom_1.default.DOMParser();
    /*  it('Template: should parse FIT activity file', done => {
      // Given FIT Source: https://connect.garmin.com/modern/activity/xxxxxxxx OR https://www.strava.com/activities/xxxxxxx (should be "public")
      const path = '/path/to/your/file.fit';
      const buffer = fs.readFileSync(path);
  
      // When
      const eventInterfacePromise = SportsLib.importFromFit(buffer);
  
      // Then
      eventInterfacePromise.then((event: EventInterface) => {
        const activity = event.getFirstActivity();
        done();
      });
    });*/
    /*  it('Template: should parse TCX activity file', done => {
      // Given TCX Source: https://connect.garmin.com/modern/activity/xxxxxxxx OR https://www.strava.com/activities/xxxxxxx (should be "public")
      const path = '/path/to/your/file.tcx';
      const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
  
      // When
      const eventInterfacePromise = SportsLib.importFromTCX(doc);
  
      // Then
      eventInterfacePromise.then((event: EventInterface) => {
        const activity = event.getFirstActivity();
        done();
      });
    });*/
    /*  it('Template: should parse GPX activity file', done => {
      // Given GPX Source: https://connect.garmin.com/modern/activity/xxxxxxxx OR https://www.strava.com/activities/xxxxxxx (should be "public")
      const path = '/path/to/your/file.gpx';
      const gpxString = fs.readFileSync(path).toString();
  
      // When
      const eventInterfacePromise = SportsLib.importFromGPX(gpxString, xmldom.DOMParser);
  
      // Then
      eventInterfacePromise.then((event: EventInterface) => {
        const activity = event.getFirstActivity();
        done();
      });
    });*/
    describe('Swimming', () => {
        describe('FIT', () => {
            it('should parse swimming pool FIT file (1)', done => {
                // Given FIT Source:  https://connect.garmin.com/modern/activity/6688025408 OR https://www.strava.com/activities/4232464474
                const path = __dirname + '/fixtures/swim/fit/6688025408.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Forerunner 935');
                    expect(activity.creator.productId).toEqual(2691);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Swimming);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(2300);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(458);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(20);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(23);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(126);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(146);
                    expect(activity.getStat(data_pool_length_1.DataPoolLength.type).getValue()).toEqual(50);
                    expect(activity.getStat(data_active_lengths_1.DataActiveLengths.type).getValue()).toEqual(46);
                    expect(activity.getStat(data_swolf_25m_1.DataSWOLF25m.type).getValue()).toEqual(36.7);
                    expect(activity.getStat(data_swolf_50m_1.DataSWOLF50m.type).getValue()).toEqual(73.4);
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(806);
                    const laps = activity.getLaps();
                    expect(laps.length).toEqual(36);
                    expect(laps[0].getStat(data_active_lap_1.DataActiveLap.type).getValue()).toBeTruthy();
                    expect(laps[1].getStat(data_active_lap_1.DataActiveLap.type).getValue()).toBeFalsy();
                    expect(laps[1].lapId).toEqual(2);
                    expect(activity.hasStreamData(data_speed_1.DataSpeed.type)).toBeTruthy();
                    expect(activity.hasStreamData(data_heart_rate_1.DataHeartRate.type)).toBeTruthy();
                    expect(activity.hasStreamData(data_cadence_1.DataCadence.type)).toBeTruthy();
                    expect(activity.hasStreamData(data_distance_1.DataDistance.type)).toBeTruthy();
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '01:50');
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '44:06');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:06:03');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:06:23');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 0);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse swimming pool FIT file (2)', done => {
                // Given FIT Source:  https://connect.garmin.com/modern/activity/6021532030 OR https://www.strava.com/activities/5258304128
                const path = __dirname + '/fixtures/swim/fit/6021532030.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Swimming);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(780);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(235);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(26);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(28);
                    expect(activity.getStat(data_pool_length_1.DataPoolLength.type).getValue()).toEqual(20);
                    expect(activity.getStat(data_active_lengths_1.DataActiveLengths.type).getValue()).toEqual(39);
                    expect(activity.getStat(data_swolf_25m_1.DataSWOLF25m.type).getValue()).toEqual(63.9);
                    expect(activity.getStat(data_swolf_50m_1.DataSWOLF50m.type).getValue()).toEqual(127.7);
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(596);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '02:58');
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '23:09');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '23:09');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '23:31');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse swimming pool FIT file (3)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/6860712481 OR https://www.strava.com/activities/5376106733
                const path = __dirname + '/fixtures/swim/fit/6860712481.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Swimming);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(2000);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(401);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(28);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(131);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(157);
                    expect(activity.getStat(data_pool_length_1.DataPoolLength.type).getValue()).toEqual(25);
                    expect(activity.getStat(data_active_lengths_1.DataActiveLengths.type).getValue()).toEqual(80);
                    expect(activity.getStat(data_swolf_25m_1.DataSWOLF25m.type).getValue()).toEqual(46.1);
                    expect(activity.getStat(data_swolf_50m_1.DataSWOLF50m.type).getValue()).toEqual(92.2);
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(984);
                    // TODO Check streams based on laps for swims performed in a pool
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '02:06');
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '41:25');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '47:27');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '49:43');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse swimming pool FIT file (4)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/7617306288 OR https://www.strava.com/activities/6076695527
                const path = __dirname + '/fixtures/swim/fit/7617306288.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Swimming);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(150);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '01:54');
                    expect(activity.getLaps().length).toEqual(6);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse swimming open water FIT file (1)', done => {
                // Given https://connect.garmin.com/modern/activity/6788312639/1 OR https://www.strava.com/activities/5305763421
                const path = __dirname + '/fixtures/swim/fit/6788312639-1.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.OpenWaterSwimming);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(1505.03);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(403);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(32);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(48);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(158);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(170);
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(993);
                    expect(activity.getStat(data_swolf_25m_1.DataSWOLF25m.type).getValue()).toEqual(47.5);
                    expect(activity.getStat(data_swolf_50m_1.DataSWOLF50m.type).getValue()).toEqual(95);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '02:04');
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '24:28');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '31:06');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '31:06');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
        describe('TCX', () => {
            it('should parse swimming pool TCX file (1)', done => {
                // Given TCX Source: https://connect.garmin.com/modern/activity/6832570127 OR https://www.strava.com/activities/5347012220
                // Given FIT Source: https://connect.garmin.com/modern/activity/6688025408 OR https://www.strava.com/activities/4232464474
                const path = __dirname + '/fixtures/swim/tcx/6688025408.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    // expect(activity.type).toEqual(ActivityTypes.Swimming); // TODO To be auto-detected by sports-data-science library (work in progress)
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(2300);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(458);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(119);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(146);
                    const laps = activity.getLaps();
                    expect(laps.length).toEqual(36);
                    expect(laps[0].getStat(data_active_lap_1.DataActiveLap.type).getValue()).toBeTruthy();
                    expect(laps[1].getStat(data_active_lap_1.DataActiveLap.type).getValue()).toBeFalsy();
                    expect(laps[1].lapId).toEqual(2);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '01:50');
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '44:06');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:06:03');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:06:23');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse swimming pool TCX file (2)', done => {
                // Given TCX Source: https://connect.garmin.com/modern/activity/6861441616 or https://www.strava.com/activities/5378130384
                // Given FIT Source: https://connect.garmin.com/modern/activity/6860712481 OR https://www.strava.com/activities/5376106733
                const path = __dirname + '/fixtures/swim/tcx/6860712481.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    // expect(activity.type).toEqual(ActivityTypes.Swimming); // TODO To be auto-detected by sports-data-science library (work in progress)
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(2000);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(401);
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(984);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(128);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(156);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '02:05');
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '41:25');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '47:27');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '47:27');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 0);
                    done();
                })
                    .catch(e => done(e));
            });
        });
        describe('GPX', () => {
            it('should parse swimming open water GPX file (1)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6867388194 OR https://www.strava.com/activities/5382390985
                // Given FIT Source: https://connect.garmin.com/modern/activity/4623204522/1 OR https://www.strava.com/activities/5352030147
                const path = __dirname + '/fixtures/swim/gpx/4623204522-1.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    // Swim
                    const swimActivity = event.getFirstActivity();
                    // expect(swimActivity.type).toEqual(ActivityTypes.OpenWaterSwimming); // TODO To be auto-detected by sports-data-science library (work in progress)
                    expect(swimActivity.getStreamData(data_speed_1.DataSpeed.type).length).toEqual(3689);
                    expect(swimActivity.startDate.toISOString()).toEqual('2018-10-13T17:05:01.000Z');
                    expect(swimActivity.endDate.toISOString()).toEqual('2018-10-13T18:06:29.000Z');
                    expect(swimActivity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(3869, 0);
                    expect(swimActivity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(36);
                    expect(swimActivity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(39);
                    expect(swimActivity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(74);
                    expect(swimActivity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(115);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(swimActivity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '01:31', 2);
                    // Verifying time data
                    const movingTime = swimActivity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = swimActivity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = swimActivity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = swimActivity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:00:35', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:01:29');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:01:29');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse swimming open water GPX file (2)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6867446668 OR https://www.strava.com/activities/5382426315
                // Given FIT Source: https://connect.garmin.com/modern/activity/6090674952 OR https://www.strava.com/activities/5366783958
                const path = __dirname + '/fixtures/swim/gpx/6090674952.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const swimActivity = event.getFirstActivity();
                    // expect(swimActivity.type).toEqual(ActivityTypes.OpenWaterSwimming);  // TODO To be auto-detected by sports-data-science library (work in progress)
                    expect(swimActivity.startDate.toISOString()).toEqual('2021-01-04T16:22:18.000Z');
                    expect(swimActivity.endDate.toISOString()).toEqual('2021-01-04T17:37:05.000Z');
                    expect(swimActivity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(2537, 0);
                    expect(swimActivity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(145);
                    expect(swimActivity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(184);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(swimActivity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '02:29');
                    // Verifying time data
                    const movingTime = swimActivity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = swimActivity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = swimActivity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = swimActivity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '55:43', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:14:47');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:14:47');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
    });
    describe('Running', () => {
        describe('FIT', () => {
            it('should parse running FIT file (1)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/2067489619 OR https://www.strava.com/activities/1221143311
                const path = __dirname + '/fixtures/runs/fit/2067489619.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin VivoActive HR');
                    expect(activity.creator.manufacturer).toEqual('garmin');
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(4489.39);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(58);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(88);
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(2782);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(130);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(179);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '10:28', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '09:11', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '45:42');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '47:00');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '47:04');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running FIT file (2)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/6782987395 OR https://www.strava.com/activities/2451375851
                const path = __dirname + '/fixtures/runs/fit/6782987395.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(14004.85);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(79);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(111);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(137);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(167);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '05:56', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '05:19', 1);
                    const laps = activity.getLaps();
                    expect(laps.length).toEqual(2);
                    expect(laps[0].getStat(data_active_lap_1.DataActiveLap.type).getValue()).toBeTruthy();
                    expect(laps[1].getStat(data_active_lap_1.DataActiveLap.type).getValue()).toBeTruthy();
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:19:37');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:23:09');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:23:09');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running FIT file (Suunto export) (3)', done => {
                // Given FIT Source (Suunto export): https://connect.garmin.com/modern/activity/6909950168 OR https://www.strava.com/activities/5423646653
                const path = __dirname + '/fixtures/runs/fit/6909950168.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.TrailRunning);
                    expect(activity.creator.name).toEqual('Suunto 9');
                    expect(activity.creator.productId).toEqual(34);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(6458);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(487);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(90);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(94);
                    expect(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue()).toEqual(227);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toEqual(294);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(148);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(161);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '05:35', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '05:34', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '35:42');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '36:01');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '36:36');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running FIT file (Suunto export) (4)', done => {
                // Given FIT Source (Suunto export): https://connect.garmin.com/modern/activity/6910052863 OR https://www.strava.com/activities/5423660493
                const path = __dirname + '/fixtures/runs/fit/6910052863.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.TrailRunning);
                    expect(activity.creator.name).toEqual('Suunto 9');
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(8225);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toEqual(1817);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(2540);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(44);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(96);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(164);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(174);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '19:20', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '07:32', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '02:35:40');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '02:39:03');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '02:40:02');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running FIT file (Suunto export) (5)', done => {
                // Given FIT Source (Suunto export): https://connect.garmin.com/modern/activity/6914448270 OR https://www.strava.com/activities/5427988571
                const path = __dirname + '/fixtures/runs/fit/6914448270.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    expect(activity.creator.name).toEqual('Suunto 9 Baroless');
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(49897);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toEqual(1063);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(4445);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(74);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(119);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '06:49', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '06:20', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue(); // TODO If moving time unknown or INVALID loop on all records in activity utils
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '05:28:14');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '05:40:19');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '05:40:19');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running FIT file (Suunto export) (6)', done => {
                // Given FIT Source (Suunto export): https://connect.garmin.com/modern/activity/6914538454 OR https://www.strava.com/activities/5428064152
                const path = __dirname + '/fixtures/runs/fit/6914538454.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    expect(activity.creator.name).toEqual('Suunto 9 Baroless');
                    expect(activity.creator.manufacturer).toEqual('suunto');
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(4330);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toEqual(0);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(354);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(87);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(109);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '04:52', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '18:51');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '21:04');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '21:04');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running FIT file (Coros export) (7)', done => {
                // Given FIT Source (Coros export): https://connect.garmin.com/modern/activity/6916663933 OR https://www.strava.com/activities/5429996380
                const path = __dirname + '/fixtures/runs/fit/6916663933.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    expect(activity.creator.name).toEqual('Coros APEX Pro');
                    expect(activity.creator.productId).toEqual(841);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(10743.64);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toEqual(142);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(685);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(92);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(106);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(160);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(173);
                    expect(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue()).toEqual(332);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toEqual(518);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '04:31', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '04:24', 1);
                    const stanceTimeBalanceLeft = activity.getStat(data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type).getValue();
                    const stanceTimeBalanceRight = activity.getStat(data_stance_time_balance_right_1.DataStanceTimeBalanceRight.type).getValue();
                    expect(stanceTimeBalanceLeft).toEqual(49.25);
                    expect(stanceTimeBalanceRight).toEqual(50.75);
                    expect(stanceTimeBalanceLeft).toEqual(activity.getStat(data_ground_contact_time_balance_left_1.DataGroundContactTimeBalanceLeft.type).getValue());
                    expect(stanceTimeBalanceRight).toEqual(activity.getStat(data_ground_contact_time_balance_right_1.DataGroundContactTimeBalanceRight.type).getValue());
                    expect(activity.getStat(data_ground_contact_time_avg_1.DataGroundContactTimeAvg.type).getValue()).toEqual(206);
                    expect(activity.getStat(data_vertical_oscillation_avg_1.DataVerticalOscillationAvg.type).getValue()).toEqual(94);
                    expect(activity.getStat(data_vertical_ratio_avg_1.DataVerticalRatioAvg.type).getValue()).toEqual(7.9);
                    expect(activity.getStat(data_avg_stride_length_1.DataAvgStrideLength.type).getValue()).toEqual(1.2);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '48:35');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '48:42');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '48:42');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running FIT file (Coros export) (8)', done => {
                // Given FIT Source (Coros export): https://connect.garmin.com/modern/activity/6916728382 OR https://www.strava.com/activities/5430055225
                const path = __dirname + '/fixtures/runs/fit/6916728382.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    expect(activity.creator.name).toEqual('Coros APEX Pro');
                    expect(activity.creator.manufacturer).toEqual('coros');
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(21524.3);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toEqual(539);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(1661);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(71);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(88);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(131);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(164);
                    expect(activity.getStat(data_temperature_avg_1.DataTemperatureAvg.type).getValue()).toEqual(22);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '07:31', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '02:39:59');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '02:41:39');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '02:41:39');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running treadmill FIT file (1)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/6860622783 or https://www.strava.com/activities/5375834427
                const path = __dirname + '/fixtures/runs/fit/6860622783.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Treadmill);
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.isTrainer()).toBeTruthy();
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(10630.37);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(82);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(128);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(145);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(177);
                    expect(activity.getStat(data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type).getValue()).toEqual(49.91);
                    expect(activity.getStat(data_stance_time_balance_right_1.DataStanceTimeBalanceRight.type).getValue()).toEqual(50.09);
                    expect(activity.getStat(data_ground_contact_time_avg_1.DataGroundContactTimeAvg.type).getValue()).toEqual(271.3);
                    expect(activity.getStat(data_vertical_oscillation_avg_1.DataVerticalOscillationAvg.type).getValue()).toEqual(97.2);
                    expect(activity.getStat(data_vertical_ratio_avg_1.DataVerticalRatioAvg.type).getValue()).toEqual(9.57);
                    expect(activity.getStat(data_avg_stride_length_1.DataAvgStrideLength.type).getValue()).toEqual(1.04);
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(4242);
                    expect(activity.getStat(data_aerobic_training_effect_1.DataAerobicTrainingEffect.type).getValue()).toEqual(2.2);
                    expect(activity.getStat(data_anaerobic_training_effect_1.DataAnaerobicTrainingEffect.type).getValue()).toEqual(1.8);
                    expect(activity.getStat(data_power_work_1.DataPowerWork.type).getValue()).toEqual(692);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '04:51', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '48:43');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '51:38');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:02:44');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
        describe('TCX', () => {
            it('should parse running TCX file (1)', done => {
                // Given Recorded with "Strava Android App" => https://connect.garmin.com/modern/activity/1604524853 OR https://www.strava.com/activities/708752345
                const path = __dirname + '/fixtures/runs/tcx/1604524853.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.run);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '09:15', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '07:07', 1);
                    spec_utils_1.SpecUtils.assertEqual(event.getFirstActivity().getStat(data_ascent_1.DataAscent.type).getValue(), 432);
                    spec_utils_1.SpecUtils.assertEqual(event.getFirstActivity().getStat(data_descent_1.DataDescent.type).getValue(), 440);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(6106.6);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(69);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(99);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(158);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(191);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '58:59', 3);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:07:47');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:07:47');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running TCX file (2)', done => {
                // Given TCX Source: https://connect.garmin.com/modern/activity/6851149716 OR  https://www.strava.com/activities/5366592367
                // Given FIT Source: https://connect.garmin.com/modern/activity/6782987395 OR https://www.strava.com/activities/2451375851
                const path = __dirname + '/fixtures/runs/tcx/6782987395.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.run);
                    expect(activity.creator.name).toEqual('Forerunner 945');
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '05:41');
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '05:19', 1);
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_ascent_1.DataAscent.type).getValue(), 363);
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_descent_1.DataDescent.type).getValue(), 386);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(14004.85);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(982);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(80);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(111);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(137);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(167);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:19:38');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:23:09');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:23:09');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running TCX file (3)', done => {
                // Given TCX Source: https://connect.garmin.com/modern/activity/6860622916 or https://www.strava.com/activities/5375754773
                const path = __dirname + '/fixtures/runs/tcx/6860622916.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.run);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '04:25');
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '04:24');
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_ascent_1.DataAscent.type).getValue(), 85);
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_descent_1.DataDescent.type).getValue(), 74);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(13973.09);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(739);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(89);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(98);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(143);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(168);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:02:17');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:02:17');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:02:17');
                    expect(Math.abs(pauseTime - (elapsedTime - timerTime))).toBeLessThanOrEqual(1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running TCX file (4)', done => {
                // Given TCX Source: (garmin connect upload impossible) or https://www.strava.com/activities/6281425038
                const path = __dirname + '/fixtures/runs/tcx/6281425038.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.run);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '06:19');
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '05:58');
                    const laps = activity.getLaps();
                    expect(laps.length).toEqual(5);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '25:45');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '25:45');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '36:02');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running treadmill TCX file (3)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/6860622783 or https://www.strava.com/activities/5375834427
                const path = __dirname + '/fixtures/runs/tcx/6860622783.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.IndoorRunning);
                    expect(activity.isTrainer()).toBeTruthy();
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(10630.37);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(82);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(128);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(145);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(177);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '04:51', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '48:43');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '51:38');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:02:44');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
        describe('GPX', () => {
            it('should parse running GPX file (1)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6870534840 OR https://www.strava.com/activities/5385528846
                // Given FIT Source: https://connect.garmin.com/modern/activity/2067489619 OR https://www.strava.com/activities/1221143311
                const path = __dirname + '/fixtures/runs/gpx/2067489619.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    // Swim
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '09:18', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '09:18', 1);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(4400, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(35, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(67);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(88);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(134);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(178);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '44:48');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '47:00');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '47:04');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running GPX file (2)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6870566668 OR https://www.strava.com/activities/5385561485
                // Given FIT Source: https://connect.garmin.com/modern/activity/6782987395 OR https://www.strava.com/activities/2451375851
                const path = __dirname + '/fixtures/runs/gpx/6782987395.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '05:53', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '05:18', 1);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(14170.5, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(363, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(82);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(111);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(137);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(167);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:17:11');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:23:09');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:23:09');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running GPX file (3)', done => {
                // Given Recorded with "Strava Android App" => https://connect.garmin.com/modern/activity/1681613317 OR https://www.strava.com/activities/906581465
                const path = __dirname + '/fixtures/runs/gpx/1681613317.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.run);
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.isTrainer()).toBeFalsy();
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '06:27', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '06:23', 1);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(4593, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(39, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(79);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(96);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(146);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(176);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '32:09');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '32:38');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '32:38');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running GPX file (4)', done => {
                // Given Recorded with "MyTracks" => https://connect.garmin.com/modern/activity/6909258631 OR https://www.strava.com/activities/5422847134
                const path = __dirname + '/fixtures/runs/gpx/6909258631.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    // expect(activity.type).toEqual(ActivityTypes.run); // TODO To be auto-detected by sports-data-science library (work in progress)
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(40878.5, 1);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(2780, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(2780, 0);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '07:22', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '04:51:49');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '06:30:22');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '06:30:22');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running GPX file (5)', done => {
                // Given https://connect.garmin.com/modern/activity/6048438275 OR https://www.strava.com/activities/3497177564
                const path = __dirname + '/fixtures/runs/gpx/6048438275.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.run);
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.isTrainer()).toBeFalsy();
                    spec_utils_1.SpecUtils.assertNearEqual(activity.getStat(data_distance_1.DataDistance.type).getValue(), 16771.3, 1, 1);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(579, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(86);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(123);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '04:48', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '04:17', 1);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    expect(activity.getSquashedStreamData('Distance').length).toEqual(activity.getSquashedStreamData('Speed').length);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:04:19');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:22:50');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:22:50');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse running GPX file (6)', done => {
                // Given https://www.strava.com/activities/3632493456 or https://connect.garmin.com/modern/activity/6037744996
                const path = __dirname + '/fixtures/runs/gpx/6037744996.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.run);
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.isTrainer()).toBeFalsy();
                    spec_utils_1.SpecUtils.assertNearEqual(activity.getStat(data_distance_1.DataDistance.type).getValue(), 5115.1, 1, 1);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(516, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(68);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(124);
                    expect(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue()).toBeGreaterThanOrEqual(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue());
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '13:10', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type).getValue(), '09:07', 1);
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '28:35');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:07:19');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:07:19');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
    });
    describe('Cycling', () => {
        describe('FIT', () => {
            it('should parse cycling FIT file (1)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/3939576645 OR https://www.strava.com/activities/2610176355
                const path = __dirname + '/fixtures/rides/fit/3939576645.fit';
                const buffer = fs.readFileSync(path);
                const expectedSamplesLength = 2547;
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    // Verify streams consistency
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Edge 1000');
                    expect(activity.generateTimeStream([data_distance_1.DataDistance.type]).getData(true).length).toEqual(expectedSamplesLength);
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.isTrainer()).toBeFalsy();
                    expect(activity.getSquashedStreamData(data_longitude_degrees_1.DataLongitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_latitude_degrees_1.DataLatitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_distance_1.DataDistance.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_altitude_1.DataAltitude.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_altitude_smooth_1.DataAltitudeSmooth.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_speed_1.DataSpeed.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_cadence_1.DataCadence.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_heart_rate_1.DataHeartRate.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_grade_1.DataGrade.type).length).toEqual(expectedSamplesLength);
                    const missingStreamCall = () => {
                        activity.getSquashedStreamData(data_power_1.DataPower.type);
                    };
                    expect(missingStreamCall).toThrow();
                    // Verify global activity stats
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(42220.87);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toEqual(668);
                    expect(activity.getStat(data_descent_1.DataDescent.type).getValue()).toEqual(664);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(1497);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(68);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(109);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(155);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(186);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toEqual(5.812); // Or 20.9 kph
                    expect(activity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(6550);
                    // Verifying time data
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '02:00:42', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '02:01:04');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '02:04:36');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (2)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/828989227 OR https://www.strava.com/activities/343080886
                const path = __dirname + '/fixtures/rides/fit/828989227.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.creator.name).toEqual('Garmin Edge 810');
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(141944.2);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toEqual(2052);
                    expect(activity.getStat(data_descent_1.DataDescent.type).getValue()).toEqual(2028);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(2629);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(79);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(118);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(148);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(174);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toEqual(7.219); // Or 26 kph
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '05:26:49');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '05:27:44');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '06:07:08');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (3)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/614953343 OR https://www.strava.com/activities/208748758
                const path = __dirname + '/fixtures/rides/fit/614953343.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Edge 800');
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '05:52:28', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '05:54:34');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '07:04:31');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (4)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/6783622686 OR https://www.strava.com/activities/5300988022
                const path = __dirname + '/fixtures/rides/fit/6783622686.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Edge 1030');
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '05:07:53');
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '05:08:22');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '07:26:55');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (5)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/7386755164 OR https://www.strava.com/activities/5952147686
                const path = __dirname + '/fixtures/rides/fit/7386755164.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Edge 1030');
                    // Power extended stats. FIT invalid L/R balance samples (0xFF) are excluded.
                    expect(activity.getStat(data_power_balance_left_1.DataPowerBalanceLeft.type).getValue()).toEqual(51.66);
                    expect(activity.getStat(data_power_balance_right_1.DataPowerBalanceRight.type).getValue()).toEqual(48.34);
                    expect(activity.getStat(data_power_torque_effectiveness_left_1.DataPowerTorqueEffectivenessLeft.type).getValue()).toEqual(80);
                    expect(activity.getStat(data_power_torque_effectiveness_right_1.DataPowerTorqueEffectivenessRight.type).getValue()).toEqual(76.5);
                    expect(activity.getStat(data_power_pedal_smoothness_left_1.DataPowerPedalSmoothnessLeft.type).getValue()).toEqual(22);
                    expect(activity.getStat(data_power_pedal_smoothness_right_1.DataPowerPedalSmoothnessRight.type).getValue()).toEqual(20.5);
                    expect(activity.getStat(data_power_normalized_1.DataPowerNormalized.type).getValue()).toEqual(179);
                    expect(activity.getStat(data_power_intensity_factor_1.DataPowerIntensityFactor.type).getValue()).toEqual(0.786);
                    expect(activity.getStat(data_training_stress_score_1.DataTrainingStressScore.type).getValue()).toEqual(105.4);
                    expect(activity.getStat(data_power_work_1.DataPowerWork.type).getValue()).toEqual(832);
                    // Cycling dynamics: Power "position" stats
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_cycling_standing_time_1.DataCyclingStandingTime.type).getValue(), '17:53', 0);
                    spec_utils_1.SpecUtils.assertNearEqualTime(activity.getStat(data_cycling_seated_time_1.DataCyclingSeatedTime.type).getValue(), '01:25:02', 0);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (6)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/7445393868 OR https://www.strava.com/activities/5921768617
                const path = __dirname + '/fixtures/rides/fit/7445393868.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Edge 1000');
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.getStat(data_power_balance_left_1.DataPowerBalanceLeft.type).getValue()).toEqual(45.91);
                    expect(activity.getStat(data_power_balance_right_1.DataPowerBalanceRight.type).getValue()).toEqual(54.09);
                    expect(activity.getStat(data_power_torque_effectiveness_left_1.DataPowerTorqueEffectivenessLeft.type).getValue()).toEqual(71);
                    expect(activity.getStat(data_power_torque_effectiveness_right_1.DataPowerTorqueEffectivenessRight.type).getValue()).toEqual(73);
                    expect(activity.getStat(data_power_pedal_smoothness_left_1.DataPowerPedalSmoothnessLeft.type).getValue()).toEqual(20);
                    expect(activity.getStat(data_power_pedal_smoothness_right_1.DataPowerPedalSmoothnessRight.type).getValue()).toEqual(21.5);
                    expect(activity.getStat(data_power_normalized_1.DataPowerNormalized.type).getValue()).toEqual(147);
                    expect(activity.getStat(data_power_intensity_factor_1.DataPowerIntensityFactor.type).getValue()).toEqual(0.733);
                    expect(activity.getStat(data_training_stress_score_1.DataTrainingStressScore.type).getValue()).toEqual(48.3);
                    expect(activity.getStat(data_power_work_1.DataPowerWork.type).getValue()).toEqual(417);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (7)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/7432332116 OR https://www.strava.com/activities/5910143591
                const path = __dirname + '/fixtures/rides/fit/7432332116.fit';
                const buffer = fs.readFileSync(path);
                const expectedSamplesLength = 10063;
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Edge 1000');
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue()).toEqual(152);
                    expect(activity.getStat(data_power_normalized_1.DataPowerNormalized.type).getValue()).toEqual(172);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toEqual(564);
                    expect(activity.getSquashedStreamData(data_longitude_degrees_1.DataLongitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_latitude_degrees_1.DataLatitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_distance_1.DataDistance.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_altitude_1.DataAltitude.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_speed_1.DataSpeed.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_cadence_1.DataCadence.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_heart_rate_1.DataHeartRate.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_power_1.DataPower.type).length).toEqual(expectedSamplesLength);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (8)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/7739869618 OR https://www.strava.com/activities/2380240532
                const path = __dirname + '/fixtures/rides/fit/7739869618.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Wahoo ELEMNT BOLT');
                    expect(activity.creator.manufacturer).toEqual('wahoo_fitness');
                    expect(activity.creator.isRecognized).toBeTruthy();
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling FIT file (9)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/5319808632 OR https://www.strava.com/activities/3849490840
                const path = __dirname + '/fixtures/rides/fit/5319808632.fit';
                const buffer = fs.readFileSync(path);
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.startDate.toISOString()).toEqual('2020-07-26T15:28:41.000Z');
                    expect(activity.endDate.toISOString()).toEqual('2020-07-26T16:31:26.063Z');
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse virtual cycling FIT file (1)', done => {
                // Given FIT Source: https://connect.garmin.com/modern/activity/971150603 OR https://www.strava.com/activities/442080924
                const path = __dirname + '/fixtures/rides/fit/971150603.fit';
                const buffer = fs.readFileSync(path);
                const expectedSamplesLength = 3806;
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    // Verify streams consistency
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Zwift');
                    expect(activity.creator.productId).toEqual(15706);
                    expect(activity.creator.isRecognized).toBeTruthy();
                    expect(activity.generateTimeStream([data_distance_1.DataDistance.type]).getData(true).length).toEqual(expectedSamplesLength);
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.isTrainer()).toBeFalsy();
                    expect(activity.getSquashedStreamData(data_longitude_degrees_1.DataLongitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_latitude_degrees_1.DataLatitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_distance_1.DataDistance.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_altitude_1.DataAltitude.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_speed_1.DataSpeed.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_cadence_1.DataCadence.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_heart_rate_1.DataHeartRate.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_power_1.DataPower.type).length).toEqual(expectedSamplesLength);
                    // Verify global activity stats
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(32227.5);
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_ascent_1.DataAscent.type).getValue(), 242, 0);
                    expect(activity.getStat(data_energy_1.DataEnergy.type)).toBeUndefined(); // Zwift didn't give the calories
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(76);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(114);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(148);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(180);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toEqual(8.476); // Or 30.5 kph
                    expect(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue()).toEqual(143);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toEqual(381);
                    // Verifying time data
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:02:53', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:03:35');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:03:42');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should generate grade adjusted speed for a cycling FIT file (samples)', done => {
                const path = __dirname + '/../../samples/fit/2026-02-10_14-28.fit';
                const buffer = fs.readFileSync(path);
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.hasStreamData(data_speed_1.DataSpeed.type)).toBeTruthy();
                    expect(activity.hasStreamData(data_grade_adjusted_speed_1.DataGradeAdjustedSpeed.type)).toBeTruthy();
                    expect(activity.getStat(data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type)).toBeDefined();
                    done();
                })
                    .catch(e => done(e));
            });
        });
        describe('TCX', () => {
            it('should parse cycling TCX file (1)', done => {
                // Given TCX Source: https://connect.garmin.com/modern/activity/6791039036 OR https://www.strava.com/activities/5308417342
                // Given FIT Source: https://connect.garmin.com/modern/activity/3939576645 OR https://www.strava.com/activities/2610176355
                const path = __dirname + '/fixtures/rides/tcx/6791039036.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    // Verify global activity stats
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.creator.name).toEqual('Garmin Edge 1000');
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_ascent_1.DataAscent.type).getValue(), 672, 0);
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_descent_1.DataDescent.type).getValue(), 664);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(42220.87);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(1497);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(69);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(108);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(153);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(186);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(6.536); // Or 23.5 kph
                    // Verifying time data
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '02:01:59', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '02:01:04');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '02:04:36');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling TCX file (2)', done => {
                // Given TCX Source: https://connect.garmin.com/modern/activity/6838497277 or https://www.strava.com/activities/5354278524
                // Given FIT Source: https://connect.garmin.com/modern/activity/3953195468 or https://www.strava.com/activities/2621275265
                const path = __dirname + '/fixtures/rides/tcx/6838497277.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.isTrainer()).toBeFalsy();
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_ascent_1.DataAscent.type).getValue(), 685, 0);
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_descent_1.DataDescent.type).getValue(), 670);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(59853.31);
                    expect(activity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(2206);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(68);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(109);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(160);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(192);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(6.278); // 22.6 kph
                    // Verifying time data
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '02:52:10', 1.5);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '02:55:15');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '02:55:15');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling TCX file (3)', done => {
                // Given TCX Source: https://connect.garmin.com/modern/activity/7555170032 or https://www.strava.com/activities/6020442882
                // Given FIT Source: https://connect.garmin.com/modern/activity/7432332116 OR https://www.strava.com/activities/5910143591
                const path = __dirname + '/fixtures/rides/tcx/7555170032.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                const expectedSamplesLength = 10063;
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.creator.name).toEqual('Garmin Edge 1000');
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue()).toBeCloseTo(152, 0);
                    expect(activity.getStat(data_power_normalized_1.DataPowerNormalized.type).getValue()).toBeCloseTo(171, 0);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toEqual(564);
                    expect(activity.getSquashedStreamData(data_longitude_degrees_1.DataLongitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_latitude_degrees_1.DataLatitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_distance_1.DataDistance.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_altitude_1.DataAltitude.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_speed_1.DataSpeed.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_cadence_1.DataCadence.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_heart_rate_1.DataHeartRate.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_power_1.DataPower.type).length).toEqual(expectedSamplesLength);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse virtual cycling TCX file (1)', done => {
                // Given https://connect.garmin.com/modern/activity/6823905801 OR https://www.strava.com/activities/5340305665
                const path = __dirname + '/fixtures/rides/tcx/6823905801.tcx';
                const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromTCX(doc);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.isTrainer()).toBeFalsy();
                    // Verify global activity stats
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(32227.5);
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_ascent_1.DataAscent.type).getValue(), 242);
                    expect(activity.getStat(data_energy_1.DataEnergy.type)).toBeUndefined(); // Zwift didn't give the calories
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(76);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(114);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(148);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(180);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(8.47, 3); // Or 30.5 kph
                    spec_utils_1.SpecUtils.assertEqual(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue(), 143);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toEqual(381);
                    // Verifying time data
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:03:10', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:03:35');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:03:42');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
        describe('GPX', () => {
            it('should parse cycling GPX file (1)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6870609105 OR https://www.strava.com/activities/5385601807
                // Given FIT Source: https://connect.garmin.com/modern/activity/3939576645 OR https://www.strava.com/activities/2610176355
                const path = __dirname + '/fixtures/rides/gpx/3939576645.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(41829, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(672, 0);
                    expect(activity.getStat(data_descent_1.DataDescent.type).getValue()).toBeCloseTo(664, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(69);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(108);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(153);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(186);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(6.479); // Or 23.32 kph
                    // Verifying time data
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '02:00:42', 1.5);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '02:04:35');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '02:04:36');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling GPX file (2)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6870692308 OR https://www.strava.com/activities/5385683390
                // Given FIT Source: https://connect.garmin.com/modern/activity/828989227 OR https://www.strava.com/activities/343080886
                const path = __dirname + '/fixtures/rides/gpx/828989227.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.hasPowerMeter()).toBeFalsy();
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(141975, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(2052, 0);
                    expect(activity.getStat(data_descent_1.DataDescent.type).getValue()).toBeCloseTo(2034, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(79);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(118);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(148);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(174);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(7.329); // Or 26.3 kph
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '05:26:49', 2);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '06:07:13');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '06:07:13');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling GPX file (3)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6905455978 OR https://www.strava.com/activities/5419099678
                // Given FIT Source: https://connect.garmin.com/modern/activity/4108490848 OR https://www.strava.com/activities/2749884297
                const path = __dirname + '/fixtures/rides/gpx/4108490848.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.name).toEqual('Meylan Road Cycling');
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(49909, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(292, 0);
                    expect(activity.getStat(data_descent_1.DataDescent.type).getValue()).toBeCloseTo(283, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(76);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(117);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(165);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(186);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(7.903); // Or 28.4 kph
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:47:13', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:49:20');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:49:20');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse cycling GPX file (4)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/7555261629 or https://www.strava.com/activities/6020530554
                // Given FIT Source: https://connect.garmin.com/modern/activity/7432332116 OR https://www.strava.com/activities/5910143591
                const path = __dirname + '/fixtures/rides/gpx/7555261629.gpx';
                const gpxString = fs.readFileSync(path).toString();
                const expectedSamplesLength = 10063;
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue()).toBeCloseTo(152, 0);
                    expect(activity.getStat(data_power_normalized_1.DataPowerNormalized.type).getValue()).toBeCloseTo(171, 0);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toEqual(564);
                    expect(activity.getSquashedStreamData(data_longitude_degrees_1.DataLongitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_latitude_degrees_1.DataLatitudeDegrees.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_distance_1.DataDistance.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_altitude_1.DataAltitude.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_speed_1.DataSpeed.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_cadence_1.DataCadence.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_heart_rate_1.DataHeartRate.type).length).toEqual(expectedSamplesLength);
                    expect(activity.getSquashedStreamData(data_power_1.DataPower.type).length).toEqual(expectedSamplesLength);
                    done();
                })
                    .catch(e => done(e));
            });
            it('should parse virtual cycling GPX file (1)', done => {
                // Given GPX Source: https://connect.garmin.com/modern/activity/6909869014 OR https://www.strava.com/activities/5423473093
                // Given FIT Source: https://connect.garmin.com/modern/activity/1137672073 OR https://www.strava.com/activities/553573871
                const path = __dirname + '/fixtures/rides/gpx/6909869014.gpx';
                const gpxString = fs.readFileSync(path).toString();
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromGPX(gpxString, xmldom_1.default.DOMParser);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    const activity = event.getFirstActivity();
                    expect(activity.type).toEqual(activity_types_1.ActivityTypes.VirtualCycling);
                    expect(activity.hasPowerMeter()).toBeTruthy();
                    expect(activity.isTrainer()).toBeTruthy();
                    expect(activity.getStat(data_distance_1.DataDistance.type).getValue()).toBeCloseTo(28620, 0);
                    expect(activity.getStat(data_ascent_1.DataAscent.type).getValue()).toBeCloseTo(271, 0);
                    expect(activity.getStat(data_descent_1.DataDescent.type).getValue()).toBeCloseTo(257, 0);
                    expect(activity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(75);
                    expect(activity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(120);
                    expect(activity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(161);
                    expect(activity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(184);
                    expect(activity.getStat(data_power_avg_1.DataPowerAvg.type).getValue()).toBeCloseTo(142, 0);
                    expect(activity.getStat(data_power_max_1.DataPowerMax.type).getValue()).toBeCloseTo(330);
                    expect(activity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(7.55); // Or 27.2 kph
                    const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    const pauseTime = activity.getStat(data_pause_1.DataPause.type).getValue();
                    const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:02:58', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:03:09');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:03:09');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
    });
    describe('Triathlon', () => {
        describe('FIT', () => {
            it('should parse a .FIT Triathlon IronMan w/ 3 activities (swim + ride + run) ', done => {
                // Given https://connect.garmin.com/modern/activity/4623204522 ; https://www.strava.com/activities/5352030147 + https://www.strava.com/activities/5352030778 + https://www.strava.com/activities/5352030764
                const path = __dirname + '/fixtures/triathlons/fit/4623204522.fit';
                const buffer = fs.readFileSync(path);
                const activitiesCount = 5;
                // When
                const eventInterfacePromise = index_1.SportsLib.importFromFit(buffer);
                // Then
                eventInterfacePromise
                    .then((event) => {
                    expect(event.getActivities().length).toEqual(activitiesCount);
                    // Swim
                    const swimActivity = event.getFirstActivity();
                    expect(swimActivity.type).toEqual(activity_types_1.ActivityTypes.OpenWaterSwimming);
                    expect(swimActivity.getStreamData(data_speed_1.DataSpeed.type).length).toEqual(3689);
                    expect(swimActivity.startDate.toISOString()).toEqual('2018-10-13T17:05:01.000Z');
                    expect(swimActivity.endDate.toISOString()).toEqual('2018-10-13T18:06:29.000Z');
                    expect(swimActivity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(3933.3);
                    expect(swimActivity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(869);
                    expect(swimActivity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(37);
                    expect(swimActivity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(48);
                    expect(swimActivity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(93);
                    expect(swimActivity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(112);
                    expect(swimActivity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(2294);
                    spec_utils_1.SpecUtils.assertNearEqualTime(spec_utils_1.SpecUtils.speedToSwimPace(swimActivity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()), '01:34');
                    // Verifying time data
                    let movingTime = swimActivity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    let timerTime = swimActivity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    let pauseTime = swimActivity.getStat(data_pause_1.DataPause.type).getValue();
                    let elapsedTime = swimActivity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '01:01:16', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '01:01:29');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '01:01:29');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    // Transition
                    let transition = event.getActivities()[1];
                    expect(transition.type).toEqual(activity_types_1.ActivityTypes.Transition);
                    // Cycling
                    const cyclingActivity = event.getActivities()[2];
                    expect(cyclingActivity.type).toEqual(activity_types_1.ActivityTypes.Cycling);
                    expect(cyclingActivity.getStreamData(data_speed_1.DataSpeed.type).length).toEqual(17250);
                    expect(cyclingActivity.startDate.toISOString()).toEqual('2018-10-13T18:10:15.000Z');
                    expect(cyclingActivity.endDate.toISOString()).toEqual('2018-10-13T22:57:44.000Z');
                    expect(cyclingActivity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(180301.58);
                    expect(cyclingActivity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(3804);
                    expect(cyclingActivity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(89);
                    expect(cyclingActivity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(117);
                    expect(cyclingActivity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(140);
                    expect(cyclingActivity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(153);
                    expect(cyclingActivity.getStat(data_total_cycles_1.DataTotalCycles.type).getValue()).toEqual(24373);
                    expect(cyclingActivity.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue()).toBeCloseTo(10.453, 2); // Or 37.6 kph
                    // Verifying time data
                    movingTime = cyclingActivity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    timerTime = cyclingActivity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    pauseTime = cyclingActivity.getStat(data_pause_1.DataPause.type).getValue();
                    elapsedTime = cyclingActivity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '04:42:28', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '04:47:29');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '04:47:29');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime);
                    transition = event.getActivities()[3];
                    expect(transition.type).toEqual(activity_types_1.ActivityTypes.Transition);
                    const runningActivity = event.getActivities()[4];
                    expect(runningActivity.type).toEqual(activity_types_1.ActivityTypes.Running);
                    expect(runningActivity.startDate.toISOString()).toEqual('2018-10-13T22:57:45.000Z');
                    expect(runningActivity.endDate.toISOString()).toEqual('2018-10-14T02:42:23.000Z');
                    expect(runningActivity.getStat(data_distance_1.DataDistance.type).getValue()).toEqual(42563.91);
                    expect(runningActivity.getStat(data_energy_1.DataEnergy.type).getValue()).toEqual(2056);
                    expect(runningActivity.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue()).toEqual(84);
                    expect(runningActivity.getStat(data_cadence_max_1.DataCadenceMax.type).getValue()).toEqual(116);
                    expect(runningActivity.getStat(data_heart_rate_avg_1.DataHeartRateAvg.type).getValue()).toEqual(142);
                    expect(runningActivity.getStat(data_heart_rate_max_1.DataHeartRateMax.type).getValue()).toEqual(151);
                    spec_utils_1.SpecUtils.assertNearEqualTime(runningActivity.getStat(data_pace_avg_1.DataPaceAvg.type).getValue(), '05:08', 1);
                    // Verifying time data
                    movingTime = runningActivity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
                    timerTime = runningActivity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
                    pauseTime = runningActivity.getStat(data_pause_1.DataPause.type).getValue();
                    elapsedTime = runningActivity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
                    spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '03:36:57', 1);
                    spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '03:38:13');
                    spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '03:39:01');
                    spec_utils_1.SpecUtils.assertEqual(pauseTime, elapsedTime - timerTime, 1);
                    done();
                })
                    .catch(e => done(e));
            });
        });
    });
    describe('Others', () => {
        it('should reject parsing of broken fit file (empty activities)', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given
            const path = __dirname + '/fixtures/others/empty-activities.fit';
            const buffer = fs.readFileSync(path);
            const expectedErrorMessage = 'No activities found';
            const expectedErrorClassName = 'EmptyEventLibError';
            const expectedCode = 'EVENT_EMPTY_ERROR';
            // When & Then
            try {
                yield index_1.SportsLib.importFromFit(buffer);
                throw new Error('Should not be resolved...');
            }
            catch (err) {
                expect(err.constructor.name).toEqual(expectedErrorClassName);
                expect(err.message).toEqual(expectedErrorMessage);
                expect(err.code).toEqual(expectedCode);
                expect(err.event).toBeNull();
            }
        }));
        it('should reject parsing of broken fit file (empty sessions)', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given
            const path = __dirname + '/fixtures/others/empty-sessions.fit';
            const buffer = fs.readFileSync(path);
            const expectedErrorMessage = 'No activities found';
            const expectedErrorClassName = 'EmptyEventLibError';
            const expectedCode = 'EVENT_EMPTY_ERROR';
            // When & Then
            try {
                yield index_1.SportsLib.importFromFit(buffer);
                throw new Error('Should not be resolved...');
            }
            catch (err) {
                expect(err.constructor.name).toEqual(expectedErrorClassName);
                expect(err.message).toEqual(expectedErrorMessage);
                expect(err.code).toEqual(expectedCode);
                expect(err.event).toBeNull();
            }
        }));
        it('should parse fit file with broken sessionObject.start_time date', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given
            const path = __dirname + '/fixtures/others/broken-dates.fit';
            const buffer = fs.readFileSync(path);
            // When
            const event = yield index_1.SportsLib.importFromFit(buffer);
            // Then
            expect(event.startDate.toISOString()).toEqual('2017-03-20T19:09:28.000Z');
            expect(event.endDate.toISOString()).toEqual('2017-03-20T19:20:26.083Z');
        }));
        it('should handle activity with broken start lat/lng', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given FIT Source: https://connect.garmin.com/modern/activity/7606651718 OR https://www.strava.com/activities/6066984530
            const path = __dirname + '/fixtures/others/broken-start-latlng.fit';
            const buffer = fs.readFileSync(path);
            // When
            const event = yield index_1.SportsLib.importFromFit(buffer);
            // Then
            const activity = event.getFirstActivity();
            const longStream = activity.getSquashedStreamData(data_longitude_degrees_1.DataLongitudeDegrees.type);
            const latStream = activity.getSquashedStreamData(data_latitude_degrees_1.DataLatitudeDegrees.type);
            expect(longStream[0]).not.toEqual(0);
            expect(latStream[0]).not.toEqual(0);
        }));
        it('should reject parsing of a too long activity (31 days)', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given
            const path = __dirname + '/fixtures/others/31-days-activity.fit';
            const buffer = fs.readFileSync(path);
            const expectedErrorMessage = 'Activity duration exceeds 14 days. That is not supported';
            const expectedErrorClassName = 'DurationExceededEventLibError';
            const expectedCode = 'DURATION_EXCEEDED_EVENT_ERROR';
            // When & Then
            try {
                yield index_1.SportsLib.importFromFit(buffer);
                throw new Error('Should not be resolved...');
            }
            catch (err) {
                expect(err.constructor.name).toEqual(expectedErrorClassName);
                expect(err.message).toEqual(expectedErrorMessage);
                expect(err.code).toEqual(expectedCode);
                expect(err.event).toBeNull();
            }
        }));
        it.each([
            {
                fileName: 'garmin-corrupt-session-duration-record-range-1.fit',
                startDate: '2024-01-01T00:00:00.000Z',
                endDate: '2024-01-01T00:01:58.000Z',
                elapsedTime: 118,
                timerTime: 117
            },
            {
                fileName: 'garmin-corrupt-session-duration-record-range-2.fit',
                startDate: '2024-02-01T00:00:00.000Z',
                endDate: '2024-02-01T00:01:27.000Z',
                elapsedTime: 87,
                timerTime: 85
            }
        ])('should parse Garmin FIT file with corrupt session duration: $fileName', (expected) => __awaiter(void 0, void 0, void 0, function* () {
            // Given
            const path = process.cwd() + `/samples/fit/${expected.fileName}`;
            const buffer = fs.readFileSync(path);
            // When
            const event = yield index_1.SportsLib.importFromFit(buffer);
            // Then
            const activity = event.getFirstActivity();
            const lap = activity.getLaps()[0];
            expect(event.startDate.toISOString()).toEqual(expected.startDate);
            expect(event.endDate.toISOString()).toEqual(expected.endDate);
            expect(activity.startDate.toISOString()).toEqual(expected.startDate);
            expect(activity.endDate.toISOString()).toEqual(expected.endDate);
            expect(lap.startDate.toISOString()).toEqual(expected.startDate);
            expect(lap.endDate.toISOString()).toEqual(expected.endDate);
            expect(activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue()).toEqual(expected.elapsedTime);
            expect(activity.getStat(data_timer_time_1.DataTimerTime.type).getValue()).toEqual(expected.timerTime);
            expect(lap.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue()).toEqual(expected.elapsedTime);
            expect(lap.getStat(data_timer_time_1.DataTimerTime.type).getValue()).toEqual(expected.timerTime);
        }));
        it('should handle inverted elapsed and timer time', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given FIT Source: https://connect.garmin.com/modern/activity/7852903753 OR https://www.strava.com/activities/6288405028
            const path = __dirname + '/fixtures/others/inverted-times.fit';
            const buffer = fs.readFileSync(path);
            // When
            const event = yield index_1.SportsLib.importFromFit(buffer);
            // Then
            const activity = event.getFirstActivity();
            // Verifying time data
            const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
            const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
            const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
            spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '47:20', 1);
            spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '47:20');
            spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '06:01:20');
        }));
        it('should handle calculation on a ultra long activity (27 days) with acceptable human time', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given FIT Source: https://connect.garmin.com/modern/activity/7769719668 OR https://www.strava.com/activities/6197356353
            const path = __dirname + '/fixtures/others/27-days-activity.fit';
            const buffer = fs.readFileSync(path);
            const options = activity_parsing_options_1.ActivityParsingOptions.DEFAULT;
            options.maxActivityDurationDays = 30;
            const expectedSamplesLength = 3699;
            // When
            const event = yield index_1.SportsLib.importFromFit(buffer, options);
            // Then
            const activity = event.getFirstActivity();
            expect(activity.getSquashedStreamData(data_distance_1.DataDistance.type).length).toEqual(expectedSamplesLength);
            expect(activity.getSquashedStreamData(data_speed_1.DataSpeed.type).length).toEqual(expectedSamplesLength);
            expect(activity.getSquashedStreamData(data_cadence_1.DataCadence.type).length).toEqual(expectedSamplesLength);
            expect(activity.getSquashedStreamData(data_heart_rate_1.DataHeartRate.type).length).toEqual(expectedSamplesLength);
            expect(activity.getSquashedStreamData(data_grade_1.DataGrade.type).length).toEqual(expectedSamplesLength);
        }));
        it('should handle and detect an activity with broken speed data', () => __awaiter(void 0, void 0, void 0, function* () {
            // Given TCX Source: (unable to upload on garmin connect) OR https://www.strava.com/activities/3197023890
            const path = __dirname + '/fixtures/others/broken-speed-activity.tcx';
            const doc = domParser.parseFromString(fs.readFileSync(path).toString(), 'application/xml');
            const options = activity_parsing_options_1.ActivityParsingOptions.DEFAULT;
            options.streams.fixAbnormal.speed = true;
            // When
            const event = yield index_1.SportsLib.importFromTCX(doc);
            // Then
            const activity = event.getFirstActivity();
            const speedStdDev = (0, helpers_1.standardDeviation)(activity.getSquashedStreamData(data_speed_1.DataSpeed.type));
            expect(speedStdDev).toBeCloseTo(0.55, 2);
            // Verifying time data
            const movingTime = activity.getStat(data_moving_time_1.DataMovingTime.type).getValue();
            const timerTime = activity.getStat(data_timer_time_1.DataTimerTime.type).getValue();
            const elapsedTime = activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue();
            spec_utils_1.SpecUtils.assertNearEqualTime(movingTime, '05:04:20');
            spec_utils_1.SpecUtils.assertNearEqualTime(timerTime, '5:07:54');
            spec_utils_1.SpecUtils.assertNearEqualTime(elapsedTime, '5:07:54');
        }));
    });
});