@testable import App import DatabaseClient import Dependencies import HtmlSnapshotTesting import SharedModels import SnapshotTesting import Vapor import XCTVapor final class ViewSnapshotTests: XCTestCase { var app: Application! let router = ViewRoute.router override func setUp() { app = Application(.testing) } override func invokeTest() { withSnapshotTesting(record: .missing) { super.invokeTest() } } override func tearDown() { app.shutdown() } func testEmployeeViews() async throws { try await withDependencies { $0.database.employees = .mock } operation: { @Dependency(\.database) var database try await configure(app, makeDatabaseClient: { _ in database }) try await app.test(.GET, router.path(for: .employee(.index))) { res in assertSnapshot(of: res.body.string, as: .html) } try await app.test(.GET, router.path(for: .employee(.form))) { res in assertSnapshot(of: res.body.string, as: .html) } for context in SharedModels.ViewRoute.SelectContext.allCases { try app.test(.GET, router.path(for: .employee(.select(context: context)))) { res in assertSnapshot(of: res.body.string, as: .html) } } try app.test(.GET, router.path(for: .employee(.get(id: UUID(0))))) { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.POST, router.path(for: .employee(.index)), beforeRequest: { req in req.body = ByteBuffer(string: "firstName=Testy&lastName=McTestface") }, afterResponse: { res in assertSnapshot(of: res.body.string, as: .html) }) try app.test(.PUT, router.path(for: .employee(.update(id: UUID(0), updates: .mock))), beforeRequest: { req in req.body = ByteBuffer(string: "firstName=Testy&lastName=McTestface") }, afterResponse: { res in assertSnapshot(of: res.body.string, as: .html) }) } } // TODO: These need to come after mocks are generated. // func testPurchaseOrderIndex() async throws { // try await configure(app) // try await app.test(.GET, router.path(for: .purchaseOrder(.index))) { res in // assertSnapshot(of: res.body.string, as: .html) // } // } func testUserViews() async throws { try await withDependencies { $0.database.users = .mock } operation: { @Dependency(\.database) var database try await configure(app, makeDatabaseClient: { _ in database }) try app.test(.GET, router.path(for: .user(.form))) { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.POST, router.path(for: .user(.index))) { req in req.body = ByteBuffer(string: "username=test&email=test@test.com&password=super-secret&confirmPassword=super-secret") } afterResponse: { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.GET, router.path(for: .user(.index))) { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.GET, router.path(for: .user(.get(id: UUID(0))))) { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.PATCH, router.path(for: .user(.update(id: UUID(0), updates: .mock)))) { req in req.body = .init(string: "username=test&email=test@test.com") } afterResponse: { res in assertSnapshot(of: res.body.string, as: .html) } } } func testVendorViews() async throws { try await withDependencies { $0.database.vendors = .mock } operation: { @Dependency(\.database) var database try await configure(app, makeDatabaseClient: { _ in database }) try app.test(.GET, router.path(for: .vendor(.form))) { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.POST, router.path(for: .vendor(.index))) { req in req.body = ByteBuffer(string: "name=Test") } afterResponse: { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.GET, router.path(for: .vendor(.index))) { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.GET, router.path(for: .vendor(.get(id: UUID(0))))) { res in assertSnapshot(of: res.body.string, as: .html) } try app.test(.PUT, router.path(for: .vendor(.update(id: UUID(0), updates: .mock)))) { req in req.body = .init(string: "name=Test") } afterResponse: { res in assertSnapshot(of: res.body.string, as: .html) } } } func testVendorBranchViews() async throws { try await withDependencies { $0.database.vendorBranches = .mock } operation: { @Dependency(\.database) var database try await configure(app, makeDatabaseClient: { _ in database }) try app.test(.GET, router.path(for: .vendorBranch(.index(for: UUID(0))))) { res in assertSnapshot(of: res.body.string, as: .html) } for context in SharedModels.ViewRoute.SelectContext.allCases { try app.test(.GET, router.path(for: .vendorBranch(.select(context: context)))) { res in assertSnapshot(of: res.body.string, as: .html) } } try app.test(.POST, router.path(for: .vendorBranch(.create(.mock)))) { req in req.body = .init(string: "name=Test&vendorID=\(UUID(0))") } afterResponse: { res in assertSnapshot(of: res.body.string, as: .html) } } } } extension DatabaseClient.Employees { static var mock: Self { .init( create: { _ in .mock }, delete: { _ in }, fetchAll: { _ in [Employee.mock] }, get: { _ in Employee.mock }, update: { _, _ in Employee.mock } ) } } extension DatabaseClient.Users { static var mock: Self { .init( count: { 1 }, create: { _ in User.mock }, delete: { _ in }, fetchAll: { [User.mock] }, get: { _ in User.mock }, login: { _ in User.Token.mock }, logout: { _ in }, token: { _ in User.Token.mock }, update: { _, _ in User.mock } ) } } extension DatabaseClient.Vendors { static var mock: Self { .init( create: { _ in Vendor.mock }, delete: { _ in }, fetchAll: { _ in [Vendor.mock] }, get: { _, _ in Vendor.mock }, update: { _, _, _ in Vendor.mock } ) } } extension DatabaseClient.VendorBranches { static var mock: Self { .init( create: { _ in VendorBranch.mock }, delete: { _ in }, fetchAll: { _ in [VendorBranch.mock] }, fetchAllWithDetail: { [VendorBranch.Detail.mock] }, get: { _ in VendorBranch.mock }, update: { _, _ in VendorBranch.mock } ) } } extension Date { static var mock: Self { Date(timeIntervalSince1970: 1_234_567_890) } } extension Employee { static var mock: Self { Employee( id: UUID(0), createdAt: Date(timeIntervalSince1970: 1_234_567_890), firstName: "Testy", lastName: "McTestface", updatedAt: Date(timeIntervalSince1970: 1_234_567_890) ) } } extension Employee.Create { static var mock: Self { .init(firstName: "Testy", lastName: "McTestface") } func employeeMock() -> Employee { @Dependency(\.date.now) var now return .init( id: UUID(0), createdAt: Date(timeIntervalSince1970: 1_234_567_890), firstName: firstName, lastName: lastName, updatedAt: Date(timeIntervalSince1970: 1_234_567_890) ) } } extension Employee.Update { static var mock: Self { .init(firstName: "Testy", lastName: "McTestface", active: false) } } extension User { static var mock: Self { .init(id: UUID(0), email: "test@example.com", username: "test") } } extension User.Create { static var mock: Self { .init(username: "test", email: "test@example.com", password: "super-secret", confirmPassword: "super-secret") } } extension User.Token { static var mock: Self { .init(id: UUID(1), userID: UUID(0), value: "test-token") } } extension User.Update { static var mock: Self { User.Update(username: "test", email: "test@test.com") } } extension Vendor { static var mock: Self { .init(id: UUID(0), name: "Test", branches: nil, createdAt: .mock, updatedAt: .mock) } } extension Vendor.Create { static var mock: Self { .init(name: "Test") } } extension Vendor.Update { static var mock: Self { .init(name: "Test") } } extension VendorBranch { static var mock: Self { .init(id: UUID(1), name: "Mock", vendorID: UUID(0), createdAt: .mock, updatedAt: .mock) } } extension VendorBranch.Create { static var mock: Self { .init(name: "Mock", vendorID: UUID(0)) } } extension VendorBranch.Detail { static var mock: Self { .init(id: UUID(1), name: "Mock", vendor: .mock, createdAt: .mock, updatedAt: .mock) } } extension PurchaseOrder { static var mock: Self { .init( id: 1, workOrder: 12245, materials: "foo", customer: "Testy McTestface", truckStock: true, createdBy: .mock, createdFor: .mock, vendorBranch: .mock, createdAt: .mock, updatedAt: .mock ) } }