Skip to content

feat: improve test & bundler#14434

Merged
darkskygit merged 8 commits intocanaryfrom
darksky/improve-test-and-bundle
Feb 14, 2026
Merged

feat: improve test & bundler#14434
darkskygit merged 8 commits intocanaryfrom
darksky/improve-test-and-bundle

Conversation

@darkskygit
Copy link
Member

@darkskygit darkskygit commented Feb 13, 2026

PR Dependency Tree

This tree was auto-generated by Charcoal

Summary by CodeRabbit

  • New Features

    • Introduced rspack bundler as an alternative to webpack for optimized builds.
  • Tests & Quality

    • Added comprehensive editor semantic tests covering markdown, hotkeys, and slash-menu operations.
    • Expanded CI cross-browser testing to Chromium, Firefox, and WebKit; improved shape-rendering tests to account for zoom.
  • Bug Fixes

    • Corrected CSS overlay styling for development servers.
    • Fixed TypeScript typings for build tooling.
  • Other

    • Document duplication now produces consistent "(n)" suffixes.
    • French i18n completeness increased to 100%.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds rspack as a supported bundler alongside webpack, refactors bundling CLI and dev server paths, consolidates CI cross‑browser testing into a unified platform, extracts route and title-duplication helpers, centralizes workspace ID utilities, and adds/updates multiple integration tests and type/css tweaks.

Changes

Cohort / File(s) Summary
CI/CD Workflow Modernization
.github/workflows/build-test.yml
Consolidates E2E cross-browser testing to a single playwright-platform value (chromium,firefox,webkit) and unified artifact naming; adds a new bundler-matrix job (ubuntu-24.04-arm) to run builds for webpack and rspack and upload per-bundler timing artifacts.
Browser Testing & Tests
blocksuite/integration-test/vitest.config.ts, blocksuite/integration-test/src/__tests__/main/editor-semantics.spec.ts, blocksuite/integration-test/src/__tests__/edgeless/shape-dom.spec.ts, tests/kit/src/utils/load-page.ts
Expands Vitest Playwright browsers to Chromium/Firefox/WebKit; adds a comprehensive editor-semantics integration test; updates shape-dom assertions to be zoom-aware; defers expect import to runtime in load-page util.
Rspack Bundler Integration (CLI)
tools/cli/package.json, tools/cli/src/bundler.ts, tools/cli/src/bundle.ts, tools/cli/src/rspack/index.ts, tools/cli/src/bundle-shared.ts, tools/cli/src/webpack/html-plugin.ts
Implements dual-bundler architecture (webpack + rspack): adds bundler selection helpers, default/bundler-specific build/dev functions, extensive rspack config builders (HTML/Worker/Node), shared dev-server defaults, and webpack plugin typing abstraction for cross-bundler compatibility.
Routing & Paths
packages/frontend/core/src/desktop/route-paths.ts, packages/frontend/core/src/desktop/router.tsx
Extracts route constants and getWorkspaceDocPath; updates router to use constants and helper for redirects instead of inline path strings.
Document Duplication
packages/frontend/core/src/modules/doc/services/docs.ts, packages/frontend/core/src/modules/doc/services/duplicate-title.ts
Moves document title-duplication logic into getDuplicatedDocTitle helper and replaces inline title parsing in DocsService duplicate flows.
Workspace ID Utilities
packages/frontend/core/src/modules/workspace-engine/impls/local.ts, packages/frontend/core/src/modules/workspace-engine/impls/workspace-id-utils.ts
Adds normalizeWorkspaceIds and dedupeWorkspaceIds utilities and replaces manual dedupe/normalization logic in local workspace engine implementation.
Types, CSS, Small Edits
packages/frontend/core/src/types/types.d.ts, packages/frontend/apps/electron-renderer/src/app/global.css, packages/frontend/i18n/src/i18n-completenesses.json
Fixes triple-slash references to include @rspack/core/module; extends CSS selector to target #rspack-dev-server-client-overlay; updates French i18n completeness from 98 → 100.
Misc Tests & Helpers
blocksuite/integration-test/src/__tests__/main/editor-semantics.spec.ts, blocksuite/integration-test/src/__tests__/edgeless/shape-dom.spec.ts
Adds/updates integration tests: new editor semantics test and pixel-tolerant assertions using viewport zoom for DOM shape checks.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Dev as Developer CLI
participant CLI as tools/cli
participant Bundler as Bundler Selector
participant Webpack as Webpack
participant Rspack as Rspack
participant DevServer as DevServer
Dev->>CLI: run build/dev command (pkg, optional bundler)
CLI->>Bundler: getBundler(env) / normalizeBundler
Bundler-->>CLI: selected bundler (webpack | rspack)
CLI->>Webpack: buildWithWebpack / devWithWebpack (if webpack)
CLI->>Rspack: buildWithRspack / devWithRspack (if rspack)
Webpack->>DevServer: start webpack-dev-server (uses DEFAULT_DEV_SERVER_CONFIG)
Rspack->>DevServer: start rspack-dev-server (uses DEFAULT_DEV_SERVER_CONFIG)
DevServer-->>Dev: serve assets / hot reload

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐰 A nimble rabbit hops through code and test,
Two bundlers now dance where one once rest,
Browsers line up — Chromium, Firefox, WebKit,
Routes and titles tidy, IDs kept fit,
CI hums, builds report — a hopping, tidy quest. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
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.
Title check ❓ Inconclusive The title 'feat: improve test & bundler' is vague and does not clearly summarize the main changes in the changeset, which include cross-browser testing consolidation, rspack bundler integration, test infrastructure improvements, and multiple related refactorings. Consider a more specific title that highlights key changes, such as 'feat: consolidate cross-browser testing and add rspack bundler support' or break into more granular commits with focused titles.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into canary

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch darksky/improve-test-and-bundle

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 and usage tips.

