Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Samples/iOS-Swift/iOS-Swift/ExtraViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ class ExtraViewController: UIViewController {

@IBAction func captureUserFeedbackV2(_ sender: UIButton) {
highlightButton(sender)
var attachments: [Data]?
var attachments: [Attachment]?
if let url = BundleResourceProvider.screenshotURL, let data = try? Data(contentsOf: url) {
attachments = [data]
attachments = [Attachment(data: data, filename: "screenshot.png", contentType: "image/png")]
}
let errorEventID = SentrySDK.capture(error: NSError(domain: "test-error.user-feedback.iOS-Swift", code: 1))
let feedback = SentryFeedback(message: "It broke again on iOS-Swift. I don't know why, but this happens.", name: "John Me", email: "[email protected]", source: .custom, associatedEventId: errorEventID, attachments: attachments)
Expand Down
36 changes: 22 additions & 14 deletions Sources/Swift/Integrations/UserFeedback/SentryFeedback.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ public final class SentryFeedback: NSObject {
var message: String
var source: SentryFeedbackSource
@_spi(Private) public let eventId: SentryId
/// Data objects for any attachments. Currently the web UI only supports showing one attached image, like for a screenshot.
private var attachments: [Data]?

/// Attachments for this feedback submission, like a screenshot.
private var attachments: [Attachment]?

/// The event id that this feedback is associated with, like a crash report.
var associatedEventId: SentryId?

/// - parameters:
/// - associatedEventId The ID for an event you'd like associated with the feedback.
/// - attachments Data objects for any attachments. Currently the web UI only supports showing one attached image, like for a screenshot.
@objc public init(message: String, name: String?, email: String?, source: SentryFeedbackSource = .widget, associatedEventId: SentryId? = nil, attachments: [Data]? = nil) {
/// - attachments Attachment objects for any files to include with the feedback.
@objc public init(message: String, name: String?, email: String?, source: SentryFeedbackSource = .widget, associatedEventId: SentryId? = nil, attachments: [Attachment]? = nil) {
self.eventId = SentryId()
self.name = name
self.email = email
Expand Down Expand Up @@ -90,19 +90,27 @@ extension SentryFeedback {
dict["email"] = email
}
if let attachments = attachments {
dict["attachments"] = attachments
dict["attachments"] = attachments.map { attachment -> [String: Any] in
var attDict: [String: Any] = ["filename": attachment.filename]
if let data = attachment.data {
attDict["data"] = data
}
if let path = attachment.path {
attDict["path"] = path
}
if let contentType = attachment.contentType {
attDict["contentType"] = contentType
}
return attDict
}
}
return dict
}

/**
* - note: Currently there is only a single attachment possible, for the screenshot, of which there can be only one.
* Returns all attachments for inclusion in the feedback envelope.
*/
@_spi(Private) public func attachmentsForEnvelope() -> [Attachment] {
var items = [Attachment]()
if let screenshot = attachments?.first {
items.append(Attachment(data: screenshot, filename: "screenshot.png", contentType: "application/png"))
}
return items
return attachments ?? []
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -455,11 +455,11 @@ extension SentryUserFeedbackFormViewModel {
}

func feedbackObject() -> SentryFeedback {
var attachmentDatas: [Data]?
var attachments: [Attachment]?
if let image = screenshotImageView.image, let data = image.pngData() {
attachmentDatas = [data]
attachments = [Attachment(data: data, filename: "screenshot.png", contentType: "image/png")]
}
return SentryFeedback(message: messageTextView.text, name: fullNameTextField.text, email: emailTextField.text, attachments: attachmentDatas)
return SentryFeedback(message: messageTextView.text, name: fullNameTextField.text, email: emailTextField.text, attachments: attachments)
}
}

Expand Down
49 changes: 34 additions & 15 deletions Tests/SentryTests/Integrations/Feedback/SentryFeedbackTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,65 +30,84 @@ class SentryFeedbackTests: XCTestCase {
}

func testSerializeWithAllFields() throws {
let sut = SentryFeedback(message: "Test feedback message", name: "Test feedback provider", email: "[email protected]", attachments: [Data()])

let attachment = Attachment(data: Data(), filename: "screenshot.png.png", contentType: "image/png")
let sut = SentryFeedback(message: "Test feedback message", name: "Test feedback provider", email: "[email protected]", attachments: [attachment])

let serialization = sut.serialize()
XCTAssertEqual(try XCTUnwrap(serialization["message"] as? String), "Test feedback message")
XCTAssertEqual(try XCTUnwrap(serialization["name"] as? String), "Test feedback provider")
XCTAssertEqual(try XCTUnwrap(serialization["contact_email"] as? String), "[email protected]")
XCTAssertEqual(try XCTUnwrap(serialization["source"] as? String), "widget")

let attachments = sut.attachmentsForEnvelope()
XCTAssertEqual(attachments.count, 1)
XCTAssertEqual(try XCTUnwrap(attachments.first).filename, "screenshot.png")
XCTAssertEqual(try XCTUnwrap(attachments.first).contentType, "application/png")
XCTAssertEqual(try XCTUnwrap(attachments.first).contentType, "image/png")
}

func testSerializeCustomFeedback() throws {
let sut = SentryFeedback(message: "Test feedback message", name: "Test feedback provider", email: "[email protected]", source: .custom, attachments: [Data()])

let attachment = Attachment(data: Data(), filename: "screenshot.png", contentType: "image/png")
let sut = SentryFeedback(message: "Test feedback message", name: "Test feedback provider", email: "[email protected]", source: .custom, attachments: [attachment])

let serialization = sut.serialize()
XCTAssertEqual(try XCTUnwrap(serialization["message"] as? String), "Test feedback message")
XCTAssertEqual(try XCTUnwrap(serialization["name"] as? String), "Test feedback provider")
XCTAssertEqual(try XCTUnwrap(serialization["contact_email"] as? String), "[email protected]")
XCTAssertEqual(try XCTUnwrap(serialization["source"] as? String), "custom")

let attachments = sut.attachmentsForEnvelope()
XCTAssertEqual(attachments.count, 1)
XCTAssertEqual(try XCTUnwrap(attachments.first).filename, "screenshot.png")
XCTAssertEqual(try XCTUnwrap(attachments.first).contentType, "application/png")
XCTAssertEqual(try XCTUnwrap(attachments.first).contentType, "image/png")
}

func testSerializeWithAssociatedEventID() throws {
let eventID = SentryId()

let sut = SentryFeedback(message: "Test feedback message", name: "Test feedback provider", email: "[email protected]", source: .custom, associatedEventId: eventID, attachments: [Data()])
let attachment = Attachment(data: Data(), filename: "screenshot.png", contentType: "image/png")
let sut = SentryFeedback(message: "Test feedback message", name: "Test feedback provider", email: "[email protected]", source: .custom, associatedEventId: eventID, attachments: [attachment])

let serialization = sut.serialize()
XCTAssertEqual(try XCTUnwrap(serialization["message"] as? String), "Test feedback message")
XCTAssertEqual(try XCTUnwrap(serialization["name"] as? String), "Test feedback provider")
XCTAssertEqual(try XCTUnwrap(serialization["contact_email"] as? String), "[email protected]")
XCTAssertEqual(try XCTUnwrap(serialization["source"] as? String), "custom")
XCTAssertEqual(try XCTUnwrap(serialization["associated_event_id"] as? String), eventID.sentryIdString)

let attachments = sut.attachmentsForEnvelope()
XCTAssertEqual(attachments.count, 1)
XCTAssertEqual(try XCTUnwrap(attachments.first).filename, "screenshot.png")
XCTAssertEqual(try XCTUnwrap(attachments.first).contentType, "application/png")
XCTAssertEqual(try XCTUnwrap(attachments.first).contentType, "image/png")
}

func testSerializeWithNoOptionalFields() throws {
let sut = SentryFeedback(message: "Test feedback message", name: nil, email: nil)

let serialization = sut.serialize()
XCTAssertEqual(try XCTUnwrap(serialization["message"] as? String), "Test feedback message")
XCTAssertNil(serialization["name"])
XCTAssertNil(serialization["contact_email"])
XCTAssertEqual(try XCTUnwrap(serialization["source"] as? String), "widget")

let attachments = sut.attachmentsForEnvelope()
XCTAssertEqual(attachments.count, 0)
}

func testMultipleAttachments() throws {
let screenshot = Attachment(data: Data("screenshot".utf8), filename: "screenshot.png", contentType: "image/png")
let logFile = Attachment(data: Data("log content".utf8), filename: "app.log", contentType: "text/plain")
let videoFile = Attachment(data: Data("video".utf8), filename: "recording.mp4", contentType: "video/mp4")

let sut = SentryFeedback(message: "Test feedback with multiple attachments", name: "Test User", email: "[email protected]", attachments: [screenshot, logFile, videoFile])

let attachments = sut.attachmentsForEnvelope()
XCTAssertEqual(attachments.count, 3)
XCTAssertEqual(attachments[0].filename, "screenshot.png")
XCTAssertEqual(attachments[0].contentType, "image/png")
XCTAssertEqual(attachments[1].filename, "app.log")
XCTAssertEqual(attachments[1].contentType, "text/plain")
XCTAssertEqual(attachments[2].filename, "recording.mp4")
XCTAssertEqual(attachments[2].contentType, "video/mp4")
}

private let inputCombinations: [FeedbackTestCase] = [
// base case: don't require name or email, don't input a name or email, don't input a message or screenshot
Expand Down