Skip to content

introduce-realm-enabled-tests#4191

Open
tintinthong wants to merge 24 commits intomainfrom
is-live-test
Open

introduce-realm-enabled-tests#4191
tintinthong wants to merge 24 commits intomainfrom
is-live-test

Conversation

@tintinthong
Copy link
Contributor

@tintinthong tintinthong commented Mar 16, 2026

Live Tests: Co-locate QUnit tests inside realm cards

I decided to call this live-test. But I'm not so commited to the name. Open to suggestions. I call it live-test bcos these are test loaded from the realm

Exercised in external catalog

Look at this PR cardstack/boxel-catalog#244

Screenshot 2026-03-24 at 17 18 24

What this does

This adds a new test mode called live tests that lets you write QUnit tests directly inside a realm (e.g. alongside a card definition in catalog-realm/), and run them against a live running realm server — without having to add them to the host test bundle.

Previously, all host tests were compiled into the Ember test bundle at build time. Live tests are different: the realm serves the test files over HTTP, and the host loads and executes them at runtime.

What changed

  • test-helper.js — the existing test entry point now checks for a ?liveTest query param. If present it runs the live-test path; otherwise it runs the normal ember-exam path as before. A single check prevents double QUnit initialisation (two competing app instances).

  • live-test.js — contains loadRealmTests(application), which is the async function that:

    • fetches the realm index to discover .gts test files
    • loads each file through the realm's own module loader (not the Ember bundle)
    • calls runTests() on each to register QUnit modules
  • helpers/setup-qunit.js — shared QUnit bootstrap (maxDepth, test waiters, qunit-dom setup, autostart flag) used by both live and normal test paths.

  • testem-live.js — Testem config that drives Chrome against tests/index.html?liveTest=true&realmURL=http://localhost:4201/catalog/.

  • scripts/live-test-wait-for-servers.sh — waits for all required services then runs ember test --config-file testem-live.js --path ./dist.

  • package.json — adds test:live script.

  • ci-host.yaml — adds a live-test CI job (non-sharded, runs with catalog realm, no SKIP_CATALOG).

  • catalog-realm/sample-command-card.gts — example card with a co-located runTests() export demonstrating the pattern.

How tests are discovered in a co-located module

A .gts file in the realm can export a runTests() function alongside its card definition:

// catalog-realm/my-card.gts
export class MyCard extends CardDef { ... }

export function runTests() {
  module('Catalog | MyCard', function (hooks) {
    test('it works', async function (assert) { ... });
  });
}

At runtime, loadRealmTests fetches the realm index, finds all .gts files, imports each one through the realm loader, and calls runTests() if it exists. Files without runTests() are skipped silently.

The loader boundary

There are two separate module loaders at play:

  1. Host bundle loader — the normal Ember/webpack compiled bundle. All standard host tests run here.
  2. Realm loader — a second Ember app instance (application.buildInstance(...)) that fetches modules over HTTP from the realm server. Live test files are imported through this loader.

The realm loader needs the test helpers (@cardstack/host/tests/helpers, mock-matrix, etc.) to be shimmed into it explicitly — otherwise realm test files can't import them. loadRealmTests does this before importing any test modules.

Things to know

  • The realm must be running to run live tests. The test files live on the realm server — they are fetched at runtime, not compiled into the bundle. If the realm is down, no tests load.
  • Tests must be in a publicly readable realm. The realm loader fetches modules without Matrix auth. For CI, we cover the catalog realm (/catalog/) which has '*': read=true permissions.
  • For CI, the live-test job starts the catalog realm (no SKIP_CATALOG) and runs pnpm test:live against it. sample-command-card.gts in catalog-realm/ is the first test covered.

Future work

  • Immediate next thing: Move listing-create test into the gts files
  • Make test helpers available in Code Mode. Right now the helpers are shimmed from within the host test bundle. The goal is to make them available inside Code Mode so realm tests can be authored and run directly in the browser without needing the host test bundle.
  • Use an iframe when running in Code Mode. The current implementation runs live tests in the same browser context as the host test page, which is sufficient for Testem/CI. When integrating into Code Mode, the test runner should be mounted as an <iframe> — giving it a fully isolated JS heap, its own Ember app instance, its own SQLite WASM, and no shared state with the running host app. Testem is not involved in the Code Mode case; QUnit renders pass/fail directly inside the iframe's own UI.