@github-actions github-actions bot added mod:dev test Related to test cases app:core labels Feb 13, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (2)
.github/workflows/build-test.yml (1)

1345-1380: ⚠️ Potential issue | 🟡 Minor

Add bundler-matrix to the test-done job's needs array, or document why it's intentionally excluded.

The test-done job does not list bundler-matrix in its needs array, meaning bundler-matrix failures won't block PR merges. If this is intentional (e.g., rspack support is experimental), add a comment explaining the exclusion. Otherwise, add bundler-matrix to the needs list.

tools/cli/src/bundle.ts (1)

235-263: ⚠️ Potential issue | 🟠 Major

buildWithWebpack is async but compiler.run() uses a callback—the returned promise resolves before the build completes.

await BundleCommand.build(pkg) in execute() resolves immediately, not when the build finishes. Additionally, compiler.close() is never called after run(), which is required by webpack to allow plugins to clean up.

The same issue exists in buildWithRspack (lines 318–349).

Suggested fix (wrap in a promise and close the compiler)
 static async buildWithWebpack(pkg: Package) {
   process.env.NODE_ENV = 'production';
   const logger = new Logger('bundle');
   logger.info(`Packing package ${pkg.name} with webpack...`);
   logger.info('Cleaning old output...');
   rmSync(pkg.distPath.value, { recursive: true, force: true });

   const config = getWebpackBundleConfigs(pkg);
   config.parallelism = cpus().length;

   const compiler = webpack(config);
   if (!compiler) {
     throw new Error('Failed to create webpack compiler');
   }

-  compiler.run((error, stats) => {
-    if (error) {
-      console.error(error);
-      process.exit(1);
-    }
-    if (stats) {
-      if (stats.hasErrors()) {
-        console.error(stats.toString('errors-only'));
-        process.exit(1);
-      } else {
-        console.log(stats.toString('minimal'));
+  return new Promise<void>((resolve, reject) => {
+    compiler.run((error, stats) => {
+      if (error) {
+        compiler.close(() => {});
+        reject(error);
+        return;
       }
-    }
+      if (stats?.hasErrors()) {
+        console.error(stats.toString('errors-only'));
+        compiler.close(() => {});
+        reject(new Error('Build failed with errors'));
+        return;
+      }
+      if (stats) {
+        console.log(stats.toString('minimal'));
+      }
+      compiler.close(closeErr => {
+        if (closeErr) reject(closeErr);
+        else resolve();
+      });
+    });
   });
 }
🤖 Fix all issues with AI agents
In @.github/workflows/build-test.yml:
- Around line 226-231: The BROWSER environment variable in the "Run playwright
tests" step references a matrix variable that no longer exists in the job
definition, causing it to resolve to an empty string. Either remove the BROWSER
environment variable from this step entirely if the tests no longer need it, or
replace the empty matrix.browser reference with an explicit browser value if the
BROWSER variable is still required by the test code.

In `@tools/cli/src/bundle.ts`:
- Around line 273-278: The unsafe cast occurs in the rspack→webpack fallback
path: when bundler === 'rspack' but !isRspackSupportedPackageName(pkg.name) we
call BundleCommand.devWithWebpack(pkg, devServerConfig as
WebpackDevServerConfiguration) which can pass an RspackDevServerConfiguration to
webpack. Fix by removing the unsafe cast: call BundleCommand.devWithWebpack(pkg)
(omit devServerConfig) and add a clear warning (e.g., logger.warn or
console.warn) right before the fallback that the requested 'rspack' bundler is
unsupported for this package and webpack is being used instead; modify the
branch containing bundler, isRspackSupportedPackageName, and the
BundleCommand.devWithWebpack call accordingly.

In `@tools/cli/src/rspack/index.ts`:
- Around line 10-11: Update the rspack integration to enforce or document
minimum compatible versions and a dev split-chunks workaround: check/validate
that Rspack is >=0.3.3 when using sentryWebpackPlugin and ensure
`@sentry/webpack-plugin` is >=1.20.1 before registering sentryWebpackPlugin;
likewise note/vet the `@vanilla-extract/webpack-plugin` usage and add a
development-time configuration or guard to avoid using splitChunks with
VanillaExtractPlugin (or provide a dedicated chunk-splitting config) to avoid
HMR issues. Locate the plugin registrations for sentryWebpackPlugin and
VanillaExtractPlugin and add runtime/version checks or clear comments and a
conditional config branch that applies split-chunks only when safe.
- Around line 225-232: The plugins array currently passes
require(pkg.join('tailwind.config.js').value) as an option to the
'@tailwindcss/postcss' plugin (see the plugins: [...] block and the
pkg.join('tailwind.config.js').exists() check); update this so the
'@tailwindcss/postcss' entry is configured with an empty object (i.e., plugin
tuple becomes ['@tailwindcss/postcss', {}]) instead of passing the JS config,
and ensure any Tailwind configuration is loaded via the CSS `@config` directive
(e.g., add documentation or comments to instruct using '@config
"./tailwind.config.js";' in the CSS entry) rather than supplying the config as
the PostCSS plugin option.
🧹 Nitpick comments (6)
packages/frontend/core/src/desktop/router.tsx (1)

123-141: Inconsistent URL construction in /template/preview loader.

Line 134 still manually constructs /workspace/${workspaceId}/${docId} instead of reusing getWorkspaceDocPath. Consider using it here too for consistency:

Suggested change
          return redirect(
-            `/workspace/${workspaceId}/${docId}?${new URLSearchParams({
+            `${getWorkspaceDocPath(workspaceId ?? '', docId ?? '')}?${new URLSearchParams({
               isTemplate: 'true',
packages/frontend/core/src/modules/workspace-engine/impls/local.ts (1)

167-174: Double deduplication is harmless but redundant.

dedupeWorkspaceIds is called here at line 168, but setLocalWorkspaceIds already deduplicates the result of the updater function (line 113). The extra call is idempotent so it won't cause issues — just noting it makes the intent explicit at the call site, which is fine.

tools/cli/src/webpack/html-plugin.ts (1)

206-206: Return type WebpackPluginInstance[] may mislead when used with rspack.

The function returns WebpackPluginInstance[], but the plugins now accept CompilerLike (not the full webpack Compiler). This works via structural subtyping at runtime, but the import of WebpackPluginInstance from 'webpack' could cause confusion for maintainers seeing this used in an rspack context.

tools/cli/src/rspack/index.ts (1)

608-610: process.env.NODE_ENV is hardcoded to "production" regardless of dev mode.

In createNodeTargetConfig, DefinePlugin always sets process.env.NODE_ENV to '"production"' (Line 609), even when the dev variable (Line 504) is true. This may be intentional for the server target, but could cause confusion if this config is used in development workflows. Consider gating it on dev or adding a comment explaining the rationale.

tools/cli/src/bundle.ts (2)

34-35: WorkerConfig type is too narrow for how the values are actually used.

The objects returned by createWebpackWorkerTargetConfig / createRspackWorkerTargetConfig are spread into MultiConfiguration / MultiRspackOptions arrays (e.g., line 96, 166), meaning they must be full bundler configuration objects—not just { name: string }. The as casts silence the type checker, but the generic type erases useful type information in getBaseWorkerConfigs.

Consider parameterizing the return type:

Suggested improvement
-type WorkerConfig = { name: string };
-type CreateWorkerTargetConfig = (pkg: Package, entry: string) => WorkerConfig;
+type CreateWorkerTargetConfig<T extends { name: string } = { name: string }> = (
+  pkg: Package,
+  entry: string
+) => T;

-function getBaseWorkerConfigs(
+function getBaseWorkerConfigs<T extends { name: string }>(
   pkg: Package,
-  createWorkerTargetConfig: CreateWorkerTargetConfig
+  createWorkerTargetConfig: CreateWorkerTargetConfig<T>
 ) {

This preserves the full config type through inference, potentially eliminating the need for as casts at the call sites.


67-198: Substantial duplication between getWebpackBundleConfigs and getRspackBundleConfigs.

These two functions share identical switch-case structures, entry points, and options—differing only in which create*TargetConfig helpers they call. If a new package or worker entry is added, both functions must be updated in lockstep.

Consider a generic getBundleConfigs that accepts the create helpers as parameters (similar to how getBaseWorkerConfigs already does for workers). This would consolidate the switch logic into one place.

@codecov
Copy link

codecov bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 20.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.81%. Comparing base (72df9cb) to head (b24c2ec).
⚠️ Report is 2 commits behind head on canary.

Files with missing lines Patch % Lines
...d/core/src/modules/doc/services/duplicate-title.ts 25.00% 3 Missing ⚠️
...ges/frontend/core/src/modules/doc/services/docs.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           canary   #14434      +/-   ##
==========================================
+ Coverage   53.44%   53.81%   +0.37%     
==========================================
  Files        2831     2832       +1     
  Lines      153338   153319      -19     
  Branches    22969    22937      -32     
==========================================
+ Hits        81945    82513     +568     
+ Misses      68170    67407     -763     
- Partials     3223     3399     +176     
Flag Coverage Δ
server-test 75.09% <ø> (+0.19%) ⬆️
unittest 33.53% <20.00%> (+0.74%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (2)
.github/workflows/build-test.yml (1)

1344-1372: ⚠️ Potential issue | 🟡 Minor

bundler-matrix is not included in the test-done gate job.

The new bundler-matrix job is absent from the needs list of test-done. This means bundler build failures won't block the "3, 2, 1 Launch" status check. If this is intentional (informational-only), consider adding a comment to document it. If bundler regressions should block merges, add it to the list.

Proposed fix (if blocking is desired)
     needs:
       - analyze
       - lint
       - typecheck
       - lint-rust
       - check-git-status
       - check-yarn-binary
+      - bundler-matrix
       - e2e-test
       - e2e-blocksuite-test
tools/cli/src/bundle.ts (1)

241-269: ⚠️ Potential issue | 🟠 Major

async methods never await compiler.run — callers get an immediately-resolved promise.

Both buildWithWebpack and buildWithRspack are declared async, but compiler.run(callback) is fire-and-forget from the promise's perspective. await BundleCommand.build(...) in execute() (line 224) resolves before compilation finishes.

This works today only because process.exit(1) in the callback terminates on failure, and Node stays alive for the pending callback on success. But any programmatic caller (tests, orchestration scripts) that relies on the await will get a false "done" signal.

Wrap compiler.run in a promise:

Proposed fix (shown for webpack; apply same pattern to rspack)
-    compiler.run((error, stats) => {
-      if (error) {
-        console.error(error);
-        process.exit(1);
-      }
-      if (stats) {
-        if (stats.hasErrors()) {
-          console.error(stats.toString('errors-only'));
-          process.exit(1);
-        } else {
-          console.log(stats.toString('minimal'));
-        }
-      }
-    });
+    await new Promise<void>((resolve, reject) => {
+      compiler.run((error, stats) => {
+        if (error) {
+          return reject(error);
+        }
+        if (stats?.hasErrors()) {
+          return reject(new Error(stats.toString('errors-only')));
+        }
+        if (stats) {
+          console.log(stats.toString('minimal'));
+        }
+        compiler.close((closeErr) => {
+          if (closeErr) return reject(closeErr);
+          resolve();
+        });
+      });
+    });

This also avoids the process.exit calls, which skip cleanup and prevent proper error propagation.

Also applies to: 324-355

🤖 Fix all issues with AI agents
In `@tools/cli/src/bundle.ts`:
- Around line 228-238: In BundleCommand.build, when bundler === 'rspack' but
isRspackSupportedPackageName(pkg.name) is false, add a logger.warn before
returning BundleCommand.buildWithWebpack(pkg) to surface the silent fallback;
the warning should mention that rspack was requested, the package name
(pkg.name), and that webpack will be used instead so callers can see the
implicit fallback.
- Around line 375-378: DEFAULT_DEV_SERVER_CONFIG is currently typed as
WebpackDevServerConfiguration but is passed into RspackDevServer (via merge(...,
DEFAULT_DEV_SERVER_CONFIG, ...)), creating a type mismatch; fix by either
(preferred) adding a separate DEFAULT_RSPACK_DEV_SERVER_CONFIG constant typed as
RspackDevServerConfiguration and use that when constructing RspackDevServer
(update the RspackDevServer instantiation to merge({},
DEFAULT_RSPACK_DEV_SERVER_CONFIG, devServerConfig)), or define a shared subset
type (e.g., DevServerCommonConfig or Partial<WebpackDevServerConfiguration &
RspackDevServerConfiguration>) and retype DEFAULT_DEV_SERVER_CONFIG to that
shared type and use it in both WebpackDevServer and RspackDevServer
constructions; ensure you update the symbol DEFAULT_DEV_SERVER_CONFIG usage in
the WebpackDevServer and RspackDevServer instantiations and adjust imports/types
to reference WebpackDevServerConfiguration and RspackDevServerConfiguration as
needed.
🧹 Nitpick comments (3)
blocksuite/integration-test/src/__tests__/edgeless/shape-dom.spec.ts (1)

8-14: Default precision=2 gives a tolerance of only ±0.005 — very tight for pixel values.

toBeCloseTo(expected, 2) checks that |actual - expected| < 0.005. For pixel-based assertions this is effectively exact equality, making the helper's "CloseTo" semantics misleading and the tests potentially flaky if the renderer introduces any sub-pixel rounding.

Consider using precision = 0 (~0.5 px tolerance) or precision = 1 (~0.05 px) as the default, which better matches the intent of an approximate pixel comparison.

Suggested change
 function expectPxCloseTo(
   value: string,
   expected: number,
-  precision: number = 2
+  precision: number = 0
 ) {
   expect(Number.parseFloat(value)).toBeCloseTo(expected, precision);
 }
tools/cli/src/bundle.ts (2)

38-40: Thin wrapper adds indirection without value.

assertRspackSupportedPackage just forwards pkg.name to assertRspackSupportedPackageName. Consider calling the shared function directly at call sites (lines 137, 326, 362) instead of adding this wrapper.


136-204: Near-identical duplication with getWebpackBundleConfigs.

getRspackBundleConfigs mirrors getWebpackBundleConfigs (lines 68–134) almost line-for-line — the only differences are the imported config creators and the return type. Consider a generic helper parameterized by the config creators to eliminate the duplication, e.g.:

function getBundleConfigs<T>(
  pkg: Package,
  createHTML: typeof createWebpackHTMLTargetConfig,
  createNode: typeof createWebpackNodeTargetConfig,
  createWorker: CreateWorkerTargetConfig
): T[] { /* shared switch logic */ }

This would keep the bundler-specific wiring at the call sites while centralizing the package→entry mapping.

@darkskygit darkskygit force-pushed the darksky/improve-test-and-bundle branch from 7ee128d to 84dfe9f Compare February 14, 2026 06:40
@github-actions github-actions bot added the mod:i18n Related to i18n label Feb 14, 2026
@darkskygit darkskygit merged commit 2b71b3f into canary Feb 14, 2026
65 checks passed
@darkskygit darkskygit deleted the darksky/improve-test-and-bundle branch February 14, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app:core mod:dev mod:i18n Related to i18n test Related to test cases

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant