Add target for UI tests (#959)
Create UITesting target with: - AppCommandLine/AppEnvironment: strongly typed refactoring of PP_* environment values - AccessibilityInfo: identifies and locates elements for UI testing Make the app behave differently when launched with `.uiTesting`, and expose the flag to SwiftUI via `.environment(\.isUITesting)` to: - Use the mock AppContext - Skip onboarding Add PassepartoutUITests target with two screenshot tests: - Connected screen - Profile modal
This commit is contained in:
parent
fc711ae98f
commit
581673c617
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0E2D68DC2CF7CF7500DC95BC /* UITesting in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2D68DB2CF7CF7500DC95BC /* UITesting */; };
|
||||
0E3E22962CE53510005135DF /* AppUIMain in Frameworks */ = {isa = PBXBuildFile; platformFilters = (ios, macos, ); productRef = 0E3E22952CE53510005135DF /* AppUIMain */; };
|
||||
0E3E22982CE53510005135DF /* AppUITV in Frameworks */ = {isa = PBXBuildFile; platformFilters = (tvos, ); productRef = 0E3E22972CE53510005135DF /* AppUITV */; };
|
||||
0E3FF4BA2CE3AFBC00BFF640 /* Profiles.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 0E3FF4B72CE3AFBC00BFF640 /* Profiles.sqlite */; };
|
||||
|
@ -20,6 +21,9 @@
|
|||
0E7C3CCD2C9AF44600B72E69 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7C3CCC2C9AF44600B72E69 /* AppDelegate.swift */; };
|
||||
0E7E3D692B9345FD002BBDB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E7E3D5C2B9345FD002BBDB4 /* Assets.xcassets */; };
|
||||
0E7E3D6B2B9345FD002BBDB4 /* PassepartoutApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E3D5F2B9345FD002BBDB4 /* PassepartoutApp.swift */; };
|
||||
0E7F46022CF7D5E300B1C53A /* AppEnvironment+IAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F46012CF7D5E300B1C53A /* AppEnvironment+IAP.swift */; };
|
||||
0E7F460E2CF7F01600B1C53A /* PassepartoutUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F460B2CF7F01600B1C53A /* PassepartoutUITests.swift */; };
|
||||
0E7F460F2CF7F01600B1C53A /* XCUIApplication+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F460C2CF7F01600B1C53A /* XCUIApplication+Extensions.swift */; };
|
||||
0E94EE582B93554B00588243 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E3D672B9345FD002BBDB4 /* PacketTunnelProvider.swift */; };
|
||||
0EB08B982CA46F4900A02591 /* AppPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EB08B962CA46F4900A02591 /* AppPlist.strings */; };
|
||||
0EBE80DC2BF55C0E00E36A20 /* TunnelLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0EBE80DB2BF55C0E00E36A20 /* TunnelLibrary */; };
|
||||
|
@ -57,6 +61,13 @@
|
|||
remoteGlobalIDString = 0E757F0F2CD0CFFC006E13E1;
|
||||
remoteInfo = PassepartoutLoginItem;
|
||||
};
|
||||
0E78FE522CF799F400B0C5BF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0E06D1872B87629100176E1D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 0E06D18E2B87629100176E1D;
|
||||
remoteInfo = Passepartout;
|
||||
};
|
||||
0EC332D02B8A1808000B9C2F /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0E06D1872B87629100176E1D /* Project object */;
|
||||
|
@ -121,6 +132,7 @@
|
|||
0E757F122CD0CFFC006E13E1 /* PassepartoutLoginItemApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassepartoutLoginItemApp.swift; sourceTree = "<group>"; };
|
||||
0E757F182CD0CFFD006E13E1 /* LoginItem.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LoginItem.entitlements; sourceTree = "<group>"; };
|
||||
0E757F212CD0D2B7006E13E1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
0E78FE4C2CF799F400B0C5BF /* PassepartoutUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PassepartoutUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0E7C3CCC2C9AF44600B72E69 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
0E7D0EAD2CAEA47700A2F28D /* Passepartout.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Passepartout.xctestplan; sourceTree = "<group>"; };
|
||||
0E7E3D5B2B9345FD002BBDB4 /* App.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
||||
|
@ -128,6 +140,9 @@
|
|||
0E7E3D5F2B9345FD002BBDB4 /* PassepartoutApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PassepartoutApp.swift; sourceTree = "<group>"; };
|
||||
0E7E3D662B9345FD002BBDB4 /* Tunnel.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Tunnel.entitlements; sourceTree = "<group>"; };
|
||||
0E7E3D672B9345FD002BBDB4 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = "<group>"; };
|
||||
0E7F46012CF7D5E300B1C53A /* AppEnvironment+IAP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEnvironment+IAP.swift"; sourceTree = "<group>"; };
|
||||
0E7F460B2CF7F01600B1C53A /* PassepartoutUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassepartoutUITests.swift; sourceTree = "<group>"; };
|
||||
0E7F460C2CF7F01600B1C53A /* XCUIApplication+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUIApplication+Extensions.swift"; sourceTree = "<group>"; };
|
||||
0E8D852F2C328CA1005493DE /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
||||
0E94EE5C2B93570600588243 /* Tunnel.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Tunnel.plist; sourceTree = "<group>"; };
|
||||
0EB08B972CA46F4900A02591 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AppPlist.strings; sourceTree = "<group>"; };
|
||||
|
@ -165,6 +180,14 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0E78FE492CF799F400B0C5BF /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0E2D68DC2CF7CF7500DC95BC /* UITesting in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0EC332C52B8A1808000B9C2F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -213,6 +236,7 @@
|
|||
0EDE56F02CABE42E0082D21C /* PassepartoutIntents.appex */,
|
||||
0E757F102CD0CFFC006E13E1 /* PassepartoutLoginItem.app */,
|
||||
0E3FF4AE2CE3AF6F00BFF640 /* PassepartoutTests.xctest */,
|
||||
0E78FE4C2CF799F400B0C5BF /* PassepartoutUITests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -265,6 +289,7 @@
|
|||
0E7E3D612B9345FD002BBDB4 /* Shared */,
|
||||
0E3FF4A92CE3AF4700BFF640 /* Tests */,
|
||||
0E7E3D652B9345FD002BBDB4 /* Tunnel */,
|
||||
0E7F460D2CF7F01600B1C53A /* UITests */,
|
||||
0EBE80DD2BF55C9100E36A20 /* Library */,
|
||||
);
|
||||
path = Passepartout;
|
||||
|
@ -289,6 +314,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
0EC797402B9378E000C093B7 /* AppContext+Shared.swift */,
|
||||
0E7F46012CF7D5E300B1C53A /* AppEnvironment+IAP.swift */,
|
||||
0EC797412B9378E000C093B7 /* Shared.swift */,
|
||||
0E483E822CE6501100584B32 /* Shared+App.swift */,
|
||||
0E483E7F2CE64D6B00584B32 /* Shared+Tunnel.swift */,
|
||||
|
@ -306,6 +332,15 @@
|
|||
path = Tunnel;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0E7F460D2CF7F01600B1C53A /* UITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0E7F460B2CF7F01600B1C53A /* PassepartoutUITests.swift */,
|
||||
0E7F460C2CF7F01600B1C53A /* XCUIApplication+Extensions.swift */,
|
||||
);
|
||||
path = UITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0ED61CF62CD04174008FE259 /* Platforms */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -395,6 +430,27 @@
|
|||
productReference = 0E757F102CD0CFFC006E13E1 /* PassepartoutLoginItem.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
0E78FE4B2CF799F400B0C5BF /* PassepartoutUITests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0E78FE562CF799F400B0C5BF /* Build configuration list for PBXNativeTarget "PassepartoutUITests" */;
|
||||
buildPhases = (
|
||||
0E78FE482CF799F400B0C5BF /* Sources */,
|
||||
0E78FE492CF799F400B0C5BF /* Frameworks */,
|
||||
0E78FE4A2CF799F400B0C5BF /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
0E78FE532CF799F400B0C5BF /* PBXTargetDependency */,
|
||||
);
|
||||
name = PassepartoutUITests;
|
||||
packageProductDependencies = (
|
||||
0E2D68DB2CF7CF7500DC95BC /* UITesting */,
|
||||
);
|
||||
productName = PassepartoutUITests;
|
||||
productReference = 0E78FE4C2CF799F400B0C5BF /* PassepartoutUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
0EC332C72B8A1808000B9C2F /* PassepartoutTunnel */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0EC332D32B8A1808000B9C2F /* Build configuration list for PBXNativeTarget "PassepartoutTunnel" */;
|
||||
|
@ -441,7 +497,7 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1540;
|
||||
LastSwiftUpdateCheck = 1610;
|
||||
LastUpgradeCheck = 1610;
|
||||
TargetAttributes = {
|
||||
0E06D18E2B87629100176E1D = {
|
||||
|
@ -453,6 +509,10 @@
|
|||
0E757F0F2CD0CFFC006E13E1 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
};
|
||||
0E78FE4B2CF799F400B0C5BF = {
|
||||
CreatedOnToolsVersion = 16.1;
|
||||
TestTargetID = 0E06D18E2B87629100176E1D;
|
||||
};
|
||||
0EC332C72B8A1808000B9C2F = {
|
||||
CreatedOnToolsVersion = 15.2;
|
||||
};
|
||||
|
@ -479,6 +539,7 @@
|
|||
0E757F0F2CD0CFFC006E13E1 /* PassepartoutLoginItem */,
|
||||
0E3FF4AD2CE3AF6F00BFF640 /* PassepartoutTests */,
|
||||
0EC332C72B8A1808000B9C2F /* PassepartoutTunnel */,
|
||||
0E78FE4B2CF799F400B0C5BF /* PassepartoutUITests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -510,6 +571,13 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0E78FE4A2CF799F400B0C5BF /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0EC332C62B8A1808000B9C2F /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -560,6 +628,7 @@
|
|||
0EE8D7E12CD112C200F6600C /* App+tvOS.swift in Sources */,
|
||||
0E483E842CE6501100584B32 /* Shared+App.swift in Sources */,
|
||||
0EC797432B9378E000C093B7 /* Shared.swift in Sources */,
|
||||
0E7F46022CF7D5E300B1C53A /* AppEnvironment+IAP.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -581,6 +650,15 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0E78FE482CF799F400B0C5BF /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0E7F460E2CF7F01600B1C53A /* PassepartoutUITests.swift in Sources */,
|
||||
0E7F460F2CF7F01600B1C53A /* XCUIApplication+Extensions.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0EC332C42B8A1808000B9C2F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -623,6 +701,11 @@
|
|||
target = 0E757F0F2CD0CFFC006E13E1 /* PassepartoutLoginItem */;
|
||||
targetProxy = 0E757F242CD0D812006E13E1 /* PBXContainerItemProxy */;
|
||||
};
|
||||
0E78FE532CF799F400B0C5BF /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 0E06D18E2B87629100176E1D /* Passepartout */;
|
||||
targetProxy = 0E78FE522CF799F400B0C5BF /* PBXContainerItemProxy */;
|
||||
};
|
||||
0EC332D12B8A1808000B9C2F /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 0EC332C72B8A1808000B9C2F /* PassepartoutTunnel */;
|
||||
|
@ -962,6 +1045,36 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
0E78FE542CF799F400B0C5BF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.algoritmico.ios.PassepartoutUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = auto;
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = Passepartout;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
0E78FE552CF799F400B0C5BF /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.algoritmico.ios.PassepartoutUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = auto;
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = Passepartout;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
0EC332D42B8A1808000B9C2F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
@ -1108,6 +1221,15 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
0E78FE562CF799F400B0C5BF /* Build configuration list for PBXNativeTarget "PassepartoutUITests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
0E78FE542CF799F400B0C5BF /* Debug */,
|
||||
0E78FE552CF799F400B0C5BF /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
0EC332D32B8A1808000B9C2F /* Build configuration list for PBXNativeTarget "PassepartoutTunnel" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
@ -1129,6 +1251,10 @@
|
|||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
0E2D68DB2CF7CF7500DC95BC /* UITesting */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = UITesting;
|
||||
};
|
||||
0E3E22952CE53510005135DF /* AppUIMain */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = AppUIMain;
|
||||
|
|
|
@ -45,6 +45,17 @@
|
|||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E78FE4B2CF799F400B0C5BF"
|
||||
BuildableName = "PassepartoutUITests.xctest"
|
||||
BlueprintName = "PassepartoutUITests"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
@ -68,6 +79,18 @@
|
|||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-pp_fake_iap"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-pp_ui_tests"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-pp_fake_migration"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.SQLDebug 1"
|
||||
isEnabled = "NO">
|
||||
|
@ -106,16 +129,6 @@
|
|||
value = "1"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "PP_FAKE_IAP"
|
||||
value = "1"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "PP_FAKE_MIGRATION"
|
||||
value = "1"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<StoreKitConfigurationFileReference
|
||||
identifier = "../../Passepartout/Passepartout.storekit">
|
||||
|
|
|
@ -56,6 +56,17 @@
|
|||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E78FE4B2CF799F400B0C5BF"
|
||||
BuildableName = "PassepartoutUITests.xctest"
|
||||
BlueprintName = "PassepartoutUITests"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
|
|
@ -55,6 +55,17 @@
|
|||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E78FE4B2CF799F400B0C5BF"
|
||||
BuildableName = "PassepartoutUITests.xctest"
|
||||
BlueprintName = "PassepartoutUITests"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1610"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E78FE4B2CF799F400B0C5BF"
|
||||
BuildableName = "PassepartoutUITests.xctest"
|
||||
BlueprintName = "PassepartoutUITests"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -27,11 +27,16 @@ import CommonLibrary
|
|||
import PassepartoutKit
|
||||
import SwiftUI
|
||||
import UILibrary
|
||||
import UITesting
|
||||
|
||||
@MainActor
|
||||
final class AppDelegate: NSObject {
|
||||
let context: AppContext = .shared
|
||||
// let context: AppContext = .mock(withRegistry: .shared)
|
||||
let context: AppContext = {
|
||||
guard !AppCommandLine.contains(.uiTesting) else {
|
||||
return .mock(withRegistry: .shared)
|
||||
}
|
||||
return .shared
|
||||
}()
|
||||
|
||||
#if os(macOS)
|
||||
let settings = MacSettingsModel(
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
import AppUIMain
|
||||
import SwiftUI
|
||||
import UITesting
|
||||
|
||||
extension AppDelegate: UIApplicationDelegate {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
|
@ -49,6 +50,7 @@ extension PassepartoutApp {
|
|||
}
|
||||
.themeLockScreen()
|
||||
.withEnvironment(from: context, theme: theme)
|
||||
.environment(\.isUITesting, AppCommandLine.contains(.uiTesting))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import CommonLibrary
|
|||
import CommonUtils
|
||||
import PassepartoutKit
|
||||
import SwiftUI
|
||||
import UITesting
|
||||
|
||||
extension AppDelegate: NSApplicationDelegate {
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
|
@ -57,10 +58,11 @@ extension PassepartoutApp {
|
|||
var body: some Scene {
|
||||
Window(appName, id: appName) {
|
||||
contentView()
|
||||
.withEnvironment(from: context, theme: theme)
|
||||
.onReceive(didActivateNotificationPublisher) {
|
||||
context.onApplicationActive()
|
||||
}
|
||||
.withEnvironment(from: context, theme: theme)
|
||||
.environment(\.isUITesting, AppCommandLine.contains(.uiTesting))
|
||||
}
|
||||
.defaultSize(width: 600, height: 400)
|
||||
|
||||
|
@ -69,6 +71,7 @@ extension PassepartoutApp {
|
|||
.frame(minWidth: 300, minHeight: 300)
|
||||
.withEnvironment(from: context, theme: theme)
|
||||
.environmentObject(settings)
|
||||
.environment(\.isUITesting, AppCommandLine.contains(.uiTesting))
|
||||
}
|
||||
MenuBarExtra {
|
||||
AppMenu(
|
||||
|
@ -77,6 +80,7 @@ extension PassepartoutApp {
|
|||
)
|
||||
.withEnvironment(from: context, theme: theme)
|
||||
.environmentObject(settings)
|
||||
.environment(\.isUITesting, AppCommandLine.contains(.uiTesting))
|
||||
} label: {
|
||||
AppMenuImage(tunnel: context.tunnel)
|
||||
.environmentObject(theme)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
import AppUITV
|
||||
import SwiftUI
|
||||
import UITesting
|
||||
|
||||
extension AppDelegate: UIApplicationDelegate {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
|
@ -45,6 +46,7 @@ extension PassepartoutApp {
|
|||
}
|
||||
}
|
||||
.withEnvironment(from: context, theme: theme)
|
||||
.environment(\.isUITesting, AppCommandLine.contains(.uiTesting))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,10 @@ let package = Package(
|
|||
.library(
|
||||
name: "UILibrary",
|
||||
targets: ["UILibrary"]
|
||||
),
|
||||
.library(
|
||||
name: "UITesting",
|
||||
targets: ["UITesting"]
|
||||
)
|
||||
],
|
||||
dependencies: [
|
||||
|
@ -165,12 +169,16 @@ let package = Package(
|
|||
"AppDataProfiles",
|
||||
"AppDataProviders",
|
||||
"CommonAPI",
|
||||
"CommonLibrary"
|
||||
"CommonLibrary",
|
||||
"UITesting"
|
||||
],
|
||||
resources: [
|
||||
.process("Resources")
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "UITesting"
|
||||
),
|
||||
.testTarget(
|
||||
name: "AppUIMainTests",
|
||||
dependencies: ["AppUIMain"]
|
||||
|
|
|
@ -27,6 +27,7 @@ import CommonLibrary
|
|||
import CommonUtils
|
||||
import PassepartoutKit
|
||||
import SwiftUI
|
||||
import UITesting
|
||||
|
||||
struct InstalledProfileView: View, Routable {
|
||||
|
||||
|
@ -54,6 +55,7 @@ struct InstalledProfileView: View, Routable {
|
|||
debugChanges()
|
||||
return HStack(alignment: .center) {
|
||||
cardView
|
||||
.uiAccessibility(.App.installedProfile)
|
||||
Spacer()
|
||||
toggleButton
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ import SwiftUI
|
|||
|
||||
struct OnboardingModifier: ViewModifier {
|
||||
|
||||
@Environment(\.isUITesting)
|
||||
private var isUITesting
|
||||
|
||||
@AppStorage(UIPreference.onboardingStep.key)
|
||||
private var step: OnboardingStep?
|
||||
|
||||
|
@ -67,6 +70,10 @@ struct OnboardingModifier: ViewModifier {
|
|||
|
||||
private extension OnboardingModifier {
|
||||
func advance() {
|
||||
guard !isUITesting else {
|
||||
pp_log(.app, .info, "UI tests, skip onboarding")
|
||||
return
|
||||
}
|
||||
Task {
|
||||
try await Task.sleep(for: .milliseconds(300))
|
||||
doAdvance()
|
||||
|
|
|
@ -27,6 +27,7 @@ import CommonLibrary
|
|||
import CommonUtils
|
||||
import PassepartoutKit
|
||||
import SwiftUI
|
||||
import UITesting
|
||||
|
||||
struct ProfileContextMenu: View, Routable {
|
||||
enum Style {
|
||||
|
@ -128,6 +129,7 @@ private extension ProfileContextMenu {
|
|||
} label: {
|
||||
ThemeImageLabel(Strings.Global.Actions.edit, .profileEdit)
|
||||
}
|
||||
.uiAccessibility(.ProfileMenu.edit)
|
||||
}
|
||||
|
||||
var profileDuplicateButton: some View {
|
||||
|
|
|
@ -165,6 +165,7 @@ private extension ProfileRowView {
|
|||
}
|
||||
)
|
||||
.foregroundStyle(.primary)
|
||||
.uiAccessibility(.App.profileToggle)
|
||||
}
|
||||
|
||||
var attributesView: some View {
|
||||
|
@ -197,6 +198,7 @@ private extension ProfileRowView {
|
|||
.foregroundStyle(.secondary)
|
||||
.buttonStyle(.plain)
|
||||
#endif
|
||||
.uiAccessibility(.App.profileMenu)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ struct ProfileListView: View {
|
|||
headerView
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
List {
|
||||
ForEach(previews, id: \.id, content: toggleButton(for:))
|
||||
ForEach(allPreviews, id: \.id, content: toggleButton(for:))
|
||||
}
|
||||
.themeList()
|
||||
.themeProgress(if: false, isEmpty: !profileManager.hasProfiles) {
|
||||
|
@ -64,7 +64,7 @@ struct ProfileListView: View {
|
|||
}
|
||||
|
||||
private extension ProfileListView {
|
||||
var previews: [ProfilePreview] {
|
||||
var allPreviews: [ProfilePreview] {
|
||||
profileManager.previews
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// EnvironmentValues+Extensions.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension EnvironmentValues {
|
||||
public var isUITesting: Bool {
|
||||
get {
|
||||
self[IsUITestingKey.self]
|
||||
}
|
||||
set {
|
||||
self[IsUITestingKey.self] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct IsUITestingKey: EnvironmentKey {
|
||||
static let defaultValue = false
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// AccessibilityInfo.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct AccessibilityInfo: Equatable {
|
||||
public enum ElementType {
|
||||
case button
|
||||
|
||||
case menu
|
||||
|
||||
case menuItem
|
||||
|
||||
case text
|
||||
}
|
||||
|
||||
public let id: String
|
||||
|
||||
public let elementType: ElementType
|
||||
|
||||
public init(_ id: String, _ elementType: ElementType) {
|
||||
self.id = id
|
||||
self.elementType = elementType
|
||||
}
|
||||
|
||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// View+Accessibility.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
public func uiAccessibility(_ info: AccessibilityInfo) -> some View {
|
||||
accessibilityIdentifier(info.id)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// AppCommandLine.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum AppCommandLine {
|
||||
public enum Value: String {
|
||||
case fakeIAP = "-pp_fake_iap"
|
||||
|
||||
case fakeMigration = "-pp_fake_migration"
|
||||
|
||||
case uiTesting = "-pp_ui_tests"
|
||||
}
|
||||
|
||||
public static func contains(_ argument: Value) -> Bool {
|
||||
CommandLine.arguments.contains(argument.rawValue)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// AppEnvironment.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum AppEnvironment {
|
||||
public enum Key: String {
|
||||
case userLevel = "PP_USER_LEVEL"
|
||||
}
|
||||
|
||||
public static func string(for key: Key) -> String? {
|
||||
ProcessInfo.processInfo.environment[key.rawValue]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// App.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension AccessibilityInfo {
|
||||
public enum App {
|
||||
public static let installedProfile = AccessibilityInfo("app.installedProfile", .text)
|
||||
|
||||
public static let profileToggle = AccessibilityInfo("app.profileToggle", .button)
|
||||
|
||||
public static let profileMenu = AccessibilityInfo("app.profileMenu", .menu)
|
||||
}
|
||||
|
||||
public enum ProfileMenu {
|
||||
public static let edit = AccessibilityInfo("app.profileMenu.edit", .menuItem)
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ import Foundation
|
|||
import LegacyV2
|
||||
import PassepartoutKit
|
||||
import UILibrary
|
||||
import UITesting
|
||||
|
||||
// shared registry and environment are picked from Shared.swift
|
||||
|
||||
|
@ -105,7 +106,7 @@ extension AppContext {
|
|||
)
|
||||
)
|
||||
let migrationSimulation: MigrationManager.Simulation?
|
||||
if Configuration.Environment.isFakeMigration {
|
||||
if AppCommandLine.contains(.fakeMigration) {
|
||||
migrationSimulation = MigrationManager.Simulation(
|
||||
fakeProfiles: true,
|
||||
maxMigrationTime: 3.0,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// AppEnvironment+IAP.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import CommonIAP
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import UITesting
|
||||
|
||||
extension AppEnvironment {
|
||||
public static var userLevel: AppUserLevel? {
|
||||
if let envString = string(for: .userLevel),
|
||||
let envValue = Int(envString),
|
||||
let testAppType = AppUserLevel(rawValue: envValue) {
|
||||
|
||||
return testAppType
|
||||
}
|
||||
if let infoValue = BundleConfiguration.mainIntegerIfPresent(for: .userLevel),
|
||||
let testAppType = AppUserLevel(rawValue: infoValue) {
|
||||
|
||||
return testAppType
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -27,12 +27,13 @@ import CommonLibrary
|
|||
import CommonUtils
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import UITesting
|
||||
|
||||
extension IAPManager {
|
||||
static let sharedForApp = IAPManager(
|
||||
customUserLevel: Configuration.Environment.userLevel,
|
||||
inAppHelper: Configuration.IAPManager.inAppHelper,
|
||||
receiptReader: Configuration.IAPManager.appReceiptReader,
|
||||
customUserLevel: AppEnvironment.userLevel,
|
||||
inAppHelper: Configuration.IAPManager.simulatedInAppHelper,
|
||||
receiptReader: Configuration.IAPManager.simulatedAppReceiptReader,
|
||||
betaChecker: Configuration.IAPManager.betaChecker,
|
||||
productsAtBuild: Configuration.IAPManager.productsAtBuild
|
||||
)
|
||||
|
@ -82,28 +83,19 @@ extension IAPManager {
|
|||
|
||||
// MARK: - Configuration
|
||||
|
||||
private extension Configuration.Environment {
|
||||
static var userLevel: AppUserLevel? {
|
||||
if let envString = ProcessInfo.processInfo.environment["PP_USER_LEVEL"],
|
||||
let envValue = Int(envString),
|
||||
let testAppType = AppUserLevel(rawValue: envValue) {
|
||||
|
||||
return testAppType
|
||||
}
|
||||
if let infoValue = BundleConfiguration.mainIntegerIfPresent(for: .userLevel),
|
||||
let testAppType = AppUserLevel(rawValue: infoValue) {
|
||||
|
||||
return testAppType
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private extension Configuration.IAPManager {
|
||||
|
||||
@MainActor
|
||||
static var appReceiptReader: AppReceiptReader {
|
||||
guard !Configuration.Environment.isFakeIAP else {
|
||||
static let simulatedInAppHelper: any AppProductHelper = {
|
||||
guard !AppCommandLine.contains(.fakeIAP) else {
|
||||
return FakeAppProductHelper()
|
||||
}
|
||||
return inAppHelper
|
||||
}()
|
||||
|
||||
@MainActor
|
||||
static var simulatedAppReceiptReader: AppReceiptReader {
|
||||
guard !AppCommandLine.contains(.fakeIAP) else {
|
||||
guard let mockHelper = inAppHelper as? FakeAppProductHelper else {
|
||||
fatalError("When .isFakeIAP, productHelper is expected to be MockAppProductHelper")
|
||||
}
|
||||
|
|
|
@ -92,9 +92,6 @@ extension TunnelEnvironment where Self == AppGroupEnvironment {
|
|||
// MARK: - Configuration
|
||||
|
||||
enum Configuration {
|
||||
enum Environment {
|
||||
}
|
||||
|
||||
enum ProfileManager {
|
||||
}
|
||||
|
||||
|
@ -102,16 +99,6 @@ enum Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
extension Configuration.Environment {
|
||||
static var isFakeIAP: Bool {
|
||||
ProcessInfo.processInfo.environment["PP_FAKE_IAP"] == "1"
|
||||
}
|
||||
|
||||
static var isFakeMigration: Bool {
|
||||
ProcessInfo.processInfo.environment["PP_FAKE_MIGRATION"] == "1"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: ProfileManager
|
||||
|
||||
extension Configuration.ProfileManager {
|
||||
|
@ -140,9 +127,6 @@ extension Configuration.IAPManager {
|
|||
|
||||
@MainActor
|
||||
static let inAppHelper: any AppProductHelper = {
|
||||
guard !Configuration.Environment.isFakeIAP else {
|
||||
return FakeAppProductHelper()
|
||||
}
|
||||
return StoreKitHelper(
|
||||
products: AppProduct.all,
|
||||
inAppIdentifier: {
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// PassepartoutUITests.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import UITesting
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
final class PassepartoutUITests: XCTestCase {
|
||||
private var app: XCUIApplication!
|
||||
|
||||
override func setUp() async throws {
|
||||
continueAfterFailure = false
|
||||
|
||||
app = XCUIApplication()
|
||||
app.appArguments = [.uiTesting]
|
||||
app.launch()
|
||||
}
|
||||
|
||||
func testConnected() async throws {
|
||||
let container = app.get(.App.installedProfile)
|
||||
XCTAssertTrue(container.waitForExistence(timeout: 1.0))
|
||||
|
||||
let profileToggle = app.get(.App.profileToggle).firstMatch
|
||||
XCTAssertTrue(profileToggle.waitForExistence(timeout: 1.0))
|
||||
profileToggle.tap()
|
||||
|
||||
try await Task.sleep(for: .seconds(3))
|
||||
|
||||
snapshot("1_Connected")
|
||||
}
|
||||
|
||||
func testProfile() async throws {
|
||||
let container = app.get(.App.installedProfile)
|
||||
XCTAssertTrue(container.waitForExistence(timeout: 1.0))
|
||||
|
||||
let profileMenu = app.get(.App.profileMenu).firstMatch
|
||||
XCTAssertTrue(profileMenu.waitForExistence(timeout: 1.0))
|
||||
profileMenu.tap()
|
||||
|
||||
let editButton = app.get(.ProfileMenu.edit)
|
||||
XCTAssertTrue(editButton.waitForExistence(timeout: 1.0))
|
||||
editButton.tap()
|
||||
|
||||
try await Task.sleep(for: .seconds(2))
|
||||
|
||||
snapshot("2_Profile")
|
||||
}
|
||||
}
|
||||
|
||||
private extension PassepartoutUITests {
|
||||
var window: XCUIElement {
|
||||
app.windows.firstMatch
|
||||
}
|
||||
|
||||
func snapshot(_ name: String) {
|
||||
// let attachment = XCTAttachment(screenshot: window.screenshot())
|
||||
// attachment.name = name
|
||||
// attachment.lifetime = .keepAlways
|
||||
// add(attachment)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// XCUIApplication+Extensions.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/27/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UITesting
|
||||
import XCTest
|
||||
|
||||
extension XCUIApplication {
|
||||
var appArguments: [AppCommandLine.Value] {
|
||||
get {
|
||||
launchArguments.compactMap(AppCommandLine.Value.init(rawValue:))
|
||||
}
|
||||
set {
|
||||
launchArguments = newValue.map(\.rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension XCUIElement {
|
||||
func get(_ info: AccessibilityInfo) -> XCUIElement {
|
||||
switch info.elementType {
|
||||
case .button:
|
||||
return buttons[info.id]
|
||||
case .menu:
|
||||
return menuButtons[info.id]
|
||||
case .menuItem:
|
||||
return menuItems[info.id]
|
||||
case .text:
|
||||
return staticTexts[info.id]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue