Skip to content

Testing your theme

A pre-publish routine for verifying a complete Salieno theme: local install, a full surface checklist, light/dark, mobile, forms, and common traps.

10 min readUpdated Aug 13, 2026
On this page

Testing your theme#

A Salieno theme is only finished when every public surface renders correctly, in both colour modes, on a phone, with its forms still submitting. Because Core ships with no default theme and privileges none, there is no sibling theme to quietly borrow a missing view from — your theme must ship every view it needs, or the site breaks the moment a customer reaches the gap. This article is the pre-publish routine: install locally, walk a completeness checklist, test light and dark and mobile, confirm forms still work, and avoid the handful of traps that pass a quick glance but fail in production.

Do all of this before you cut a marketplace version. Publishing is covered in Publishing & updating; here you make sure there is nothing left to fix.

Install locally#

Local development is a drop-in. No zip, no signing, no marketplace round-trip.

  1. Put your theme directory at resources/views/themes/{name}/ (the scaffolder does this for you — see Quickstart). If you started from the reference theme, php artisan template:scaffold my-theme --from=salieno clones a complete, working starting point; --minimal writes a bare skeleton instead.
  2. Publish its assets so themeAsset() URLs resolve. Activating through the admin does this, or run the asset publish step your workflow uses — the compiled files under assets/ are copied to public/assets/themes/{name}/.
  3. Activate it in Admin → Frontend → Themes. Activation writes the operator's stored choice (session('template') ?? gs('active_theme')); nothing about it is hardcoded.
  4. Load the storefront. If the theme is active but a page throws a "View not found" error, that is the point of this article — a missing view is a bug you must fix, not something Core papers over. See The fallback story below.

Re-run the asset publish step every time you change a CSS or JS file — the browser is served the copy in public/, not the source under your theme. See CSS, JavaScript & images.

The completeness checklist#

Open every one of these in a browser and confirm it renders — not just the happy path you designed against, but each real surface a customer can reach. A theme that renders home beautifully and 500s on cart/checkout is not shippable.

Marketing & content

  • home — the home page, rendered from its section list
  • Every section in sections.jsonsecs. Assign each product/landing page in the admin page-builder so its sections actually render, then open each page. The reference theme ships ~65 section slugs (hero, features, pricing, faq, domain_table, testimonials, and the per-product banners); you only need the ones your theme defines, but open each one you ship.
  • pricing — the pricing page
  • contact — the contact page (has a form; see forms below)
  • Static pages: page, pages, policy, cookie if you ship them

Store & ordering

  • products/category — a product category listing
  • products/order — the product configure/order screen (Livewire; the real cart entry point)
  • store/compare-page — the plan comparison table, if you ship /compare

Domains

  • domains/index — the domains landing page
  • domains/search — search results
  • domains/transfer — the transfer page
  • domains/pricing — the TLD pricing table
  • domains/configure — post-search domain configuration

Cart & checkout

  • cart/index — the cart
  • cart/checkout — checkout
  • cart/confirmation — the post-order confirmation

Authentication — all 8 pages (Livewire components under App\Livewire\Client\Auth\*, each returning view(themeViewName('auth.login'))->layout(themeViewName('layouts.app')); see Authentication pages):

  • auth/login
  • auth/register
  • auth/forgot-password
  • auth/reset-password
  • auth/verify-email
  • auth/two-factor-verify
  • auth/authorization
  • auth/complete-profile

Error pages — all 6 (resolved as activeTheme().'errors.'.$code in bootstrap/app.php):

  • errors/403
  • errors/404
  • errors/419
  • errors/429
  • errors/500
  • errors/503

Trigger them for real, not just by visiting the file: hit an unknown URL for 404, submit a form with a stale CSRF token for 419, and (in a non-production build) let an exception through for 500. maintenance is a separate top-level view — open it too if you ship it.

Knowledge base

  • kb/index
  • kb/category
  • kb/article
  • kb/search

Keep this list next to you and tick each surface off. The completeness bar is binary: every view a controller or Livewire component can ask for must exist in your theme.

Test light and dark#

If your theme.json declares "supports": { "dark_mode": true }, then every surface above has to be checked twice. Dark mode is where half-converted markup shows up — a card that forgot its dark: variant, a hardcoded #fff background, an icon that vanishes on a dark canvas.

Toggle the mode switcher (the reference theme gates it behind settings.show_mode_switcher) and re-walk the checklist, or at minimum re-check every page that carries a distinct surface: home, pricing, a product order screen, checkout, one auth page, one error page, a KB article. Watch for:

  • Text with no dark variant (dark grey on near-black)
  • Surfaces that stay white in dark mode (a missing dark:bg-*)
  • Borders and shadows that disappear or turn into hard lines
  • SVG illustrations with baked-in light-mode fills

Colour tokens and the switcher itself are covered in Colours, dark mode & the mode switcher.

Test mobile and responsive#

Open the site in your browser's device emulator at a phone width (375px is a good floor) and re-check the surfaces that carry dense layout: pricing tables, the plan comparison table, the product order screen, checkout, and any multi-column section. Confirm:

  • No horizontal scroll on the body — wide tables and comparison grids must scroll inside their own container, not push the page sideways.
  • Navigation collapses to a working mobile menu.
  • The pricing cycle switcher and plan cards stack legibly.
  • Tap targets are large enough and forms are usable one-handed.

Test at a mid tablet width too — the awkward breakpoints are usually between phone and desktop, not at the extremes.

Confirm forms still submit#

This is the failure mode that a visual pass misses entirely: the page looks perfect and the form does nothing. Storefront forms are Livewire-driven, so the markup you restyle must keep its bindings. A theme may ship plain markup instead of <x-theme.*> components, but it may never drop a wire: attribute.

Actually submit each interactive surface and confirm it works end to end:

  • Login / register / password reset — submit with bad input (see validation errors render) and good input (see it proceed). Confirm wire:submit, every wire:model on the inputs, and any wire:click on buttons are intact.
  • Contact form — submit and confirm the success state.
  • Product order — change a cycle, add to cart; confirm the mini-cart updates live.
  • Domain search — run a search and see results populate.
  • Cart & checkout — adjust quantities, proceed to checkout, reach confirmation.

If a form silently does nothing, open the browser console and network tab: a missing wire:model means the component never sees the field; a missing wire:submit means the browser does a full-page GET instead of a Livewire round-trip. Preserving these bindings is the whole contract of restyling an auth or order page — see Authentication pages and Components.

The fallback story#

Understand exactly what Core does when a view is missing, because it decides how your bugs surface.

  • When NO theme is installed at all, every themes.* view resolves to a neutral Core holding page via App\View\ThemeFallbackViewFinder. This is the first-run path, not an error.
  • When your theme IS installed but is missing a view, resolution throws. There is no cross-fallback to another theme — Core ships none to fall back to. The finder does this deliberately: substituting a full "no theme installed" page into a layout slot for a missing partial would hide the bug and call it success.

So during testing, a "View not found: themes.your-theme.cart.checkout" exception is Core telling you your theme is incomplete. The fix is never to suppress it — it is to ship the view. The one nuance: <x-theme.*> components you omit fall back to Core base components under resources/views/components/theme/ (registered in AppServiceProvider), so a missing component primitive renders rather than throws. That fallback is for components only, never for pages, sections, layouts, or auth/error views.

The practical test: with your theme active, walk the entire checklist above. If nothing throws, you have shipped every view. If something throws, you found the gap before a customer did.

Common pitfalls#

These are the traps that pass a glance and fail in production. Check for each one.

1. The `@lang`-array-with-nested-calls trap. Passing an array of replacements to @lang() or __() where a value is itself a Blade/PHP call can break parsing or emit the wrong string. Keep translation calls flat — resolve any dynamic value into a plain variable first, then pass it as a simple replacement:

blade
{{-- Fragile: a nested call inside the replacements array --}}
@lang('Welcome, :name', ['name' => auth()->user()->fullName()])

{{-- Robust: resolve first, pass a scalar --}}
@php $name = auth()->user()->fullName(); @endphp
{{ __('Welcome, :name', ['name' => $name]) }}

2. Blade directives inside component tags. A control-flow directive placed inside a <x-...> tag's attribute list silently corrupts the component — it does not render an error, it renders wrong. Put the directive around the tag, never inside it:

blade
{{-- Broken: @if lives inside the component tag --}}
<x-theme.btn-primary @if($featured) class="ring-2" @endif>Buy</x-theme.btn-primary>

{{-- Correct: conditionals wrap the tag, or feed a prebuilt value --}}
@php $ring = $featured ? 'ring-2' : ''; @endphp
<x-theme.btn-primary class="{{ $ring }}">Buy</x-theme.btn-primary>

3. An unlayered `<style>` block beating your utilities. A plain <style> block in a view emits at a higher effective specificity/order than your utility layer, so a single rule there silently overrides utility classes across the page. In bundled themes keep custom CSS inside the proper layer; in a precompiled uploaded theme, keep styling in your compiled assets/css/*.css file and reference it via themeAsset('css/theme.css') rather than inlining a stray <style> block that outranks everything.

4. Broken `@include` paths. Section and partial includes must go through the theme-aware helpers, not a hardcoded prefix. Use activeTemplate().'partials.render-sections' and templateViewName('sections.'.$slug) (the render loop is tolerant — a missing section slug is skipped, not fatal), but a typo'd literal path either throws or silently renders nothing. Confirm every custom @include/@includeIf resolves. See Building sections.

5. iOS auto-zoom on small inputs. Mobile Safari zooms the viewport whenever a focused input has a font-size under 16px, and it does not zoom back out — the most likely place to hit it is a login form. Give inputs a 16px minimum on mobile and drop to your smaller desktop size at a breakpoint:

css
/* iOS never zooms a control that is >= 16px on focus */
.form-input {
    font-size: 16px;
}
@media (min-width: 640px) {
    .form-input {
        font-size: 14px;
    }
}

6. Forgetting to precompile CSS. Uploaded themes ship precompiled plain CSS/JS — there is no @vite, no @tailwind, and no @apply at runtime. If you develop against a bundled build and forget to compile your final stylesheet into assets/css/, the live theme loads a file that references utilities that were never emitted, and the whole page renders unstyled. Compile, publish assets, hard-refresh, and confirm the page is actually styled from public/assets/themes/{name}/ before you package. Details in CSS, JavaScript & images.

Ship checklist#

Before you cut a version, confirm all of:

  • [ ] Every view in the completeness checklist renders — nothing throws with your theme active
  • [ ] Light and dark both clean on every distinct surface
  • [ ] No horizontal scroll at 375px; dense tables scroll inside their own container
  • [ ] Every form submits (Livewire wire: bindings intact)
  • [ ] All 6 error pages and all 8 auth pages open
  • [ ] CSS/JS precompiled into assets/ and published; page renders styled from public/
  • [ ] theme.json and salieno.json versions match

Next: once your theme passes this routine, go to Publishing & updating on the marketplace to version, sign, and ship it — including how updates swap files only and never touch a customer's page-builder content.

themestestingqualitylivewirechecklist
Was this article helpful?
Still stuck?Contact support
Testing your theme · Salieno Docs