···77import { ConditionalSearchAndReplaceRegExp, STAGE_TYPES, STAGE_TYPES_METADATA, STAGE_TYPES_USER, TRANSFORM_HOOK } from "../../common/infrastructure/Transform.js";
8899import { isConditionalSearchAndReplace } from "../../utils/PlayTransformUtils.js";
1010-import { asPlays, generateArtistsStr, generatePlay, normalizePlays } from "../../../core/PlayTestUtils.js";
1010+import { generateArtistsStr, generatePlay } from "../../../core/PlayTestUtils.js";
1111import { WebhookPayload } from "../../common/infrastructure/config/health/webhooks.js";
1212import { findCauseByMessage } from "../../utils/ErrorUtils.js";
1313import NativeTransformer from "../../common/transforms/NativeTransformer.js";
+3-3
src/backend/tests/musicbrainz/musicbrainz.test.ts
···460460461461 it('Finds none missing when all mbids are defined', function() {
462462463463- const play = withBrainz(generatePlay(), ['album', 'artist', 'track']);
463463+ const play = withBrainz(generatePlay(), {include: ['album', 'artist', 'track']});
464464 const missing = missingMbidTypes(play);
465465 expect(missing.length).eq(0);
466466 });
···474474475475 it('Finds duration missing', function() {
476476477477- const play = withBrainz(generatePlay(), ['album', 'artist', 'track']);
477477+ const play = withBrainz(generatePlay(), {include: ['album', 'artist', 'track']});
478478 delete play.data.duration;
479479 const missing = missingMbidTypes(play);
480480 expect(missing.length).eq(1);
···491491492492 it('intersect is not empty when missing any desired types', function() {
493493494494- const play = withBrainz(generatePlay(), ['album', 'track']);
494494+ const play = withBrainz(generatePlay(), {include: ['album', 'track']});
495495 const missing = missingMbidTypes(play);
496496 expect(missing).to.have.members(['artists']);
497497 expect(intersect(DEFAULT_MISSING_TYPES, missing)).length.is.greaterThan(0);
+2-3
src/backend/tests/plays/playParsing.test.ts
···11-import { loggerTest, loggerDebug, childLogger } from "@foxxmd/logging";
21import chai, { assert, expect } from 'chai';
32import asPromised from 'chai-as-promised';
43import { after, before, describe, it } from 'mocha';
5466-import { asPlays, generateArtistsStr, generatePlay, normalizePlays } from "../../../core/PlayTestUtils.js";
77-import { parseArtistCredits, parseContextAwareStringList, parseCredits, parseTrackCredits, uniqueNormalizedStrArr } from "../../utils/StringUtils.js";
55+import { generateArtistsStr, } from "../../../core/PlayTestUtils.js";
66+import { parseArtistCredits, parseCredits, parseTrackCredits, uniqueNormalizedStrArr } from "../../utils/StringUtils.js";
87import testData from '../utils/playTestData.json' with { type: "json" };
98import { intersect } from "../../utils.js";
109import { ExpectedResults } from "../utils/interfaces.js";
+5-3
src/backend/tests/scrobbler/scrobblers.test.ts
···1212import mixedDuration from '../plays/mixedDuration.json' with { type: 'json' };
1313import withDuration from '../plays/withDuration.json' with { type: 'json' };
1414import { MockNetworkError, withRequestInterception } from "../utils/networking.js";
1515-import { asPlays, generatePlay, generatePlayPlatformId, generatePlays, generateSourcePlayerObj, normalizePlays } from "../../../core/PlayTestUtils.js";
1515+import { generatePlay, generatePlayPlatformId, generatePlays, generateSourcePlayerObj, normalizePlays } from "../../../core/PlayTestUtils.js";
1616import MockDate from 'mockdate';
17171818import { NowPlayingScrobbler, TestAuthScrobbler, TestScrobbler } from "./TestScrobbler.js";
···2020import { defaultLifecycle } from '../../utils/PlayTransformUtils.js';
2121import { shuffleArray } from '../../utils/DataUtils.js';
2222import { DEFAULT_CONSOLIDATE_DURATION, DEFAULT_GROUP_DURATION, groupPlaysToTimeRanges } from '../../utils/ListenFetchUtils.js';
2323+import { asPlay } from '../../../core/tests/utils/fixtures.js';
23242425chai.use(asPromised);
25262627const firstPlayDate = dayjs().subtract(1, 'hour');
2728const olderFirstPlayDate = dayjs().subtract(4, 'hour');
28292929-const withDurPlays = asPlays(withDuration);
3030-const mixedDurPlays = asPlays(mixedDuration);
3030+const withDurPlays = withDuration.map(asPlay);
3131+// @ts-expect-error mixed duration is missing meta but not used for tests
3232+const mixedDurPlays = mixedDuration.map(asPlay);
3133const normalizedWithDur = normalizePlays(withDurPlays, {initialDate: firstPlayDate});
3234const normalizedWithMixedDur = normalizePlays(mixedDurPlays, {initialDate: firstPlayDate});
3335
+11-6
src/core/Atomic.ts
···8484 }
8585}
86868787-export interface PlayProgressAmb {
8888- timestamp: string | Dayjs
8787+export interface PlayProgressAmb<D extends DateLike = Dayjs> {
8888+ timestamp: D
8989 position?: number
9090 positionPercent?: number
9191}
···299299300300export interface PlayLifecycle<D extends DateLike = Dayjs> {
301301 input?: object
302302- original: PlayObjectLifecycleless
302302+ original: PlayObjectLifecycleless<D>
303303 steps: LifecycleStep[]
304304 scrobble?: ScrobbleResult
305305}
···321321 warnings?: string[]
322322}
323323324324-export interface PlayMatchResult {
324324+export interface PlayMatchResult<D extends DateLike = Dayjs> {
325325 match: boolean
326326 score: number
327327 breakdowns: string[]
328328 reason?: string
329329- closestMatchedPlay?: PlayObjectLifecycleless
330330- transformedPlay?: PlayObjectLifecycleless
329329+ closestMatchedPlay?: PlayObjectLifecycleless<D>
330330+ transformedPlay?: PlayObjectLifecycleless<D>
331331 summary?: String
332332}
333333···575575 indicate?: boolean;
576576 };
577577}
578578+/** Only checks for DateT since we can reasonbly sure if this exists its a date we can parse with dayjs
579579+ *
580580+ * It needs to be cheap since we mostly use this when walking play objects to transform strings back to dayjs and there may be many strings to check
581581+ */
582582+export const REGEX_ISO8601_LOOSE = new RegExp(/\d{4}-[01]\d-[0-3]\dT/);