Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
shopify_iossdk
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cemarose
shopify_iossdk
Commits
2b1264cd
Commit
2b1264cd
authored
May 10, 2016
by
Brent Gulanowski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add payment provider tests.
parent
9566aaff
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
266 additions
and
1 deletions
+266
-1
BUYClientTestBase.h
Mobile Buy SDK/Mobile Buy SDK Tests/BUYClientTestBase.h
+0
-1
BUYPaymentProviderTests.m
...le Buy SDK/Mobile Buy SDK Tests/BUYPaymentProviderTests.m
+262
-0
project.pbxproj
Mobile Buy SDK/Mobile Buy SDK.xcodeproj/project.pbxproj
+4
-0
No files found.
Mobile Buy SDK/Mobile Buy SDK Tests/BUYClientTestBase.h
View file @
2b1264cd
...
@@ -30,7 +30,6 @@
...
@@ -30,7 +30,6 @@
extern
NSString
*
const
BUYShopDomain_Placeholder
;
extern
NSString
*
const
BUYShopDomain_Placeholder
;
extern
NSString
*
const
BUYAPIKey_Placeholder
;
extern
NSString
*
const
BUYAPIKey_Placeholder
;
extern
NSString
*
const
BUYAppId_Placeholder
;
extern
NSString
*
const
BUYAppId_Placeholder
;
extern
NSString
*
const
BUYChannelId_Placeholder
;
extern
NSString
*
const
BUYFakeCustomerToken
;
extern
NSString
*
const
BUYFakeCustomerToken
;
@interface
BUYClientTestBase
:
XCTestCase
@interface
BUYClientTestBase
:
XCTestCase
...
...
Mobile Buy SDK/Mobile Buy SDK Tests/BUYPaymentProviderTests.m
0 → 100644
View file @
2b1264cd
//
// BUYPaymentProviderTests.m
// Mobile Buy SDK
//
// Created by David Muzi on 2015-12-15.
// Copyright © 2015 Shopify Inc. All rights reserved.
//
@import
XCTest
;
#import <Buy/Buy.h>
#import "BUYApplePayPaymentProvider.h"
#import "BUYWebCheckoutPaymentProvider.h"
#import "BUYClientTestBase.h"
#import "BUYPaymentController.h"
#import <OHHTTPStubs/OHHTTPStubs.h>
@interface
BUYPaymentController
()
-
(
id
<
BUYPaymentProvider
>
)
providerForType
:
(
NSString
*
)
type
;
@end
@interface
BUYPaymentProviderTests
:
XCTestCase
<
BUYPaymentProviderDelegate
>
@property
(
nonatomic
)
NSMutableDictionary
<
NSString
*
,
XCTestExpectation
*>
*
expectations
;
@property
(
nonatomic
)
BUYModelManager
*
modelManager
;
@end
@implementation
BUYPaymentProviderTests
-
(
void
)
setUp
{
[
super
setUp
];
self
.
modelManager
=
[
BUYModelManager
modelManager
];
self
.
expectations
=
[@{}
mutableCopy
];
}
-
(
void
)
tearDown
{
[
super
tearDown
];
[
OHHTTPStubs
removeAllStubs
];
}
-
(
BUYClient
*
)
client
{
return
[[
BUYClient
alloc
]
initWithShopDomain
:
BUYShopDomain_Placeholder
apiKey
:
BUYAPIKey_Placeholder
appId
:
BUYAppId_Placeholder
];
}
-
(
BUYCheckout
*
)
checkout
{
return
[
self
.
modelManager
insertCheckoutWithJSONDictionary
:
nil
];
}
-
(
void
)
mockRequests
{
// This mocks a getShop, and createCheckout request
[
OHHTTPStubs
stubRequestsPassingTest
:
^
BOOL
(
NSURLRequest
*
_Nonnull
request
)
{
return
YES
;
}
withStubResponse
:
^
OHHTTPStubsResponse
*
_Nonnull
(
NSURLRequest
*
_Nonnull
request
)
{
return
[
BUYPaymentProviderTests
responseForRequest
:
request
];
}];
}
+
(
OHHTTPStubsResponse
*
)
responseForRequest
:
(
NSURLRequest
*
)
request
{
NSURLComponents
*
components
=
[
NSURLComponents
componentsWithURL
:
request
.
URL
resolvingAgainstBaseURL
:
NO
];
if
([
components
.
path
isEqualToString
:
@"/meta.json"
])
{
return
[
OHHTTPStubsResponse
responseWithJSONObject
:@{
@"id"
:
@"123"
,
@"country"
:
@"US"
,
@"currency"
:
@"USD"
}
statusCode
:
200
headers
:
nil
];
}
else
if
([
components
.
path
isEqualToString
:
@"/api/checkouts.json"
])
{
return
[
OHHTTPStubsResponse
responseWithJSONObject
:@{
@"checkout"
:
@{
@"payment_due"
:
@
(
99
),
@"web_checkout_url"
:
@"https://example.com"
}}
statusCode
:
200
headers
:
nil
];
}
return
nil
;
}
#pragma mark - Apple Pay
-
(
void
)
testAppleAvailability
{
BUYApplePayPaymentProvider
*
applePay
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@"merchant.id.1"
];
XCTAssertTrue
(
applePay
.
isAvailable
);
BUYApplePayPaymentProvider
*
applePay2
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@""
];
XCTAssertFalse
(
applePay2
.
isAvailable
);
}
-
(
void
)
testApplePayPresentationCallbacks
{
[
self
mockRequests
];
BUYApplePayPaymentProvider
*
applePay
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@"merchant.id.1"
];
applePay
.
delegate
=
self
;
self
.
expectations
[
@"presentController"
]
=
[
self
expectationWithDescription
:
NSStringFromSelector
(
_cmd
)];
[
applePay
startCheckout
:
self
.
checkout
];
[
self
waitForExpectationsWithTimeout
:
1
handler
:
^
(
NSError
*
error
)
{
XCTAssertNil
(
error
);
}];
}
-
(
void
)
testApplePayProvider
{
BUYApplePayPaymentProvider
*
applePay1
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@"merchant.id.1"
];
XCTAssertEqualObjects
(
applePay1
.
merchantID
,
@"merchant.id.1"
);
// 4 default networks should be configured
XCTAssertEqual
(
applePay1
.
supportedNetworks
.
count
,
4
);
applePay1
.
supportedNetworks
=
@[
PKPaymentNetworkMasterCard
];
XCTAssertEqual
(
applePay1
.
supportedNetworks
.
count
,
1
);
XCTAssertEqualObjects
(
applePay1
.
supportedNetworks
[
0
],
PKPaymentNetworkMasterCard
);
}
-
(
void
)
testCanShowApplePaySetup
{
BUYApplePayPaymentProvider
*
applePay
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@"merchant.id.1"
];
XCTAssertTrue
(
applePay
.
canShowApplePaySetup
);
BUYApplePayPaymentProvider
*
applePay2
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@""
];
XCTAssertFalse
(
applePay2
.
canShowApplePaySetup
);
}
-
(
void
)
testFailedApplePayCallbacks
{
[
OHHTTPStubs
stubRequestsPassingTest
:
^
BOOL
(
NSURLRequest
*
_Nonnull
request
)
{
return
YES
;
}
withStubResponse
:
^
OHHTTPStubsResponse
*
_Nonnull
(
NSURLRequest
*
_Nonnull
request
)
{
return
[
OHHTTPStubsResponse
responseWithJSONObject
:@{}
statusCode
:
400
headers
:
nil
];
}];
BUYApplePayPaymentProvider
*
applePay
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@"merchant.id.1"
];
applePay
.
delegate
=
self
;
self
.
expectations
[
@"failedCheckout"
]
=
[
self
expectationWithDescription
:
NSStringFromSelector
(
_cmd
)];
self
.
expectations
[
@"failedShop"
]
=
[
self
expectationWithDescription
:
NSStringFromSelector
(
_cmd
)];
[
applePay
startCheckout
:
self
.
checkout
];
[
self
waitForExpectationsWithTimeout
:
1
handler
:
^
(
NSError
*
error
)
{
XCTAssertNil
(
error
);
}];
}
#pragma mark - Web
-
(
void
)
testWebAvailability
{
BUYWebCheckoutPaymentProvider
*
webProvider
=
[[
BUYWebCheckoutPaymentProvider
alloc
]
initWithClient
:
self
.
client
];
XCTAssertTrue
(
webProvider
.
isAvailable
);
}
-
(
void
)
testWebPresentationCallbacks
{
[
self
mockRequests
];
BUYWebCheckoutPaymentProvider
*
webProvider
=
[[
BUYWebCheckoutPaymentProvider
alloc
]
initWithClient
:
self
.
client
];
webProvider
.
delegate
=
self
;
self
.
expectations
[
@"presentController"
]
=
[
self
expectationWithDescription
:
NSStringFromSelector
(
_cmd
)];
[
webProvider
startCheckout
:
self
.
checkout
];
[
self
waitForExpectationsWithTimeout
:
1
handler
:
^
(
NSError
*
error
)
{
XCTAssertNil
(
error
);
}];
}
#pragma mark - Payment Controller
-
(
void
)
testPaymentController
{
BUYPaymentController
*
controller
=
[[
BUYPaymentController
alloc
]
init
];
BUYApplePayPaymentProvider
*
applePay1
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@"merchant.id.1"
];
[
controller
addPaymentProvider
:
applePay1
];
XCTAssertEqual
(
controller
.
providers
.
count
,
1
);
id
<
BUYPaymentProvider
>
provider
=
[
controller
providerForType
:
BUYApplePayPaymentProviderId
];
XCTAssertEqualObjects
(
provider
,
applePay1
);
BUYWebCheckoutPaymentProvider
*
webProvider
=
[[
BUYWebCheckoutPaymentProvider
alloc
]
initWithClient
:
self
.
client
];
[
controller
addPaymentProvider
:
webProvider
];
XCTAssertEqual
(
controller
.
providers
.
count
,
2
);
provider
=
[
controller
providerForType
:
BUYWebPaymentProviderId
];
XCTAssertEqualObjects
(
provider
,
webProvider
);
// Attempt to add an alternate Apple Pay provider
BUYApplePayPaymentProvider
*
applePay2
=
[[
BUYApplePayPaymentProvider
alloc
]
initWithClient
:
self
.
client
merchantID
:
@"merchant.id.2"
];
[
controller
addPaymentProvider
:
applePay2
];
XCTAssertEqual
(
controller
.
providers
.
count
,
2
);
}
-
(
void
)
testStartingPaymentWithPaymentController
{
[
self
mockRequests
];
BUYPaymentController
*
controller
=
[[
BUYPaymentController
alloc
]
init
];
BUYWebCheckoutPaymentProvider
*
webProvider
=
[[
BUYWebCheckoutPaymentProvider
alloc
]
initWithClient
:
self
.
client
];
webProvider
.
delegate
=
self
;
[
controller
addPaymentProvider
:
webProvider
];
self
.
expectations
[
@"presentController"
]
=
[
self
expectationWithDescription
:
NSStringFromSelector
(
_cmd
)];
[
controller
startCheckout
:
self
.
checkout
withProviderType
:
BUYWebPaymentProviderId
];
[
self
waitForExpectationsWithTimeout
:
1
handler
:
^
(
NSError
*
error
)
{
XCTAssertNil
(
error
);
}];
}
#pragma mark - Payment Provider delegate
-
(
void
)
paymentProvider
:
(
id
<
BUYPaymentProvider
>
)
provider
wantsControllerPresented
:
(
UIViewController
*
)
controller
{
[
self
.
expectations
[
@"presentController"
]
fulfill
];
}
-
(
void
)
paymentProviderWantsControllerDismissed
:
(
id
<
BUYPaymentProvider
>
)
provider
{
}
-
(
void
)
paymentProviderWillStartCheckout
:
(
id
<
BUYPaymentProvider
>
)
provider
{
}
-
(
void
)
paymentProviderDidDismissCheckout
:
(
id
<
BUYPaymentProvider
>
)
provider
{
}
-
(
void
)
paymentProvider
:
(
id
<
BUYPaymentProvider
>
)
provider
didFailToUpdateCheckoutWithError
:
(
NSError
*
)
error
{
}
-
(
void
)
paymentProvider
:
(
id
<
BUYPaymentProvider
>
)
provider
didFailCheckoutWithError
:
(
NSError
*
)
error
;
{
if
(
self
.
expectations
[
@"failedCheckout"
])
{
[
self
.
expectations
[
@"failedCheckout"
]
fulfill
];
[
self
.
expectations
removeObjectForKey
:
@"failedCheckout"
];
}
if
(
self
.
expectations
[
@"failedShop"
])
{
[
self
.
expectations
[
@"failedShop"
]
fulfill
];
[
self
.
expectations
removeObjectForKey
:
@"failedShop"
];
}
}
-
(
void
)
paymentProvider
:
(
id
<
BUYPaymentProvider
>
)
provider
didCompleteCheckout
:
(
BUYCheckout
*
)
checkout
withStatus
:
(
BUYStatus
)
status
{
}
@end
Mobile Buy SDK/Mobile Buy SDK.xcodeproj/project.pbxproj
View file @
2b1264cd
...
@@ -73,6 +73,7 @@
...
@@ -73,6 +73,7 @@
841ADE241CB6C942000004B0
/* NSURLComponents+BUYAdditions.h in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
841ADDFD1CB6C942000004B0
/* NSURLComponents+BUYAdditions.h */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
841ADE241CB6C942000004B0
/* NSURLComponents+BUYAdditions.h in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
841ADDFD1CB6C942000004B0
/* NSURLComponents+BUYAdditions.h */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
841ADE251CB6C942000004B0
/* NSURLComponents+BUYAdditions.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
841ADDFE1CB6C942000004B0
/* NSURLComponents+BUYAdditions.m */
;
};
841ADE251CB6C942000004B0
/* NSURLComponents+BUYAdditions.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
841ADDFE1CB6C942000004B0
/* NSURLComponents+BUYAdditions.m */
;
};
841ADE261CB6C942000004B0
/* NSURLComponents+BUYAdditions.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
841ADDFE1CB6C942000004B0
/* NSURLComponents+BUYAdditions.m */
;
};
841ADE261CB6C942000004B0
/* NSURLComponents+BUYAdditions.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
841ADDFE1CB6C942000004B0
/* NSURLComponents+BUYAdditions.m */
;
};
8443E2D11CE2917500EA08D4
/* BUYPaymentProviderTests.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
8443E2D01CE2917500EA08D4
/* BUYPaymentProviderTests.m */
;
};
849110311CCE708900E53B93
/* BUYArrayAdditionsTests.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
8491102E1CCE708900E53B93
/* BUYArrayAdditionsTests.m */
;
};
849110311CCE708900E53B93
/* BUYArrayAdditionsTests.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
8491102E1CCE708900E53B93
/* BUYArrayAdditionsTests.m */
;
};
849110321CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
8491102F1CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m */
;
};
849110321CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
8491102F1CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m */
;
};
849110331CCE708900E53B93
/* BUYStringAdditionsTests.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
849110301CCE708900E53B93
/* BUYStringAdditionsTests.m */
;
};
849110331CCE708900E53B93
/* BUYStringAdditionsTests.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
849110301CCE708900E53B93
/* BUYStringAdditionsTests.m */
;
};
...
@@ -590,6 +591,7 @@
...
@@ -590,6 +591,7 @@
841ADDFC1CB6C942000004B0
/* NSURL+BUYAdditions.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
"NSURL+BUYAdditions.m"
;
sourceTree
=
"<group>"
;
};
841ADDFC1CB6C942000004B0
/* NSURL+BUYAdditions.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
"NSURL+BUYAdditions.m"
;
sourceTree
=
"<group>"
;
};
841ADDFD1CB6C942000004B0
/* NSURLComponents+BUYAdditions.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
"NSURLComponents+BUYAdditions.h"
;
sourceTree
=
"<group>"
;
};
841ADDFD1CB6C942000004B0
/* NSURLComponents+BUYAdditions.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
"NSURLComponents+BUYAdditions.h"
;
sourceTree
=
"<group>"
;
};
841ADDFE1CB6C942000004B0
/* NSURLComponents+BUYAdditions.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
"NSURLComponents+BUYAdditions.m"
;
sourceTree
=
"<group>"
;
};
841ADDFE1CB6C942000004B0
/* NSURLComponents+BUYAdditions.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
"NSURLComponents+BUYAdditions.m"
;
sourceTree
=
"<group>"
;
};
8443E2D01CE2917500EA08D4
/* BUYPaymentProviderTests.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
BUYPaymentProviderTests.m
;
sourceTree
=
"<group>"
;
};
8465CF441CC13CFE0010B2E6
/* Templates */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
folder
;
path
=
Templates
;
sourceTree
=
"<group>"
;
};
8465CF441CC13CFE0010B2E6
/* Templates */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
folder
;
path
=
Templates
;
sourceTree
=
"<group>"
;
};
8491102E1CCE708900E53B93
/* BUYArrayAdditionsTests.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
BUYArrayAdditionsTests.m
;
sourceTree
=
"<group>"
;
};
8491102E1CCE708900E53B93
/* BUYArrayAdditionsTests.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
BUYArrayAdditionsTests.m
;
sourceTree
=
"<group>"
;
};
8491102F1CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
BUYRegularExpressionAdditionsTests.m
;
sourceTree
=
"<group>"
;
};
8491102F1CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
BUYRegularExpressionAdditionsTests.m
;
sourceTree
=
"<group>"
;
};
...
@@ -1113,6 +1115,7 @@
...
@@ -1113,6 +1115,7 @@
90F592FF1B0D5F4C0026B382
/* BUYObjectTests.m */
,
90F592FF1B0D5F4C0026B382
/* BUYObjectTests.m */
,
849110461CCEA85C00E53B93
/* BUYObserverTests.m */
,
849110461CCEA85C00E53B93
/* BUYObserverTests.m */
,
8498DCC41CDD208200BD12A8
/* BUYOrderTests.m */
,
8498DCC41CDD208200BD12A8
/* BUYOrderTests.m */
,
8443E2D01CE2917500EA08D4
/* BUYPaymentProviderTests.m */
,
8491102F1CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m */
,
8491102F1CCE708900E53B93
/* BUYRegularExpressionAdditionsTests.m */
,
849110301CCE708900E53B93
/* BUYStringAdditionsTests.m */
,
849110301CCE708900E53B93
/* BUYStringAdditionsTests.m */
,
90F593001B0D5F4C0026B382
/* BUYTestConstants.h */
,
90F593001B0D5F4C0026B382
/* BUYTestConstants.h */
,
...
@@ -1931,6 +1934,7 @@
...
@@ -1931,6 +1934,7 @@
90F593071B0D5F4C0026B382
/* BUYCheckoutTest.m in Sources */
,
90F593071B0D5F4C0026B382
/* BUYCheckoutTest.m in Sources */
,
90F593091B0D5F4C0026B382
/* BUYClientTest.m in Sources */
,
90F593091B0D5F4C0026B382
/* BUYClientTest.m in Sources */
,
90F5930B1B0D5F4C0026B382
/* BUYObjectTests.m in Sources */
,
90F5930B1B0D5F4C0026B382
/* BUYObjectTests.m in Sources */
,
8443E2D11CE2917500EA08D4
/* BUYPaymentProviderTests.m in Sources */
,
90F593041B0D5F4C0026B382
/* BUYIntegrationTest.m in Sources */
,
90F593041B0D5F4C0026B382
/* BUYIntegrationTest.m in Sources */
,
9A102D1B1CDD1F960026CC43
/* BUYErrorTests.m in Sources */
,
9A102D1B1CDD1F960026CC43
/* BUYErrorTests.m in Sources */
,
90F593081B0D5F4C0026B382
/* BUYClientTest_Storefront.m in Sources */
,
90F593081B0D5F4C0026B382
/* BUYClientTest_Storefront.m in Sources */
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment