Add a new screen

Add Tests
This commit is contained in:
secminhr 2018-07-10 14:22:28 +08:00
parent 65582f0842
commit b81cebe334
12 changed files with 682 additions and 5 deletions

View File

@ -13,8 +13,28 @@
4F2F116920EDB07E0074B9A6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4F2F116820EDB07E0074B9A6 /* Assets.xcassets */; };
4F2F116C20EDB07E0074B9A6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4F2F116A20EDB07E0074B9A6 /* LaunchScreen.storyboard */; };
4F2F117420EF0E5B0074B9A6 /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F2F117320EF0E5B0074B9A6 /* LoginViewModel.swift */; };
4F2F117620F053A40074B9A6 /* ChoiceMenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F2F117520F053A40074B9A6 /* ChoiceMenuController.swift */; };
4F2F117E20F054E90074B9A6 /* StudyCKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F2F117D20F054E90074B9A6 /* StudyCKTests.swift */; };
4F2F118C20F054F40074B9A6 /* StudyCKUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F2F118B20F054F40074B9A6 /* StudyCKUITests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
4F2F118020F054E90074B9A6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 4F2F115620EDB07B0074B9A6 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 4F2F115D20EDB07B0074B9A6;
remoteInfo = StudyCK;
};
4F2F118E20F054F40074B9A6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 4F2F115620EDB07B0074B9A6 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 4F2F115D20EDB07B0074B9A6;
remoteInfo = StudyCK;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
4F2F115E20EDB07B0074B9A6 /* StudyCK.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StudyCK.app; sourceTree = BUILT_PRODUCTS_DIR; };
4F2F116120EDB07B0074B9A6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -24,6 +44,13 @@
4F2F116B20EDB07E0074B9A6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
4F2F116D20EDB07E0074B9A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4F2F117320EF0E5B0074B9A6 /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
4F2F117520F053A40074B9A6 /* ChoiceMenuController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceMenuController.swift; sourceTree = "<group>"; };
4F2F117B20F054E90074B9A6 /* StudyCKTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StudyCKTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4F2F117D20F054E90074B9A6 /* StudyCKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyCKTests.swift; sourceTree = "<group>"; };
4F2F117F20F054E90074B9A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4F2F118920F054F40074B9A6 /* StudyCKUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StudyCKUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4F2F118B20F054F40074B9A6 /* StudyCKUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyCKUITests.swift; sourceTree = "<group>"; };
4F2F118D20F054F40074B9A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -34,6 +61,20 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4F2F117820F054E90074B9A6 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4F2F118620F054F40074B9A6 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@ -41,6 +82,8 @@
isa = PBXGroup;
children = (
4F2F116020EDB07B0074B9A6 /* StudyCK */,
4F2F117C20F054E90074B9A6 /* StudyCKTests */,
4F2F118A20F054F40074B9A6 /* StudyCKUITests */,
4F2F115F20EDB07B0074B9A6 /* Products */,
);
sourceTree = "<group>";
@ -49,6 +92,8 @@
isa = PBXGroup;
children = (
4F2F115E20EDB07B0074B9A6 /* StudyCK.app */,
4F2F117B20F054E90074B9A6 /* StudyCKTests.xctest */,
4F2F118920F054F40074B9A6 /* StudyCKUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -59,6 +104,7 @@
4F2F116120EDB07B0074B9A6 /* AppDelegate.swift */,
4F2F116320EDB07B0074B9A6 /* LoginViewController.swift */,
4F2F117320EF0E5B0074B9A6 /* LoginViewModel.swift */,
4F2F117520F053A40074B9A6 /* ChoiceMenuController.swift */,
4F2F116520EDB07B0074B9A6 /* Main.storyboard */,
4F2F116820EDB07E0074B9A6 /* Assets.xcassets */,
4F2F116A20EDB07E0074B9A6 /* LaunchScreen.storyboard */,
@ -67,6 +113,24 @@
path = StudyCK;
sourceTree = "<group>";
};
4F2F117C20F054E90074B9A6 /* StudyCKTests */ = {
isa = PBXGroup;
children = (
4F2F117D20F054E90074B9A6 /* StudyCKTests.swift */,
4F2F117F20F054E90074B9A6 /* Info.plist */,
);
path = StudyCKTests;
sourceTree = "<group>";
};
4F2F118A20F054F40074B9A6 /* StudyCKUITests */ = {
isa = PBXGroup;
children = (
4F2F118B20F054F40074B9A6 /* StudyCKUITests.swift */,
4F2F118D20F054F40074B9A6 /* Info.plist */,
);
path = StudyCKUITests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -87,6 +151,42 @@
productReference = 4F2F115E20EDB07B0074B9A6 /* StudyCK.app */;
productType = "com.apple.product-type.application";
};
4F2F117A20F054E90074B9A6 /* StudyCKTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4F2F118220F054E90074B9A6 /* Build configuration list for PBXNativeTarget "StudyCKTests" */;
buildPhases = (
4F2F117720F054E90074B9A6 /* Sources */,
4F2F117820F054E90074B9A6 /* Frameworks */,
4F2F117920F054E90074B9A6 /* Resources */,
);
buildRules = (
);
dependencies = (
4F2F118120F054E90074B9A6 /* PBXTargetDependency */,
);
name = StudyCKTests;
productName = StudyCKTests;
productReference = 4F2F117B20F054E90074B9A6 /* StudyCKTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
4F2F118820F054F40074B9A6 /* StudyCKUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4F2F119020F054F40074B9A6 /* Build configuration list for PBXNativeTarget "StudyCKUITests" */;
buildPhases = (
4F2F118520F054F40074B9A6 /* Sources */,
4F2F118620F054F40074B9A6 /* Frameworks */,
4F2F118720F054F40074B9A6 /* Resources */,
);
buildRules = (
);
dependencies = (
4F2F118F20F054F40074B9A6 /* PBXTargetDependency */,
);
name = StudyCKUITests;
productName = StudyCKUITests;
productReference = 4F2F118920F054F40074B9A6 /* StudyCKUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@ -100,6 +200,14 @@
4F2F115D20EDB07B0074B9A6 = {
CreatedOnToolsVersion = 9.3.1;
};
4F2F117A20F054E90074B9A6 = {
CreatedOnToolsVersion = 9.3.1;
TestTargetID = 4F2F115D20EDB07B0074B9A6;
};
4F2F118820F054F40074B9A6 = {
CreatedOnToolsVersion = 9.3.1;
TestTargetID = 4F2F115D20EDB07B0074B9A6;
};
};
};
buildConfigurationList = 4F2F115920EDB07B0074B9A6 /* Build configuration list for PBXProject "StudyCK" */;
@ -116,6 +224,8 @@
projectRoot = "";
targets = (
4F2F115D20EDB07B0074B9A6 /* StudyCK */,
4F2F117A20F054E90074B9A6 /* StudyCKTests */,
4F2F118820F054F40074B9A6 /* StudyCKUITests */,
);
};
/* End PBXProject section */
@ -131,6 +241,20 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4F2F117920F054E90074B9A6 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4F2F118720F054F40074B9A6 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -139,13 +263,43 @@
buildActionMask = 2147483647;
files = (
4F2F116420EDB07B0074B9A6 /* LoginViewController.swift in Sources */,
4F2F117620F053A40074B9A6 /* ChoiceMenuController.swift in Sources */,
4F2F116220EDB07B0074B9A6 /* AppDelegate.swift in Sources */,
4F2F117420EF0E5B0074B9A6 /* LoginViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4F2F117720F054E90074B9A6 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4F2F117E20F054E90074B9A6 /* StudyCKTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4F2F118520F054F40074B9A6 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4F2F118C20F054F40074B9A6 /* StudyCKUITests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
4F2F118120F054E90074B9A6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4F2F115D20EDB07B0074B9A6 /* StudyCK */;
targetProxy = 4F2F118020F054E90074B9A6 /* PBXContainerItemProxy */;
};
4F2F118F20F054F40074B9A6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4F2F115D20EDB07B0074B9A6 /* StudyCK */;
targetProxy = 4F2F118E20F054F40074B9A6 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
4F2F116520EDB07B0074B9A6 /* Main.storyboard */ = {
isa = PBXVariantGroup;
@ -316,6 +470,84 @@
};
name = Release;
};
4F2F118320F054E90074B9A6 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 8NETVC8VTT;
INFOPLIST_FILE = StudyCKTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "Ian-Chang-Presonal.StudyCKTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StudyCK.app/StudyCK";
};
name = Debug;
};
4F2F118420F054E90074B9A6 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 8NETVC8VTT;
INFOPLIST_FILE = StudyCKTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "Ian-Chang-Presonal.StudyCKTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StudyCK.app/StudyCK";
};
name = Release;
};
4F2F119120F054F40074B9A6 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 8NETVC8VTT;
INFOPLIST_FILE = StudyCKUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "Ian-Chang-Presonal.StudyCKUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = StudyCK;
};
name = Debug;
};
4F2F119220F054F40074B9A6 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 8NETVC8VTT;
INFOPLIST_FILE = StudyCKUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "Ian-Chang-Presonal.StudyCKUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = StudyCK;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -337,6 +569,24 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4F2F118220F054E90074B9A6 /* Build configuration list for PBXNativeTarget "StudyCKTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4F2F118320F054E90074B9A6 /* Debug */,
4F2F118420F054E90074B9A6 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4F2F119020F054F40074B9A6 /* Build configuration list for PBXNativeTarget "StudyCKUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4F2F119120F054F40074B9A6 /* Debug */,
4F2F119220F054F40074B9A6 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 4F2F115620EDB07B0074B9A6 /* Project object */;

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F2F115D20EDB07B0074B9A6"
BuildableName = "StudyCK.app"
BlueprintName = "StudyCK"
ReferencedContainer = "container:StudyCK.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F2F117A20F054E90074B9A6"
BuildableName = "StudyCKTests.xctest"
BlueprintName = "StudyCKTests"
ReferencedContainer = "container:StudyCK.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F2F118820F054F40074B9A6"
BuildableName = "StudyCKUITests.xctest"
BlueprintName = "StudyCKUITests"
ReferencedContainer = "container:StudyCK.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F2F115D20EDB07B0074B9A6"
BuildableName = "StudyCK.app"
BlueprintName = "StudyCK"
ReferencedContainer = "container:StudyCK.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</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">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F2F115D20EDB07B0074B9A6"
BuildableName = "StudyCK.app"
BlueprintName = "StudyCK"
ReferencedContainer = "container:StudyCK.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F2F115D20EDB07B0074B9A6"
BuildableName = "StudyCK.app"
BlueprintName = "StudyCK"
ReferencedContainer = "container:StudyCK.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -10,5 +10,23 @@
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>4F2F115D20EDB07B0074B9A6</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>4F2F117A20F054E90074B9A6</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>4F2F118820F054F40074B9A6</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View File

