惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
小众软件
小众软件
Last Week in AI
Last Week in AI
月光博客
月光博客
博客园 - 聂微东
Recent Announcements
Recent Announcements
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
博客园 - Franky
云风的 BLOG
云风的 BLOG
量子位
N
Netflix TechBlog - Medium
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
博客园 - 司徒正美
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队
Google DeepMind News
Google DeepMind News
宝玉的分享
宝玉的分享

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Symfony Asset Mapper: How to Finally Test JavaScript Prop...
Jozef Môstka · 2026-04-20 · via DEV Community

You know the drill. Symfony Asset Mapper is a great tool. You've gotten rid of Webpack, npm install, and complex build processes. Everything is fast, clean, and modern. And then comes the fateful question: "And how do we actually test this?"

Then comes the reality check. Asset Mapper works on the principle of importmap.php, which your Node.js (and thus most test runners) has no clue about. You try to run a test and you get: ERR_MODULE_NOT_FOUND.

Many people just wave it off and say that testing Asset Mapper is simply impossible, or you have to switch back to a complex frontend stack. But what if I told you there's an elegant solution that bridges both worlds?

The "Aha!" moment: Symlinks as a bridge

My idea was simple: Node.js expects libraries in the node_modules folder. Symfony has them in assets/vendor/ or in vendor/ (for Stimulus bundles). So why not force Node.js to see what Symfony sees, without having to duplicate anything or "hack" the imports?

The solution is a small PHP script that reads your import map and creates a symlink structure in node_modules. Node.js will think everything is installed, while in reality, it will be reading the same files your browser uses.

Step 1: The PHP script that does the magic

Here is a simplified version of our "linker" script. It uses the Symfony Filesystem component for safe file manipulation.

// bin/setup-js-tests.php
require_once __DIR__ . '/../vendor/autoload.php';

use Symfony\Component\Filesystem\Filesystem;

$projectRoot = dirname(__DIR__);
$importmap = require $projectRoot . '/importmap.php';
$fs = new Filesystem();
$nodeModules = $projectRoot . '/node_modules';

if (!$fs->exists($nodeModules)) $fs->mkdir($nodeModules);

foreach ($importmap as $name => $config) {
    $targetDir = $nodeModules . '/' . $name;
    $sourcePath = isset($config['path']) 
        ? $projectRoot . '/' . ltrim($config['path'], './')
        : $projectRoot . '/assets/vendor/' . $name;

    if (!$fs->exists($sourcePath)) continue;

    if (!$fs->exists(dirname($targetDir))) $fs->mkdir(dirname($targetDir));

    if (is_dir($sourcePath)) {
        $fs->symlink($sourcePath, $targetDir);
    } else {
        // If it's a single file, we turn it into a package with index.js
        if (!$fs->exists($targetDir)) $fs->mkdir($targetDir);
        $fs->symlink($sourcePath, $targetDir . '/index.js');
        $fs->dumpFile($targetDir . '/package.json', json_encode([
            'name' => $name, 'type' => 'module', 'main' => 'index.js'
        ]));
    }
}
echo "Imports for JS tests have been successfully linked!\n";

Enter fullscreen mode Exit fullscreen mode

Step 2: Node.js Configuration

Now we need to tell Node.js how to run the tests. We'll use a standard package.json, but with a small improvement: we'll use the pretest hook, which automatically runs our PHP script before every test.

{
  "name": "my-project",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --test tests/js/*.test.mjs",
    "test:watch": "node --watch --test tests/js/*.test.mjs",
    "pretest": "php bin/setup-js-tests.php"
  }
}

Enter fullscreen mode Exit fullscreen mode

Methodology: Why this way?

For testing, we chose the native Node.js test runner (available since version 20). Why?

  1. Zero configuration: No need to install Jest, Vitest, or anything similar.
  2. Speed: It starts instantly.
  3. Reality-based: No complex import mocking. You are testing the exact same files that run in production.

Thanks to symlinks, we can write clean imports in our tests:

import assert from 'node:assert/strict';
import test from 'node:test';
import { myFunction } from '../assets/js/my-function.js';
import { Midi } from '@tonejs/midi'; // This now works!

Enter fullscreen mode Exit fullscreen mode

This approach allows us to follow TDD (Test Driven Development) on the frontend while maintaining the simplicity of Asset Mapper. If you add a new library via importmap:require, just run npm test and everything will be automatically re-linked.

Conclusion

Testing JavaScript in Symfony Asset Mapper is not impossible. All it takes is a small bridge in the form of a PHP script, and you can leverage the power of a modern Node.js environment without having to leave the comfort zone of your PHP framework.

Give it a try in your project and say goodbye to "missing module" errors. Your code (and your mental health) will thank you. ?