Skip to content
Merged
105 changes: 105 additions & 0 deletions .github/workflows/bcit-integration-test-embedded-messages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: BCIT Embedded Messages Integration Test

on:
pull_request:
types: [opened, synchronize, reopened, labeled]
workflow_dispatch:
inputs:
ref:
description: 'Branch or commit to test (leave empty for current branch)'
required: false
type: string

jobs:
embedded-messages-test:
name: BCIT Embedded Messages Integration Test
runs-on: macos-latest
timeout-minutes: 30
env:
XCODE_VERSION: '16.4'
if: >
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'pull_request' && (
contains(github.event.pull_request.labels.*.name, 'bcit') ||
contains(github.event.pull_request.labels.*.name, 'BCIT') ||
contains(github.event.pull_request.labels.*.name, 'bcit-embedded') ||
contains(github.event.pull_request.labels.*.name, 'BCIT-EMBEDDED') ||
contains(github.event.pull_request.labels.*.name, 'bcit-embedded-messages') ||
contains(github.event.pull_request.labels.*.name, 'BCIT-EMBEDDED-MESSAGES') ||
contains(github.event.pull_request.labels.*.name, 'Bcit') ||
contains(github.event.pull_request.labels.*.name, 'Bcit-Embedded') ||
startsWith(github.event.pull_request.head.ref, 'release/')
)
)

steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.ref || github.ref }}

- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ env.XCODE_VERSION }}

- name: Validate Xcode Version
run: |
echo "🔍 Validating Xcode version and environment..."
echo "DEVELOPER_DIR: $DEVELOPER_DIR"

# Check xcodebuild version
echo "🔍 Checking xcodebuild version..."
ACTUAL_XCODE_VERSION=$(xcodebuild -version | head -n 1 | awk '{print $2}')
echo "Xcode version: $ACTUAL_XCODE_VERSION"
echo "Expected version: $XCODE_VERSION"

# Check xcodebuild path
XCODEBUILD_PATH=$(which xcodebuild)
echo "xcodebuild path: $XCODEBUILD_PATH"

# Verify we're using the correct Xcode version
if echo "$ACTUAL_XCODE_VERSION" | grep -q "$XCODE_VERSION"; then
echo "✅ Using correct Xcode version: $ACTUAL_XCODE_VERSION"
else
echo "❌ Incorrect Xcode version!"
echo "Current: $ACTUAL_XCODE_VERSION"
echo "Expected: $XCODE_VERSION"
exit 1
fi

- name: Setup Local Environment
working-directory: tests/business-critical-integration
run: |
echo "🚀 Setting up local environment for integration tests..."

# Run setup script with parameters from repository secrets
./scripts/setup-local-environment.sh \
"${{ secrets.BCIT_TEST_PROJECT_ID }}" \
"${{ secrets.BCIT_ITERABLE_SERVER_KEY }}" \
"${{ secrets.BCIT_ITERABLE_API_KEY }}"

- name: Validate Setup
working-directory: tests/business-critical-integration
run: |
echo "🔍 Validating environment setup..."
./scripts/validate-setup.sh

- name: Run Embedded Messages Tests
working-directory: tests/business-critical-integration
run: |
echo "🧪 Running embedded messages integration tests..."
CI=true ./scripts/run-tests.sh embedded

- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: embedded-messages-test-results
path: |
tests/business-critical-integration/reports/
tests/business-critical-integration/screenshots/
tests/business-critical-integration/logs/
retention-days: 7

Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ extension AppDelegate {
config.inAppDisplayInterval = 1
config.autoPushRegistration = false // Disable automatic push registration for testing control
config.allowedProtocols = ["tester"] // Allow our custom tester:// deep link scheme
config.enableEmbeddedMessaging = true

let apiKey = loadApiKeyFromConfig()
IterableAPI.initialize(apiKey: apiKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if let isGhostPush = iterableData["isGhostPush"] as? Bool {
print("👻 [APP] Ghost push flag: \(isGhostPush)")
}

if let notificationType = iterableData["notificationType"] as? String {
print("📝 [APP] Notification type: \(notificationType)")
}
}

// Call completion handler
completionHandler(.newData)
// Pass to Iterable SDK for processing
// This enables automatic embedded message sync when silent push with "UpdateEmbedded" type is received
print("📲 [APP] Passing silent push to Iterable SDK for processing...")
IterableAppIntegration.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
}

// MARK: - Deep link
Expand Down Expand Up @@ -242,6 +248,22 @@ extension AppDelegate: UNUserNotificationCenterDelegate {

if let iterableData = notification.request.content.userInfo["itbl"] as? [String: Any] {
print("🔔 [APP] Iterable-specific data: \(iterableData)")

// Check if this is a silent push for embedded messages
if let notificationType = iterableData["notificationType"] as? String {
print("📝 [APP] Notification type: \(notificationType)")
if notificationType == "UpdateEmbedded" {
print("🎯 [APP] Silent push for embedded messages detected in FOREGROUND")
print("💡 [APP] Passing to SDK for embedded message sync...")

// Pass to SDK even when in foreground
IterableAppIntegration.application(
UIApplication.shared,
didReceiveRemoteNotification: notification.request.content.userInfo,
fetchCompletionHandler: { _ in }
)
}
}
}

print("🔔 Foreground notification received: \(notification.request.content.userInfo)")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// EmbeddedMessageTestHostingController.swift
// IterableSDK-Integration-Tester
//

import UIKit
import SwiftUI

final class EmbeddedMessageTestHostingController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Create SwiftUI view
let embeddedTestView = EmbeddedMessageTestView()
let hostingController = UIHostingController(rootView: embeddedTestView)

// Add hosting controller as child
addChild(hostingController)
view.addSubview(hostingController.view)

// Setup constraints
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])

hostingController.didMove(toParent: self)
}
}

Loading
Loading