mirror of
https://github.com/Ujwal223/FocusGram.git
synced 2026-04-02 17:41:16 +02:00
fixed external redirect on instagram m's settings. fixed bug where it opened app session instead of reel session. hided vertical scroll bar. removed custom bottom bar. fixed bug where it wasnt showing searchbar in /explore. FIXED/ADDED/IMPROVED A LOT MORE THINGS. Ready for Release
373 lines
12 KiB
Dart
373 lines
12 KiB
Dart
// test/services/injection_controller_test.dart
|
|
//
|
|
// Tests for InjectionController — JS/CSS builder, Ghost Mode keyword resolver,
|
|
// and JS string generation.
|
|
//
|
|
// Run with: flutter test test/services/injection_controller_test.dart
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:focusgram/services/injection_controller.dart';
|
|
|
|
void main() {
|
|
// ── resolveBlockedKeywords ───────────────────────────────────────────────
|
|
|
|
group('InjectionController.resolveBlockedKeywords', () {
|
|
test('returns empty list when all flags are false', () {
|
|
final kws = InjectionController.resolveBlockedKeywords(
|
|
typingIndicator: false,
|
|
seenStatus: false,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(kws, isEmpty);
|
|
});
|
|
|
|
test('includes seen keywords when seenStatus is true', () {
|
|
final kws = InjectionController.resolveBlockedKeywords(
|
|
typingIndicator: false,
|
|
seenStatus: true,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(
|
|
kws,
|
|
containsAll(['/seen', 'media/seen', 'reel/seen', '/mark_seen']),
|
|
);
|
|
});
|
|
|
|
test('includes typing keywords when typingIndicator is true', () {
|
|
final kws = InjectionController.resolveBlockedKeywords(
|
|
typingIndicator: true,
|
|
seenStatus: false,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(kws, containsAll(['set_typing_status', '/typing']));
|
|
});
|
|
|
|
test('includes live keywords when stories is true', () {
|
|
final kws = InjectionController.resolveBlockedKeywords(
|
|
typingIndicator: false,
|
|
seenStatus: false,
|
|
stories: true,
|
|
dmPhotos: false,
|
|
);
|
|
expect(kws, contains('/live/'));
|
|
});
|
|
|
|
test('includes visual_item_seen when dmPhotos is true', () {
|
|
final kws = InjectionController.resolveBlockedKeywords(
|
|
typingIndicator: false,
|
|
seenStatus: false,
|
|
stories: false,
|
|
dmPhotos: true,
|
|
);
|
|
expect(kws, contains('visual_item_seen'));
|
|
});
|
|
|
|
test('all flags true — returns all groups combined', () {
|
|
final kws = InjectionController.resolveBlockedKeywords(
|
|
typingIndicator: true,
|
|
seenStatus: true,
|
|
stories: true,
|
|
dmPhotos: true,
|
|
);
|
|
// Must contain at least one keyword from every group
|
|
expect(
|
|
kws,
|
|
containsAll([
|
|
'/seen',
|
|
'set_typing_status',
|
|
'/live/',
|
|
'visual_item_seen',
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('no duplicates in result (seen + typing + stories + dmPhotos)', () {
|
|
final kws = InjectionController.resolveBlockedKeywords(
|
|
typingIndicator: true,
|
|
seenStatus: true,
|
|
stories: true,
|
|
dmPhotos: true,
|
|
);
|
|
final unique = kws.toSet();
|
|
expect(kws.length, unique.length);
|
|
});
|
|
});
|
|
|
|
// ── resolveWsBlockedKeywords ─────────────────────────────────────────────
|
|
|
|
group('InjectionController.resolveWsBlockedKeywords', () {
|
|
test('returns empty list when typingIndicator is false', () {
|
|
expect(
|
|
InjectionController.resolveWsBlockedKeywords(typingIndicator: false),
|
|
isEmpty,
|
|
);
|
|
});
|
|
|
|
test('returns non-empty list when typingIndicator is true', () {
|
|
final kws = InjectionController.resolveWsBlockedKeywords(
|
|
typingIndicator: true,
|
|
);
|
|
expect(kws, isNotEmpty);
|
|
expect(kws, contains('activity_status'));
|
|
});
|
|
});
|
|
|
|
// ── buildGhostModeJS ─────────────────────────────────────────────────────
|
|
|
|
group('InjectionController.buildGhostModeJS', () {
|
|
test('returns empty string when all flags are false', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: false,
|
|
seenStatus: false,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(js.trim(), isEmpty);
|
|
});
|
|
|
|
test('generated JS contains seen keywords when seenStatus=true', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: false,
|
|
seenStatus: true,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(js, contains('/seen'));
|
|
expect(js, contains('media/seen'));
|
|
});
|
|
|
|
test('generated JS contains typing keywords when typingIndicator=true', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: true,
|
|
seenStatus: false,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(js, contains('set_typing_status'));
|
|
});
|
|
|
|
test('generated JS contains live keyword when stories=true', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: false,
|
|
seenStatus: false,
|
|
stories: true,
|
|
dmPhotos: false,
|
|
);
|
|
expect(js, contains('/live/'));
|
|
});
|
|
|
|
test('generated JS contains BLOCKED array and shouldBlock function', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: false,
|
|
seenStatus: true,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(js, contains('BLOCKED'));
|
|
expect(js, contains('shouldBlock'));
|
|
});
|
|
|
|
test('generated JS wraps XHR and fetch', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: true,
|
|
seenStatus: true,
|
|
stories: true,
|
|
dmPhotos: true,
|
|
);
|
|
expect(js, contains('window.fetch'));
|
|
expect(js, contains('XMLHttpRequest.prototype.open'));
|
|
expect(js, contains('XMLHttpRequest.prototype.send'));
|
|
});
|
|
|
|
test('WS patch is included when typingIndicator=true', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: true,
|
|
seenStatus: false,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
expect(js, contains('WebSocket'));
|
|
});
|
|
|
|
test('WS patch is NOT included when typingIndicator=false', () {
|
|
final js = InjectionController.buildGhostModeJS(
|
|
typingIndicator: false,
|
|
seenStatus: true,
|
|
stories: false,
|
|
dmPhotos: false,
|
|
);
|
|
// WS_KEYS will be empty array; the `if (WS_KEYS.length > 0)` guard
|
|
// prevents the WS override from running — but the string may still be present.
|
|
// At minimum, WS_KEYS should be empty in the output.
|
|
expect(js, contains('WS_KEYS = []'));
|
|
});
|
|
});
|
|
|
|
// ── buildSessionStateJS ──────────────────────────────────────────────────
|
|
|
|
group('InjectionController.buildSessionStateJS', () {
|
|
test('returns true assignment when active', () {
|
|
expect(
|
|
InjectionController.buildSessionStateJS(true),
|
|
contains('__focusgramSessionActive = true'),
|
|
);
|
|
});
|
|
|
|
test('returns false assignment when inactive', () {
|
|
expect(
|
|
InjectionController.buildSessionStateJS(false),
|
|
contains('__focusgramSessionActive = false'),
|
|
);
|
|
});
|
|
});
|
|
|
|
// ── softNavigateJS ───────────────────────────────────────────────────────
|
|
|
|
group('InjectionController.softNavigateJS', () {
|
|
test('contains the target path', () {
|
|
final js = InjectionController.softNavigateJS('/direct/inbox/');
|
|
expect(js, contains('/direct/inbox/'));
|
|
});
|
|
|
|
test('contains location.href assignment', () {
|
|
final js = InjectionController.softNavigateJS('/explore/');
|
|
expect(js, contains('location.href'));
|
|
});
|
|
});
|
|
|
|
// ── buildInjectionJS ─────────────────────────────────────────────────────
|
|
|
|
group('InjectionController.buildInjectionJS', () {
|
|
InjectionController.buildInjectionJS; // reference check
|
|
|
|
test('contains session state flag', () {
|
|
final js = _buildFull();
|
|
expect(js, contains('__focusgramSessionActive'));
|
|
});
|
|
|
|
test('contains path tracker when assembled', () {
|
|
final js = _buildFull();
|
|
expect(js, contains('fgTrackPath'));
|
|
});
|
|
|
|
test('includes reels block JS when session is not active', () {
|
|
final js = InjectionController.buildInjectionJS(
|
|
sessionActive: false,
|
|
blurExplore: false,
|
|
blurReels: false,
|
|
ghostTyping: false,
|
|
ghostSeen: false,
|
|
ghostStories: false,
|
|
ghostDmPhotos: false,
|
|
enableTextSelection: false,
|
|
);
|
|
expect(js, contains('fgReelsBlock'));
|
|
});
|
|
|
|
test('does NOT include reels block JS when session is active', () {
|
|
final js = InjectionController.buildInjectionJS(
|
|
sessionActive: true,
|
|
blurExplore: false,
|
|
blurReels: false,
|
|
ghostTyping: false,
|
|
ghostSeen: false,
|
|
ghostStories: false,
|
|
ghostDmPhotos: false,
|
|
enableTextSelection: false,
|
|
);
|
|
expect(js, isNot(contains('fgReelsBlock')));
|
|
});
|
|
|
|
test('always includes link sanitizer', () {
|
|
final js = InjectionController.buildInjectionJS(
|
|
sessionActive: false,
|
|
blurExplore: false,
|
|
blurReels: false,
|
|
ghostTyping: false,
|
|
ghostSeen: false,
|
|
ghostStories: false,
|
|
ghostDmPhotos: false,
|
|
enableTextSelection: false,
|
|
);
|
|
// linkSanitizationJS is now always injected (not togglable)
|
|
expect(js, contains('fgSanitize'));
|
|
});
|
|
|
|
test('returns non-empty string in all cases', () {
|
|
expect(_buildFull().trim(), isNotEmpty);
|
|
});
|
|
});
|
|
|
|
// ── iOSUserAgent sanity ──────────────────────────────────────────────────
|
|
|
|
group('InjectionController.iOSUserAgent', () {
|
|
test('contains iPhone identifier', () {
|
|
expect(InjectionController.iOSUserAgent, contains('iPhone'));
|
|
});
|
|
|
|
test('contains FBAN (Instagram app identifier)', () {
|
|
expect(InjectionController.iOSUserAgent, contains('FBAN'));
|
|
});
|
|
|
|
test('is non-empty', () {
|
|
expect(InjectionController.iOSUserAgent, isNotEmpty);
|
|
});
|
|
});
|
|
|
|
// ── notificationBridgeJS ─────────────────────────────────────────────────
|
|
|
|
group('InjectionController.notificationBridgeJS', () {
|
|
test('contains Notification bridge guard', () {
|
|
expect(
|
|
InjectionController.notificationBridgeJS,
|
|
contains('fgNotifBridged'),
|
|
);
|
|
});
|
|
|
|
test('patches window.Notification', () {
|
|
expect(
|
|
InjectionController.notificationBridgeJS,
|
|
contains('window.Notification'),
|
|
);
|
|
});
|
|
});
|
|
|
|
// ── linkSanitizationJS ───────────────────────────────────────────────────
|
|
|
|
group('InjectionController.linkSanitizationJS', () {
|
|
test('strips igsh param', () {
|
|
expect(InjectionController.linkSanitizationJS, contains('igsh'));
|
|
});
|
|
|
|
test('strips utm params', () {
|
|
expect(InjectionController.linkSanitizationJS, contains('utm_source'));
|
|
});
|
|
|
|
test('strips fbclid', () {
|
|
expect(InjectionController.linkSanitizationJS, contains('fbclid'));
|
|
});
|
|
|
|
test('patches navigator.share', () {
|
|
expect(
|
|
InjectionController.linkSanitizationJS,
|
|
contains('navigator.share'),
|
|
);
|
|
});
|
|
});
|
|
}
|
|
|
|
/// Helper to create a fully-featured injection JS for common assertions.
|
|
String _buildFull() => InjectionController.buildInjectionJS(
|
|
sessionActive: false,
|
|
blurExplore: true,
|
|
blurReels: true,
|
|
ghostTyping: true,
|
|
ghostSeen: true,
|
|
ghostStories: true,
|
|
ghostDmPhotos: true,
|
|
enableTextSelection: false,
|
|
);
|