How to run locally

# Manual browser (services must be running)
open http://localhost:4200/tests?liveTest=true&realmURL=http://localhost:4201/catalog/

# Testem (services must be running, dist must be built)
cd packages/host
pnpm build
ember test --config-file testem-live.js --path ./dist

@tintinthong tintinthong changed the title introduce is live test introduce-realm-enabled-tests Mar 16, 2026
@tintinthong tintinthong marked this pull request as draft March 16, 2026 13:17
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7c22d07243

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions
Copy link

Preview deployments

@github-actions
Copy link

github-actions bot commented Mar 16, 2026

Host Test Results

    1 files  ±  0      1 suites  ±0   2h 8m 56s ⏱️ + 4m 57s
2 051 tests +205  2 036 ✅ +207  15 💤 ±0  0 ❌  - 1 
2 066 runs  +206  2 051 ✅ +209  15 💤 ±0  0 ❌  - 2 

Results for commit b24d62d. ± Comparison against base commit 86cb8e6.

This pull request removes 1 and adds 206 tests. Note that renamed tests count towards both.
Chrome ‑ Global error: Uncaught TypeError: Failed to fetch at http://localhost:7357/assets/chunk.ba748e4cc236bfaae5b8.js, line 156670  While executing test: Acceptance | code-submode | field playground > single realm: can create new field instance (has preexisting Spec) 
Chrome ‑ Acceptance | code submode | inspector tests: cancel button in Create Listing modal closes the modal
Chrome ‑ Acceptance | code submode | inspector tests: clicking "Create Listing" on a card instance opens modal with instance pre-selected
Chrome ‑ Acceptance | code submode | inspector tests: clicking "Create Listing" opens confirmation modal for card definition
Chrome ‑ Acceptance | code-submode | field playground > multiple realms: can autogenerate new Spec and field instance (no preexisting Spec)
Chrome ‑ Acceptance | code-submode | field playground > multiple realms: can autogenerate new field instance when spec exists but has no examples
Chrome ‑ Acceptance | code-submode | field playground > multiple realms: can create new field instance (has preexisting Spec)
Chrome ‑ Acceptance | code-submode | field playground > single realm: can autogenerate new field instance when spec exists but has no examples
Chrome ‑ Acceptance | code-submode | field playground > single realm: can create new field instance (has preexisting Spec)
Chrome ‑ Acceptance | code-submode | field playground > single realm: can request AI assistant to bulk generate samples
Chrome ‑ Acceptance | code-submode | field playground > single realm: can request AI assistant to fill in sample data
…

♻️ This comment has been updated with latest results.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a “live test” runner page intended to execute realm-hosted (card) tests in a host-like Ember/QUnit environment, and refactors an experiments realm sample card test to use a consolidated host test setup helper.

Changes:

  • Add a dedicated live-test.html + live-test.js runner to load realm modules and execute their runTests() exports under QUnit.
  • Update the standard host tests/test-helper.js boot to skip normal initialization when running on the live-test page.
  • Add a setupCardTest(hooks) helper and update sample-command-card.gts tests (including a new search assertion).

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/host/tests/test-helper.js Skips normal test initialization on live-test.html; imports live-test runner module.
packages/host/tests/live-test.js New runtime for loading realm test modules and starting QUnit manually.
packages/host/tests/live-test.html New test runner HTML page with QUnit UI and a “Start QUnit” button.
packages/host/tests/helpers/index.gts Adds setupCardTest() convenience helper used by realm-hosted tests.
packages/host/ember-cli-build.js Formatting-only change.
packages/host/app/lib/externals.ts Adds shims for QUnit/test helpers/test modules to support realm-loaded tests.
packages/experiments-realm/sample-command-card.gts Refactors test setup to setupCardTest() and adds a search-based assertion.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a “live” test runner mode that can load and execute test modules served from a running realm (instead of only running the host’s compiled test bundle), and wires it into CI.

Changes:

  • Add a live-test bootstrap (tests/live-test.js + optional tests/live-test.html) and gate the normal tests/test-helper.js startup when ?liveTest=true.
  • Add a Testem config + wait-for-services script + CI job to run these realm-backed tests headlessly.
  • Add a convenience helper (setupCardTest) and a sample realm card test that validates indexing/search against a live realm.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/host/tests/test-helper.js Skips standard Ember Exam/QUnit startup when running in live-test mode; imports live-test bootstrap.
