8000 Add tests for ordering and selecting the tracks by activity · firefox-devtools/profiler@bb2c8b3 · GitHub
[go: up one dir, main page]

Skip to content

Commit bb2c8b3

Browse files
committed
Add tests for ordering and selecting the tracks by activity
1 parent 9d200f8 commit bb2c8b3

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed

src/test/store/tracks.test.js

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
getNetworkTrackProfile,
88
addIPCMarkerPairToThreads,
99
getProfileWithMarkers,
10+
getProfileFromTextSamples,
11+
getProfileWithThreadCPUDelta,
1012
} from '../fixtures/profiles/processed-profile';
1113
import { getEmptyThread } from '../../profile-logic/data-structures';
1214
import { storeWithProfile } from '../fixtures/stores';
@@ -396,6 +398,202 @@ describe('ordering and hiding', function () {
396398
).toEqual(userFacingSortOrder);
397399
});
398400
});
401+
402+
describe('ordering by activity', function () {
403+
it('orders process tracks by activity score while keeping parent process first', function () {
404+
const { profile } = getProfileFromTextSamples(
405+
'A B C D E F G H I J', // High activity parent process
406+
'X Y', // Low activity tab process
407+
'P Q R S T U V W X Y Z A B C D' // Very high activity tab process
408+
);
409+
410+
// Set up threads as different processes
411+
profile.threads[0].name = 'GeckoMain';
412+
profile.threads[0].isMainThread = true;
413+
profile.threads[0].processType = 'default'; // Parent process
414+
profile.threads[0].pid = '1';
415+
416+
profile.threads[1].name = 'GeckoMain';
417+
profile.threads[1].isMainThread = true;
418+
profile.threads[1].processType = 'tab';
419+
profile.threads[1].pid = '2';
420+
421+
profile.threads[2].name = 'GeckoMain';
422+
profile.threads[2].isMainThread = true;
423+
profile.threads[2].processType = 'tab';
424+
profile.threads[2].pid = '3';
425+
426+
const { getState } = storeWithProfile(profile);
427+
428+
// Parent process should be first, then tab processes ordered by activity
429+
// The highest activity tab process (index 2) should be selected by default
430+
expect(getHumanReadableTracks(getState())).toEqual([
431+
'show [thread GeckoMain default]', // Parent process first
432+
'show [thread GeckoMain tab] SELECTED', // Very high activity tab process selected
433+
'show [thread GeckoMain tab]', // Low activity tab process
434+
]);
435+
436+
const globalTrackOrder =
437+
UrlStateSelectors.getGlobalTrackOrder(getState());
438+
expect(globalTrackOrder).toEqual([0, 2, 1]);
439+
});
440+
441+
it('orders multiple tab processes by their activity levels', function () {
442+
const profile = getProfileWithThreadCPUDelta([
443+
[5, 5, 5], // Low activity tab process
444+
[50, 50, 50], // High activity tab process
445+
[25, 25, 25], // Medium activity tab process
446+
]);
447+
448+
profile.threads[0].name = 'GeckoMain';
449+
profile.threads[0].isMainThread = true;
450+
profile.threads[0].processType = 'tab';
451+
profile.threads[0].pid = '1';
452+
453+
profile.threads[1].name = 'GeckoMain';
454+
profile.threads[1].isMainThread = true;
455+
profile.threads[1].processType = 'tab';
456+
profile.threads[1].pid = '2';
457+
458+
profile.threads[2].name = 'GeckoMain';
459+
profile.threads[2].isMainThread = true;
460+
profile.threads[2].processType = 'tab';
461+
profile.threads[2].pid = '3';
462+
463+
const { getState } = storeWithProfile(profile);
464+
465+
// Processes should be ordered by activity: high, medium, low
466+
expect(getHumanReadableTracks(getState())).toEqual([
467+
'show [thread GeckoMain tab] SELECTED', // High activity (index 1)
468+
'show [thread GeckoMain tab]', // Medium activity (index 2)
469+
'show [thread GeckoMain tab]', // Low activity (index 0)
470+
]);
471+
472+
const globalTrackOrder =
473+
UrlStateSelectors.getGlobalTrackOrder(getState());
474+
expect(globalTrackOrder).toEqual([1, 2, 0]);
475+
});
476+
477+
it('handles processes without main threads gracefully', function () {
478+
const { profile } = getProfileFromTextSamples('A', 'B');
479+
480+
profile.threads[0].name = 'GeckoMain';
481+
profile.threads[0].isMainThread = true;
482+
profile.threads[0].processType = 'tab';
483+
profile.threads[0].pid = '1';
484+
485+
profile.threads[1].name = 'DOM Worker';
486+
profile.threads[1].isMainThread = false;
487+
profile.threads[1].processType = 'tab';
488+
profile.threads[1].pid = '2'; // Different PID, no main thread
489+
490+
const { getState } = storeWithProfile(profile);
491+
492+
// Should not crash and maintain a stable order
493+
expect(getHumanReadableTracks(getState())).toEqual([
494+
'show [thread GeckoMain tab] SELECTED',
495+
'show [process]',
496+
' - show [thread DOM Worker]',
497+
]);
498+
499+
const globalTrackOrder =
500+
UrlStateSelectors.getGlobalTrackOrder(getState());
501+
expect(globalTrackOrder).toEqual([0, 1]);
502+
});
503+
});
504+
505+
describe('default selected thread selection by activity', function () {
506+
it('selects the tab process with highest activity as default', function () {
507+
const profile = getProfileWithThreadCPUDelta([
508+
[10, 10, 10], // Low activity parent process
509+
[5, 5, 5], // Low activity tab process
510+
[50, 50, 50], // High activity tab process
511+
]);
512+
513+
profile.threads[0].name = 'GeckoMain';
514+
profile.threads[0].isMainThread = true;
515+
profile.threads[0].processType = 'default'; // Parent process
516+
profile.threads[0].pid = '0';
517+
518+
profile.threads[1].name = 'GeckoMain';
519+
profile.threads[1].isMainThread = true;
520+
profile.threads[1].processType = 'tab';
521+
profile.threads[1].pid = '1';
522+
523+
profile.threads[2].name = 'GeckoMain';
524+
profile.threads[2].isMainThread = true;
525+
profile.threads[2].processType = 'tab';
526+
profile.threads[2].pid = '2';
527+
528+
const { getState } = storeWithProfile(profile);
529+
530+
// The high activity tab process (index 2) should be selected
531+
expect(getHumanReadableTracks(getState())).toEqual([
532+
'show [thread GeckoMain default]', // Parent process
533+
'show [thread GeckoMain tab] SELECTED', // High activity tab selected
534+
'show [thread GeckoMain tab]', // Low activity tab
535+
]);
536+
537+
const globalTrackOrder =
538+
UrlStateSelectors.getGlobalTrackOrder(getState());
539+
expect(globalTrackOrder).toEqual([0, 2, 1]);
540+
});
541+
542+
it('falls back to first thread when no tab processes exist', function () {
543+
const profile = getProfileWithThreadCPUDelta([
544+
[10, 10, 10], // Parent process only
545+
]);
546+
547+
profile.threads[0].name = 'GeckoMain';
548+
profile.threads[0].isMainThread = true;
549+
profile.threads[0].processType = 'default';
550+
profile.threads[0].pid = '0';
551+
552+
const { getState } = storeWithProfile(profile);
553+
554+
// Parent process should be selected as fallback
555+
expect(getHumanReadableTracks(getState())).toEqual([
556+
'show [thread GeckoMain default] SELECTED',
557+
]);
558+
});
559+
560+
it('selects highest activity tab even when parent has higher activity', function () {
561+
const profile = getProfileWithThreadCPUDelta([
562+
[100, 100, 100], // Very high activity parent process
563+
[50, 50, 50], // Medium activity tab process
564+
[75, 75, 75], // High activity tab process
565+
]);
566+
567+
profile.threads[0].name = 'GeckoMain';
568+
profile.threads[0].isMainThread = true;
569+
profile.threads[0].processType = 'default'; // Parent process
570+
profile.threads[0].pid = '0';
571+
572+
profile.threads[1].name = 'GeckoMain';
573+
profile.threads[1].isMainThread = true;
574+
profile.threads[1].processType = 'tab';
575+
profile.threads[1].pid = '1';
576+
577+
profile.threads[2].name = 'GeckoMain';
578+
profile.threads[2].isMainThread = true;
579+
profile.threads[2].processType = 'tab';
580+
profile.threads[2].pid = '2';
581+
582+
const { getState } = storeWithProfile(profile);
583+
584+
// The highest activity tab process (index 2) should be selected,
585+
// not the parent process despite it having higher activity
586+
expect(getHumanReadableTracks(getState())).toEqual([
587+
'show [thread GeckoMain default]', // Parent process not selected
588+
'show [thread GeckoMain tab] SELECTED', // High activity tab selected
589+
'show [thread GeckoMain tab]', // Medium activity tab
590+
]);
591+
592+
const globalTrackOrder =
593+
UrlStateSelectors.getGlobalTrackOrder(getState());
594+
expect(globalTrackOrder).toEqual([0, 2, 1]);
595+
});
596+
});
399597
});
400598

401599
describe('local tracks', function () {

0 commit comments

Comments
 (0)
0