Skip to content

Commit b183a43

Browse files
chore: add store API in iOS side
1 parent d9acd3a commit b183a43

File tree

13 files changed

+512
-111
lines changed

13 files changed

+512
-111
lines changed

example/ios/InstabugTests/ApmApiTests.m

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,5 +266,325 @@ - (void)testEndScreenLoading {
266266
OCMVerify([self.mAPM endScreenLoadingCPWithEndTimestampMUS:endScreenLoadingCPWithEndTimestampMUS]);
267267
}
268268

269+
- (void)testIsScreenRenderEnabled {
270+
XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"];
271+
272+
BOOL isScreenRenderEnabled = YES;
273+
OCMStub([self.mAPM isScreenRenderingOperational]).andReturn(isScreenRenderEnabled);
274+
275+
[self.api isScreenRenderEnabledWithCompletion:^(NSNumber *isEnabledNumber, FlutterError *error) {
276+
[expectation fulfill];
277+
278+
XCTAssertEqualObjects(isEnabledNumber, @(isScreenRenderEnabled));
279+
XCTAssertNil(error);
280+
}];
281+
282+
[self waitForExpectations:@[expectation] timeout:5.0];
283+
}
284+
285+
- (void)testIsScreenRenderEnabledWhenDisabled {
286+
XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"];
287+
288+
BOOL isScreenRenderEnabled = NO;
289+
OCMStub([self.mAPM isScreenRenderingOperational]).andReturn(isScreenRenderEnabled);
290+
291+
[self.api isScreenRenderEnabledWithCompletion:^(NSNumber *isEnabledNumber, FlutterError *error) {
292+
[expectation fulfill];
293+
294+
XCTAssertEqualObjects(isEnabledNumber, @(isScreenRenderEnabled));
295+
XCTAssertNil(error);
296+
}];
297+
298+
[self waitForExpectations:@[expectation] timeout:5.0];
299+
}
300+
301+
- (void)testSetScreenRenderEnabled {
302+
NSNumber *isEnabled = @1;
303+
FlutterError *error;
304+
305+
[self.api setScreenRenderEnabledIsEnabled:isEnabled error:&error];
306+
307+
OCMVerify([self.mAPM setScreenRenderingEnabled:YES]);
308+
}
309+
310+
- (void)testSetScreenRenderDisabled {
311+
NSNumber *isEnabled = @0;
312+
FlutterError *error;
313+
314+
[self.api setScreenRenderEnabledIsEnabled:isEnabled error:&error];
315+
316+
OCMVerify([self.mAPM setScreenRenderingEnabled:NO]);
317+
}
318+
319+
- (void)testDeviceRefreshRate {
320+
XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"];
321+
322+
// Mock UIScreen for iOS 10.3+
323+
id mockScreen = OCMClassMock([UIScreen class]);
324+
OCMStub([mockScreen mainScreen]).andReturn(mockScreen);
325+
OCMStub([mockScreen maximumFramesPerSecond]).andReturn(120.0);
326+
327+
[self.api deviceRefreshRateWithCompletion:^(NSNumber *refreshRate, FlutterError *error) {
328+
[expectation fulfill];
329+
330+
XCTAssertEqualObjects(refreshRate, @(120.0));
331+
XCTAssertNil(error);
332+
}];
333+
334+
[self waitForExpectations:@[expectation] timeout:5.0];
335+
336+
[mockScreen stopMocking];
337+
}
338+
339+
- (void)testDeviceRefreshRateFallback {
340+
XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"];
341+
342+
// Note: Testing the fallback behavior for iOS < 10.3 is challenging in unit tests
343+
// since we can't easily mock the iOS version check. In a real scenario, this would
344+
// return 60.0 for older iOS versions. For now, we'll test the normal case.
345+
346+
// Mock UIScreen to return 60.0 (typical fallback value)
347+
id mockScreen = OCMClassMock([UIScreen class]);
348+
OCMStub([mockScreen mainScreen]).andReturn(mockScreen);
349+
OCMStub([mockScreen maximumFramesPerSecond]).andReturn(60.0);
350+
351+
[self.api deviceRefreshRateWithCompletion:^(NSNumber *refreshRate, FlutterError *error) {
352+
[expectation fulfill];
353+
354+
XCTAssertEqualObjects(refreshRate, @(60.0));
355+
XCTAssertNil(error);
356+
}];
357+
358+
[self waitForExpectations:@[expectation] timeout:5.0];
359+
360+
[mockScreen stopMocking];
361+
}
362+
363+
- (void)testEndScreenRenderForAutoUiTrace {
364+
FlutterError *error;
365+
366+
// Create mock frame data
367+
NSDictionary *frameData = @{
368+
@"frameData": @[
369+
@[@(1000.0), @(16.67)], // Frame 1: start time 1000.0µs, duration 16.67µs
370+
@[@(1016.67), @(33.33)], // Frame 2: start time 1016.67µs, duration 33.33µs
371+
@[@(1050.0), @(50.0)] // Frame 3: start time 1050.0µs, duration 50.0µs
372+
]
373+
};
374+
375+
[self.api endScreenRenderForAutoUiTraceData:frameData error:&error];
376+
377+
// Verify that endAutoUITraceCPWithFrames was called
378+
OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
379+
// Verify that we have the correct number of frames
380+
XCTAssertEqual(frames.count, 3);
381+
382+
// Verify the first frame
383+
IBGFrameInfo *firstFrame = frames[0];
384+
XCTAssertEqual(firstFrame.startTimestampInMicroseconds, 1000.0);
385+
XCTAssertEqual(firstFrame.durationInMicroseconds, 16.67);
386+
387+
// Verify the second frame
388+
IBGFrameInfo *secondFrame = frames[1];
389+
XCTAssertEqual(secondFrame.startTimestampInMicroseconds, 1016.67);
390+
XCTAssertEqual(secondFrame.durationInMicroseconds, 33.33);
391+
392+
// Verify the third frame
393+
IBGFrameInfo *thirdFrame = frames[2];
394+
XCTAssertEqual(thirdFrame.startTimestampInMicroseconds, 1050.0);
395+
XCTAssertEqual(thirdFrame.durationInMicroseconds, 50.0);
396+
397+
return YES;
398+
}]]);
399+
}
400+
401+
- (void)testEndScreenRenderForCustomUiTrace {
402+
FlutterError *error;
403+
404+
// Create mock frame data
405+
NSDictionary *frameData = @{
406+
@"frameData": @[
407+
@[@(2000.0), @(20.0)], // Frame 1: start time 2000.0µs, duration 20.0µs
408+
@[@(2020.0), @(25.0)] // Frame 2: start time 2020.0µs, duration 25.0µs
409+
]
410+
};
411+
412+
[self.api endScreenRenderForCustomUiTraceData:frameData error:&error];
413+
414+
// Verify that endCustomUITraceCPWithFrames was called
415+
OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
416+
// Verify that we have the correct number of frames
417+
XCTAssertEqual(frames.count, 2);
418+
419+
// Verify the first frame
420+
IBGFrameInfo *firstFrame = frames[0];
421+
XCTAssertEqual(firstFrame.startTimestampInMicroseconds, 2000.0);
422+
XCTAssertEqual(firstFrame.durationInMicroseconds, 20.0);
423+
424+
// Verify the second frame
425+
IBGFrameInfo *secondFrame = frames[1];
426+
XCTAssertEqual(secondFrame.startTimestampInMicroseconds, 2020.0);
427+
XCTAssertEqual(secondFrame.durationInMicroseconds, 25.0);
428+
429+
return YES;
430+
}]]);
431+
}
432+
433+
- (void)testEndScreenRenderForAutoUiTraceWithEmptyFrameData {
434+
FlutterError *error;
435+
436+
// Create empty frame data
437+
NSDictionary *frameData = @{
438+
@"frameData": @[]
439+
};
440+
441+
[self.api endScreenRenderForAutoUiTraceData:frameData error:&error];
442+
443+
// Verify that endAutoUITraceCPWithFrames was called with empty array
444+
OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
445+
XCTAssertEqual(frames.count, 0);
446+
return YES;
447+
}]]);
448+
}
449+
450+
- (void)testEndScreenRenderForCustomUiTraceWithEmptyFrameData {
451+
FlutterError *error;
452+
453+
// Create empty frame data
454+
NSDictionary *frameData = @{
455+
@"frameData": @[]
456+
};
457+
458+
[self.api endScreenRenderForCustomUiTraceData:frameData error:&error];
459+
460+
// Verify that endCustomUITraceCPWithFrames was called with empty array
461+
OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
462+
XCTAssertEqual(frames.count, 0);
463+
return YES;
464+
}]]);
465+
}
466+
467+
- (void)testEndScreenRenderForAutoUiTraceWithMalformedFrameData {
468+
FlutterError *error;
469+
470+
// Create malformed frame data (missing values or extra values)
471+
NSDictionary *frameData = @{
472+
@"frameData": @[
473+
@[@(1000.0)], // Frame with only one value (should be ignored)
474+
@[@(1016.67), @(33.33)], // Valid frame
475+
@[@(1050.0), @(50.0), @(100.0)] // Frame with extra values (should be ignored)
476+
]
477+
};
478+
479+
[self.api endScreenRenderForAutoUiTraceData:frameData error:&error];
480+
481+
// Verify that endAutoUITraceCPWithFrames was called with only valid frames
482+
OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
483+
// Should only have 1 valid frame (first and third frames are ignored due to wrong count)
484+
XCTAssertEqual(frames.count, 1);
485+
486+
// Verify the valid frame
487+
IBGFrameInfo *frame = frames[0];
488+
XCTAssertEqual(frame.startTimestampInMicroseconds, 1016.67);
489+
XCTAssertEqual(frame.durationInMicroseconds, 33.33);
490+
491+
return YES;
492+
}]]);
493+
}
494+
495+
- (void)testEndScreenRenderForCustomUiTraceWithMalformedFrameData {
496+
FlutterError *error;
497+
498+
// Create malformed frame data (missing values)
499+
NSDictionary *frameData = @{
500+
@"frameData": @[
501+
@[@(2000.0)], // Frame with only one value (should be ignored)
502+
@[@(2020.0), @(25.0)] // Valid frame
503+
]
504+
};
505+
506+
[self.api endScreenRenderForCustomUiTraceData:frameData error:&error];
507+
508+
// Verify that endCustomUITraceCPWithFrames was called with only valid frames
509+
OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
510+
// Should only have 1 valid frame
511+
XCTAssertEqual(frames.count, 1);
512+
513+
// Verify the valid frame
514+
IBGFrameInfo *frame = frames[0];
515+
XCTAssertEqual(frame.startTimestampInMicroseconds, 2020.0);
516+
XCTAssertEqual(frame.durationInMicroseconds, 25.0);
517+
518+
return YES;
519+
}]]);
520+
}
521+
522+
- (void)testEndScreenRenderForAutoUiTraceWithNilFrameData {
523+
FlutterError *error;
524+
525+
// Create frame data with nil frameData
526+
NSDictionary *frameData = @{
527+
@"frameData": [NSNull null]
528+
};
529+
530+
[self.api endScreenRenderForAutoUiTraceData:frameData error:&error];
531+
532+
// Verify that endAutoUITraceCPWithFrames was called with empty array
533+
OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
534+
XCTAssertEqual(frames.count, 0);
535+
return YES;
536+
}]]);
537+
}
538+
539+
- (void)testEndScreenRenderForCustomUiTraceWithNilFrameData {
540+
FlutterError *error;
541+
542+
// Create frame data with nil frameData
543+
NSDictionary *frameData = @{
544+
@"frameData": [NSNull null]
545+
};
546+
547+
[self.api endScreenRenderForCustomUiTraceData:frameData error:&error];
548+
549+
// Verify that endCustomUITraceCPWithFrames was called with empty array
550+
OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
551+
XCTAssertEqual(frames.count, 0);
552+
return YES;
553+
}]]);
554+
}
555+
556+
- (void)testEndScreenRenderForAutoUiTraceWithMissingFrameDataKey {
557+
FlutterError *error;
558+
559+
// Create frame data without frameData key
560+
NSDictionary *frameData = @{
561+
@"otherKey": @"someValue"
562+
};
563+
564+
[self.api endScreenRenderForAutoUiTraceData:frameData error:&error];
565+
566+
// Verify that endAutoUITraceCPWithFrames was called with empty array
567+
OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
568+
XCTAssertEqual(frames.count, 0);
569+
return YES;
570+
}]]);
571+
}
572+
573+
- (void)testEndScreenRenderForCustomUiTraceWithMissingFrameDataKey {
574+
FlutterError *error;
575+
576+
// Create frame data without frameData key
577+
NSDictionary *frameData = @{
578+
@"otherKey": @"someValue"
579+
};
580+
581+
[self.api endScreenRenderForCustomUiTraceData:frameData error:&error];
582+
583+
// Verify that endCustomUITraceCPWithFrames was called with empty array
584+
OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray<IBGFrameInfo *> *frames) {
585+
XCTAssertEqual(frames.count, 0);
586+
return YES;
587+
}]]);
588+
}
269589

270590
@end

example/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ target 'Runner' do
3030

3131
use_frameworks!
3232
use_modular_headers!
33-
pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec'
33+
pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec'
3434
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
3535
end
3636

example/ios/Podfile.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
PODS:
22
- Flutter (1.0.0)
3-
- Instabug (15.1.6)
3+
- Instabug (15.1.13)
44
- instabug_flutter (14.3.0):
55
- Flutter
6-
- Instabug (= 15.1.6)
6+
- Instabug (= 15.1.13)
77
- OCMock (3.6)
88

99
DEPENDENCIES:
1010
- Flutter (from `Flutter`)
11-
- Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec`)
11+
- Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec`)
1212
- instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`)
1313
- OCMock (= 3.6)
1414

@@ -20,16 +20,16 @@ EXTERNAL SOURCES:
2020
Flutter:
2121
:path: Flutter
2222
Instabug:
23-
:podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec
23+
:podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec
2424
instabug_flutter:
2525
:path: ".symlinks/plugins/instabug_flutter/ios"
2626

2727
SPEC CHECKSUMS:
2828
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
29-
Instabug: 160e6c775d933adcb577bb6b0246392d4e2c7796
30-
instabug_flutter: 8dd37e80d4f4883723b7f7b211e3f1907d85e5d3
29+
Instabug: 697dc090bbdb9b99a9a91758558f8a2014ee5725
30+
instabug_flutter: 1093324eaca70f9d310a4bc7f1f3537c746c1d6c
3131
OCMock: 5ea90566be239f179ba766fd9fbae5885040b992
3232

33-
PODFILE CHECKSUM: 96100ba35e9247b6dd1f0e51d13d3880f140fb35
33+
PODFILE CHECKSUM: 509cc3728286920762d8cbecfac090a3af93635d
3434

3535
COCOAPODS: 1.15.2

example/lib/main.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22
import 'dart:convert';
33
import 'dart:developer';
44
import 'dart:io';
5+
import 'dart:math' show Random;
56

67
import 'package:flutter/material.dart';
78
import 'package:instabug_flutter/instabug_flutter.dart';

0 commit comments

Comments
 (0)