Skip to content

Commit f3337f9

Browse files
Test 37 of CI
1 parent 32d500b commit f3337f9

File tree

8 files changed

+136
-25
lines changed

8 files changed

+136
-25
lines changed

.github/workflows/ios-simulator-tests.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,20 @@ jobs:
6464
- name: Start test server
6565
run: |
6666
echo "Starting test server..."
67-
node specs/server/server.mjs &
67+
node specs/server/server.mjs > server.log 2>&1 &
6868
echo $! > server.pid
6969
7070
- name: Run End-to-End iOS Simulator Tests
7171
env:
7272
APNS_TOKEN_KEY: ${{ secrets.APNS_TOKEN_KEY }}
7373
run: pnpm run test
7474

75+
- name: Print server logs on failure
76+
if: failure()
77+
run: |
78+
echo "Dumping server logs..."
79+
cat server.log
80+
7581
- name: Retrieve and Print Test Logs on Failure (1/2)
7682
if: failure()
7783
run: |

examples/AlertNotification-example/ios-app/personalized-news-feed/personalized-news-feed.xcodeproj/project.pbxproj

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@
2121
116EE97A2DE27F0000EB1F7A /* personalized-news-feed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "personalized-news-feed.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2222
/* End PBXFileReference section */
2323

24+
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
25+
11C501D92E2C12BF00815CC6 /* Exceptions for "personalized-news-feed" folder in "UITests" target */ = {
26+
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
27+
membershipExceptions = (
28+
registerDeviceWithServer.swift,
29+
);
30+
target = 11336D5C2E2057F80012D56D /* UITests */;
31+
};
32+
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
33+
2434
/* Begin PBXFileSystemSynchronizedRootGroup section */
2535
11336D5E2E2057F80012D56D /* UITests */ = {
2636
isa = PBXFileSystemSynchronizedRootGroup;
@@ -29,6 +39,9 @@
2939
};
3040
116EE97C2DE27F0000EB1F7A /* personalized-news-feed */ = {
3141
isa = PBXFileSystemSynchronizedRootGroup;
42+
exceptions = (
43+
11C501D92E2C12BF00815CC6 /* Exceptions for "personalized-news-feed" folder in "UITests" target */,
44+
);
3245
path = "personalized-news-feed";
3346
sourceTree = "<group>";
3447
};
@@ -367,6 +380,7 @@
367380
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
368381
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
369382
CODE_SIGN_ENTITLEMENTS = "personalized-news-feed/personalized-news-feed.entitlements";
383+
CODE_SIGN_IDENTITY = "Apple Development";
370384
CODE_SIGN_STYLE = Automatic;
371385
CURRENT_PROJECT_VERSION = 1;
372386
DEVELOPMENT_TEAM = F53WB8AE67;
@@ -375,18 +389,23 @@
375389
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
376390
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
377391
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
378-
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
379-
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
392+
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
393+
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
380394
LD_RUNPATH_SEARCH_PATHS = (
381395
"$(inherited)",
382396
"@executable_path/Frameworks",
383397
);
384398
MARKETING_VERSION = 1.0;
385399
PRODUCT_BUNDLE_IDENTIFIER = "com.alexandercerutti.personalized-news-feed";
386400
PRODUCT_NAME = "$(TARGET_NAME)";
401+
PROVISIONING_PROFILE_SPECIFIER = "";
402+
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
403+
SUPPORTS_MACCATALYST = NO;
404+
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
405+
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
387406
SWIFT_EMIT_LOC_STRINGS = YES;
388407
SWIFT_VERSION = 5.0;
389-
TARGETED_DEVICE_FAMILY = "1,2";
408+
TARGETED_DEVICE_FAMILY = 1;
390409
};
391410
name = Debug;
392411
};
@@ -396,6 +415,7 @@
396415
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
397416
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
398417
CODE_SIGN_ENTITLEMENTS = "personalized-news-feed/personalized-news-feed.entitlements";
418+
CODE_SIGN_IDENTITY = "Apple Development";
399419
CODE_SIGN_STYLE = Automatic;
400420
CURRENT_PROJECT_VERSION = 1;
401421
DEVELOPMENT_TEAM = F53WB8AE67;
@@ -404,18 +424,23 @@
404424
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
405425
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
406426
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
407-
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
408-
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
427+
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
428+
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
409429
LD_RUNPATH_SEARCH_PATHS = (
410430
"$(inherited)",
411431
"@executable_path/Frameworks",
412432
);
413433
MARKETING_VERSION = 1.0;
414434
PRODUCT_BUNDLE_IDENTIFIER = "com.alexandercerutti.personalized-news-feed";
415435
PRODUCT_NAME = "$(TARGET_NAME)";
436+
PROVISIONING_PROFILE_SPECIFIER = "";
437+
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
438+
SUPPORTS_MACCATALYST = NO;
439+
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
440+
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
416441
SWIFT_EMIT_LOC_STRINGS = YES;
417442
SWIFT_VERSION = 5.0;
418-
TARGETED_DEVICE_FAMILY = "1,2";
443+
TARGETED_DEVICE_FAMILY = 1;
419444
};
420445
name = Release;
421446
};
@@ -429,7 +454,7 @@
429454
11336D662E2057F80012D56D /* Release */,
430455
);
431456
defaultConfigurationIsVisible = 0;
432-
defaultConfigurationName = Debug;
457+
defaultConfigurationName = Release;
433458
};
434459
116EE9752DE27F0000EB1F7A /* Build configuration list for PBXProject "personalized-news-feed" */ = {
435460
isa = XCConfigurationList;
@@ -438,7 +463,7 @@
438463
116EE9842DE27F0300EB1F7A /* Release */,
439464
);
440465
defaultConfigurationIsVisible = 0;
441-
defaultConfigurationName = Debug;
466+
defaultConfigurationName = Release;
442467
};
443468
116EE9852DE27F0300EB1F7A /* Build configuration list for PBXNativeTarget "personalized-news-feed" */ = {
444469
isa = XCConfigurationList;
@@ -447,7 +472,7 @@
447472
116EE9872DE27F0300EB1F7A /* Release */,
448473
);
449474
defaultConfigurationIsVisible = 0;
450-
defaultConfigurationName = Debug;
475+
defaultConfigurationName = Release;
451476
};
452477
/* End XCConfigurationList section */
453478
};

