Files
mattermost/e2e-tests/playwright/mock_file_server.js
T
sabrilandMattermost Build a8c2307bee E2E/Playwright: Add testcontainers to playwright-lib (#37570)
* add testcontainers to playwright-lib

* include retry mechanism for transient failures

* - Introduced a new command `testcontainers:up` in package.json to run Playwright tests with Testcontainers.
- Created a standalone Playwright configuration file `playwright.testcontainers-up.config.ts` for managing Testcontainers.
- Added a no-op test `testcontainers_up.spec.ts` to ensure the Testcontainers stack is up during the test run.
- Implemented a global setup script `testcontainers_up_global_setup.ts` to start and stop the Testcontainers stack.
- Updated dependencies in package.json, including adding `chalk` for logging.

* fix package-lock

* fix tsc and restore waiting for all migrations to complete

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-07-28 10:06:36 +02:00

115 lines
3.7 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable no-console */
// A tiny file server that serves the contents of the `asset` directory for use by tests for things like link previews
// and Markdown images that need an external server which the MM server can contact.
//
// Run standalone with `npm run start:file-server-mock`, or fork it from a spec. When forked with an IPC channel,
// it posts a {type: 'listening', port} message once it is ready so the parent can learn the port (use PORT=0 to get
// an ephemeral one).
const {createServer} = require('http');
const fs = require('fs');
const path = require('path');
const PORT = Number(process.env.PORT) || 3011;
const ASSET_DIR = process.env.ASSET_DIR || path.join(__dirname, 'asset');
if (process.argv[2]) {
process.title = process.argv[2];
}
const CONTENT_TYPES = {
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.txt': 'text/plain; charset=utf-8',
'.html': 'text/html; charset=utf-8',
'.json': 'application/json',
'.zip': 'application/zip',
};
function setCorsHeaders(res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Range');
}
const server = createServer((req, res) => {
const method = req.method;
let requestPath;
try {
requestPath = decodeURIComponent(req.url.split('?')[0]);
} catch (err) {
console.log(`[mock-file-server] Invalid request URL ${req.url.split('?')[0]}:`, err);
res.writeHead(400);
res.end();
return;
}
// Handle CORS preflight
if (method === 'OPTIONS') {
setCorsHeaders(res);
res.writeHead(204);
res.end();
return;
}
console.log(`[mock-file-server] ${method} ${requestPath}`);
if (method !== 'GET' && method !== 'HEAD') {
res.writeHead(405);
res.end('Method not allowed');
return;
}
// Resolve the requested file within ASSET_DIR, rejecting anything that escapes it (path traversal).
const relativePath = requestPath.replace(/^\/+/, '');
const filePath = path.join(ASSET_DIR, relativePath);
if (filePath !== ASSET_DIR && !filePath.startsWith(ASSET_DIR + path.sep)) {
res.writeHead(403);
res.end('Forbidden');
return;
}
fs.stat(filePath, (err, stats) => {
if (err || !stats.isFile()) {
console.log(`[mock-file-server] 404: ${requestPath}`);
res.writeHead(404);
res.end('Not found');
return;
}
setCorsHeaders(res);
const ext = path.extname(filePath).toLowerCase();
res.setHeader('Content-Type', CONTENT_TYPES[ext] || 'application/octet-stream');
res.setHeader('Content-Length', stats.size);
if (method === 'HEAD') {
res.writeHead(200);
res.end();
return;
}
res.writeHead(200);
fs.createReadStream(filePath).pipe(res);
});
});
// Bind to all interfaces, not just loopback, so the Mattermost server container can reach this
// over the Docker network in `testcontainers` mode.
server.listen(PORT, () => {
const address = server.address();
const actualPort = typeof address === 'object' && address ? address.port : PORT;
console.log(`File server serving ${ASSET_DIR} on port ${actualPort}!`);
// Let the parent process know the server is ready and which port it's on
if (process.send) {
process.send({type: 'listening', port: actualPort});
}
});