/* catcrafts.net Copyright (C) 2026 Catcrafts The source code of this website is made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. */ // The shop front: prices rendered from the same integers the checkout // charges, the currency conversions the shop card carries, and the copy // around them. Runs in both shop states — coming-soon asserts the closed // shape, launch re-arms the open one with no edit here. import std; import Catcrafts.E2eHarness; using namespace Catcrafts::E2e; int main(int argc, char** argv) { TestServer srv(argv[1], 8216); // The price is rendered from the same integers the checkout charges, with // the derived ex-VAT twin alongside — asserting both pins the arithmetic. srv.BodyHas("/shop/fp6-pmos", "€573.80", "product page shows the from-price (green supplier + €60.50 gross markup)"); srv.BodyHas("/shop/fp6-pmos", "€474.21", "product page shows the derived ex-VAT price"); srv.BodyHas("/shop/fp6-pmos", ">from<", "product page marks the price as a from-price"); srv.BodyHas("/shop", "€573.80", "shop card shows the from-price"); // Every colour is priced in the selector, and the form carries the exact // data blob the preview computes from. srv.BodyHas("/shop/fp6-pmos", "Black — €579.80", "colour selector prices black"); srv.BodyHas("/shop/fp6-pmos", "White — €665.38", "colour selector prices white"); if (srv.ShopOpen()) { srv.BodyHas("/shop/fp6-pmos", "data-cc=", "form embeds the pricing blob"); srv.BodyHas("/shop/fp6-pmos", "id=\"cc-total\"", "live total element present"); } else { srv.BodyHas("/shop/fp6-pmos", "Coming soon", "coming-soon notice on the buy panel"); srv.BodyHas("/shop", "coming soon", "shop card carries the coming-soon badge"); srv.BodyLacks("/shop/fp6-pmos", "", "donation page ships no executable script"); srv.BodyHas("/shop/fp6-pmos", "src=\"/fp6-pmos.jpg\"", "product page embeds the photo"); srv.BodyHas("/shop", "src=\"/fp6-pmos.jpg\"", "shop card embeds the thumbnail"); // The image file itself is Caddy's to serve (static asset), so its // presence is asserted against the repo, not this server. Check(std::filesystem::exists("images/fp6-pmos.jpg"), "product photo exists in the repo"); srv.BodyHas("/shop/fp6-pmos", "not yet verified", "emergency-calling caveat is on the page"); srv.BodyLacks("/shop", "reservation", "no reservation copy survives on /shop"); srv.BodyLacks("/shop/fp6-pmos", "Reserve one", "no reservation form survives"); // The shop card: one euro number as the crawler/no-JS text, every // supported currency pre-formatted server-side as a data attribute for // the script to pick from. Converted amounts carry "~". GBP converts the // ex-VAT price; SEK (an EU member's currency) converts the VAT-inclusive // price. USD and CAD are absent on purpose — the shop refuses those // destinations, so it does not quote a local price to them either. srv.BodyHas("/shop", "class=\"price__single\"", "shop card renders the single-number price"); srv.BodyHas("/shop", "data-gbp=\"~£", "shop card carries a GBP conversion"); srv.BodyHas("/shop", "data-sek=\"~kr ", "shop card carries an SEK conversion"); srv.BodyHas("/shop", "data-world=\"€474.21\"", "shop card carries the euro export fallback"); srv.BodyLacks("/shop", "data-usd=", "no USD price for a country the shop refuses"); srv.BodyLacks("/shop", "data-cad=", "no CAD price for a country the shop refuses"); // The product page gets the same headline element, so a British visitor // sees ~£ at the top there too, and the buy card states the customs // position plainly. srv.BodyHas("/shop/fp6-pmos", "data-gbp=\"~£", "product page headline carries the conversion"); srv.BodyHas("/shop/fp6-pmos", "indicative only", "buy card says converted prices are indicative"); srv.BodyHas("/shop/fp6-pmos", "customs authority", "buy card names whose problem import charges are"); srv.BodyLacks("/shop/fp6-pmos", "collected on arrival", "the vague customs phrasing is gone"); // The label must not claim the Dutch rate is an EU-wide one. srv.BodyLacks("/shop/fp6-pmos", "EU VAT", "price label does not call 21% an EU-wide rate"); return Finish(); }