examples/AlertNotification-example/ios-app/personalized-news-feed/personalized-news-feed.xcodeproj/xcshareddata/xcschemes/personalized-news-feed.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
<EnvironmentVariables>
8383
<EnvironmentVariable
8484
key = "DEVICE_REGISTRATION_ADDRESS"
85-
value = "http://192.168.1.89:3000/registration"
85+
value = "http://localhost:8571/registration"
8686
isEnabled = "YES">
8787
</EnvironmentVariable>
8888
</EnvironmentVariables>

examples/AlertNotification-example/ios-app/personalized-news-feed/personalized-news-feed.xctestplan

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,21 @@
99
}
1010
],
1111
"defaultOptions" : {
12+
"codeCoverage" : false,
1213
"commandLineArgumentEntries" : [
1314

1415
],
16+
"diagnosticCollectionPolicy" : "Always",
1517
"environmentVariableEntries" : [
1618

1719
],
1820
"targetForVariableExpansion" : {
1921
"containerPath" : "container:personalized-news-feed.xcodeproj",
2022
"identifier" : "11336D5C2E2057F80012D56D",
2123
"name" : "UITests"
22-
}
24+
},
25+
"testRepetitionMode" : "retryOnFailure",
26+
"uiTestingScreenshotsLifetime" : "keepAlways"
2327
},
2428
"testTargets" : [
2529
{
@@ -29,14 +33,6 @@
2933
"identifier" : "11336D5C2E2057F80012D56D",
3034
"name" : "UITests"
3135
}
32-
},
33-
{
34-
"parallelizable" : true,
35-
"target" : {
36-
"containerPath" : "container:personalized-news-feed.xcodeproj",
37-
"identifier" : "11336D6B2E20835C0012D56D",
38-
"name" : "UITests-1"
39-
}
4036
}
4137
],
4238
"version" : 1

