Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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 @@ -83,19 +83,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