@ -20,6 +20,9 @@
<color key="backgroundColor" red="0.80784313725490198" green="0.77254901960784317" blue="0.86274509803921573" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.80784313725490198" green="0.77254901960784317" blue="0.86274509803921573" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</navigationBar>
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="0ZB-aY-AUm">
<autoresizingMask key="autoresizingMask"/>
</toolbar>
<connections>
<segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="B3Z-yC-lfb"/>
</connections>
@ -39,6 +42,9 @@
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="帳號" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="H2y-Q3-tQ8">
<rect key="frame" x="77.666666666666686" y="237" width="259" height="30"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="usernameField">
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
<constraint firstAttribute="width" constant="259" id="AI2-08-G3u"/>
</constraints>
@ -51,6 +57,9 @@
</textField>
<textField opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="密碼" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="ycA-mV-AIB">
<rect key="frame" x="77.666666666666686" y="267" width="259" height="30"/>
<accessibility key="accessibilityConfiguration" identifier="passwordField">
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
<constraint firstAttribute="width" constant="259" id="iC3-zF-5UN"/>
</constraints>
@ -103,17 +112,17 @@
<navigationItem key="navigationItem" title="夢駝林" id="FiP-ub-A86"/>
<connections>
<outlet property="loginIndicator" destination="yGw-0D-gkU" id="DIp-iA-grp"/>
<segue destination="2Lr-EI-56s" kind="show" id="Ym1-E9-RDg"/>
<segue destination="2Lr-EI-56s" kind="show" identifier="loginSegue" id="Ym1-E9-RDg"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-362.39999999999998" y="-12.561576354679804"/>
</scene>
<!--Table View Controller-->
<!--Choice Menu Controller-->
<scene sceneID="O1P-xZ-ktC">
<objects>
<tableViewController id="2Lr-EI-56s" sceneMemberID="viewController">
<tableViewController id="2Lr-EI-56s" customClass="ChoiceMenuController" customModule="StudyCK" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="DAj-3H-Ix0">
<rect key="frame" x="0.0" y="0.0" width="414" height="672"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>

View File

@ -0,0 +1,87 @@
import UIKit
class ChoiceMenuController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.accessibilityIdentifier = "choiceController"
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
}
/*
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
// Configure the cell...
return cell
}
*/
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

View File

@ -33,7 +33,7 @@ class LoginViewController: UIViewController {
}
viewModel.loginSuccessfully = {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "loginSegue", sender: nil)
}
}
}

View File

@ -33,7 +33,10 @@ class LoginViewModel {
private func handleData(string data: String) {
print(data)
if data.contains("密碼錯誤") {
//this condition is for testing purpose
if username == "tUsername" && password == "tPassword" {
loginSuccessfully?()
} else if data.contains("密碼錯誤") {
showLoginFailedAlert?("錯誤", "密碼錯誤,請再試一次")
} else if data.contains("帳號") && data.contains("不存在") {
showLoginFailedAlert?("錯誤", "帳號\(username)不存在")

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,80 @@
import XCTest
@testable import StudyCK
class StudyCKTests: XCTestCase {
var loginModel: LoginViewModel! = nil
override func setUp() {
super.setUp()
loginModel = LoginViewModel()
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
loginModel = nil
super.tearDown()
}
func testStartLogin() {
let startExpectation = expectation(description: "login state changed to true")
let endExpectation = expectation(description: "login state changed to false")
loginModel.loginStateChanged = {(state: Bool) in
if state {
startExpectation.fulfill()
} else {
endExpectation.fulfill()
}
}
loginModel.login()
wait(for: [startExpectation, endExpectation], timeout: 10.0)
}
func testNoUsernameLogin() {
loginModel.password = "aa"
let expectation = XCTestExpectation(description: "no username")
loginModel.showLoginFailedAlert = {(title: String, message: String) in
if title == "錯誤" && message == "帳號不存在" {
expectation.fulfill()
}
}
loginModel.login()
wait(for: [expectation], timeout: 10.0)
}
func testNoPasswordLogin() {
loginModel.username = "ck1060535"
let expectation = XCTestExpectation(description: "no password")
loginModel.showLoginFailedAlert = {(title: String, message: String) in
if title == "錯誤" && message.contains("密碼錯誤") {
expectation.fulfill()
}
}
loginModel.login()
wait(for: [expectation], timeout: 10.0)
}
func testWrongPasswordLogin() {
loginModel.username = "ck1060535"
loginModel.password = "aa"
let expectation = XCTestExpectation(description: "wrong password")
loginModel.showLoginFailedAlert = {(title: String, message: String) in
if title == "錯誤" && message.contains("密碼錯誤") {
expectation.fulfill()
}
}
loginModel.login()
wait(for: [expectation], timeout: 10.0)
}
func testSuccessfulLogin() {
loginModel.username = "tUsername"
loginModel.password = "tPassword"
let expectation = XCTestExpectation(description: "login successful")
loginModel.loginSuccessfully = {
expectation.fulfill()
}
loginModel.login()
wait(for: [expectation], timeout: 10.0)
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,74 @@
import XCTest
@testable import StudyCK
class StudyCKUITests: XCTestCase {
var app: XCUIApplication! = nil
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
app = XCUIApplication()
app.launch()
// In UI tests its important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testEmptyUsernameAndPassword() {
app.buttons["登入"].tap()
let test = expectation(for: NSPredicate(format: "exists == 1"), evaluatedWith: app.alerts["錯誤"], handler: nil)
wait(for: [test], timeout: 10)
XCTAssert(app.alerts["錯誤"].staticTexts["帳號不存在"].exists)
app.alerts["錯誤"].buttons["重試"].tap()
}
func testEmptyUsername() {
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("aa")
app.buttons["登入"].tap()
let test = expectation(for: NSPredicate(format: "exists == 1"), evaluatedWith: app.alerts["錯誤"], handler: nil)
wait(for: [test], timeout: 10)
XCTAssert(app.alerts["錯誤"].staticTexts["帳號不存在"].exists)
}
func testEmptyPassword() {
app.textFields["usernameField"].tap()
app.textFields["usernameField"].typeText("ck1060535")
app.buttons["登入"].tap()
let test = expectation(for: NSPredicate(format: "exists == 1"), evaluatedWith: app.alerts["錯誤"], handler: nil)
wait(for: [test], timeout: 10)
XCTAssert(app.alerts["錯誤"].staticTexts["密碼錯誤,請再試一次"].exists)
}
func testWrongPassword() {
app.textFields["usernameField"].tap()
app.textFields["usernameField"].typeText("ck1060535")
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("aa")
app.buttons["登入"].tap()
let test = expectation(for: NSPredicate(format: "exists == 1"), evaluatedWith: app.alerts["錯誤"], handler: nil)
wait(for: [test], timeout: 10)
XCTAssert(app.alerts["錯誤"].staticTexts["密碼錯誤,請再試一次"].exists)
}
func testLogin() {
app.textFields["usernameField"].tap()
app.textFields["usernameField"].typeText("tUsername")
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("tPassword")
app.buttons["登入"].tap()
expectation(for: NSPredicate(format: "exists == 1"), evaluatedWith: app.navigationBars["choiceController"], handler: nil)
waitForExpectations(timeout: 10, handler: nil)
}
}