Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding tests #76

Merged
merged 23 commits into from
Mar 14, 2024
Merged
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
8 changes: 8 additions & 0 deletions Intake.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
2FF53D8D2A8729D600042B76 /* IntakeStandard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FF53D8C2A8729D600042B76 /* IntakeStandard.swift */; };
3C89F66D2B9D948B00A4F52D /* PatientInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89F66C2B9D948B00A4F52D /* PatientInfo.swift */; };
510CAAF12BA0DFFB00872B1A /* MedicationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510CAAF02BA0DFFB00872B1A /* MedicationTests.swift */; };
3CD23D612BA137D500AB9914 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = 3CD23D602BA137D500AB9914 /* Documentation.docc */; };
3CD23D642BA14D6D00AB9914 /* NinasTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CD23D632BA14D6D00AB9914 /* NinasTests.swift */; };
511827962B740192002033A0 /* SurgeryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511827952B740191002033A0 /* SurgeryView.swift */; };
51805C122B81853800D17109 /* IntakeMedication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51805C112B81853700D17109 /* IntakeMedication.swift */; };
51805C152B81857100D17109 /* IntakeMedicationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51805C142B81857100D17109 /* IntakeMedicationViewModel.swift */; };
Expand Down Expand Up @@ -182,6 +184,8 @@
2FF53D8C2A8729D600042B76 /* IntakeStandard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntakeStandard.swift; sourceTree = "<group>"; };
3C89F66C2B9D948B00A4F52D /* PatientInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatientInfo.swift; sourceTree = "<group>"; };
510CAAF02BA0DFFB00872B1A /* MedicationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MedicationTests.swift; sourceTree = "<group>"; };
3CD23D602BA137D500AB9914 /* Documentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Documentation.docc; sourceTree = "<group>"; };
3CD23D632BA14D6D00AB9914 /* NinasTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NinasTests.swift; sourceTree = "<group>"; };
511827952B740191002033A0 /* SurgeryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SurgeryView.swift; sourceTree = "<group>"; };
51805C112B81853700D17109 /* IntakeMedication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntakeMedication.swift; sourceTree = "<group>"; };
51805C142B81857100D17109 /* IntakeMedicationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntakeMedicationViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -353,6 +357,7 @@
ACAA47802B571C7F0032D21F /* Questionnaire.json */,
2FE5DC5529EDD811004B9AB4 /* SocialSupportQuestionnaire.json */,
637BE1D42B572B4800EA19C6 /* Questionnaire.json.license */,
3CD23D602BA137D500AB9914 /* Documentation.docc */,
);
path = Resources;
sourceTree = "<group>";
Expand Down Expand Up @@ -563,6 +568,7 @@
children = (
2F4E237D2989A2FE0013F3D9 /* LaunchTests.swift */,
510CAAF02BA0DFFB00872B1A /* MedicationTests.swift */,
3CD23D632BA14D6D00AB9914 /* NinasTests.swift */,
);
path = IntakeUITests;
sourceTree = "<group>";
Expand Down Expand Up @@ -896,6 +902,7 @@
5A2B9F8F2B69E286005CA63F /* MockData.swift in Sources */,
5A2B9FBC2B6C7B29005CA63F /* ReactionView.swift in Sources */,
566155292AB8447C00209B80 /* Package+LicenseType.swift in Sources */,
3CD23D612BA137D500AB9914 /* Documentation.docc in Sources */,
5680DD392AB8983D004E6D4A /* PackageCell.swift in Sources */,
5AEA5F422B90710B00F1577A /* EditPatient.swift in Sources */,
5AAB83A72B9C04E70008407A /* LLMFiltering.swift in Sources */,
Expand Down Expand Up @@ -933,6 +940,7 @@
files = (
510CAAF12BA0DFFB00872B1A /* MedicationTests.swift in Sources */,
2F4E237E2989A2FE0013F3D9 /* LaunchTests.swift in Sources */,
3CD23D642BA14D6D00AB9914 /* NinasTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion Intake/ChiefComplaint/LLMAssistantView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
LLMOnboardingView(showOnboarding: $showOnboarding)
}
.navigationTitle(pageTitle)
.toolbar { // Is this doing anything except causing problems?
.toolbar {

Check warning on line 39 in Intake/ChiefComplaint/LLMAssistantView.swift

View check run for this annotation

Codecov / codecov/patch

Intake/ChiefComplaint/LLMAssistantView.swift#L39

Added line #L39 was not covered by tests
if AccountButton.shouldDisplay {
AccountButton(isPresented: $presentingAccount)
}
Expand Down
20 changes: 11 additions & 9 deletions Intake/ChiefComplaint/LLMInteraction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
//
// SPDX-License-Identifier: MIT
//
// LLMInteraction is the core functionality of Chief Complaint. It initializes the LLM, uses a robust system prompt to ensure that the questions
// asked are specific and medically sound. It utilizes function calling to identify when enough information has been gathered about the patient
// to be helpful to a doctor. The function call


import Foundation
import SpeziChat
Expand All @@ -21,24 +25,22 @@


struct LLMInteraction: View {
// I needed to disable this error because any order I tried would not work. Seems to be an issue with swiftlint
// swiftlint:disable type_contents_order
@State private var fullName: String = ""
@State private var firstName: String = ""
@State private var dob: String = ""
@State private var gender: String = ""
@State var showOnboarding = true
@State var greeting = true
@State var stringBox: StringBox = .init()
@State var showSheet = false

Check warning on line 37 in Intake/ChiefComplaint/LLMInteraction.swift

View check run for this annotation

Codecov / codecov/patch

Intake/ChiefComplaint/LLMInteraction.swift#L34-L37

Added lines #L34 - L37 were not covered by tests
@Environment(LLMRunner.self) var runner: LLMRunner
@Environment(FHIRStore.self) private var fhirStore
@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath

@Binding var presentingAccount: Bool
@LLMSessionProvider<LLMOpenAISchema> var session: LLMOpenAISession

@State var showOnboarding = true
@State var greeting = true

@State var stringBox: StringBox = .init()
@State var showSheet = false

@Observable
class StringBox: Equatable {
Expand All @@ -62,8 +64,8 @@
"""

static let summaryDescription = """
A summary of the patient's primary concern. Include a sentence introducing the patient's name,\
age, and gender, if you have access to this information.
A brief summary of the patient's primary concern. Include all information that would be relevant\
for a doctor who will treat the patient.
"""
@Parameter(description: summaryDescription) var patientSummary: String

Expand Down
1 change: 1 addition & 0 deletions Intake/Elements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct SubmitButtonWithAction: View {
@Environment(ReachedEndWrapper.self) private var end
var nextView: NavigationViews
var onButtonTap: () -> Void
var accessibilityIdentifier: String

var body: some View {
Button(action: {
Expand Down
9 changes: 4 additions & 5 deletions Intake/Export/ExportView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@
//
// SPDX-License-Identifier: MIT
//
//
// ExportView displays all of the information gathered from Intake thus far in one view. It then uses ImageRenderer to export the information to a PDF
// with a simple share button.

// swiftlint disable: closure_body_length
import PDFKit
import SpeziFHIR
import SwiftUI
import UIKit

// Again, I had to disable this error as it was causing issues and could not be resolved.
// swiftlint:disable file_types_order
struct ExportView: View {
@Environment(DataStore.self) var data
@State private var isSharing = false
@State private var pdfData: PDFDocument?

// A long closure body length here is imperative for this view to be formatted correctly. Thus, I had to disable this warning.
// swiftlint:disable closure_body_length
var body: some View {
ScrollView {
Expand Down Expand Up @@ -222,8 +225,6 @@ struct ExportView: View {
func exportToPDF() async -> PDFDocument? {
let renderer = ImageRenderer(content: self.wrappedBody)

// issue: proposed height is not expanding as necessary. uncomment to attempt to fix this.

let proposedHeightOptional = renderer.uiImage?.size.height

guard let proposedHeight = proposedHeightOptional else {
Expand All @@ -238,7 +239,6 @@ struct ExportView: View {
renderer.render { _, context in
var box = CGRect(origin: .zero, size: pageSize)

/// Create in-memory `CGContext` that stores the PDF
guard let mutableData = CFDataCreateMutable(kCFAllocatorDefault, 0),
let consumer = CGDataConsumer(data: mutableData),
let pdf = CGContext(consumer: consumer, mediaBox: &box, nil) else {
Expand Down Expand Up @@ -279,7 +279,6 @@ struct ShareSheet: UIViewControllerRepresentable {


func makeUIViewController(context: Context) -> UIActivityViewController {
// Note: Need to write down the PDF to storage as in-memory PDFs are not recognized properly
let temporaryPath = FileManager.default.temporaryDirectory.appendingPathComponent(
LocalizedStringResource("Intake Form").localizedString() + ".pdf"
)
Expand Down
40 changes: 30 additions & 10 deletions Intake/General Data View/PatientInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,26 @@
//
// SPDX-License-Identifier: MIT
//
// The Patient Info View allows the patient to enter their name, date of birth, and sex. If the patient is connected with Healthkit, it allows
// them to verify their information is correct and edit it if not. The information is automatically pulled from Healthkit if the patient is connected.

import SpeziFHIR
import SwiftUI

// swiftlint:disable type_contents_order
// Again, no matter the order of these variables, there is still issues with type_contents_order. It was necessary to just disable this.
struct PatientInfo: View {
@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath
@Environment(FHIRStore.self) private var fhirStore


@State private var fullName: String = ""
@State private var firstName: String = ""
@State private var birthdate: String = ""
@State private var gender: String = "female"
@State private var sexOption: String = ""
@State private var birthdateDateFormat = Date()

@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath
@Environment(FHIRStore.self) private var fhirStore

func calculateAge(from dobString: String, with format: String = "yyyy-MM-dd") -> String {
if dobString.isEmpty {
return ""
Expand Down Expand Up @@ -55,11 +59,11 @@
if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
if key == "name" {
if let nameArray = dictionary[key] as? [[String: Any]], !nameArray.isEmpty {
let nameDict = nameArray[0] // Accessing the first name object
let nameDict = nameArray[0]
if let family = nameDict["family"] as? String,
let givenArray = nameDict["given"] as? [String],
!givenArray.isEmpty {
let given = givenArray.joined(separator: " ") // Assuming there might be more than one given name
let given = givenArray.joined(separator: " ")

return "\(given) \(family)"
}
Expand Down Expand Up @@ -91,6 +95,8 @@

var body: some View {
@Bindable var data = data
// Necessary because without it other linting errors arise regarding each argument needing their own line
// swiftlint:disable closure_body_length
Form {
Section(header: Text("Patient Information")) {
HStack {
Expand All @@ -112,9 +118,23 @@
}
}
Spacer()
SubmitButtonWithAction(nextView: .medical, onButtonTap: {
updateData()
})
if FeatureFlags.skipToScrollable {
SubmitButtonWithAction(
nextView: .pdfs,
onButtonTap: {
updateData()
},
accessibilityIdentifier: "Next"
)
} else {
SubmitButtonWithAction(
nextView: .medical,
onButtonTap: {
updateData()
},
accessibilityIdentifier: "Next"
)

Check warning on line 136 in Intake/General Data View/PatientInfo.swift

View check run for this annotation

Codecov / codecov/patch

Intake/General Data View/PatientInfo.swift#L130-L136

Added lines #L130 - L136 were not covered by tests
}
}
.task {
loadData()
Expand Down
4 changes: 2 additions & 2 deletions Intake/Home.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ struct StartButton: View {
.padding()
.background(Color.blue)
.cornerRadius(10)
}
}.accessibilityIdentifier("Create New Form")
}
}

Expand Down Expand Up @@ -114,7 +114,7 @@ struct SettingsButton: View {
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
.foregroundColor(.blue)
.accessibilityLabel(Text("SETTINGS"))
.accessibilityLabel("SETTINGS")
}
)
}
Expand Down
1 change: 0 additions & 1 deletion Intake/IntakeTestingSetup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ private struct IntakeAppTestingSetup: ViewModifier {
}
}
}

extension View {
func testingSetup() -> some View {
self.modifier(IntakeAppTestingSetup())
Expand Down
17 changes: 17 additions & 0 deletions Intake/Resources/Documentation.docc/Documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2023 Stanford University
//
// SPDX-License-Identifier: MIT

# ``Intake``

<!--@START_MENU_TOKEN@-->Summary<!--@END_MENU_TOKEN@-->

## Overview

<!--@START_MENU_TOKEN@-->Text<!--@END_MENU_TOKEN@-->

## Topics

### <!--@START_MENU_TOKEN@-->Group<!--@END_MENU_TOKEN@-->

- <!--@START_MENU_TOKEN@-->``Symbol``<!--@END_MENU_TOKEN@-->
75 changes: 75 additions & 0 deletions IntakeUITests/NinasTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// This source file is part of the Intake based on the Stanford Spezi Template Application project
//
// SPDX-FileCopyrightText: 2023 Stanford University
//
// SPDX-License-Identifier: MIT
//

// I test the following:
// 1. If a patient is connected with healthkit, does the information in the PatientInfo view show up?
// 2. If a patient is not connected with healthkit and fills in their information manually, does the information in the PatientInfo view show up?
// 3. Does the data in each case persist to scrollableView?

import XCTest

final class NinasTests: XCTestCase {
override func setUpWithError() throws {
continueAfterFailure = false
}

override func tearDownWithError() throws {
let app = XCUIApplication()
if app.buttons["Back"].exists {
app.buttons["Back"].tap()
}
try super.tearDownWithError()
}

func testIfHealthKitDataInScrollable() throws {
let app = XCUIApplication()
app.launchArguments = ["--disableFirebase", "--skipOnboarding", "--testPatient", "--skipToScrollable"]
app.launch()
sleep(1)
let startButton = app.buttons["Create New Form"]
let isStartButtonExist = startButton.waitForExistence(timeout: 5)
if isStartButtonExist {
startButton.tap()
}
let next = app.buttons["Next"]
next.tap()
XCTAssertTrue(app.staticTexts["Gonzalo Alejandro Dueñas"].waitForExistence(timeout: 5))
XCTAssertTrue(app.staticTexts["1958-02-06"].waitForExistence(timeout: 5))
XCTAssertTrue(app.staticTexts["66"].waitForExistence(timeout: 5))
XCTAssertTrue(app.staticTexts["Male"].waitForExistence(timeout: 5))
}

func testIfCustomDataInScrollable() throws {
let app = XCUIApplication()
app.launchArguments = ["--disableFirebase", "--skipOnboarding", "--skipToScrollable"]
app.launch()
sleep(1)
let startButton = app.buttons["Create New Form"]
let isStartButtonExist = startButton.waitForExistence(timeout: 5)
if isStartButtonExist {
startButton.tap()
}
let nameTextField = app.textFields["Full name"]
let dobDatePicker = app.datePickers.firstMatch
let sexPicker = app.buttons["Sex, Female"]
let next = app.buttons["Next"]
nameTextField.tap()
nameTextField.typeText("John Doe")
dobDatePicker.tap()
sleep(1)
dobDatePicker.tap()
nameTextField.tap()
sexPicker.tap()
sleep(1)
app.buttons["Male"].tap()
next.tap()

XCTAssertTrue(app.staticTexts["John Doe"].waitForExistence(timeout: 5))
XCTAssertTrue(app.staticTexts["Male"].waitForExistence(timeout: 5))
}
}
Loading