Skip to content

Optimise core UI test scope#238

Merged
eviltester merged 5 commits into
masterfrom
237-optimise-core-ui-tests
Jun 22, 2026
Merged

Optimise core UI test scope#238
eviltester merged 5 commits into
masterfrom
237-optimise-core-ui-tests

Conversation

@eviltester

@eviltester eviltester commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • reduce the hot core-ui Jest suites by splitting generator tests into mounted smoke, runtime, and text-mode scopes
  • move barrel/contract assertions into focused no-DOM tests and keep shared-schema behavior at the shared-schema seam
  • remove the Tabulator performance benchmark test from the default codebase and trim default Jest worker usage to 75%
  • add lifecycle coverage to protect destroy/remount cleanup after reducing mount depth

Testing

  • pnpm run test:ui:jest
  • pnpm run verify:ui
  • pnpm run verify:local

Closes #237

Summary by CodeRabbit

  • Tests
    • Added Jest suites for generator page runtime/text-mode flows and expanded shared schema definition coverage (including destroy/timer cleanup).
    • Added contract tests to validate public module surface exports for core UI components.
    • Introduced a microtask-based waiting helper and migrated relevant async assertions; removed redundant generator/schema tests and deleted the Tabulator performance benchmark test.
  • CI / Automation
    • Updated Node.js CI to split unit vs workspace tests, added test toolchain dependency checks, adjusted job gating, and set persist-credentials: false for multiple steps.
    • Updated Jest scripts to run with --maxWorkers=75% and removed the benchmark:tabulator script.

Copilot AI review requested due to automatic review settings June 22, 2026 13:02
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Jest scripts gain --maxWorkers=75% parallelism; the benchmark script and its test file are removed. A new waitForMicrotaskAssertions helper replaces waitFor across import-export and shared-schema tests. The large data-generator-page.test.js is split into dedicated runtime and text-mode files, and new contract tests assert public barrel exports. CI workflows separate unit and workspace tests into distinct jobs and disable credential persistence globally.

Changes

Test Suite Optimization

Layer / File(s) Summary
Jest parallelism config and benchmark removal
package.json, packages/core-ui/src/tests/grid/tabulator-performance.benchmark.test.js
Adds --maxWorkers=75% to test, testverbose, testcoverage, and test:ui:jest scripts; removes the benchmark:tabulator script entry and deletes the benchmark test file entirely.
waitForMicrotaskAssertions helper
packages/core-ui/src/tests/helpers/wait-for-microtasks.js
Introduces an async helper that repeatedly awaits microtask checkpoints, returning on the first successful assertions execution and throwing the last captured error after maxMicrotasks iterations.
New public barrel contract tests
packages/core-ui/src/tests/app/import-export-workspace.contract.test.js, packages/core-ui/src/tests/shared/shared-schema-definition.contract.test.js
Adds contract test suites verifying that import-export-workspace and shared-schema-definition barrels expose only their component factory functions, with controller/view and internal test-data symbols absent.
import-export-workspace test migration
packages/core-ui/src/tests/app/import-export-workspace.test.js
Replaces all waitFor-based async assertions with waitForMicrotaskAssertions blocks across import/export/clipboard/file/trim-settings scenarios; removes the inlined barrel-export assertion and its namespace import.
shared-schema-definition-view test updates and expansion
packages/core-ui/src/tests/shared/shared-schema-definition-view.test.js
Switches waitFor to waitForMicrotaskAssertions in existing file-load tests, adds ...props override support to the test helper, and introduces new test cases for comment/blank-line round-trips, hash-prefixed rule parsing, domain command mapping, row reordering, and destroy/remount lifecycle.
New data-generator-page runtime test file
packages/core-ui/src/tests/generator/data-generator-page.runtime.test.js
Introduces a dedicated runtime test file with fakes for Tabulator/grid/exporter/download and tests covering schema-rule mapping, validation, constructor without global document, facade API surface, output-type fallback, format-state resync, pairwise visibility, and runtime actions/state bridge delegation.
New data-generator-page text-mode test file
packages/core-ui/src/tests/generator/data-generator-page.text-mode.test.js
Introduces a dedicated text-mode test file covering schema↔text toggle round-trips, row/caret preservation, tooltip/help behavior, direct parser and generation-from-text flows, fake-timer error clearing, schema runtime bridge routing, and destroy/remount lifecycle.
data-generator-page.test.js cleanup
packages/core-ui/src/tests/generator/data-generator-page.test.js
Removes imports, helper setup, and all test blocks migrated to the new runtime and text-mode files, including schema-rule helpers, uninitialized page API, format-state resync, runtime actions bridge, and all schema editor/text-toggle flows.

CI Workflow Infrastructure

Layer / File(s) Summary
Unit and workspace test job separation
.github/workflows/node.js.yml
Renames the combined job to unit-tests running only pnpm test, creates a new workspace-tests job running pnpm run test:workspaces with Jest/JSDOM toolchain verification, and updates both verify-ci and verify-ci-main gate workflows to require the workspace-tests job.
Disable credential persistence across checkout steps
.github/workflows/node.js.yml
Adds persist-credentials: false to actions/checkout steps in checks, coverage, storybook, browser, api-tests, cross-language-toolchain, and docker-smoke jobs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Possibly related PRs

  • eviltester/grid-table-editor#206: The main PR's updates to shared-schema-definition-view.test.js add/adjust coverage for the "edit params" guided params dialog and its controller/modal/UI flow, directly corresponding to the retrieved PR's guided params editor implementation.
  • eviltester/grid-table-editor#213: The main PR updates shared-schema-definition test coverage to assert new schema file load/save UI and behaviors with microtask-based waiting, which directly matches the retrieved PR's production implementation of schema file transfer services and controller/view methods.

Poem

🐇 Hopping through the test lanes fast,
No more benchmarks weighing down the past!
Microtasks await in tidy rows,
waitForMicrotaskAssertions — off it goes!
Split the files, trim the wait,
Speedy suites — now that's great! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Optimise core UI test scope' directly reflects the main objective of restructuring and optimizing the core-ui test suite by reorganizing test scope and removing redundant tests.
Linked Issues check ✅ Passed The PR addresses issue #237's objective to optimize core-ui tests for speed through test restructuring, worker optimization, and removal of performance benchmarks.
Out of Scope Changes check ✅ Passed All changes are directly related to test optimization: generator test restructuring, barrel/contract assertions, benchmark removal, Jest worker adjustment, and workflow updates for test execution.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 237-optimise-core-ui-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR reduces the hot core-ui Jest suite by splitting a monolithic generator test file into three focused scopes (smoke/runtime/text-mode), moves barrel contract assertions into lightweight no-DOM files, replaces the old fixed-iteration flushAsyncWork(N) pattern with a shared waitForMicrotaskAssertions retry helper, removes the Tabulator performance benchmark from the default run, and parallelises the CI by splitting the combined "Unit and Workspace Tests" job into two independent jobs.

  • New test files: data-generator-page.runtime.test.js (schema helpers + uninitialized API), data-generator-page.text-mode.test.js (toggle/lifecycle flows), and two contract tests that assert public barrels expose only the factory function.
  • waitForMicrotaskAssertions improves on the old fixed-tick flush by retrying up to 12 microtask ticks until assertions pass; all async tests in import-export-workspace.test.js and shared-schema-definition-view.test.js are migrated to it.
  • CI workflow: persist-credentials: false added to all checkout steps, new workspace-tests job added to both verify-ci and verify-ci-main gate aggregates.

Confidence Score: 5/5

Safe to merge — changes are test-only and CI configuration; no production source files are touched.

The PR reorganises test files and CI jobs without modifying any production code. The new waitForMicrotaskAssertions helper is correct for all current synchronous callers. The helper's try/catch would silently skip retries for a future async callback, but a one-line await fix is available and no async callers exist today.

packages/core-ui/src/tests/helpers/wait-for-microtasks.js — consider await assertions() to keep the retry logic intact if async callbacks are added in the future.

Important Files Changed

Filename Overview
packages/core-ui/src/tests/helpers/wait-for-microtasks.js New shared async helper using a polling loop; retry logic works correctly for synchronous assertion callbacks but silently bypasses retries if an async callback is passed
packages/core-ui/src/tests/generator/data-generator-page.runtime.test.js New focused no-DOM test suite for schema helper and uninitialized page API; test isolation is handled via beforeEach reassignment
packages/core-ui/src/tests/generator/data-generator-page.text-mode.test.js New mounted DOM test suite covering text/schema mode toggle flows and lifecycle (destroy/remount); cleanup is correct with delete of globals in afterEach
packages/core-ui/src/tests/app/import-export-workspace.test.js Updated to use the new waitForMicrotaskAssertions helper; all async tests migrated correctly
packages/core-ui/src/tests/shared/shared-schema-definition-view.test.js Updated to use waitForMicrotaskAssertions for async schema file load/error tests; adds destroy/timer-cleanup lifecycle test
.github/workflows/node.js.yml Splits the old combined job into parallel unit-tests and workspace-tests jobs; adds persist-credentials: false to all checkout steps; updates verify-ci and verify-ci-main gates
package.json Adds --maxWorkers=75% to test scripts; removes the benchmark:tabulator script

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before["Before"]
        A["data-generator-page.test.js\n(schema helpers + mounted UI + text-mode)"]
        B["import-export-workspace.test.js\n(flushAsyncWork fixed-tick)"]
        C["shared-schema-definition-view.test.js\n(flushAsyncWork fixed-tick)"]
    end
    subgraph After["After"]
        D["data-generator-page.runtime.test.js\n(no DOM)"]
        E["data-generator-page.test.js\n(mounted smoke)"]
        F["data-generator-page.text-mode.test.js\n(mounted toggle/lifecycle)"]
        G["import-export-workspace.contract.test.js\n(barrel — no DOM)"]
        H["import-export-workspace.test.js\n(waitForMicrotaskAssertions)"]
        I["shared-schema-definition.contract.test.js\n(barrel — no DOM)"]
        J["shared-schema-definition-view.test.js\n(waitForMicrotaskAssertions)"]
        K["helpers/wait-for-microtasks.js"]
        H --> K
        J --> K
    end
    subgraph CI["CI"]
        L["unit-tests"]
        M["workspace-tests"]
        N["verify-ci gate"]
        L --> N
        M --> N
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph Before["Before"]
        A["data-generator-page.test.js\n(schema helpers + mounted UI + text-mode)"]
        B["import-export-workspace.test.js\n(flushAsyncWork fixed-tick)"]
        C["shared-schema-definition-view.test.js\n(flushAsyncWork fixed-tick)"]
    end
    subgraph After["After"]
        D["data-generator-page.runtime.test.js\n(no DOM)"]
        E["data-generator-page.test.js\n(mounted smoke)"]
        F["data-generator-page.text-mode.test.js\n(mounted toggle/lifecycle)"]
        G["import-export-workspace.contract.test.js\n(barrel — no DOM)"]
        H["import-export-workspace.test.js\n(waitForMicrotaskAssertions)"]
        I["shared-schema-definition.contract.test.js\n(barrel — no DOM)"]
        J["shared-schema-definition-view.test.js\n(waitForMicrotaskAssertions)"]
        K["helpers/wait-for-microtasks.js"]
        H --> K
        J --> K
    end
    subgraph CI["CI"]
        L["unit-tests"]
        M["workspace-tests"]
        N["verify-ci gate"]
        L --> N
        M --> N
    end
Loading

Reviews (6): Last reviewed commit: "Harden CI checkout credentials" | Re-trigger Greptile

Comment thread packages/core-ui/src/tests/app/import-export-workspace.test.js Outdated

@eviltester eviltester left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Review: Optimise core UI test scope

I found no bugs, but have a few observations.


fireEvent.change(fileInput);
await waitFor(() => {
await waitForMicrotaskAssertions(() => {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Potential timing change: assertions that were previously split between inside and outside waitFor/flushAsyncWork are now all consolidated inside a single waitForMicrotaskAssertions callback. This means every assertion must pass in the same polling iteration. If any chain requires intermediate synchronous side-effects (assertion A must pass before the code that triggers assertion B), this consolidated form could fail where the old code passed. Consider whether any of these converted sites rely on that interleaving.

This also applies to similar consolidations in import-export-workspace.test.js.

});

test('default validation errors surface inline and do not throw', () => {
const page = createMountedPage({

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Inconsistent cleanup: afterEach only calls dom.window.close() but does not clean up global.document and global.window. Compare with shared-schema-definition-view.test.js which explicitly deletes these globals. Since beforeEach unconditionally reassigns them, cross-test contamination is unlikely, but if a test failure prevents beforeEach from running in a subsequent test, stale global references to a closed JSDOM window could cause confusing errors.

@@ -0,0 +1,467 @@
import { jest } from '@jest/globals';
import { JSDOM } from 'jsdom';
import { faker } from '@faker-js/faker';

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Default faker/RandExp imports add weight: createMountedPage defaults use real faker and RandExp. Most tests override these with mocks via the overrides parameter, making the real imports unnecessary for the majority of tests. Consider making the defaults use stubs and only pass real faker/RandExp in the subset of tests that exercise domain/faker command resolution.

throw lastError;
}

return assertions();

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Dead code: When all maxMicrotasks iterations throw, lastError is set, the if (lastError) branch fires, and this return assertions() is unreachable. It is only reached if maxMicrotasks === 0 (loop never runs). Consider either removing the trailing call or documenting it as a safety net for the zero-iteration edge case.

@eviltester eviltester left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Review: Optimise core UI test scope

I found no bugs, but have a few observations.


fireEvent.change(fileInput);
await waitFor(() => {
await waitForMicrotaskAssertions(() => {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Potential timing change: assertions that were previously split between inside and outside waitFor/flushAsyncWork are now all consolidated inside a single waitForMicrotaskAssertions callback. This means every assertion must pass in the same polling iteration. If any chain requires intermediate synchronous side-effects (assertion A must pass before the code that triggers assertion B), this consolidated form could fail where the old code passed. Consider whether any of these converted sites rely on that interleaving.

This also applies to similar consolidations in import-export-workspace.test.js.

});

test('default validation errors surface inline and do not throw', () => {
const page = createMountedPage({

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Inconsistent cleanup: afterEach only calls dom.window.close() but does not clean up global.document and global.window. Compare with shared-schema-definition-view.test.js which explicitly deletes these globals. Since beforeEach unconditionally reassigns them, cross-test contamination is unlikely, but if a test failure prevents beforeEach from running in a subsequent test, stale global references to a closed JSDOM window could cause confusing errors.

@@ -0,0 +1,467 @@
import { jest } from '@jest/globals';
import { JSDOM } from 'jsdom';
import { faker } from '@faker-js/faker';

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Default faker/RandExp imports add weight: createMountedPage defaults use real faker and RandExp. Most tests override these with mocks via the overrides parameter, making the real imports unnecessary for the majority of tests. Consider making the defaults use stubs and only pass real faker/RandExp in the subset of tests that exercise domain/faker command resolution.

throw lastError;
}

return assertions();

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Dead code: When all maxMicrotasks iterations throw, lastError is set, the if (lastError) branch fires, and this return assertions() is unreachable. It is only reached if maxMicrotasks === 0 (loop never runs). Consider either removing the trailing call or documenting it as a safety net for the zero-iteration edge case.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/node.js.yml (1)

60-60: ⚠️ Potential issue | 🟠 Major

Disable credential persistence in checkout steps.

Both checkout steps on Line 60 and Line 94 are missing persist-credentials: false. Credentials persist in local git config by default, increasing token-exposure risk during dependency installation steps that may execute arbitrary lifecycle scripts.

Suggested fix
       - name: Check out repository
         uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+        with:
+          persist-credentials: false

Apply to both occurrences.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/node.js.yml at line 60, The actions/checkout action is
missing the persist-credentials configuration option in both checkout steps,
which allows git credentials to remain in the local git config and increases
token exposure risk during dependency installation. Add the parameter
persist-credentials: false to both occurrences of the actions/checkout action to
prevent credentials from being persisted in the local git configuration after
the checkout completes.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/node.js.yml:
- Line 60: The actions/checkout action is missing the persist-credentials
configuration option in both checkout steps, which allows git credentials to
remain in the local git config and increases token exposure risk during
dependency installation. Add the parameter persist-credentials: false to both
occurrences of the actions/checkout action to prevent credentials from being
persisted in the local git configuration after the checkout completes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 04c60f02-5a2c-4ca7-8e82-26982b2cf4c5

📥 Commits

Reviewing files that changed from the base of the PR and between a03f7d1 and 7f95d17.

📒 Files selected for processing (4)
  • .github/workflows/node.js.yml
  • packages/core-ui/src/tests/generator/data-generator-page.runtime.test.js
  • packages/core-ui/src/tests/generator/data-generator-page.text-mode.test.js
  • packages/core-ui/src/tests/helpers/wait-for-microtasks.js
💤 Files with no reviewable changes (1)
  • packages/core-ui/src/tests/helpers/wait-for-microtasks.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core-ui/src/tests/generator/data-generator-page.runtime.test.js
  • packages/core-ui/src/tests/generator/data-generator-page.text-mode.test.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/node.js.yml (1)

90-124: 📐 Maintainability & Code Quality | 🟠 Major

Gate jobs must include workspace-tests in their needs lists.

The new workspace-tests job is cleanly structured and runs in parallel with unit-tests. However, the verify-ci and verify-ci-main gate jobs (lines 283–289 and 298–304) currently list only checks and unit-tests in their needs arrays. They must also include workspace-tests to ensure workspace test failures block merges.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/node.js.yml around lines 90 - 124, The gate jobs verify-ci
and verify-ci-main do not include the new workspace-tests job in their needs
arrays, which means workspace test failures will not block merges. Locate the
verify-ci job (around line 283) and the verify-ci-main job (around line 298),
and update their respective needs arrays to include workspace-tests alongside
the existing checks and unit-tests dependencies to ensure workspace test
failures properly gate pull request merges.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/node.js.yml:
- Around line 90-124: The gate jobs verify-ci and verify-ci-main do not include
the new workspace-tests job in their needs arrays, which means workspace test
failures will not block merges. Locate the verify-ci job (around line 283) and
the verify-ci-main job (around line 298), and update their respective needs
arrays to include workspace-tests alongside the existing checks and unit-tests
dependencies to ensure workspace test failures properly gate pull request
merges.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 230c8629-b416-47f1-b5df-c5db292e8ca7

📥 Commits

Reviewing files that changed from the base of the PR and between 7f95d17 and a2c7186.

📒 Files selected for processing (1)
  • .github/workflows/node.js.yml

@eviltester

Copy link
Copy Markdown
Owner Author

closes #237

@eviltester eviltester closed this Jun 22, 2026
@eviltester eviltester reopened this Jun 22, 2026
@eviltester eviltester merged commit 32e6729 into master Jun 22, 2026
24 checks passed
@eviltester eviltester deleted the 237-optimise-core-ui-tests branch June 22, 2026 22:25
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.

optimise core-ui tests for speed

2 participants