Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions .github/workflows/ci-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,106 @@ jobs:
- name: Print realm server logs
if: always()
run: cat /tmp/server.log

live-test:
name: Live Tests (realm)
runs-on: ubuntu-latest
concurrency:
group: live-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
# Checkout the boxel monorepo at is-live-test branch (has testem-live.js + test:live)
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
with:
repository: cardstack/boxel
ref: is-live-test

# Checkout this catalog repo into a temp location
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
with:
path: boxel-catalog-src

# Copy catalog files into the monorepo
- name: Copy catalog files into monorepo
run: |
cd packages/catalog-realm
find . -mindepth 1 \
! -name '.gitignore' \
! -name 'tsconfig.json' \
! -name 'package.json' \
! -name '.realm.json' \
! -path './Spec' \
! -path './Spec/*' \
! -path './fields' \
! -path './fields/*' \
! -path './components' \
! -path './components/*' \
! -path './commands' \
! -path './commands/suggest-avatar.gts' \
! -path './utils' \
! -path './utils/*' \
! -path './resources' \
! -path './resources/*' \
! -path './catalog-app' \
! -path './catalog-app/*' \
! -name '.' \
-exec rm -rf {} + 2>/dev/null || true
cd ../..
rsync -av --exclude='tsconfig.json' --exclude='package.json' --exclude='.realm.json' --exclude='.gitignore' --exclude='tests/' boxel-catalog-src/ packages/catalog-realm/

- uses: ./.github/actions/init

- name: Build common dependencies
run: pnpm run build-common-deps

- name: Build Host for tests
run: NODE_OPTIONS='--max-old-space-size=8192' pnpm build
working-directory: packages/host

- name: Serve boxel-icons
run: pnpm serve &> /tmp/icon-server.log &
working-directory: packages/boxel-icons

- name: Disable TCP/UDP network offloading
run: sudo ethtool -K eth0 tx off rx off

- name: Serve host dist for realm server
uses: JarvusInnovations/background-action@2428e7b970a846423095c79d43f759abf979a635 # 1.0.7
with:
run: pnpm serve:dist &
working-directory: packages/host
wait-for: 3m
wait-on: http-get://localhost:4200

- name: Start realm servers
run: pnpm start:services-for-host-tests | tee -a /tmp/server.log &
working-directory: packages/realm-server

- name: Create realm users
run: pnpm register-realm-users
working-directory: packages/matrix

- name: Install D-Bus helpers
run: |
sudo apt-get update
sudo apt-get install -y dbus-x11 upower
sudo service dbus restart
sudo service upower restart

- name: Live test suite
run: dbus-run-session -- pnpm test:live
working-directory: packages/host
env:
DBUS_SYSTEM_BUS_ADDRESS: unix:path=/run/dbus/system_bus_socket

- name: Upload junit report
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # 4.6.1
if: ${{ !cancelled() }}
with:
name: host-live-test-report
path: junit/host-live.xml
retention-days: 30

- name: Print realm server logs
if: ${{ !cancelled() }}
run: cat /tmp/server.log
144 changes: 144 additions & 0 deletions sample-command-card.gts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import {
CardDef,
field,
contains,
Component,
} from 'https://cardstack.com/base/card-api';
import StringField from 'https://cardstack.com/base/string';

export class SampleCommandCard extends CardDef {
static displayName = 'Sample Command Card';
@field title = contains(StringField);

static isolated = class Isolated extends Component<typeof SampleCommandCard> {
<template>
<h1><@fields.title /></h1>
<button type='button'>Create Card</button>
</template>
};
}

// ── Tests (imports resolved via loader.shimModule in live-test.js) ────────────
import { on } from '@ember/modifier';
import { service } from '@ember/service';
import { click, render, waitUntil } from '@ember/test-helpers';
import GlimmerComponent from '@glimmer/component';
import { module, test } from 'qunit';

import { type Store } from '@cardstack/runtime-common';
import {
setupCardTest,
setupIntegrationTestRealm,
testRealmURL,
withCachedRealmSetup,
type TestContextWithSave,
} from '@cardstack/host/tests/helpers';
import { TestRealmAdapter } from '@cardstack/host/tests/helpers/adapter';

class CreateCardButton extends GlimmerComponent {
@service declare store: Store;

createCard = async () => {
await this.store.add(
new SampleCommandCard({ title: 'Hello from live-test' }),
);
};

<template>
<button type='button' {{on 'click' this.createCard}}>Create Card</button>
</template>
}

export function runTests() {
module('Catalog | SampleCommandCard', function (hooks) {
let { mockMatrixUtils } = setupCardTest(hooks);

let testRealmAdapter: TestRealmAdapter;
let testRealm: Awaited<ReturnType<typeof setupIntegrationTestRealm>>['realm'];

hooks.beforeEach(async function () {
let result = await withCachedRealmSetup(async () =>
setupIntegrationTestRealm({
mockMatrixUtils,
contents: {
'sample-command-card.gts': { SampleCommandCard },
'.realm.json': '{ "name": "Sample Realm" }',
},
}),
);
testRealmAdapter = result.adapter;
testRealm = result.realm;
});

test('clicking Create Card writes a new card to the realm', async function (this: TestContextWithSave, assert) {
assert.expect(3);

let savedUrl: URL | undefined;
this.onSave((url, doc) => {
savedUrl = url;
assert.strictEqual(
(doc as any).data.attributes.title,
'Hello from live-test',
'saved doc has correct title',
);
});

await render(<template><CreateCardButton /></template>);
await click('button');

assert.ok(savedUrl, 'card was saved to realm');
let relativePath = `${savedUrl!.href.substring(testRealmURL.length)}.json`;
let file = await testRealmAdapter.openFile(relativePath);
assert.ok(file, 'card JSON file exists in the realm adapter');
});

test('search finds the newly created card', async function (this: TestContextWithSave, assert) {
assert.expect(3);

let savedUrl: URL | undefined;
this.onSave((url) => {
savedUrl = url;
});

await render(<template><CreateCardButton /></template>);
await click('button');

await waitUntil(() => Boolean(savedUrl), { timeout: 5000 });

await waitUntil(
async () => {
let { data: cards } =
await testRealm.realmIndexQueryEngine.searchCards({
filter: {
on: {
module: `${testRealmURL}sample-command-card`,
name: 'SampleCommandCard',
},
eq: { title: 'Hello from live-test' },
},
});
return cards.length === 1;
},
{ timeout: 5000 },
);

let { data: cards } = await testRealm.realmIndexQueryEngine.searchCards({
filter: {
on: {
module: `${testRealmURL}sample-command-card`,
name: 'SampleCommandCard',
},
eq: { title: 'Hello from live-test' },
},
});

assert.strictEqual(cards.length, 1, 'search returns the created card');
assert.strictEqual(
(cards[0] as any).attributes?.title,
'Hello from live-test',
'search result has correct title',
);
assert.ok(savedUrl, 'card save completed');
});
});
}
Loading