add Coffeescript test app to modern-tests

This commit is contained in:
Nacho Codoñer
2025-08-13 17:34:50 +02:00
parent d4fbe2600f
commit 63c673cc40
21 changed files with 1763 additions and 5 deletions

View File

@@ -0,0 +1 @@
node_modules/

View File

@@ -0,0 +1 @@
local

View File

@@ -0,0 +1,7 @@
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
# - ensuring you don't accidentally deploy one app on top of another
# - providing package authors with aggregated statistics
lv2ipazth09.ysbw5dwq9qvl

View File

@@ -0,0 +1,23 @@
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-base # Packages every Meteor app needs to have
mobile-experience # Packages for a great mobile UX
mongo # The database Meteor supports right now
reactive-var # Reactive variable for tracker
standard-minifier-css # CSS minifier run for production mode
standard-minifier-js # JS minifier run for production mode
es5-shim # ECMAScript 5 compatibility for older browsers
ecmascript # Enable ECMAScript2015+ syntax in app code
typescript # Enable TypeScript syntax in .ts and .tsx modules
shell-server # Server-side component of the `meteor shell` command
hot-module-replacement # Update client in development without reloading the page
static-html # Define static page content in .html files
react-meteor-data # React higher-order component for reactively tracking Meteor data
coffeescript # Enable CoffeeScript syntax in .coffee files

View File

@@ -0,0 +1,2 @@
server
browser

View File

@@ -0,0 +1 @@
none

View File

@@ -0,0 +1,68 @@
allow-deny@2.1.0
autoupdate@2.0.1
babel-compiler@7.12.1-rc331.2
babel-runtime@1.5.2
base64@1.0.13
binary-heap@1.0.12
boilerplate-generator@2.0.1
caching-compiler@2.0.1
callback-hook@1.6.1-rc331.2
check@1.4.4
core-runtime@1.0.0
ddp@1.4.2
ddp-client@3.1.1
ddp-common@1.4.4
ddp-server@3.1.2
diff-sequence@1.1.3
dynamic-import@0.7.4
ecmascript@0.16.12-rc331.2
ecmascript-runtime@0.8.3
ecmascript-runtime-client@0.12.3
ecmascript-runtime-server@0.11.1
ejson@1.1.5
es5-shim@4.8.1
facts-base@1.0.2
fetch@0.1.6
geojson-utils@1.0.12
hot-code-push@1.0.5
hot-module-replacement@0.5.4
id-map@1.2.0
inter-process-messaging@0.1.2
launch-screen@2.0.1
logging@1.3.6
meteor@2.1.1
meteor-base@1.5.2
minifier-css@2.0.1
minifier-js@3.0.3-rc331.2
minimongo@2.0.3-rc331.2
mobile-experience@1.1.2
mobile-status-bar@1.1.1
modern-browsers@0.2.3-rc331.2
modules@0.20.3
modules-runtime@0.13.2
modules-runtime-hot@0.14.3
mongo@2.1.3-rc331.2
mongo-decimal@0.2.0
mongo-dev-server@1.1.1
mongo-id@1.0.9
npm-mongo@6.16.0-rc331.2
ordered-dict@1.2.0
promise@1.0.0
random@1.2.2
react-fast-refresh@0.2.9
react-meteor-data@4.0.0
reactive-var@1.0.13
reload@1.3.2
retry@1.1.1
routepolicy@1.1.2
shell-server@0.6.1
socket-stream-client@0.6.1
standard-minifier-css@1.9.3
standard-minifier-js@3.1.1-rc331.2
static-html@1.4.0
static-html-tools@1.0.0
tracker@1.3.4
typescript@5.6.5-rc331.2
webapp@2.0.7
webapp-hashing@1.1.2
zodern:types@1.0.13

View File

@@ -0,0 +1,9 @@
import React from 'react'
import { createRoot } from 'react-dom/client'
import { Meteor } from 'meteor/meteor'
import { App } from '/imports/ui/App.coffee'
Meteor.startup ->
container = document.getElementById('react-target')
root = createRoot(container)
root.render(<App />)

View File

@@ -0,0 +1,4 @@
body {
padding: 10px;
font-family: sans-serif;
}

View File

@@ -0,0 +1,8 @@
<head>
<title>coffeescript</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="react-target"></div>
</body>

View File

@@ -0,0 +1,3 @@
import { Mongo } from 'meteor/mongo'
export LinksCollection = new Mongo.Collection('links')

View File

@@ -0,0 +1,10 @@
import React from 'react'
import { Hello } from './Hello.coffee'
import { Info } from './Info.coffee'
export App = ->
<div>
<h1>Welcome to Meteor!</h1>
<Hello/>
<Info/>
</div>

View File

@@ -0,0 +1,12 @@
import React, { useState } from 'react'
export Hello = ->
[counter, setCounter] = useState(0)
increment = ->
setCounter(counter + 1)
<div>
<button onClick={increment}>Click Me</button>
<p>You've pressed the button {counter} times.</p>
</div>

View File

@@ -0,0 +1,19 @@
import React from 'react'
import { useFind, useSubscribe } from 'meteor/react-meteor-data'
import { LinksCollection } from '../api/links.coffee'
export Info = ->
isLoading = useSubscribe('links')
links = useFind(-> LinksCollection.find())
if isLoading()
return <div>Loading...</div>
<div>
<h2>Learn Meteor!</h2>
<ul>{links.map (link) ->
<li key={link._id}>
<a href={link.url} target="_blank">{link.title}</a>
</li>
}</ul>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
{
"name": "react",
"private": true,
"scripts": {
"start": "meteor run",
"test": "meteor test --once --driver-package meteortesting:mocha",
"test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
"visualize": "meteor --production --extra-packages bundle-visualizer"
},
"dependencies": {
"@babel/runtime": "^7.23.5",
"@swc/helpers": "^0.5.17",
"coffeescript": "^2.7.0",
"meteor-node-stubs": "^1.2.12",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"playwright": "^1.54.2"
},
"meteor": {
"mainModule": {
"client": "client/main.coffee",
"server": "server/main.coffee"
},
"testModule": "tests/main.coffee",
"modern": true
}
}

View File

@@ -0,0 +1,29 @@
import { Meteor } from 'meteor/meteor'
import { LinksCollection } from '/imports/api/links.coffee'
insertLink = ({ title, url }) ->
await LinksCollection.insertAsync({ title, url, createdAt: new Date() })
Meteor.startup ->
# If the Links collection is empty, add some data.
if await LinksCollection.find().countAsync() is 0
await insertLink
title: 'Do the Tutorial'
url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html'
await insertLink
title: 'Follow the Guide'
url: 'https://guide.meteor.com'
await insertLink
title: 'Read the Docs'
url: 'https://docs.meteor.com'
await insertLink
title: 'Discussions'
url: 'https://forums.meteor.com'
# We publish the entire Links collection to all clients.
# In order to be fetched in real-time to the clients
Meteor.publish "links", ->
LinksCollection.find()

View File

@@ -0,0 +1,14 @@
import assert from "assert"
describe "react", ->
it "package.json has correct name", ->
{ name } = await import("../package.json")
assert.strictEqual(name, "react")
if Meteor.isClient
it "client is not server", ->
assert.strictEqual(Meteor.isServer, false)
if Meteor.isServer
it "server is not client", ->
assert.strictEqual(Meteor.isClient, false)

View File

@@ -24,12 +24,14 @@ export async function assertMeteorApp(port, options = {}) {
if (inTitle) {
const title = await page.title();
expect(title).toMatch(new RegExp(inTitle));
console.log(`✅ Title: ${title}`);
}
// Check for static content if specified
if (inH1) {
const h1Text = await page.$eval('h1', el => el.textContent);
expect(h1Text).toMatch(new RegExp(inH1));
console.log(`✅ H1: ${h1Text}`);
}
}

View File

