diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5bbe73ad578..eee80bdf886 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -494,85 +494,13 @@ jobs: if: needs.change-check.outputs.realm-server == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true' runs-on: ubuntu-latest concurrency: - group: realm-server-test-${{ matrix.testModule }}-${{ github.head_ref || github.run_id }} + group: realm-server-test-${{ matrix.shardIndex }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true strategy: fail-fast: false matrix: - testModule: - [ - "auth-client-test.ts", - "billing-test.ts", - "card-dependencies-endpoint-test.ts", - "card-endpoints-test.ts", - "card-reference-resolver-test.ts", - "card-source-endpoints-test.ts", - "definition-lookup-test.ts", - "file-watcher-events-test.ts", - "indexing-event-sink-test.ts", - "indexing-test.ts", - "runtime-dependency-tracker-test.ts", - "transpile-test.ts", - "module-syntax-test.ts", - "node-realm-test.ts", - "permissions/permission-checker-test.ts", - "prerendering-test.ts", - "prerender-server-test.ts", - "prerender-manager-test.ts", - "prerender-proxy-test.ts", - "remote-prerenderer-test.ts", - "queue-test.ts", - "realm-endpoints/cancel-indexing-job-test.ts", - "realm-endpoints/dependencies-test.ts", - "realm-endpoints/directory-test.ts", - "realm-endpoints/info-test.ts", - "realm-endpoints/invalidate-urls-test.ts", - "realm-endpoints/lint-test.ts", - "realm-endpoints/mtimes-test.ts", - "realm-endpoints/permissions-test.ts", - "realm-endpoints/publishability-test.ts", - "realm-endpoints/reindex-test.ts", - "realm-endpoints/search-test.ts", - "realm-endpoints/user-test.ts", - "realm-endpoints-test.ts", - "sanitize-head-html-test.ts", - "search-prerendered-test.ts", - "types-endpoint-test.ts", - "server-config-test.ts", - "server-endpoints/authentication-test.ts", - "server-endpoints/bot-commands-test.ts", - "server-endpoints/bot-registration-test.ts", - "server-endpoints/delete-realm-test.ts", - "server-endpoints/download-realm-test.ts", - "server-endpoints/index-responses-test.ts", - "server-endpoints/maintenance-endpoints-test.ts", - "server-endpoints/queue-status-test.ts", - "server-endpoints/realm-lifecycle-test.ts", - "server-endpoints/search-test.ts", - "server-endpoints/info-test.ts", - "server-endpoints/search-prerendered-test.ts", - "server-endpoints/stripe-session-test.ts", - "server-endpoints/stripe-webhook-test.ts", - "server-endpoints/user-and-catalog-test.ts", - "server-endpoints/incoming-webhook-test.ts", - "server-endpoints/webhook-commands-test.ts", - "server-endpoints/webhook-receiver-test.ts", - "server-endpoints/federated-types-test.ts", - "virtual-network-test.ts", - "atomic-endpoints-test.ts", - "request-forward-test.ts", - "publish-unpublish-realm-test.ts", - "boxel-domain-availability-test.ts", - "claim-boxel-domain-test.ts", - "command-parsing-utils-test.ts", - "delete-boxel-claimed-domain-test.ts", - "get-boxel-claimed-domain-test.ts", - "realm-auth-test.ts", - "run-command-task-test.ts", - "queries-test.ts", - "session-room-queries-test.ts", - "full-reindex-test.ts", - ] + shardIndex: [1, 2, 3, 4, 5, 6] + shardTotal: [6] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: ./.github/actions/init @@ -586,6 +514,10 @@ jobs: run: | shopt -s dotglob cp -a .test-web-assets-artifact/. ./ + - name: Compute shard test modules + id: shard_modules + run: echo "modules=$(node scripts/shard-test-modules.js ${{ matrix.shardIndex }} 6)" >> "$GITHUB_OUTPUT" + working-directory: packages/realm-server - name: Start test services (icons + host dist + realm servers) run: mise run test-services:realm-server | tee -a /tmp/server.log & - name: create realm users @@ -595,7 +527,15 @@ jobs: run: pnpm test:wait-for-servers working-directory: packages/realm-server env: - TEST_MODULE: ${{matrix.testModule}} + TEST_MODULES: ${{ steps.shard_modules.outputs.modules }} + JUNIT_OUTPUT_FILE: ${{ github.workspace }}/junit/realm-server-${{ matrix.shardIndex }}.xml + - name: Upload junit report + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # 4.6.1 + if: ${{ !cancelled() }} + with: + name: realm-server-test-report-${{ matrix.shardIndex }} + path: junit/realm-server-${{ matrix.shardIndex }}.xml + retention-days: 30 - name: Print realm server logs if: ${{ !cancelled() }} run: cat /tmp/server.log @@ -603,7 +543,7 @@ jobs: id: artifact_name if: ${{ !cancelled() }} run: | - export SAFE_ARTIFACT_NAME=$(echo ${{ matrix.testModule }} | sed 's/[/]/_/g') + export SAFE_ARTIFACT_NAME=shard-${{ matrix.shardIndex }} echo "artifact_name=$SAFE_ARTIFACT_NAME" >> "$GITHUB_OUTPUT" - name: Extract worker and prerender logs if: ${{ !cancelled() }} @@ -672,6 +612,39 @@ jobs: path: /tmp/host-dist.log retention-days: 30 + realm-server-merge-reports: + name: Merge Realm Server reports and publish + if: ${{ !cancelled() && (needs.change-check.outputs.realm-server == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true') }} + concurrency: + group: realm-server-merge-reports-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + needs: [change-check, realm-server-test] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: ./.github/actions/init + - name: Download JUnit reports + uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # 4.2.0 + with: + path: all-realm-server-reports + pattern: realm-server-test-report-* + merge-multiple: true + - name: Merge reports + run: npx junit-report-merger realm-server.xml "./all-realm-server-reports/*.xml" + - name: Upload merged report + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # 4.6.1 + if: ${{ !cancelled() }} + with: + name: realm-server-test-report-merged + path: realm-server.xml + retention-days: 30 + - name: Publish test results + uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # 2.18.0 + if: ${{ !cancelled() }} + with: + junit_files: realm-server.xml + check_name: Realm Server Test Results + software-factory-test: name: Software Factory Tests needs: [change-check, test-web-assets] diff --git a/AGENTS.md b/AGENTS.md index 06974549b91..1a0056340b9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -116,6 +116,8 @@ `pnpm test` - Run a single module: `TEST_MODULE=card-endpoints-test.ts pnpm test-module` +- Run a list of modules: + `TEST_MODULES=card-endpoints-test.ts|another-module-test.ts pnpm test` - Focusing on single test or module: Add `.only` to module/test declaration (`test.only('returns a 201 response', ...)`) Then run `pnpm test` diff --git a/README.md b/README.md index 2f37714ed1a..2557ea8194a 100644 --- a/README.md +++ b/README.md @@ -462,7 +462,11 @@ First make sure to generate the host app's `dist/` output in order to support ca To run the `packages/realm-server/` workspace tests start: 1. `mise run dev` from the repo root to serve _both_ the base realm and the realm that serves the test cards for node. -2. Run `pnpm test` in the `packages/realm-server/` workspace to run the realm node tests. `TEST_MODULE=realm-endpoints-test.ts pnpm test-module` is an example of how to run a single test module. +2. Run the realm server tests: + +- `pnpm test` in the `packages/realm-server/` workspace to run the realm node tests in full (~1hr). +- `TEST_MODULES="types-endpoint-test.ts|another-test-module.ts" pnpm test` in the `packages/realm-server/` workspace to run tests for a subset of modules. +- `TEST_MODULE="types-endpoint-test.ts" pnpm test-module` in the `packages/realm-server/` workspace to run tests for a specific module. ### Boxel UI diff --git a/packages/realm-server/package.json b/packages/realm-server/package.json index 39c1f3b623d..88e39a633f8 100644 --- a/packages/realm-server/package.json +++ b/packages/realm-server/package.json @@ -98,7 +98,7 @@ "start:host-dist": "./scripts/start-host-dist.sh", "start:pg": "./scripts/start-pg.sh", "stop:pg": "./scripts/stop-pg.sh", - "test:wait-for-servers": "WAIT_ON_TIMEOUT=900000 NODE_NO_WARNINGS=1 start-server-and-test 'pnpm run wait' 'http-get://localhost:4201/base/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson' 'pnpm run wait' 'http-get://localhost:4202/node-test/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson|http://localhost:8008|http://localhost:5001' 'test-module'", + "test:wait-for-servers": "WAIT_ON_TIMEOUT=900000 NODE_NO_WARNINGS=1 start-server-and-test 'pnpm run wait' 'http-get://localhost:4201/base/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson' 'pnpm run wait' 'http-get://localhost:4202/node-test/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson|http://localhost:8008|http://localhost:5001' 'test'", "setup:base-in-deployment": "mkdir -p /persistent/base && rsync --dry-run --itemize-changes --checksum --recursive --delete ../base/. /persistent/base/ && rsync --checksum --recursive --delete ../base/. /persistent/base/", "setup:experiments-in-deployment": "mkdir -p /persistent/experiments && rsync --dry-run --itemize-changes --checksum --recursive ../experiments-realm/. /persistent/experiments/ && rsync --checksum --recursive ../experiments-realm/. /persistent/experiments/", "setup:catalog-in-deployment": "mkdir -p /persistent/catalog && rsync --dry-run --itemize-changes --checksum --recursive --delete ../catalog-realm/. /persistent/catalog/ && rsync --checksum --recursive --delete ../catalog-realm/. /persistent/catalog/", @@ -131,7 +131,6 @@ "lint:js": "eslint . --report-unused-disable-directives --cache", "lint:js:fix": "eslint . --report-unused-disable-directives --fix", "lint:glint": "glint", - "lint:test-shards": "ts-node --transpileOnly scripts/lint-test-shards.ts", "full-reset": "./scripts/full-reset.sh", "full-reindex": "./scripts/full-reindex.sh", "clear-modules-cache": "NODE_NO_WARNINGS=1 PGDATABASE=${PGDATABASE:-boxel} PGPORT=${PGPORT:-5435} ts-node --transpileOnly scripts/clear-modules-cache.ts", diff --git a/packages/realm-server/scripts/junit-reporter.js b/packages/realm-server/scripts/junit-reporter.js new file mode 100644 index 00000000000..3081188c711 --- /dev/null +++ b/packages/realm-server/scripts/junit-reporter.js @@ -0,0 +1,111 @@ +#!/usr/bin/env node +/* eslint-env node */ +'use strict'; + +// QUnit JUnit XML reporter for CI. +// +// Usage: qunit --reporter junit-reporter.js ... +// Or: qunit --require ./scripts/junit-reporter.js --reporter console ... +// +// Set JUNIT_OUTPUT_FILE to control the output path (default: junit/realm-server.xml). +// When used as a --require module, this attaches alongside the default console +// reporter so you get both terminal output and a JUnit file. + +const fs = require('node:fs'); // eslint-disable-line @typescript-eslint/no-var-requires +const path = require('node:path'); // eslint-disable-line @typescript-eslint/no-var-requires +const QUnit = require('qunit'); // eslint-disable-line @typescript-eslint/no-var-requires + +const outputFile = + process.env.JUNIT_OUTPUT_FILE || + path.join(process.cwd(), '..', '..', 'junit', 'realm-server.xml'); + +const suites = new Map(); // moduleName -> { tests, failures, errors, time, testCases } + +function escapeXml(str) { + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} + +QUnit.on('testEnd', (data) => { + const moduleName = data.module || 'default'; + const testName = data.name || 'unknown'; + const runtime = (data.runtime || 0) / 1000; // ms → seconds + const status = data.status; // passed, failed, skipped, todo + + if (!suites.has(moduleName)) { + suites.set(moduleName, { + tests: 0, + failures: 0, + errors: 0, + skipped: 0, + time: 0, + testCases: [], + }); + } + + const suite = suites.get(moduleName); + suite.tests++; + suite.time += runtime; + + let caseXml = ` { + let msg = e.message || ''; + if (e.actual !== undefined && e.expected !== undefined) { + msg += `\nExpected: ${JSON.stringify(e.expected)}\nActual: ${JSON.stringify(e.actual)}`; + } + if (e.stack) { + msg += `\n${e.stack}`; + } + return msg; + }) + .join('\n---\n'); + caseXml += `>\n ${escapeXml(messages)}\n `; + } else if (status === 'skipped' || status === 'todo') { + suite.skipped++; + caseXml += `>\n \n `; + } else { + caseXml += ` />`; + } + + suite.testCases.push(caseXml); +}); + +QUnit.on('runEnd', () => { + const suitesXml = []; + let totalTests = 0; + let totalFailures = 0; + let totalErrors = 0; + let totalSkipped = 0; + let totalTime = 0; + + for (const [name, suite] of suites) { + totalTests += suite.tests; + totalFailures += suite.failures; + totalErrors += suite.errors; + totalSkipped += suite.skipped; + totalTime += suite.time; + + suitesXml.push( + ` \n${suite.testCases.join('\n')}\n `, + ); + } + + const xml = [ + ``, + ``, + ...suitesXml, + ``, + ].join('\n'); + + const dir = path.dirname(outputFile); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(outputFile, xml, 'utf8'); +}); diff --git a/packages/realm-server/scripts/lint-test-shards.ts b/packages/realm-server/scripts/lint-test-shards.ts deleted file mode 100755 index f0df182e839..00000000000 --- a/packages/realm-server/scripts/lint-test-shards.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { readFileSync } from 'fs-extra'; -import { glob } from 'glob'; -import yaml from 'js-yaml'; -import { join } from 'path'; - -const YAML_FILE = join( - __dirname, - '..', - '..', - '..', - '.github', - 'workflows', - 'ci.yaml', -); -const TEST_DIR = join(__dirname, '..', 'tests'); - -function getCiTestModules(yamlFilePath: string) { - try { - const yamlContent = readFileSync(yamlFilePath, 'utf8'); - const yamlData = yaml.load(yamlContent) as Record; - - const shardIndexes: string[] = - yamlData?.jobs?.['realm-server-test']?.strategy?.matrix?.testModule; - - if (!Array.isArray(shardIndexes)) { - throw new Error( - `Invalid 'jobs.realm-server-test.strategy.matrix.testModule' format in the YAML file.`, - ); - } - - return shardIndexes; - } catch (error: any) { - console.error(`Error reading shardIndex from YAML file: ${error.message}`); - process.exit(1); - } -} - -function getFilesystemTestModules(testDir: string) { - try { - const files = glob.sync(`${testDir}/**/*-test.ts`, { nodir: true }); - return files.map((file: string) => file.replace(`${testDir}/`, '')); - } catch (error: any) { - console.error( - `Error reading test files from dir ${testDir}: ${error.message}`, - ); - process.exit(1); - } -} - -function validateTestFiles(yamlFilePath: string, testDir: string) { - const ciTestModules = getCiTestModules(yamlFilePath); - const filesystemTestModules = getFilesystemTestModules(testDir); - - let errorFound = false; - - for (let filename of filesystemTestModules) { - if (!ciTestModules.includes(filename)) { - console.error( - `Error: Test file '${filename}' exists in the filesystem but not in the ${yamlFilePath} file.`, - ); - errorFound = true; - } - } - for (let filename of ciTestModules) { - if (!filesystemTestModules.includes(filename)) { - console.error( - `Error: Test file '${filename}' exists in the YAML file but not in the filesystem.`, - ); - errorFound = true; - } - } - - if (errorFound) { - process.exit(1); - } else { - console.log( - `All test files are accounted for in the ${yamlFilePath} file for the realm-server matrix strategy.`, - ); - } -} - -validateTestFiles(YAML_FILE, TEST_DIR); diff --git a/packages/realm-server/scripts/run-test-modules.js b/packages/realm-server/scripts/run-test-modules.js new file mode 100644 index 00000000000..9d3d2246865 --- /dev/null +++ b/packages/realm-server/scripts/run-test-modules.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node +/* eslint-env node */ +'use strict'; + +const { spawnSync } = require('node:child_process'); // eslint-disable-line @typescript-eslint/no-var-requires + +function buildModuleFilter(modulesToMatch) { + const escaped = modulesToMatch + .map((moduleName) => escapeRegex(moduleName)) + .join('|'); + const pattern = `^(?:${escaped})(?:\\s>\\s|:)`; + return `/${pattern}/`; +} + +function escapeRegex(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\//g, '\\/'); +} + +const rawModules = process.env.TEST_MODULES ?? ''; +const cleanedRaw = rawModules.trim(); + +if (!cleanedRaw) { + console.error('TEST_MODULES must be set.'); + process.exit(1); +} + +const modules = cleanedRaw + .split(/[|,]/) + .map((value) => value.trim()) + .filter(Boolean) + .map((value) => value.replace(/^['"]+|['"]+$/g, '')); + +if (modules.length === 0) { + console.error('No module names found in TEST_MODULES.'); + process.exit(1); +} + +const args = ['--require', 'ts-node/register/transpile-only']; + +args.push('--filter', buildModuleFilter(modules)); + +args.push('tests/index.ts'); + +const qunitBin = require.resolve('qunit/bin/qunit.js'); +const result = spawnSync(process.execPath, [qunitBin, ...args], { + stdio: 'inherit', + env: process.env, +}); + +if (typeof result.status === 'number') { + process.exit(result.status); +} + +if (result.error) { + console.error(result.error); +} + +process.exit(1); diff --git a/packages/realm-server/scripts/shard-test-modules.js b/packages/realm-server/scripts/shard-test-modules.js new file mode 100644 index 00000000000..7eaeb1124c5 --- /dev/null +++ b/packages/realm-server/scripts/shard-test-modules.js @@ -0,0 +1,53 @@ +#!/usr/bin/env node +/* eslint-env node */ +'use strict'; + +// Discovers all *-test.ts files under tests/ and outputs the subset assigned +// to the requested shard (1-based). Files are sorted alphabetically and +// distributed round-robin so every shard gets a roughly equal share. +// +// Usage: node shard-test-modules.js +// Output: module names joined by "|", suitable for TEST_MODULES. + +const fs = require('node:fs'); // eslint-disable-line @typescript-eslint/no-var-requires +const path = require('node:path'); // eslint-disable-line @typescript-eslint/no-var-requires + +const shard = parseInt(process.argv[2], 10); +const totalShards = parseInt(process.argv[3], 10); + +if (!shard || !totalShards || shard < 1 || shard > totalShards) { + console.error( + `Usage: shard-test-modules.js (got shard=${process.argv[2]}, totalShards=${process.argv[3]})`, + ); + process.exit(1); +} + +const testsDir = path.resolve(__dirname, '..', 'tests'); + +function collectTestModules(dir, prefix) { + let modules = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const relative = prefix ? `${prefix}/${entry.name}` : entry.name; + if (entry.isDirectory()) { + modules = modules.concat( + collectTestModules(path.join(dir, entry.name), relative), + ); + } else if (entry.isFile() && entry.name.endsWith('-test.ts')) { + modules.push(relative); + } + } + return modules; +} + +const allModules = collectTestModules(testsDir, '').sort(); + +const shardModules = allModules.filter( + (_, index) => (index % totalShards) + 1 === shard, +); + +if (shardModules.length === 0) { + console.error(`Shard ${shard}/${totalShards} has no test modules.`); + process.exit(1); +} + +process.stdout.write(shardModules.join('|')); diff --git a/packages/realm-server/tests/index.ts b/packages/realm-server/tests/index.ts index 61e5f187df4..623b331c7b6 100644 --- a/packages/realm-server/tests/index.ts +++ b/packages/realm-server/tests/index.ts @@ -30,6 +30,21 @@ import * as ContentTagGlobal from 'content-tag'; import QUnit from 'qunit'; QUnit.config.testTimeout = 60000; +const testModules = process.env.TEST_MODULES?.trim(); + +if (testModules) { + const modules = parseModules(testModules); + if (modules.length > 0) { + QUnit.config.filter = buildModuleFilter(modules); + console.log( + `Filtering tests to modules from TEST_MODULES: ${modules.join(', ')}`, + ); + } else { + console.warn( + 'TEST_MODULES was provided but no module names were parsed. Running full suite.', + ); + } +} // Cleanup here ensures lingering servers/prerenderers/queues don't keep the // Node event loop alive after tests finish. @@ -185,3 +200,21 @@ import './sanitize-head-html-test'; import './node-realm-test'; import './session-room-queries-test'; import './indexing-event-sink-test'; + +function parseModules(value: string): string[] { + return value + .split(/[|,]/) + .map((entry) => entry.trim()) + .filter(Boolean) + .map((entry) => entry.replace(/^['"]+|['"]+$/g, '')); +} + +function buildModuleFilter(modulesToMatch: string[]): string { + const escaped = modulesToMatch.map((moduleName) => escapeRegex(moduleName)); + const pattern = `^(?:${escaped.join('|')})(?:\\s>\\s|:)`; + return `/${pattern}/`; +} + +function escapeRegex(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\//g, '\\/'); +} diff --git a/packages/realm-server/tests/indexing-test.ts b/packages/realm-server/tests/indexing-test.ts index ae92c35c415..5d620c595ce 100644 --- a/packages/realm-server/tests/indexing-test.ts +++ b/packages/realm-server/tests/indexing-test.ts @@ -1469,6 +1469,11 @@ module(basename(__filename), function () { { clientRequestId: 'burst-2' }, ); + let expectedUrls = [ + `${testRealm}mango`, + `${testRealm}post-1`, + `${testRealm}vangogh`, + ]; let row = (await waitUntil( async () => { let rows = (await testDbAdapter.execute( @@ -1485,13 +1490,19 @@ module(basename(__filename), function () { changes: { url: string; operation: 'update' | 'delete' }[]; }; }[]; - return rows.length === 1 ? rows[0] : undefined; + if (rows.length !== 1) { + return undefined; + } + let urls = rows[0].args.changes + .map((change) => change.url) + .sort(); + return urls.length === expectedUrls.length ? rows[0] : undefined; }, { timeout: 3000, interval: 50, timeoutMessage: - 'expected exactly one pending incremental canonical job', + 'expected exactly one pending incremental canonical job with all coalesced URLs', }, )) as { id: number; @@ -1504,7 +1515,7 @@ module(basename(__filename), function () { let urls = row.args.changes.map((change) => change.url).sort(); assert.deepEqual( urls, - [`${testRealm}mango`, `${testRealm}post-1`, `${testRealm}vangogh`], + expectedUrls, 'pending canonical incremental args include union of burst invalidations', ); assert.strictEqual( diff --git a/packages/realm-server/tests/scripts/run-qunit-with-test-pg.sh b/packages/realm-server/tests/scripts/run-qunit-with-test-pg.sh index 4ef285c291e..1c41f9c8d8b 100755 --- a/packages/realm-server/tests/scripts/run-qunit-with-test-pg.sh +++ b/packages/realm-server/tests/scripts/run-qunit-with-test-pg.sh @@ -14,9 +14,14 @@ else EFFECTIVE_LOG_LEVELS="$BASE_LOG_LEVELS" fi +JUNIT_REPORTER_ARGS="" +if [ -n "${JUNIT_OUTPUT_FILE-}" ]; then + JUNIT_REPORTER_ARGS="--require ${SCRIPT_DIR}/../../scripts/junit-reporter.js" +fi + LOG_LEVELS="$EFFECTIVE_LOG_LEVELS" \ NODE_NO_WARNINGS=1 \ PGPORT=55436 \ STRIPE_WEBHOOK_SECRET=stripe-webhook-secret \ STRIPE_API_KEY=stripe-api-key \ -qunit --require ts-node/register/transpile-only "$@" tests/index.ts +qunit --require ts-node/register/transpile-only $JUNIT_REPORTER_ARGS "$@" tests/index.ts