/
githubmirror
/
meteor
Обзор
Документация
Войти
/
githubmirror
/
meteor
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
devel
tools/e2e-tests/react.test.js
287 строк
10 KB
Nacho Codoñer
add demo unplugin to Rspack config and E2E tests for cache tracking
30 мар 2026, 17:28
30 мар 2026, 17:28
8cc1efa
Код
Авторство
О чём код?
import { killProcessByPort, cleanupTempDir, killMeteorProcess, createMeteorApp, runMeteorApp, waitForMeteorOutput, waitForPlaywrightConsole } from "./helpers"; import { testMeteorBundler, testMeteorRspackBundler } from './test-helpers'; import fs from 'fs-extra'; import path from 'path'; import { assertMeteorReactApp, assertConsoleEval, assertFileExist } from "./assertions"; describe('React App Bundling /', () => { // TODO: Create one test aside for all skeletons describe.skip('Meteor Creator /', () => { const PORT = 3100; beforeAll(async () => { // Ensure any process on the port is killed await killProcessByPort(PORT); }); test('"meteor create" / should create a new Meteor react app', async () => { // Create a new Meteor app with --react example const result = await createMeteorApp('react', 'react'); const newAppTempDir = result.tempDir; const newAppMeteorProcess = result.meteorProcess; // Wait for the process to complete await newAppMeteorProcess; // Check if the app directory exists const appDirExists = await fs.pathExists(newAppTempDir); expect(appDirExists).toBe(true); // Check if package.json exists and contains react const packageJsonPath = path.join(newAppTempDir, 'package.json'); const packageJsonExists = await fs.pathExists(packageJsonPath); expect(packageJsonExists).toBe(true); const packageJson = await fs.readJson(packageJsonPath); expect(packageJson.dependencies).toHaveProperty('react'); expect(packageJson.dependencies).toHaveProperty('react-dom'); // Run the newly created app let runAppProcess = (await runMeteorApp(newAppTempDir, PORT))?.meteorProcess; // Assert that the Meteor React app is running correctly await assertMeteorReactApp(PORT); // Kill the meteor processes await killMeteorProcess(runAppProcess); if (newAppMeteorProcess) { await killMeteorProcess(newAppMeteorProcess); } // Ensure any process on the port is killed await killProcessByPort(PORT); // Clean up the temporary directory await cleanupTempDir(newAppTempDir); }); }); describe( "Meteor+Rspack Bundler /", testMeteorRspackBundler({ appName: "react", port: 3102, filePaths: { client: "client/main.jsx", server: "server/main.js", test: "tests/main.js", }, configFile: "rspack.config.cjs", buildDir: "_build-local-custom", env: { METEOR_LOCAL_DIR: ".meteor/local-custom" }, customAssertions: { afterInit: async ({ result }) => { // Verify unplugin transform hook is called on first run (fresh cache) await waitForMeteorOutput( result.outputLines, /.*\[demo-unplugin\]\[transform-enter\].*/ ); }, afterRun: async ({ result, tempDir }) => { const appDir = tempDir; // testMeteorRspackBundler uses tempDir as appDir if not monorepo const localDir = path.join(appDir, ".meteor", "local-custom"); const buildDir = path.join(appDir, "_build-local-custom"); expect(await fs.pathExists(buildDir)).toBe(true); expect(await fs.pathExists(localDir)).toBe(true); await assertFileExist(appDir, '.gitignore', { content: '.meteor/local-custom' }); await waitForReactEnvs(result.outputLines, { isJsxEnabled: true }); // Check if images exist and return 200 status code await assertImagesExistAndLoad(); // Check custom plugin is disabled with Meteor.disablePlugins // Use specific log prefix to avoid matching the filename in buildDependencies await waitForMeteorOutput( result.outputLines, /.*\[CustomConsoleLogPlugin\].*/, { negate: true } ); // Verify unplugin factory is still created on second run (with cache) // This confirms the plugin is loaded and active even when rspack uses // cached transform results (#14031 regression test) await waitForMeteorOutput( result.outputLines, /.*\[demo-unplugin\]\[factory-created\].*/ ); }, afterRunRebuildClient: async ({ allConsoleLogs }) => { // Check for HMR output as enabled by default await waitForMeteorOutput( allConsoleLogs, /.*HMR.*Updated modules:.*/ ); }, afterRunProduction: async ({ result }) => { await waitForReactEnvs(result.outputLines, { isJsxEnabled: true }); // Check if images exist and return 200 status code await assertImagesExistAndLoad(); // Check custom plugin is disabled with Meteor.disablePlugins // Use specific log prefix to avoid matching the filename in buildDependencies await waitForMeteorOutput( result.outputLines, /.*\[CustomConsoleLogPlugin\].*/, { negate: true } ); // Verify demo-unplugin.js is tracked in rspack buildDependencies (#14031) await waitForMeteorOutput( result.outputLines, /.*plugins\/demo-unplugin\.js.*/ ); // Verify unplugin transform hook fires in production (separate cache version) await waitForMeteorOutput( result.outputLines, /.*\[demo-unplugin\]\[transform-enter\].*/ ); }, afterRunProductionRebuildClient: async ({ allConsoleLogs }) => { // Check for HMR to not be enabled in production-like mode await waitForMeteorOutput( allConsoleLogs, /.*HMR.*Updated modules:*/, { negate: true } ); }, afterTest: async ({ result }) => { await waitForReactEnvs(result.outputLines); // Check custom plugin is disabled with Meteor.disablePlugins // Use specific log prefix to avoid matching the filename in buildDependencies await waitForMeteorOutput( result.outputLines, /.*\[CustomConsoleLogPlugin\].*/, { negate: true } ); }, afterTestOnce: async ({ result }) => { await waitForReactEnvs(result.outputLines); // Check custom plugin is disabled with Meteor.disablePlugins // Use specific log prefix to avoid matching the filename in buildDependencies await waitForMeteorOutput( result.outputLines, /.*\[CustomConsoleLogPlugin\].*/, { negate: true } ); }, afterBuild: async ({ result }) => { await waitForReactEnvs(result.outputLines, { isJsxEnabled: true }); // Check custom plugin is disabled with Meteor.disablePlugins // Use specific log prefix to avoid matching the filename in buildDependencies await waitForMeteorOutput( result.outputLines, /.*\[CustomConsoleLogPlugin\].*/, { negate: true } ); }, }, }) ); }); /** * Helper function to wait for React environment output from both Rspack Client and Server * @param {string[]} outputLines - Array that will be populated with output lines * @param {Object} options - Options for waiting * @param {number} options.timeout - Maximum time to wait in milliseconds * @param {number} options.checkInterval - Interval between checks in milliseconds * @returns {Promise<void>} - A promise that resolves when react envs are enabled */ export async function waitForReactEnvs(outputLines, options = {}) { await waitForMeteorOutput( outputLines, /.*isReactEnabled:.*true.*/, options ); if (options.isJsxEnabled) { await waitForMeteorOutput( outputLines, /.*isJsxEnabled:.*true.*/, options ); } } /** * Helper function to assert that images exist in the DOM and return 200 status code when fetched * @returns {Promise<void>} - A promise that resolves when images are verified */ export async function assertImagesExistAndLoad() { await assertConsoleEval(` (async () => { // Get the image elements const imageGenerated = document.getElementById('image-generated'); const imagePublic = document.getElementById('image-public'); // Check if images exist if (!imageGenerated || !imagePublic) { return { success: false, error: 'Images not found in the DOM' }; } // Function to check if an image URL returns 200 const checkImageStatus = async (url) => { try { const response = await fetch(url); return { url, status: response.status, ok: response.ok }; } catch (error) { return { url, status: 0, ok: false, error: error.message }; } }; // Function to extract URL from background-image CSS property const extractUrlFromBackgroundImage = (backgroundImage) => { // Extract the URL from the background-image property (format: url("...")) const urlMatch = backgroundImage.match(/url\\(['"]?([^'"\\)]+)['"]?\\)/); return urlMatch ? urlMatch[1] : null; }; // Get body's background-image const bodyStyle = getComputedStyle(document.body); const backgroundImage = bodyStyle.backgroundImage; const backgroundImageUrl = extractUrlFromBackgroundImage(backgroundImage); // Check both images and background image const generatedResult = await checkImageStatus(imageGenerated.src); const publicResult = await checkImageStatus(imagePublic.src); if (!backgroundImageUrl) { return { ok: false, error: 'No background image URL found on body element' }; } const backgroundResult = await checkImageStatus(backgroundImageUrl); return { success: generatedResult.ok && publicResult.ok && backgroundResult.ok, }; })() `, { success: true }, { exactMatch: false }); }