@@ -0,0 +1,64 @@
import {
waitForMeteorOutput,
} from "./helpers";
import { testMeteorBundler, testMeteorRspackBundler } from './test-helpers';
describe('CoffeeScript App Bundling /', () => {
describe('Meteor+Rspack Bundler /', testMeteorRspackBundler({
appName: 'coffeescript',
port: 3132,
filePaths: {
client: 'client/main.coffee',
server: 'server/main.coffee',
test: 'tests/main.coffee'
},
customUpdates: {
devClient: (message) => `console.log "${message}" if Meteor.isDevelopment`,
devServer: (message) => `console.log "${message}" if Meteor.isDevelopment`,
prodClient: (message) => `console.log "${message}" if Meteor.isProduction`,
prodServer: (message) => `console.log "${message}" if Meteor.isProduction`,
test: (message) => `console.log "${message}"`
},
customAssertions: {
afterRun: async ({ result }) => {
await waitForCoffeescriptEnvs(result.outputLines);
},
afterRunRebuildClient: async ({ allConsoleLogs }) => {
// Check for HMR output as enabled by default
await waitForMeteorOutput(allConsoleLogs, /.*HMR.*Updated modules:*/);
},
afterRunProduction: async ({ result }) => {
await waitForCoffeescriptEnvs(result.outputLines);
},
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 waitForCoffeescriptEnvs(result.outputLines);
},
afterTestOnce: async ({ result }) => {
await waitForCoffeescriptEnvs(result.outputLines);
},
afterBuild: async ({ result }) => {
await waitForCoffeescriptEnvs(result.outputLines);
},
}
}));
});
/**
* Helper function to wait for CoffeeScript 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 coffeescript envs are enabled
*/
export async function waitForCoffeescriptEnvs(outputLines, options = {}) {
await waitForMeteorOutput(
outputLines,
/.*isCoffeescriptEnabled:.*true.*/,
options
);
}

View File

@@ -105,6 +105,13 @@ export function testMeteorRspackBundler(options) {
prodServer: "Hello from prod server",
test: "Hello from test"
},
customUpdates = {
devClient: (message) => `if (Meteor.isDevelopment) console.log("${message}");`,
devServer: (message) => `if (Meteor.isDevelopment) console.log("${message}");`,
prodClient: (message) => `if (Meteor.isProduction) console.log("${message}");`,
prodServer: (message) => `if (Meteor.isProduction) console.log("${message}");`,
test: (message) => `console.log("${message}");`
},
customAssertions,
// Some existing tests may fail if this is not set
verbose = true,
@@ -188,7 +195,7 @@ export function testMeteorRspackBundler(options) {
// Update the client code
await appendFileContent(tempDir, filePaths.client, {
content: `if (Meteor.isDevelopment) console.log("${customMessages.devClient}");`,
content: customUpdates.devClient(customMessages.devClient),
});
const consoleLogs = await waitForPlaywrightConsole(customMessages.devClient, { returnAllLogs: true });
@@ -205,7 +212,7 @@ export function testMeteorRspackBundler(options) {
// Update the server code
await appendFileContent(tempDir, filePaths.server, {
content: `if (Meteor.isDevelopment) console.log("${customMessages.devServer}");`,
content: customUpdates.devServer(customMessages.devServer),
});
await waitForMeteorOutput(
result.outputLines,
@@ -273,7 +280,7 @@ export function testMeteorRspackBundler(options) {
// Update the client code
await appendFileContent(tempDir, filePaths.client, {
content: `if (Meteor.isProduction) console.log("${customMessages.prodClient}");`,
content: customUpdates.prodClient(customMessages.prodClient),
});
const consoleLogs = await waitForPlaywrightConsole(customMessages.prodClient, { returnAllLogs: true });
@@ -290,7 +297,7 @@ export function testMeteorRspackBundler(options) {
// Update the server code
await appendFileContent(tempDir, filePaths.server, {
content: `if (Meteor.isProduction) console.log("${customMessages.prodServer}");`,
content: customUpdates.prodServer(customMessages.prodServer),
});
await waitForMeteorOutput(
result.outputLines,
@@ -347,7 +354,7 @@ export function testMeteorRspackBundler(options) {
// Update the test code
await appendFileContent(tempDir, filePaths.test, {
content: `console.log("${customMessages.test}");`,
content: customUpdates.test(customMessages.test),
});
await waitForMeteorOutput(
result.outputLines,