From 66074d66f4a05c2497eba1d11f4b36f2ff2bc705 Mon Sep 17 00:00:00 2001 From: Michael Housh Date: Tue, 21 Jan 2025 16:00:16 -0500 Subject: [PATCH] feat: Refactoring routes to use shared / base routes. --- Sources/App/Controllers/ApiController.swift | 30 +- Sources/App/Controllers/ViewController.swift | 26 ++ .../App/Extensions/Request+extensions.swift | 14 - Sources/SharedModels/Routes/ApiRoute.swift | 208 +------------ Sources/SharedModels/Routes/BaseRoutes.swift | 294 ++++++++++++++++++ Tests/AppTests/ViewSnapshotTests.swift | 91 ++++++ .../testVendorBranchViews.1.html | 1 + .../testVendorBranchViews.2.html | 1 + .../testVendorBranchViews.3.html | 1 + .../testVendorBranchViews.4.html | 1 + .../ViewSnapshotTests/testVendorViews.1.html | 1 + .../ViewSnapshotTests/testVendorViews.2.html | 1 + .../ViewSnapshotTests/testVendorViews.3.html | 1 + .../ViewSnapshotTests/testVendorViews.4.html | 1 + .../ViewSnapshotTests/testVendorViews.5.html | 1 + 15 files changed, 445 insertions(+), 227 deletions(-) create mode 100644 Sources/SharedModels/Routes/BaseRoutes.swift create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.1.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.2.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.3.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.4.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.1.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.2.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.3.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.4.html create mode 100644 Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.5.html diff --git a/Sources/App/Controllers/ApiController.swift b/Sources/App/Controllers/ApiController.swift index 1d4f2ab..35d10e1 100644 --- a/Sources/App/Controllers/ApiController.swift +++ b/Sources/App/Controllers/ApiController.swift @@ -16,22 +16,22 @@ extension ApiRoute { func handle(request: Request) async throws -> any AsyncResponseEncodable { switch self { case let .employee(route): - return try await route.handle(request: request) + return try await route.handleApiRequest(request: request) case let .purchaseOrder(route): - return try await route.handle(request: request) + return try await route.handleApiRequest(request: request) case let .user(route): - return try await route.handle(request: request) + return try await route.handleApiRequest(request: request) case let .vendor(route): - return try await route.handle(request: request) + return try await route.handleApiRequest(request: request) case let .vendorBranch(route): - return try await route.handle(request: request) + return try await route.handleApiRequest(request: request) } } } -extension ApiRoute.EmployeeApiRoute { +extension BaseRoute.EmployeeRoute { - func handle(request: Request) async throws -> any AsyncResponseEncodable { + func handleApiRequest(request: Request) async throws -> any AsyncResponseEncodable { @Dependency(\.database) var database switch self { case let .create(employee): @@ -52,9 +52,9 @@ extension ApiRoute.EmployeeApiRoute { } } -extension ApiRoute.PurchaseOrderApiRoute { +extension BaseRoute.PurchaseOrderRoute { - func handle(request: Request) async throws -> any AsyncResponseEncodable { + func handleApiRequest(request: Request) async throws -> any AsyncResponseEncodable { @Dependency(\.database.purchaseOrders) var purchaseOrders switch self { case .index: @@ -76,9 +76,9 @@ extension ApiRoute.PurchaseOrderApiRoute { } // TODO: Add Login. -extension ApiRoute.UserApiRoute { +extension BaseRoute.UserRoute { - func handle(request: Request) async throws -> any AsyncResponseEncodable { + func handleApiRequest(request: Request) async throws -> any AsyncResponseEncodable { @Dependency(\.database.users) var users switch self { case let .create(user): @@ -101,8 +101,8 @@ extension ApiRoute.UserApiRoute { } } -extension ApiRoute.VendorApiRoute { - func handle(request: Request) async throws -> any AsyncResponseEncodable { +extension BaseRoute.VendorRoute { + func handleApiRequest(request: Request) async throws -> any AsyncResponseEncodable { @Dependency(\.database.vendors) var vendors switch self { case let .create(vendor): @@ -126,8 +126,8 @@ extension ApiRoute.VendorApiRoute { } } -extension ApiRoute.VendorBranchApiRoute { - func handle(request: Request) async throws -> any AsyncResponseEncodable { +extension BaseRoute.VendorBranchRoute { + func handleApiRequest(request: Request) async throws -> any AsyncResponseEncodable { @Dependency(\.database.vendorBranches) var vendorBranches switch self { case let .create(branch): diff --git a/Sources/App/Controllers/ViewController.swift b/Sources/App/Controllers/ViewController.swift index 54cbc75..b0c01a4 100644 --- a/Sources/App/Controllers/ViewController.swift +++ b/Sources/App/Controllers/ViewController.swift @@ -12,6 +12,7 @@ private let viewProtectedMiddleware: [any Middleware] = [ } ] +// TODO: Return `any HTML` instead to make testing the rendered documents easier. extension SharedModels.ViewRoute { var middleware: [any Middleware]? { @@ -348,6 +349,31 @@ extension SharedModels.ViewRoute.VendorBranchRoute { var middleware: [any Middleware]? { viewProtectedMiddleware } + // func html() async throws -> any HTML { + // @Dependency(\.database) var database + // + // switch self { + // case let .index(for: vendorID): + // guard let vendorID else { + // throw Abort(.badRequest, reason: "Vendor id not supplied") + // } + // return try await VendorBranchList( + // vendorID: vendorID, + // branches: database.vendorBranches.fetchAll(.for(vendorID: vendorID)) + // ) + // + // case let .select(context: context): + // return try await context.toHTML(branches: database.vendorBranches.fetchAllWithDetail()) + // + // case let .create(branch): + // return try await VendorBranchList.Row(branch: database.vendorBranches.create(branch)) + // + // case let .delete(id: id): + // try await database.vendorBranches.delete(id) + // return HTTPStatus.ok + // } + // } + func handle(request: Request) async throws -> any AsyncResponseEncodable { @Dependency(\.database) var database diff --git a/Sources/App/Extensions/Request+extensions.swift b/Sources/App/Extensions/Request+extensions.swift index ad805d7..261ba1e 100644 --- a/Sources/App/Extensions/Request+extensions.swift +++ b/Sources/App/Extensions/Request+extensions.swift @@ -4,20 +4,6 @@ import Vapor import VaporElementary extension Request { - func ensureValidContent(_ decoding: T.Type) throws -> T where T: Content, T: Validatable { - try T.validate(content: self) - return try content.decode(T.self) - } - - func ensureIDPathComponent( - as decoding: T.Type = UUID.self, - key: String = "id" - ) throws -> T { - guard let id = parameters.get(key, as: T.self) else { - throw Abort(.badRequest, reason: "Id not supplied.") - } - return id - } var isHtmxRequest: Bool { headers.contains(name: "hx-request") diff --git a/Sources/SharedModels/Routes/ApiRoute.swift b/Sources/SharedModels/Routes/ApiRoute.swift index e7f0602..42e937a 100644 --- a/Sources/SharedModels/Routes/ApiRoute.swift +++ b/Sources/SharedModels/Routes/ApiRoute.swift @@ -4,222 +4,34 @@ import Foundation public enum ApiRoute: Sendable, Equatable { - case employee(EmployeeApiRoute) - case purchaseOrder(PurchaseOrderApiRoute) - case user(UserApiRoute) - case vendor(VendorApiRoute) - case vendorBranch(VendorBranchApiRoute) + case employee(BaseRoute.EmployeeRoute) + case purchaseOrder(BaseRoute.PurchaseOrderRoute) + case user(BaseRoute.UserRoute) + case vendor(BaseRoute.VendorRoute) + case vendorBranch(BaseRoute.VendorBranchRoute) static let rootPath = Path { "api"; "v1" } public static let router = OneOf { Route(.case(Self.employee)) { rootPath - EmployeeApiRoute.router + BaseRoute.EmployeeRoute.router } Route(.case(Self.purchaseOrder)) { rootPath - PurchaseOrderApiRoute.router + BaseRoute.PurchaseOrderRoute.router } Route(.case(Self.user)) { rootPath - UserApiRoute.router + BaseRoute.UserRoute.router } Route(.case(Self.vendor)) { rootPath - VendorApiRoute.router + BaseRoute.VendorRoute.router } Route(.case(Self.vendorBranch)) { rootPath - VendorBranchApiRoute.router - } - } - - public enum EmployeeApiRoute: Sendable, Equatable { - case create(Employee.Create) - case delete(id: Employee.ID) - case get(id: Employee.ID) - case index - case update(id: Employee.ID, updates: Employee.Update) - - static let rootPath = "employees" - - public static let router = OneOf { - Route(.case(Self.create)) { - Path { rootPath } - Method.post - Body(.json(Employee.Create.self)) - } - Route(.case(Self.index)) { - Path { rootPath } - Method.get - } - Route(.case(Self.delete(id:))) { - Path { rootPath; UUID.parser() } - Method.delete - } - Route(.case(Self.get(id:))) { - Path { rootPath; UUID.parser() } - Method.get - } - Route(.case(Self.update(id:updates:))) { - Path { rootPath; UUID.parser() } - Method.put - Body(.json(Employee.Update.self)) - } - } - } - - public enum PurchaseOrderApiRoute: Sendable, Equatable { - case create(PurchaseOrder.Create) - case delete(id: PurchaseOrder.ID) - case get(id: PurchaseOrder.ID) - case index - case page(page: Int, limit: Int) - - static let rootPath = "purchase-orders" - - public static let router = OneOf { - Route(.case(Self.create)) { - Path { rootPath } - Method.post - Body(.json(PurchaseOrder.Create.self)) - } - Route(.case(Self.delete(id:))) { - Path { rootPath; Digits() } - Method.delete - } - Route(.case(Self.get(id:))) { - Path { rootPath; Digits() } - Method.get - } - Route(.case(Self.index)) { - Path { rootPath } - Method.get - } - Route(.case(Self.page(page:limit:))) { - Path { rootPath; "next" } - Method.get - Query { - Field("page", default: 1) { Digits() } - Field("limit", default: 25) { Digits() } - } - } - } - } - - // TODO: Add login / logout. - public enum UserApiRoute: Sendable, Equatable { - case create(User.Create) - case delete(id: User.ID) - case get(id: User.ID) - case index - case update(id: User.ID, updates: User.Update) - - static let rootPath = "users" - - public static let router = OneOf { - Route(.case(Self.create)) { - Path { rootPath } - Method.post - Body(.json(User.Create.self)) - } - Route(.case(Self.delete(id:))) { - Path { rootPath; User.ID.parser() } - Method.delete - } - Route(.case(Self.get(id:))) { - Path { rootPath; User.ID.parser() } - Method.get - } - Route(.case(Self.index)) { - Path { rootPath } - Method.get - } - Route(.case(Self.update(id:updates:))) { - Path { rootPath; User.ID.parser() } - Method.patch - Body(.json(User.Update.self)) - } - } - } - - public enum VendorApiRoute: Sendable, Equatable { - case index(withBranches: Bool? = nil) - case create(Vendor.Create) - case delete(id: Vendor.ID) - case get(id: Vendor.ID) - case update(id: Vendor.ID, updates: Vendor.Update) - - static let rootPath = "vendors" - - public static let router = OneOf { - Route(.case(Self.create)) { - Path { rootPath } - Method.post - Body(.json(Vendor.Create.self)) - } - Route(.case(Self.delete(id:))) { - Path { rootPath; Vendor.ID.parser() } - Method.delete - } - Route(.case(Self.get(id:))) { - Path { rootPath; Vendor.ID.parser() } - Method.get - } - Route(.case(Self.index(withBranches:))) { - Path { rootPath } - Method.get - Query { - Optionally { - Field("branches", default: nil) { - Bool.parser() - } - } - } - } - Route(.case(Self.update(id:updates:))) { - Path { rootPath; Vendor.ID.parser() } - Method.put - Body(.json(Vendor.Update.self)) - } - } - } - - public enum VendorBranchApiRoute: Sendable, Equatable { - case create(VendorBranch.Create) - case delete(id: VendorBranch.ID) - case get(id: VendorBranch.ID) - case index(for: Vendor.ID? = nil) - case update(id: VendorBranch.ID, updates: VendorBranch.Update) - - public static let router = OneOf { - Route(.case(Self.create)) { - Path { "vendors"; "branches" } - Method.post - Body(.json(VendorBranch.Create.self)) - } - Route(.case(Self.delete(id:))) { - Path { "vendors"; "branches"; VendorBranch.ID.parser() } - Method.delete - } - - Route(.case(Self.get(id:))) { - Path { "vendors"; "branches"; VendorBranch.ID.parser() } - Method.get - } - Route(.case(Self.index(for:))) { - Path { "vendors"; "branches" } - Method.get - Query { - Optionally { Field("vendorID", default: nil) { VendorBranch.ID.parser() } } - } - } - Route(.case(Self.update(id:updates:))) { - Path { "vendors"; "branches"; VendorBranch.ID.parser() } - Method.put - Body(.json(VendorBranch.Update.self)) - } + BaseRoute.VendorBranchRoute.router } } } diff --git a/Sources/SharedModels/Routes/BaseRoutes.swift b/Sources/SharedModels/Routes/BaseRoutes.swift new file mode 100644 index 0000000..f92eb76 --- /dev/null +++ b/Sources/SharedModels/Routes/BaseRoutes.swift @@ -0,0 +1,294 @@ +import CasePathsCore +import Foundation +@preconcurrency import URLRouting + +public enum BaseRoute {} + +public extension BaseRoute { + + enum EmployeeRoute: Sendable, Equatable { + case create(Employee.Create) + case delete(id: Employee.ID) + case get(id: Employee.ID) + case index + case update(id: Employee.ID, updates: Employee.Update) + + static let rootPath = "employees" + + public static let router = OneOf { + Route(.case(Self.create)) { + Path { rootPath } + Method.post + OneOf { + Body(.json(Employee.Create.self)) + Body { + FormData { + Field("firstName", .string) + Field("lastName", .string) + Optionally { Field("active") { Bool.parser() } } + } + .map(.memberwise(Employee.Create.init)) + } + } + } + Route(.case(Self.index)) { + Path { rootPath } + Method.get + } + Route(.case(Self.delete(id:))) { + Path { rootPath; UUID.parser() } + Method.delete + } + Route(.case(Self.get(id:))) { + Path { rootPath; UUID.parser() } + Method.get + } + Route(.case(Self.update(id:updates:))) { + Path { rootPath; UUID.parser() } + Method.put + OneOf { + Body(.json(Employee.Update.self)) + Body { + FormData { + Optionally { Field("firstName") { CharacterSet.alphanumerics.map(.string) } } + Optionally { Field("lastName") { CharacterSet.alphanumerics.map(.string) } } + Optionally { Field("active") { Bool.parser() } } + } + .map(.memberwise(Employee.Update.init)) + } + } + } + } + } +} + +public extension BaseRoute { + enum PurchaseOrderRoute: Sendable, Equatable { + case create(PurchaseOrder.Create) + case delete(id: PurchaseOrder.ID) + case get(id: PurchaseOrder.ID) + case index + case page(page: Int, limit: Int) + + static let rootPath = "purchase-orders" + + public static let router = OneOf { + Route(.case(Self.create)) { + Path { rootPath } + Method.post + OneOf { + Body(.json(PurchaseOrder.Create.self)) + Body { + FormData { + Optionally { Field("id") { PurchaseOrder.ID.parser() } } + Optionally { Field("workOrder") { Int.parser() } } + Field("materials", .string) + Field("customer", .string) + Optionally { Field("truckStock") { Bool.parser() } } + Field("createdByID") { User.ID.parser() } + Field("createdForID") { Employee.ID.parser() } + Field("vendorBranchID") { VendorBranch.ID.parser() } + } + .map(.memberwise(PurchaseOrder.Create.init)) + } + } + } + Route(.case(Self.delete(id:))) { + Path { rootPath; Digits() } + Method.delete + } + Route(.case(Self.get(id:))) { + Path { rootPath; Digits() } + Method.get + } + Route(.case(Self.index)) { + Path { rootPath } + Method.get + } + Route(.case(Self.page(page:limit:))) { + Path { rootPath; "next" } + Method.get + Query { + Field("page", default: 1) { Digits() } + Field("limit", default: 25) { Digits() } + } + } + } + } +} + +public extension BaseRoute { + enum UserRoute: Sendable, Equatable { + case create(User.Create) + case delete(id: User.ID) + case get(id: User.ID) + case index + case update(id: User.ID, updates: User.Update) + + static let rootPath = "users" + + public static let router = OneOf { + Route(.case(Self.create)) { + Path { rootPath } + Method.post + OneOf { + Body(.json(User.Create.self)) + Body { + FormData { + Field("username", .string) + Field("email", .string) + Field("password", .string) + Field("confirmPassword", .string) + } + .map(.memberwise(User.Create.init)) + } + } + } + Route(.case(Self.delete(id:))) { + Path { rootPath; User.ID.parser() } + Method.delete + } + Route(.case(Self.get(id:))) { + Path { rootPath; User.ID.parser() } + Method.get + } + Route(.case(Self.index)) { + Path { rootPath } + Method.get + } + Route(.case(Self.update(id:updates:))) { + Path { rootPath; User.ID.parser() } + Method.patch + OneOf { + Body(.json(User.Update.self)) + Body { + FormData { + Optionally { Field("username") { + CharacterSet.alphanumerics.map(.string) + } + } + Optionally { Field("email", .string) } + } + .map(.memberwise(User.Update.init)) + } + } + } + } + } +} + +public extension BaseRoute { + enum VendorRoute: Sendable, Equatable { + case index(withBranches: Bool? = nil) + case create(Vendor.Create) + case delete(id: Vendor.ID) + case get(id: Vendor.ID) + case update(id: Vendor.ID, updates: Vendor.Update) + + static let rootPath = "vendors" + + public static let router = OneOf { + Route(.case(Self.create)) { + Path { rootPath } + Method.post + OneOf { + Body(.json(Vendor.Create.self)) + Body { + FormData { + Field("name", .string) + } + .map(.memberwise(Vendor.Create.init)) + } + } + } + Route(.case(Self.delete(id:))) { + Path { rootPath; Vendor.ID.parser() } + Method.delete + } + Route(.case(Self.get(id:))) { + Path { rootPath; Vendor.ID.parser() } + Method.get + } + Route(.case(Self.index(withBranches:))) { + Path { rootPath } + Method.get + Query { + Optionally { + Field("branches", default: nil) { + Bool.parser() + } + } + } + } + Route(.case(Self.update(id:updates:))) { + Path { rootPath; Vendor.ID.parser() } + Method.put + OneOf { + Body(.json(Vendor.Update.self)) + Body { + FormData { + Field("name", .string) + } + .map(.memberwise(Vendor.Update.init)) + } + } + } + } + } +} + +public extension BaseRoute { + enum VendorBranchRoute: Sendable, Equatable { + case create(VendorBranch.Create) + case delete(id: VendorBranch.ID) + case get(id: VendorBranch.ID) + case index(for: Vendor.ID? = nil) + case update(id: VendorBranch.ID, updates: VendorBranch.Update) + + public static let router = OneOf { + Route(.case(Self.create)) { + Path { "vendors"; "branches" } + Method.post + OneOf { + Body(.json(VendorBranch.Create.self)) + Body { + FormData { + Field("name", .string) + Field("vendorID") { Vendor.ID.parser() } + } + .map(.memberwise(VendorBranch.Create.init)) + } + } + } + Route(.case(Self.delete(id:))) { + Path { "vendors"; "branches"; VendorBranch.ID.parser() } + Method.delete + } + + Route(.case(Self.get(id:))) { + Path { "vendors"; "branches"; VendorBranch.ID.parser() } + Method.get + } + Route(.case(Self.index(for:))) { + Path { "vendors"; "branches" } + Method.get + Query { + Optionally { Field("vendorID", default: nil) { VendorBranch.ID.parser() } } + } + } + Route(.case(Self.update(id:updates:))) { + Path { "vendors"; "branches"; VendorBranch.ID.parser() } + Method.put + OneOf { + Body(.json(VendorBranch.Update.self)) + Body { + FormData { + Field("name", .string) + } + .map(.memberwise(VendorBranch.Update.init)) + } + } + } + } + } +} diff --git a/Tests/AppTests/ViewSnapshotTests.swift b/Tests/AppTests/ViewSnapshotTests.swift index 9e77736..bdfcd42 100644 --- a/Tests/AppTests/ViewSnapshotTests.swift +++ b/Tests/AppTests/ViewSnapshotTests.swift @@ -107,6 +107,66 @@ final class ViewSnapshotTests: XCTestCase { } } } + + 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 { @@ -137,6 +197,31 @@ extension DatabaseClient.Users { } } +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) @@ -214,6 +299,12 @@ extension Vendor.Create { } } +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) diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.1.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.1.html new file mode 100644 index 0000000..0deb531 --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.1.html @@ -0,0 +1 @@ +
  • Mock
\ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.2.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.2.html new file mode 100644 index 0000000..a384bfd --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.2.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.3.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.3.html new file mode 100644 index 0000000..f4496f8 --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.3.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.4.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.4.html new file mode 100644 index 0000000..72e7a3a --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorBranchViews.4.html @@ -0,0 +1 @@ +
  • Mock
  • \ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.1.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.1.html new file mode 100644 index 0000000..2d99558 --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.1.html @@ -0,0 +1 @@ +Purchase Orders

    Vendors


    Vendors are where purchase orders can be issued to.


    NameBranches
    Test(0) Branches
    \ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.2.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.2.html new file mode 100644 index 0000000..e7e2c3f --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.2.html @@ -0,0 +1 @@ +

    Branches

    NameBranches
    Test(0) Branches
    \ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.3.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.3.html new file mode 100644 index 0000000..870e4d4 --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.3.html @@ -0,0 +1 @@ +Purchase Orders

    Vendors


    Vendors are where purchase orders can be issued to.


    NameBranches
    Test(0) Branches
    \ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.4.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.4.html new file mode 100644 index 0000000..99883ed --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.4.html @@ -0,0 +1 @@ +Purchase Orders

    Vendors


    Vendors are where purchase orders can be issued to.


    Branches

    NameBranches
    Test(0) Branches
    \ No newline at end of file diff --git a/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.5.html b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.5.html new file mode 100644 index 0000000..f48c3e8 --- /dev/null +++ b/Tests/AppTests/__Snapshots__/ViewSnapshotTests/testVendorViews.5.html @@ -0,0 +1 @@ +

    Branches

    \ No newline at end of file