packages/host/tests/live-test.js New live-test runner: boot app, discover realm modules, shim helpers into loader, run runTests() exports.
packages/host/tests/live-test.html Optional standalone HTML runner with UI controls/status for live tests.
packages/host/tests/helpers/index.gts Adds setupCardTest() helper for realm card tests.
packages/host/testem-live.js New Testem config to run tests/index.html?liveTest=true... and emit junit in CI.
packages/host/scripts/live-test-wait-for-servers.sh Waits for dependent services/readiness endpoints then runs live tests.
packages/host/package.json Adds test:live script.
packages/host/ember-cli-build.js No functional change (whitespace).
packages/host/app/lib/externals.ts Adds QUnit shim + test-module shims intended to let cards with colocated tests load.
packages/host/.eslintrc.js Allows linting testem-live.js.
packages/catalog-realm/sample-command-card.gts Updates sample card’s colocated tests; adds an indexing/search assertion.
mise-tasks/test-services-host Keeps sample-command-card.gts when preparing the catalog realm for tests.
.github/workflows/ci-host.yaml Adds a new “Live Tests (realm)” job to CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +195 to +205
const testOnlyStub = (moduleId: string) =>
new Proxy(
{},
{
get: () => {
throw new Error(
`${moduleId} is only available in a test environment.`,
);
},
},
);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testOnlyStub throws on any property access via Proxy.get. That will break module evaluation for realm cards that have static imports like import { click } from '@ember/test-helpers' or import { setupCardTest } from '@cardstack/host/tests/helpers', because the export is accessed during module instantiation (before any test code runs). To allow cards to load outside tests, the stub should return callable functions (or undefined) and only throw when those functions are invoked, not when the export is imported.

Suggested change
const testOnlyStub = (moduleId: string) =>
new Proxy(
{},
{
get: () => {
throw new Error(
`${moduleId} is only available in a test environment.`,
);
},
},
);
const testOnlyStub = (moduleId: string) => {
const throwingFunction = function () {
throw new Error(`${moduleId} is only available in a test environment.`);
};
return new Proxy(
{},
{
get() {
return throwingFunction;
},
},
);
};

Copilot uses AI. Check for mistakes.
Comment on lines +115 to +116
} catch {
testModuleNames = [];
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fetch(realmURL) error is swallowed and replaced with testModuleNames = [], which can lead to a confusing "0 tests" outcome without indicating why test discovery failed. It would be more diagnosable to log the exception (or surface a failing test) when realm discovery fails, especially in CI.

Suggested change
} catch {
testModuleNames = [];
} catch (error) {
console.error('Failed to discover tests from realm', realmURL, error);
throw error;

Copilot uses AI. Check for mistakes.
@tintinthong tintinthong marked this pull request as ready for review March 24, 2026 09:19
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c9bff23ae0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +53 to +57
testModuleNames = Object.entries(data.relationships ?? {})
.filter(
([name, entry]) =>
name.endsWith('.gts') && entry.meta?.kind === 'file',
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recurse into subdirectories when collecting live test modules

loadRealmTests() only reads one directory payload and selects root-level entries whose names end with .gts. Realm directory responses include nested folders as meta.kind: 'directory' entries (see the directory API expectations in packages/realm-server/tests/realm-endpoints-test.ts), so any co-located tests under folders like catalog-realm/<feature>/*.gts are never imported or executed. This leaves the new live-test job with incomplete coverage and can silently miss regressions in most realm cards.

Useful? React with 👍 / 👎.

@tintinthong tintinthong requested review from a team and habdelra March 24, 2026 09:52
@habdelra
Copy link
Contributor

habdelra commented Mar 24, 2026

So i think your PR description is a little ambiguous, when we say tests are run against a live realm server, we mean a realm that is running in the browser correct like the current host tests? it's not actually a server in the classic sense, right?

@tintinthong
Copy link
Contributor Author

So i think your PR description is a little ambiguous, when we say tests are run against a live realm server, we mean a realm that is running in the browser correct like the current host tests? it's not actually a server in the classic sense, right?

confirmed. Everything is made similar to host tests. The only difference is that we need to dynamically load up test specified in realm modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants