Files
ccn/Services/Website/Tests/Library/Cases/Internal/Pages/TradePagesTests.swift
T

256 lines
11 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Elementary
import Foundation
import Persistence
import Testing
@testable import WebsiteLibrary
@Suite(
"Trade pages",
.tags(.page)
)
struct TradePagesTests {
// MARK: OfferPage tests
@Test
func `offer sheet fills in a tenth under asking and offers the picks the seller would hear`() {
let html = OfferPage(listing: .stub(), mode: .offer).render()
#expect(html.contains(#"action="/listing/nightward-1/offer" method="post""#))
#expect(html.contains(#"name="amount" value="216""#))
#expect(html.contains(#"href="/listing/nightward-1/offer?amount=216" aria-current="true">€216 · −10%"#))
#expect(html.contains("€192 · −20%"))
#expect(html.contains("auto-declines under <strong>€192</strong>"))
#expect(html.contains("+ €6 shipping to NL"))
#expect(html.contains(#"content="noindex""#))
}
@Test
func `offer sheet leaves out a pick under the seller's floor`() {
// €88 asking: the floor rounds up to €71, over the −20% pick of €70.
let html = OfferPage(listing: .stub(priceCents: 8_800), mode: .offer).render()
#expect(html.contains("€75 · −15%"))
#expect(!html.contains("−20%"))
}
@Test
func `offer sheet gives back what was typed, saying what went wrong`() {
let html = OfferPage(
listing: .stub(),
mode: .offer,
amountCents: 15_000,
note: "Bundle?",
error: TradeError.offerTooLow(floorCents: 19_200).explanation
).render()
#expect(html.contains(#"value="150""#))
#expect(html.contains(">Bundle?</textarea>"))
#expect(html.contains(#"role="alert">The seller auto-declines offers under €192."#))
}
@Test
func `buy sheet sums the asking price and the shipping`() {
let html = OfferPage(listing: .stub(), mode: .buy).render()
#expect(html.contains(#"action="/listing/nightward-1/buy" method="post""#))
#expect(html.contains("Agree to buy for €246"))
#expect(html.contains("CCN handles no money"))
#expect(!html.contains(#"name="amount""#))
}
// MARK: SalePage tests
@Test
func `sale record hands each party the step that is theirs`() {
func page(_ sale: Sale, _ role: Sale.Role) -> String {
SalePage(sale: sale, role: role, now: .stub).render()
}
#expect(page(.stub(), .buyer).contains(#"name="step" value="paid""#))
#expect(page(.stub(), .seller).contains("Waiting for the buyer to pay"))
#expect(page(.stub(paid: true), .seller).contains(#"name="step" value="sent""#))
#expect(page(.stub(paid: true), .buyer).contains("Waiting for the seller to dispatch"))
#expect(page(.stub(paid: true, sent: true), .buyer).contains(#"name="step" value="received""#))
#expect(page(.stub(paid: true, sent: true, received: true), .seller).contains(#"name="stars" value="5""#))
#expect(page(.stub(paid: true, sent: true, received: true, buyerRating: 5), .buyer).contains("Waiting for the other side"))
#expect(!page(.stub(paid: true, sent: true, received: true, buyerRating: 5, sellerRating: 4), .buyer).contains(#"name="step""#))
}
@Test
func `sale record states what was agreed, frozen, and where the handshake stands`() {
let html = SalePage(sale: .stub(paid: true), role: .buyer, now: .stub).render()
#expect(html.contains("Sale record · CCN-48213 · you are the buyer"))
#expect(html.contains("Agreed today, 09:14 with Kestrel Row Comics · €215 + €6 tracked shipping"))
#expect(html.contains("Awaiting dispatch"))
#expect(html.contains("CGC 9.8 · cert 4312087-002"))
#expect(html.contains("€215 · offer accepted (asked €240)"))
#expect(html.contains("marked this as paid by iDEAL today, 09:20"))
#expect(html.contains("stepper__step--done"))
#expect(html.components(separatedBy: "stepper__step--current").count - 1 == 1)
#expect(html.contains(#"href="/messages/00000000-0000-0000-0000-0000000000cc""#))
}
@Test
func `sale record shows the seller their buyer, and both the ratings once given`() {
let html = SalePage(
sale: .stub(priceCents: 24_000, paid: true, sent: true, received: true, buyerRating: 5, sellerRating: 4),
role: .seller,
now: .stub
).render()
#expect(html.contains("you are the seller"))
#expect(html.contains("Mara Visser"))
#expect(html.contains("bought at the asking price"))
#expect(html.contains("Complete"))
#expect(html.contains("★★★★★"))
#expect(html.contains("★★★★☆"))
#expect(!html.contains("Visit shop"))
}
// MARK: MessagesPage tests
@Test
func `messages tell the viewer's words from the other side's`() {
let html = MessagesPage(
conversations: [],
open: .stub(entries: [
.text("Is the case clean?", from: .mara),
.text("Clean all round.", from: .joost),
]),
now: .stub
).render()
#expect(html.contains(#"entry--text entry--own"><p class="entry__bubble">Is the case clean?"#))
#expect(html.contains(#"entry--text entry--theirs"><p class="entry__bubble">Clean all round."#))
#expect(html.contains("You · today, 09:14"))
#expect(html.contains("Kestrel Row Comics · today, 09:14"))
#expect(html.contains(#"action="/messages/00000000-0000-0000-0000-0000000000cc" method="post""#))
}
@Test
func `messages let the seller alone answer an open offer`() {
let entries = [Conversation.Entry(kind: .offer, sender: .mara, body: "Would you take €215?", offer: .stub(), createdAt: .stub)]
let selling = MessagesPage(conversations: [], open: .stub(side: .selling, entries: entries), now: .stub).render()
let buying = MessagesPage(conversations: [], open: .stub(side: .buying, entries: entries), now: .stub).render()
#expect(selling.contains("Their offer"))
#expect(selling.contains(#"action="/sell/offers/00000000-0000-0000-0000-0000000000aa""#))
#expect(selling.contains("47 h left"))
#expect(selling.contains("“Would you take €215?”"))
#expect(buying.contains("Your offer"))
#expect(buying.contains("Offer open · €215"))
#expect(!buying.contains("/sell/offers/"))
// One open offer per listing: no way to a second while it waits.
#expect(!buying.contains(#"href="/listing/nightward-1/offer""#))
}
@Test
func `messages lead to the sale record from the event that opened it, once`() {
let html = MessagesPage(
conversations: [],
open: .stub(
entries: [
.init(kind: .offer, sender: .mara, body: "", offer: .stub(status: .accepted), createdAt: .stub),
.init(kind: .event, sender: .joost, body: "accepted the offer", saleNumber: 48_213, createdAt: .stub),
.init(kind: .event, sender: .mara, body: "marked the sale paid", saleNumber: 48_213, createdAt: .stub),
],
saleNumber: 48_213
),
now: .stub
).render()
#expect(html.contains("Kestrel Row Comics accepted the offer · today, 09:14"))
#expect(html.contains("You marked the sale paid"))
#expect(html.components(separatedBy: "Sale record CCN-48213 created").count - 1 == 1)
#expect(html.contains("Agreed · CCN-48213"))
#expect(html.contains(">Accepted<"))
}
@Test
func `messages list the side asked for, counting what is unread on each`() {
let conversations: [Conversation] = [
.stub(side: .buying, entries: [.text("Shipping Thursday.", from: .joost)], unreadCount: 2),
.stub(side: .selling, entries: [.text("Still available?", from: .mara)], unreadCount: 1),
]
let buying = MessagesPage(conversations: conversations, now: .stub).render()
let selling = MessagesPage(conversations: conversations, box: .selling, now: .stub).render()
#expect(buying.contains("2 unread"))
#expect(buying.contains(#"href="/messages?box=buying" aria-current="true">Buying · 1"#))
#expect(buying.contains("Shipping Thursday."))
#expect(!buying.contains("Still available?"))
#expect(selling.contains("Still available?"))
#expect(selling.contains(">MV<"))
#expect(buying.contains("Pick a conversation."))
}
// MARK: SellerDashboardPage tests
@Test
func `seller dashboard lists what waits for the seller`() {
let html = SellerDashboardPage(
shop: .stub(),
offers: [.stub()],
sales: [.stub(paid: true), .stub(paid: true, sent: true)],
listings: [.stub()],
viewer: .init(displayName: "Joost de Wit", shopSlug: "kestrel-row-comics", unreadMessages: 2),
now: .stub
).render()
#expect(html.contains("Hello, Joost"))
#expect(html.contains("1 offer waiting · 1 sale to dispatch · 2 unread"))
#expect(html.contains("from Mara Visser"))
#expect(html.contains(#"name="return" value="/sell""#))
#expect(html.contains(#"href="/sales/48213""#))
#expect(html.contains("1 awaiting your dispatch"))
#expect(html.contains(#"handshake__step handshake__step--done">Paid"#))
}
@Test
func `seller dashboard says so when nothing waits`() {
let html = SellerDashboardPage(shop: .stub(), offers: [], sales: [], listings: [], now: .stub).render()
#expect(html.contains("No offers waiting."))
#expect(html.contains("No sales yet."))
}
// MARK: ListingPage tests
@Test
func `listing page closes its actions once sold, and to its own seller`() {
let sold = ListingPage(listing: .stub(soldAt: .stub), related: []).render()
let own = ListingPage(
listing: .stub(),
related: [],
viewer: .init(displayName: "Joost", shopSlug: "kestrel-row-comics")
).render()
#expect(sold.contains("This copy is sold."))
#expect(!sold.contains("Buy now"))
#expect(own.contains("This is your listing."))
#expect(!own.contains("Make an offer"))
}
// MARK: Shared tests
@Test
func `no trade page renders an inline style`() {
let pages = [
OfferPage(listing: .stub(), mode: .offer).render(),
SalePage(sale: .stub(), role: .buyer, now: .stub).render(),
MessagesPage(conversations: [.stub()], open: .stub(), now: .stub).render(),
SellerDashboardPage(shop: .stub(), offers: [.stub()], sales: [.stub()], listings: [.stub()], now: .stub).render(),
]
for html in pages {
#expect(!html.contains("style="))
#expect(!html.contains("<style"))
#expect(html.contains("/css/trade.css"))
}
}
}