add file existence assertions for Meteor React app builds

This commit is contained in:
Nacho Codoñer
2025-08-07 11:33:07 +02:00
parent a3d4bc4e34
commit 8d95579c7b
2 changed files with 106 additions and 1 deletions

View File

@@ -2,6 +2,9 @@
* This file contains assertion helpers for testing Meteor applications.
*/
import fs from 'fs-extra';
import path from 'path';
/**
* Helper function to assert that a Meteor React app is running correctly
* @param {number} port - Port where the app is running
@@ -38,3 +41,75 @@ export async function assertRspackScriptTag(port, shoudlExist = true) {
const hasRspackScript = scriptTags.some(src => src && src.includes('__rspack__'));
expect(hasRspackScript).toBe(shoudlExist);
}
/**
* Helper function to assert that a single file exists and optionally contains specific content
* @param {string} tempDir - Path to the temporary directory
* @param {string} filePath - File path relative to tempDir
* @param {Object} options - Additional options
* @param {string} options.content - Content to check for
* @param {boolean} options.exactMatch - Whether the content should be an exact match (default: false)
* @param {number} options.timeout - Maximum time to wait in milliseconds (default: 5000)
* @param {number} options.checkInterval - Interval between checks in milliseconds (default: 100)
* @returns {Promise<void>}
*/
export async function assertFileExist(tempDir, filePath, options = {}) {
const { content, exactMatch = false, timeout = 5000, checkInterval = 100 } = options;
const fullPath = path.join(tempDir, filePath);
const startTime = Date.now();
// Function to check file existence and content
const checkFile = async () => {
// Check if file exists
const fileExists = await fs.pathExists(fullPath);
if (!fileExists) {
// If file doesn't exist and we haven't exceeded the timeout, wait and retry
if (Date.now() - startTime < timeout) {
await new Promise(resolve => setTimeout(resolve, checkInterval));
return checkFile();
}
// If we've exceeded the timeout, fail the test
expect(fileExists).toBe(true);
return false;
}
// If content check is requested
if (content) {
// Read the file content
const fileContent = await fs.readFile(fullPath, 'utf8');
if (exactMatch) {
// Check for exact match
if (fileContent !== content) {
// If content doesn't match and we haven't exceeded the timeout, wait and retry
if (Date.now() - startTime < timeout) {
await new Promise(resolve => setTimeout(resolve, checkInterval));
return checkFile();
}
// If we've exceeded the timeout, fail the test
expect(fileContent).toBe(content);
return false;
}
} else {
// Check if file includes the specified content
if (!fileContent.includes(content)) {
// If content doesn't include the specified content and we haven't exceeded the timeout, wait and retry
if (Date.now() - startTime < timeout) {
await new Promise(resolve => setTimeout(resolve, checkInterval));
return checkFile();
}
// If we've exceeded the timeout, fail the test
expect(fileContent).toContain(content);
return false;
}
}
}
return true;
};
// Start checking
await checkFile();
}

View File

@@ -7,7 +7,7 @@ import {
createMeteorApp,
runMeteorCommand, wait
} from "./helpers";
import { assertMeteorReactApp, assertRspackScriptTag } from './assertions';
import { assertMeteorReactApp, assertRspackScriptTag, assertFileExist } from './assertions';
import fs from 'fs-extra';
import path from 'path';
import waitOn from "wait-on";
@@ -16,6 +16,11 @@ describe('React App Bundling', () => {
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 app with --react example', async () => {
// Create a new Meteor app with --react example
const result = await createMeteorApp('react', 'react');
@@ -64,6 +69,9 @@ describe('React App Bundling', () => {
let tempDir;
beforeAll(async () => {
// Ensure any process on the port is killed
await killProcessByPort(PORT);
// Setup the Meteor app
tempDir = (await setupMeteorApp('react'))?.tempDir;
});
@@ -120,6 +128,10 @@ describe('React App Bundling', () => {
// Wait for a margin
await wait(500);
// Assert that the config files exists
await assertFileExist(tempDir, '.gitignore', { content: '_build' });
await assertFileExist(tempDir, 'rspack.config.js', { content: '@meteorjs/rspack' });
// Kill the meteor process
await killMeteorProcess(meteorProcess);
@@ -138,6 +150,14 @@ describe('React App Bundling', () => {
// Wait for a margin
await wait(500);
// Assert that the app files exists
await assertFileExist(tempDir, '_build/main-dev/client-entry.js');
await assertFileExist(tempDir, '_build/main-dev/client-rspack.js');
await assertFileExist(tempDir, '_build/main-dev/client-meteor.js');
await assertFileExist(tempDir, '_build/main-dev/server-entry.js');
await assertFileExist(tempDir, '_build/main-dev/server-rspack.js');
await assertFileExist(tempDir, '_build/main-dev/server-meteor.js');
// Assert that the Meteor React app is running correctly
await assertMeteorReactApp(PORT);
@@ -163,6 +183,16 @@ describe('React App Bundling', () => {
// Wait for a margin
await wait(500);
// Assert that the app files exists
await assertFileExist(tempDir, '_build/main-prod/client-entry.js');
await assertFileExist(tempDir, '_build/main-prod/client-rspack.js');
await assertFileExist(tempDir, '_build/main-prod/client-meteor.js');
await assertFileExist(tempDir, '_build/main-prod/server-entry.js');
await assertFileExist(tempDir, '_build/main-prod/server-rspack.js');
await assertFileExist(tempDir, '_build/main-prod/server-meteor.js');
await assertFileExist(tempDir, 'server/main.js');
// Assert that the Meteor React app is running correctly
await assertMeteorReactApp(PORT);