examples/AlertNotification-example/ios-app/personalized-news-feed/personalized-news-feed/AppDelegate.swift

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
1818
let notificationCenter = UNUserNotificationCenter.current()
1919

2020
Task {
21+
let testId = ProcessInfo.processInfo.environment["TEST_ID"] ?? "default-test-id";
22+
23+
reportProgressToStepsGuard(deviceRegistrationAddress: "http://localhost:8571/tests/\(testId)", stepName: "didFinishLaunchingWithOptions", metadata: ["launchOptions": "\(String(describing: launchOptions))"]);
24+
2125
if try await notificationCenter.requestAuthorization(options: [.alert]) {
2226
DispatchQueue.main.async {
2327
UIApplication.shared.registerForRemoteNotifications()
@@ -40,10 +44,10 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
4044
*/
4145

4246
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
43-
let deviceTokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined();
44-
print("DEVICE TOKEN IS: \(deviceTokenString)");
45-
logger.info("Device token registered: \(deviceTokenString)");
47+
let testId = ProcessInfo.processInfo.environment["TEST_ID"] ?? "default-test-id";
4648

49+
reportProgressToStepsGuard(deviceRegistrationAddress: "http://localhost:8571/tests/\(testId)", stepName: "didRegisterForRemoteNotificationsWithDeviceToken")
50+
4751
/**
4852
* Address is provided through the environment variable.
4953
* Should setting it before running the app, because if we run it on a device,
@@ -52,17 +56,28 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
5256
* Go to 'Product' -> 'Scheme' -> 'Edit Scheme...' -> 'Run' -> 'Arguments' -> 'Environment Variables'
5357
*/
5458
guard let deviceRegistrationAddress = ProcessInfo.processInfo.environment["DEVICE_REGISTRATION_ADDRESS"] else {
59+
5560
print("Device Registration Address not found in the environment. Provide one in order to send a request containing the token.");
56-
logger.error("Device registration address not found in the environment. Provide one in order to send a request containing the token.");
5761
return;
5862
}
5963

64+
reportProgressToStepsGuard(deviceRegistrationAddress: deviceRegistrationAddress, stepName: "device_registration");
65+
66+
let deviceTokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined();
67+
print("DEVICE TOKEN IS: \(deviceTokenString)");
68+
logger.info("Device token registered: \(deviceTokenString)");
69+
logger.error("Device registration address not found in the environment. Provide one in order to send a request containing the token.");
70+
71+
reportProgressToStepsGuard(deviceRegistrationAddress: deviceRegistrationAddress, stepName: "pre-apns-topic");
72+
6073
guard let apnsTopic = Bundle.main.bundleIdentifier else {
6174
print("Could not get bundle identifier")
6275
logger.error("Could not get bundle identifier");
6376
return
6477
}
6578

79+
reportProgressToStepsGuard(deviceRegistrationAddress: deviceRegistrationAddress, stepName: "post-apns-topic");
80+
6681
registerDeviceWithServer(
6782
address: URL(string: deviceRegistrationAddress)!,
6883
token: deviceTokenString,
@@ -73,6 +88,10 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
7388
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
7489
print("Failed to register for remote notifications: \(error)")
7590
logger.error("Failed to register for remote notifications: \(error.localizedDescription)");
91+
92+
let testId = ProcessInfo.processInfo.environment["TEST_ID"] ?? "default-test-id";
93+
94+
reportProgressToStepsGuard(deviceRegistrationAddress: "http://localhost:8571/tests/\(testId)", stepName: "registration-failure", metadata: ["error": error.localizedDescription]);
7695
}
7796

7897
/**

examples/AlertNotification-example/ios-app/personalized-news-feed/personalized-news-feed/registerDeviceWithServer.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,63 @@ func registerDeviceWithServer(address: URL, token: String, apnsTopic: String) {
4848

4949
task.resume()
5050
}
51+
52+
func reportProgressToStepsGuard(deviceRegistrationAddress: String, stepName: String, metadata: [String: Any]? = nil) {
53+
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "StepsGuard")
54+
55+
// Strip the /registration endpoint and replace with steps-guard endpoint
56+
var baseAddress = deviceRegistrationAddress
57+
if baseAddress.hasSuffix("/registration") {
58+
baseAddress = String(baseAddress.dropLast("/registration".count))
59+
}
60+
61+
guard let baseURL = URL(string: baseAddress) else {
62+
print("Invalid device registration address: \(deviceRegistrationAddress)")
63+
logger.error("Invalid device registration address: \(deviceRegistrationAddress)")
64+
return
65+
}
66+
67+
// Construct the steps-guard endpoint URL
68+
let stepsGuardURL = baseURL.appendingPathComponent("steps-guard").appendingPathComponent("progress")
69+
70+
var request = URLRequest(url: stepsGuardURL)
71+
request.httpMethod = "POST"
72+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
73+
74+
var body: [String: Any] = [
75+
"deviceId": UIDevice.current.identifierForVendor?.uuidString ?? "",
76+
"stepName": stepName,
77+
"timestamp": ISO8601DateFormatter().string(from: Date())
78+
]
79+
80+
// Add optional metadata if provided
81+
if let metadata = metadata {
82+
body["metadata"] = metadata
83+
}
84+
85+
do {
86+
request.httpBody = try JSONSerialization.data(withJSONObject: body, options: [])
87+
} catch {
88+
print("Error creating JSON body for steps-guard: \(error)")
89+
logger.error("Error creating JSON body for steps-guard: \(error.localizedDescription)")
90+
return
91+
}
92+
93+
let task = URLSession.shared.dataTask(with: request) { data, response, error in
94+
if let error = error {
95+
print("Error sending progress to steps-guard: \(error)")
96+
logger.error("Error sending progress to steps-guard: \(error.localizedDescription)")
97+
return
98+
}
99+
guard let httpResponse = response as? HTTPURLResponse,
100+
(200...299).contains(httpResponse.statusCode) else {
101+
print("Steps-guard returned non-200 status code")
102+
logger.error("Steps-guard returned a non-200 status code")
103+
return
104+
}
105+
print("Successfully reported progress '\(stepName)' to steps-guard.")
106+
logger.info("Successfully reported progress '\(stepName)' to steps-guard at \(stepsGuardURL.absoluteString)")
107+
}
108+
109+
task.resume()
110+
}

specs/server/server.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ fastify.get("/health", async (_request, reply) => {
232232
reply.send({ status: "ok" });
233233
});
234234

235+
fastify.post("/tests/:testId/devices/steps-guard/progress", async (request, reply) => {
236+
console.log(`[steps-guard/progress] ${JSON.stringify(request.body)}`);
237+
reply.status(200).send({ ok: true });
238+
});
239+
235240
try {
236241
await fastify.listen({
237242
port: 8571,

specs/utils/test-client.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export async function waitForDeviceRegistration(testId) {
3232
* Poll for 10000 seconds (5000 attempts * 2s interval)
3333
* This amount is less or equal to the test timeout threshold
3434
*/
35-
for (let i = 0; i < 5000; i++) {
35+
for (let i = 0; i < 800; i++) {
3636
const response = await fetch(`${SERVER_URL}/tests/${testId}/registered-devices`);
3737

3838
if (response.ok) {

0 commit comments

Comments
 (0)