Skip to content

Commit

Permalink
Update ci.yml
Browse files Browse the repository at this point in the history
- Implement testing on different OS versions
- Temporarily drop testing on watchOS
  • Loading branch information
ns-vasilev committed Dec 29, 2023
1 parent 7bb4a64 commit f3da71a
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 221 deletions.
125 changes: 100 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,54 +24,129 @@ jobs:
args: --strict
env:
DIFF_BASE: ${{ github.base_ref }}
Latest:
name: Test Latest (iOS, macOS, tvOS, watchOS)
runs-on: macOS-12
macOS:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runsOn }}
env:
DEVELOPER_DIR: "/Applications/Xcode_14.1.app/Contents/Developer"
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- destination: "OS=16.1,name=iPhone 14 Pro"
name: "iOS"
scheme: "Flare"
sdk: iphonesimulator
- destination: "OS=16.1,name=Apple TV"
name: "tvOS"
scheme: "Flare"
sdk: appletvsimulator
# - destination: "OS=9.1,name=Apple Watch Series 8 (45mm)"
# name: "watchOS"
# scheme: "Flare"
# sdk: watchsimulator
- destination: "platform=macOS"
name: "macOS"
scheme: "Flare"
sdk: macosx
- xcode: "Xcode_15.0"
runsOn: macos-13
name: "macOS 13, Xcode 15.0, Swift 5.9.0"
- xcode: "Xcode_14.3.1"
runsOn: macos-13
name: "macOS 13, Xcode 14.3.1, Swift 5.8.0"
- xcode: "Xcode_14.2"
runsOn: macOS-12
name: "macOS 12, Xcode 14.2, Swift 5.7.2"
- xcode: "Xcode_14.1"
runsOn: macOS-12
name: "macOS 12, Xcode 14.1, Swift 5.7.1"
steps:
- uses: actions/checkout@v3
- name: Install Dependencies
run: make setup_build_tools
- name: Generate project
run: make generate
- name: ${{ matrix.name }}
run: xcodebuild test CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -scheme "Flare" -destination "platform=macOS" clean -enableCodeCoverage YES -resultBundlePath "./macos.xcresult" || exit 1
- name: Upload coverage reports to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
xcode: true
xcode_archive_path: "./macos.xcresult"

iOS:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runsOn }}
env:
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- destination: "OS=17.0,name=iPhone 14 Pro"
name: "iOS 17.0"
xcode: "Xcode_15.0"
runsOn: macos-13
- destination: "OS=16.4,name=iPhone 14 Pro"
name: "iOS 16.4"
xcode: "Xcode_14.3.1"
runsOn: macos-13
- destination: "OS=15.5,name=iPhone 13 Pro"
name: "iOS 15.5"
xcode: "Xcode_14.3.1"
runsOn: macOS-13
steps:
- uses: actions/checkout@v3
- name: Install Dependencies
run: make setup_build_tools
- name: Generate project
run: make generate
- name: ${{ matrix.name }}
run: xcodebuild test -scheme "${{ matrix.scheme }}" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "./${{ matrix.sdk }}.xcresult" || exit 1
run: xcodebuild test CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -scheme "Flare" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "./iphonesimulator.xcresult" || exit 1
- name: Upload coverage reports to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
xcode: true
xcode_archive_path: "./${{ matrix.sdk }}.xcresult"
xcode_archive_path: "./iphonesimulator.xcresult"

tvOS:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runsOn }}
env:
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- destination: "OS=17.0,name=Apple TV"
name: "tvOS 17.0"
xcode: "Xcode_15.0"
runsOn: macos-13
- destination: "OS=16.4,name=Apple TV"
name: "tvOS 16.4"
xcode: "Xcode_14.3.1"
runsOn: macos-13
- destination: "OS=15.4,name=Apple TV"
name: "tvOS 15.4"
xcode: "Xcode_14.3.1"
runsOn: macos-13
steps:
- uses: actions/checkout@v3
- name: Install Dependencies
run: make setup_build_tools
- name: Generate project
run: make generate
- name: ${{ matrix.name }}
run: xcodebuild test -scheme "Flare" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "./appletvsimulator.xcresult" || exit 1
- name: Upload coverage reports to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
xcode: true
xcode_archive_path: "./appletvsimulator.xcresult"

Beta:
name: "Test Betas"
name: ${{ matrix.name }}
runs-on: macos-13
env:
DEVELOPER_DIR: "/Applications/Xcode_15.0.app/Contents/Developer"
DEVELOPER_DIR: "/Applications/Xcode_15.1.app/Contents/Developer"
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- destination: "OS=1.0,name=Apple Vision Pro"
name: "visionOS"
name: "visionOS 1.0"
scheme: "Flare"
steps:
- uses: actions/checkout@v3
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ fmt:
generate:
xcodegen generate

.PHONY: all bootstrap hook mint lint fmt generate
setup_build_tools:
sh scripts/setup_build_tools.sh

.PHONY: all bootstrap hook mint lint fmt generate setup_build_tools
14 changes: 4 additions & 10 deletions Tests/FlareTests/UnitTestHostApp/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,14 @@

