diff --git a/Packages/Persistence/Tests/Utils/Methods/WithDatabase.swift b/Packages/Persistence/Tests/Utils/Methods/WithDatabase.swift index 435d334..1496bdb 100644 --- a/Packages/Persistence/Tests/Utils/Methods/WithDatabase.swift +++ b/Packages/Persistence/Tests/Utils/Methods/WithDatabase.swift @@ -12,16 +12,12 @@ func withDatabase( logger: Logger(label: "test") )() - do { - await PrepareDB()(for: fluent) - - try await fluent.migrate() - try await body(fluent) - } catch { + defer { try? await fluent.shutdown() - - throw error } - try await fluent.shutdown() + await PrepareDB()(for: fluent) + + try await fluent.migrate() + try await body(fluent) } diff --git a/Services/Website/Sources/Library/Internal/Extensions/Listing+Display.swift b/Services/Website/Sources/Library/Internal/Extensions/Listing+Display.swift index b26dbbc..aae3306 100644 --- a/Services/Website/Sources/Library/Internal/Extensions/Listing+Display.swift +++ b/Services/Website/Sources/Library/Internal/Extensions/Listing+Display.swift @@ -18,7 +18,7 @@ extension Listing { } return ( - "\(grader) \(grade.gradeLabel)", + "\(grader) \(grade.oneDecimal)", grade >= 9 ? .good : grade < 7 ? .warn : .neutral, true ) @@ -72,7 +72,7 @@ extension Shop { /// The shop's standing in a line: where it is, since when, and how it is rated. var standing: String { - "\(location) · selling on CCN since \(sinceYear) · \(rating.formatted(.number.precision(.fractionLength(1)).locale(.init(identifier: "en")))) from \(ratedSales) rated sales" + "\(location) · selling on CCN since \(sinceYear) · \(rating.oneDecimal) from \(ratedSales) rated sales" } } @@ -81,8 +81,8 @@ extension Double { // MARK: Computed - /// The grade to one decimal place, e.g. `9.8`. - var gradeLabel: String { + /// The number to one decimal place, e.g. `9.8`. + var oneDecimal: String { formatted(.number.precision(.fractionLength(1)).locale(.init(identifier: "en"))) } diff --git a/Services/Website/Sources/Library/Internal/Pages/ComparePage.swift b/Services/Website/Sources/Library/Internal/Pages/ComparePage.swift index b6fae8d..b5016e2 100644 --- a/Services/Website/Sources/Library/Internal/Pages/ComparePage.swift +++ b/Services/Website/Sources/Library/Internal/Pages/ComparePage.swift @@ -179,7 +179,7 @@ private extension ComparePage { of copy: Listing ) -> [(term: String, value: String)] { let customs = copy.shop.shipsFromEU ? "" : " · customs may apply" - let rating = copy.shop.rating.formatted(.number.precision(.fractionLength(1)).locale(.init(identifier: "en"))) + let rating = copy.shop.rating.oneDecimal return [ ("Asking", copy.priceCents.euros + (copy.acceptsOffers ? " · accepts offers" : "")), diff --git a/Services/Website/Sources/Library/Internal/Pages/GradingGuidePage.swift b/Services/Website/Sources/Library/Internal/Pages/GradingGuidePage.swift index deb6db7..ee57946 100644 --- a/Services/Website/Sources/Library/Internal/Pages/GradingGuidePage.swift +++ b/Services/Website/Sources/Library/Internal/Pages/GradingGuidePage.swift @@ -66,7 +66,7 @@ extension GradingGuidePage: Page { ForEach(Grading.scale) { step in li(.class("guide__grade")) { strong { - step.grade.gradeLabel + step.grade.oneDecimal } span { step.code @@ -83,7 +83,7 @@ extension GradingGuidePage: Page { li(.class("card guide__reference")) { div(.class("guide__reference-grade")) { span(.class("type-stat")) { - reference.grade.gradeLabel + reference.grade.oneDecimal } span(.class("type-label")) { reference.name @@ -94,7 +94,7 @@ extension GradingGuidePage: Page { .class("guide__photo"), .custom(name: "aria-hidden", value: "true") ) { - "Photo: \(reference.grade.gradeLabel) example" + "Photo: \(reference.grade.oneDecimal) example" } div { h3(.class("type-eyebrow guide__allowed")) { diff --git a/Services/Website/Sources/Library/Internal/Pages/NewListingPage.swift b/Services/Website/Sources/Library/Internal/Pages/NewListingPage.swift index e82d366..0d08a63 100644 --- a/Services/Website/Sources/Library/Internal/Pages/NewListingPage.swift +++ b/Services/Website/Sources/Library/Internal/Pages/NewListingPage.swift @@ -213,7 +213,7 @@ private extension NewListingPage { mode(.raw, "Raw (seller-graded)", "You grade it against the guide and declare every defect.") } div(.class("listing-form__grid")) { - select(.grade, "Grade", options: [("", "Pick a grade")] + Grading.scale.map { ($0.grade.gradeLabel, "\($0.grade.gradeLabel) · \($0.code)") }) + select(.grade, "Grade", options: [("", "Pick a grade")] + Grading.scale.map { ($0.grade.oneDecimal, "\($0.grade.oneDecimal) · \($0.code)") }) select(.grader, "Grader", options: [("", "—")] + Grading.graders.map { ($0, $0) }, scope: "slabbed") select(.pageQuality, "Page quality", options: [("", "Not stated")] + Grading.pageQualities.map { ($0, $0) }, scope: "slabbed") text(.cert, "Cert number", placeholder: "4312087-002", scope: "slabbed") diff --git a/Services/Website/Sources/Library/Internal/Pages/SellerDashboardPage.swift b/Services/Website/Sources/Library/Internal/Pages/SellerDashboardPage.swift index 35c7422..e2394ae 100644 --- a/Services/Website/Sources/Library/Internal/Pages/SellerDashboardPage.swift +++ b/Services/Website/Sources/Library/Internal/Pages/SellerDashboardPage.swift @@ -112,7 +112,7 @@ extension SellerDashboardPage: Page { tile("\(offers.count)", "Open offers", offers.first.map { "next: \($0.expiresAt.countdown(from: now))" }) tile("\(viewer?.unreadMessages ?? 0)", "Unread conversations", nil) tile("\(sales.count)", "Sales", "\(sales.count { $0.next == .sent }) awaiting your dispatch") - tile(shop.rating.formatted(.number.precision(.fractionLength(1)).locale(.init(identifier: "en"))), "Rating", "\(shop.ratedSales) rated sales") + tile(shop.rating.oneDecimal, "Rating", "\(shop.ratedSales) rated sales") } section(.class("card sell__panel")) { div(.class("section-head")) { diff --git a/Services/Website/Sources/Library/Internal/Pages/WantsPage.swift b/Services/Website/Sources/Library/Internal/Pages/WantsPage.swift index 5b88759..e55b6d6 100644 --- a/Services/Website/Sources/Library/Internal/Pages/WantsPage.swift +++ b/Services/Website/Sources/Library/Internal/Pages/WantsPage.swift @@ -219,8 +219,8 @@ private extension WantsPage { SelectField( name: "min-grade", title: "Lowest grade", - options: [("", "Any grade")] + Grading.scale.map { ($0.grade.gradeLabel, "\($0.grade.gradeLabel) · \($0.code)") }, - selected: draft.minGrade?.gradeLabel ?? "" + options: [("", "Any grade")] + Grading.scale.map { ($0.grade.oneDecimal, "\($0.grade.oneDecimal) · \($0.code)") }, + selected: draft.minGrade?.oneDecimal ?? "" ) TextField( name: "max-price", @@ -260,7 +260,7 @@ private extension WantsPage { ) -> String { [ want.slabbedOnly ? "slabbed only" : nil, - want.minGrade.map { "grade ≥ \($0.gradeLabel)" }, + want.minGrade.map { "grade ≥ \($0.oneDecimal)" }, want.maxPriceCents.map { "max \($0.euros)" }, "ships from EU only", ] @@ -275,7 +275,7 @@ private extension WantsPage { var parameters = SearchParameters().setting(.query, to: want.title.replacingOccurrences(of: "·", with: " ")) if let minGrade = want.minGrade { - parameters = parameters.setting(.gradeMin, to: minGrade.gradeLabel) + parameters = parameters.setting(.gradeMin, to: minGrade.oneDecimal) } if let maxPriceCents = want.maxPriceCents { diff --git a/Services/Website/Sources/Library/Internal/Types/ListingForm.swift b/Services/Website/Sources/Library/Internal/Types/ListingForm.swift index 0e689df..c89284a 100644 --- a/Services/Website/Sources/Library/Internal/Types/ListingForm.swift +++ b/Services/Website/Sources/Library/Internal/Types/ListingForm.swift @@ -190,7 +190,7 @@ extension ListingForm { if defects.contains(.caseScuffs) { problems[.defects] = "Case scuffs are for slabs; this copy is raw." } else if defects.contains(.crease), let grade, grade > Grading.creaseCap { - problems[.defects] = "A colour-breaking crease caps a raw book at \(Grading.creaseCap.gradeLabel). Lower the grade, or untick the crease." + problems[.defects] = "A colour-breaking crease caps a raw book at \(Grading.creaseCap.oneDecimal). Lower the grade, or untick the crease." } } } else { diff --git a/Services/Website/Sources/Library/Internal/Types/SearchParameters.swift b/Services/Website/Sources/Library/Internal/Types/SearchParameters.swift index 1a5c832..5521c0e 100644 --- a/Services/Website/Sources/Library/Internal/Types/SearchParameters.swift +++ b/Services/Website/Sources/Library/Internal/Types/SearchParameters.swift @@ -125,7 +125,7 @@ extension SearchParameters { if filter.gradeMin != nil || filter.gradeMax != nil { pills.append(.init( - label: "Grade \((filter.gradeMin ?? 0.5).gradeLabel)–\((filter.gradeMax ?? 10).gradeLabel)", + label: "Grade \((filter.gradeMin ?? 0.5).oneDecimal)–\((filter.gradeMax ?? 10).oneDecimal)", removed: removing(.gradeMin).removing(.gradeMax) )) } diff --git a/Services/Website/Tests/Library/Cases/Internal/Pages/SellingPagesTests.swift b/Services/Website/Tests/Library/Cases/Internal/Pages/SellingPagesTests.swift index 40bdc89..13e801c 100644 --- a/Services/Website/Tests/Library/Cases/Internal/Pages/SellingPagesTests.swift +++ b/Services/Website/Tests/Library/Cases/Internal/Pages/SellingPagesTests.swift @@ -18,7 +18,7 @@ struct SellingPagesTests { let html = GradingGuidePage().render() for step in Grading.scale { - #expect(html.contains("\(step.grade.gradeLabel)\(step.code)")) + #expect(html.contains("\(step.grade.oneDecimal)\(step.code)")) } for defect in Grading.Defect.allCases { diff --git a/Services/Website/Tests/Library/Cases/Public/Controllers/AccountAndCollectingControllerTests.swift b/Services/Website/Tests/Library/Cases/Public/Controllers/AccountAndCollectingControllerTests.swift index 7e2f9c6..d272251 100644 --- a/Services/Website/Tests/Library/Cases/Public/Controllers/AccountAndCollectingControllerTests.swift +++ b/Services/Website/Tests/Library/Cases/Public/Controllers/AccountAndCollectingControllerTests.swift @@ -256,30 +256,26 @@ private extension AccountAndCollectingControllerTests { logger: Logger(label: "test") )() - do { - await PrepareDB()(for: fluent) - - try await fluent.migrate() - - let accounts = AccountRepository(fluent: fluent) - let catalogue = CatalogueRepository(fluent: fluent) - let collecting = CollectingRepository(fluent: fluent, now: now) - let sessions = SessionStore(trade: .init(fluent: fluent), collecting: collecting) - let router = Router(context: WebsiteRequestContext.self) - - router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions, collecting: collecting).routes) - router.addRoutes(SessionController(sessions: sessions, accounts: accounts, catalogue: catalogue).routes) - router.addRoutes(AccountController(accounts: accounts, catalogue: catalogue, sessions: sessions).routes) - router.addRoutes(CollectingController(collecting: collecting, catalogue: catalogue, sessions: sessions).routes) - - try await Application(router: router).test(.router, body) - } catch { + defer { try? await fluent.shutdown() - - throw error } - try await fluent.shutdown() + await PrepareDB()(for: fluent) + + try await fluent.migrate() + + let accounts = AccountRepository(fluent: fluent) + let catalogue = CatalogueRepository(fluent: fluent) + let collecting = CollectingRepository(fluent: fluent, now: now) + let sessions = SessionStore(trade: .init(fluent: fluent), collecting: collecting) + let router = Router(context: WebsiteRequestContext.self) + + router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions, collecting: collecting).routes) + router.addRoutes(SessionController(sessions: sessions, accounts: accounts, catalogue: catalogue).routes) + router.addRoutes(AccountController(accounts: accounts, catalogue: catalogue, sessions: sessions).routes) + router.addRoutes(CollectingController(collecting: collecting, catalogue: catalogue, sessions: sessions).routes) + + try await Application(router: router).test(.router, body) } } diff --git a/Services/Website/Tests/Library/Cases/Public/Controllers/CatalogueControllerTests.swift b/Services/Website/Tests/Library/Cases/Public/Controllers/CatalogueControllerTests.swift index a08be30..1e6c7d3 100644 --- a/Services/Website/Tests/Library/Cases/Public/Controllers/CatalogueControllerTests.swift +++ b/Services/Website/Tests/Library/Cases/Public/Controllers/CatalogueControllerTests.swift @@ -110,23 +110,19 @@ private extension CatalogueControllerTests { logger: Logger(label: "test") )() - do { - await PrepareDB()(for: fluent) - - try await fluent.migrate() - - let router = Router(context: WebsiteRequestContext.self) - - router.addRoutes(CatalogueController(repository: .init(fluent: fluent)).routes) - - try await Application(router: router).test(.router, body) - } catch { + defer { try? await fluent.shutdown() - - throw error } - try await fluent.shutdown() + await PrepareDB()(for: fluent) + + try await fluent.migrate() + + let router = Router(context: WebsiteRequestContext.self) + + router.addRoutes(CatalogueController(repository: .init(fluent: fluent)).routes) + + try await Application(router: router).test(.router, body) } } diff --git a/Services/Website/Tests/Library/Cases/Public/Controllers/ListingFormControllerTests.swift b/Services/Website/Tests/Library/Cases/Public/Controllers/ListingFormControllerTests.swift index c71b875..f5d186b 100644 --- a/Services/Website/Tests/Library/Cases/Public/Controllers/ListingFormControllerTests.swift +++ b/Services/Website/Tests/Library/Cases/Public/Controllers/ListingFormControllerTests.swift @@ -204,35 +204,31 @@ private extension ListingFormControllerTests { logger: Logger(label: "test") )() - do { - await PrepareDB()(for: fluent) - - try await fluent.migrate() - - let catalogue = CatalogueRepository(fluent: fluent) - let trade = TradeRepository(fluent: fluent) - let sessions = SessionStore(trade: trade) - let router = Router(context: WebsiteRequestContext.self) - - router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions).routes) - router.addRoutes(SessionController(sessions: sessions, accounts: .init(fluent: fluent), catalogue: catalogue).routes) - router.addRoutes(ListingFormController( - catalogue: catalogue, - trade: trade, - sessions: sessions, - photos: .init(staticFilesPath: folder) - ).routes) - - try await Application(router: router).test(.router) { client in - try await body(client, folder) - } - } catch { + defer { try? await fluent.shutdown() - - throw error } - try await fluent.shutdown() + await PrepareDB()(for: fluent) + + try await fluent.migrate() + + let catalogue = CatalogueRepository(fluent: fluent) + let trade = TradeRepository(fluent: fluent) + let sessions = SessionStore(trade: trade) + let router = Router(context: WebsiteRequestContext.self) + + router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions).routes) + router.addRoutes(SessionController(sessions: sessions, accounts: .init(fluent: fluent), catalogue: catalogue).routes) + router.addRoutes(ListingFormController( + catalogue: catalogue, + trade: trade, + sessions: sessions, + photos: .init(staticFilesPath: folder) + ).routes) + + try await Application(router: router).test(.router) { client in + try await body(client, folder) + } } } diff --git a/Services/Website/Tests/Library/Cases/Public/Controllers/PasskeyControllerTests.swift b/Services/Website/Tests/Library/Cases/Public/Controllers/PasskeyControllerTests.swift index ce65f4b..1060b3a 100644 --- a/Services/Website/Tests/Library/Cases/Public/Controllers/PasskeyControllerTests.swift +++ b/Services/Website/Tests/Library/Cases/Public/Controllers/PasskeyControllerTests.swift @@ -156,27 +156,23 @@ private extension PasskeyControllerTests { logger: Logger(label: "test") )() - do { - await PrepareDB()(for: fluent) - - try await fluent.migrate() - - let router = Router(context: WebsiteRequestContext.self) - - router.addRoutes(PasskeyController( - origin: "http://localhost:8080", - accounts: .init(fluent: fluent), - sessions: .init() - ).routes) - - try await Application(router: router).test(.router, body) - } catch { + defer { try? await fluent.shutdown() - - throw error } - try await fluent.shutdown() + await PrepareDB()(for: fluent) + + try await fluent.migrate() + + let router = Router(context: WebsiteRequestContext.self) + + router.addRoutes(PasskeyController( + origin: "http://localhost:8080", + accounts: .init(fluent: fluent), + sessions: .init() + ).routes) + + try await Application(router: router).test(.router, body) } } diff --git a/Services/Website/Tests/Library/Cases/Public/Controllers/SessionControllerTests.swift b/Services/Website/Tests/Library/Cases/Public/Controllers/SessionControllerTests.swift index 6056aab..dbad0b2 100644 --- a/Services/Website/Tests/Library/Cases/Public/Controllers/SessionControllerTests.swift +++ b/Services/Website/Tests/Library/Cases/Public/Controllers/SessionControllerTests.swift @@ -203,31 +203,27 @@ private extension SessionControllerTests { logger: Logger(label: "test") )() - do { - await PrepareDB()(for: fluent) - - try await fluent.migrate() - - let catalogue = CatalogueRepository(fluent: fluent) - let router = Router(context: WebsiteRequestContext.self) - let sessions = SessionStore() - - router.addRoutes(RootController(sessions: sessions).routes) - router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions).routes) - router.addRoutes(SessionController( - sessions: sessions, - accounts: .init(fluent: fluent), - catalogue: catalogue - ).routes) - - try await Application(router: router).test(.router, body) - } catch { + defer { try? await fluent.shutdown() - - throw error } - try await fluent.shutdown() + await PrepareDB()(for: fluent) + + try await fluent.migrate() + + let catalogue = CatalogueRepository(fluent: fluent) + let router = Router(context: WebsiteRequestContext.self) + let sessions = SessionStore() + + router.addRoutes(RootController(sessions: sessions).routes) + router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions).routes) + router.addRoutes(SessionController( + sessions: sessions, + accounts: .init(fluent: fluent), + catalogue: catalogue + ).routes) + + try await Application(router: router).test(.router, body) } } diff --git a/Services/Website/Tests/Library/Cases/Public/Controllers/TradeControllerTests.swift b/Services/Website/Tests/Library/Cases/Public/Controllers/TradeControllerTests.swift index 2f071df..d069a2f 100644 --- a/Services/Website/Tests/Library/Cases/Public/Controllers/TradeControllerTests.swift +++ b/Services/Website/Tests/Library/Cases/Public/Controllers/TradeControllerTests.swift @@ -320,28 +320,24 @@ private extension TradeControllerTests { logger: Logger(label: "test") )() - do { - await PrepareDB()(for: fluent) - - try await fluent.migrate() - - let catalogue = CatalogueRepository(fluent: fluent) - let trade = TradeRepository(fluent: fluent) - let sessions = SessionStore(trade: trade) - let router = Router(context: WebsiteRequestContext.self) - - router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions).routes) - router.addRoutes(SessionController(sessions: sessions, accounts: .init(fluent: fluent), catalogue: catalogue).routes) - router.addRoutes(TradeController(trade: trade, catalogue: catalogue, sessions: sessions).routes) - - try await Application(router: router).test(.router, body) - } catch { + defer { try? await fluent.shutdown() - - throw error } - try await fluent.shutdown() + await PrepareDB()(for: fluent) + + try await fluent.migrate() + + let catalogue = CatalogueRepository(fluent: fluent) + let trade = TradeRepository(fluent: fluent) + let sessions = SessionStore(trade: trade) + let router = Router(context: WebsiteRequestContext.self) + + router.addRoutes(CatalogueController(repository: catalogue, sessions: sessions).routes) + router.addRoutes(SessionController(sessions: sessions, accounts: .init(fluent: fluent), catalogue: catalogue).routes) + router.addRoutes(TradeController(trade: trade, catalogue: catalogue, sessions: sessions).routes) + + try await Application(router: router).test(.router, body) } }