import SwiftUI

#if os(watchOS) || os(tvOS) || os(macOS)
#if os(macOS)

import Cocoa

@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
Text("Hello World")
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate {}

#else
// Scene isn't available until iOS 14.0, so this is for backwards compatibility.

@main
class AppDelegate: UIResponder, UIApplicationDelegate {}

Expand Down
156 changes: 156 additions & 0 deletions Tests/FlareTests/UnitTests/FlareStoreKit2Tests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
//
// Flare
// Copyright © 2023 Space Code. All rights reserved.
//

@testable import Flare
import XCTest

// MARK: - FlareStoreKit2Tests

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
final class FlareStoreKit2Tests: StoreSessionTestCase {
// MARK: - Properties

private var iapProviderMock: IAPProviderMock!

private var sut: Flare!

// MARK: - XCTestCase

override func setUp() {
super.setUp()
iapProviderMock = IAPProviderMock()
sut = Flare(iapProvider: iapProviderMock)
}

override func tearDown() {
iapProviderMock = nil
sut = nil
super.tearDown()
}

#if os(iOS) || VISION_OS
func test_thatFlareRefundsPurchase() async throws {
// given
iapProviderMock.stubbedBeginRefundRequest = .success

// when
let state = try await sut.beginRefundRequest(productID: .productID)

// then
if case .success = state {}
else { XCTFail("state must be `success`") }
}

func test_thatFlareRefundRequestThrowsAnError_whenBeginRefundRequestFailed() async throws {
// given
iapProviderMock.stubbedBeginRefundRequest = .failed(error: IAPError.unknown)

// when
let state = try await sut.beginRefundRequest(productID: .productID)

// then
if case let .failed(error) = state { XCTAssertEqual(error as NSError, IAPError.unknown as NSError) }
else { XCTFail("state must be `failed`") }
}
#endif

func test_thatFlarePurchasesAProductWithOptions_whenPurchaseCompleted() async throws {
let transaction = StoreTransactionStub()
try await test_purchaseWithOptionsAndCompletion(
transaction: transaction,
canMakePayments: true,
expectedResult: .success(StoreTransaction(storeTransaction: transaction))
)
}

func test_thatFlarePurchaseThrowsAnError_whenPaymentNotAllowed() async throws {
try await test_purchaseWithOptionsAndCompletion(
canMakePayments: false,
expectedResult: .failure(IAPError.paymentNotAllowed)
)
}

func test_thatFlarePurchasesAsyncAProductWithOptionsAndCompletionHandler_whenPurchaseCompleted() async throws {
let transaction = StoreTransactionStub()
try await test_purchaseWithOptions(
canMakePayments: true,
expectedResult: .success(StoreTransaction(storeTransaction: transaction))
)
}

func test_thatFlarePurchaseAsyncThrowsAnError_whenPaymentNotAllowed() async throws {
try await test_purchaseWithOptions(
canMakePayments: false,
expectedResult: .failure(IAPError.paymentNotAllowed)
)
}

// MARK: Private

private func test_purchaseWithOptionsAndCompletion(
transaction: StoreTransactionStub? = nil,
canMakePayments: Bool,
expectedResult: Result<StoreTransaction, IAPError>
) async throws {
// given
let product = try await ProductProviderHelper.purchases.randomElement()
let storeTransactionStub = transaction ?? StoreTransactionStub()
storeTransactionStub.stubbedProductIdentifier = product?.id

iapProviderMock.stubbedCanMakePayments = canMakePayments
iapProviderMock.stubbedAsyncPurchaseWithOptions = StoreTransaction(
storeTransaction: storeTransactionStub
)

// when
let result: Result<StoreTransaction, IAPError> = await result(for: {
try await sut.purchase(
product: StoreProduct(product: product!),
options: [.simulatesAskToBuyInSandbox(false)]
)
})

// then
XCTAssertEqual(result, expectedResult)
}

private func test_purchaseWithOptions(
transaction: StoreTransactionStub? = nil,
canMakePayments: Bool,
expectedResult: Result<StoreTransaction, IAPError>
) async throws {
// given
let expectation = XCTestExpectation(description: "Purchase a product")

let product = try await ProductProviderHelper.purchases.randomElement()
let storeTransactionStub = transaction ?? StoreTransactionStub()
storeTransactionStub.stubbedProductIdentifier = product?.id

iapProviderMock.stubbedCanMakePayments = canMakePayments
iapProviderMock.stubbedPurchaseWithOptionsResult = .success(StoreTransaction(storeTransaction: storeTransactionStub))

// when
sut.purchase(
product: StoreProduct(product: product!),
options: [.simulatesAskToBuyInSandbox(false)]
) { result in
XCTAssertEqual(result, expectedResult)
expectation.fulfill()
}

// then
wait(for: [expectation], timeout: .second)
}
}

// MARK: - Constants

private extension TimeInterval {
static let second: CGFloat = 1.0
}

private extension String {
static let productID = "com.flare.test_purchase_2"
}
Loading

0 comments on commit f3da71a

Please sign in to comment.