1+ import { test , expect } from "@playwright/test" ;
2+ import {
3+ createApp ,
4+ deleteApp ,
5+ startApp ,
6+ stopApp ,
7+ getAppOutput ,
8+ getTerminalOutput ,
9+ switchTerminal ,
10+ createBackendFile ,
11+ createFrontendFile ,
12+ } from "./helpers/test_helper" ;
13+
14+ test . describe ( "Log Routing and Visibility" , ( ) => {
15+ const appName = "test-log-routing-app" ;
16+ let appId : number ;
17+
18+ test . beforeAll ( async ( { page } ) => {
19+ // Create a new app for testing
20+ appId = await createApp ( page , appName , {
21+ isFullStack : true ,
22+ selectedBackendFramework : "flask" ,
23+ } ) ;
24+ } ) ;
25+
26+ test . afterAll ( async ( { page } ) => {
27+ // Clean up the app after tests
28+ await deleteApp ( page , appId ) ;
29+ } ) ;
30+
31+ test ( "should stream all logs to system terminal and UI terminals in FullStack mode" , async ( {
32+ page,
33+ } ) => {
34+ test . setTimeout ( 120000 ) ; // Increase timeout for app startup
35+
36+ // Create a backend file that produces stdout and stderr
37+ await createBackendFile (
38+ page ,
39+ appId ,
40+ "app.py" ,
41+ `
42+ from flask import Flask, jsonify
43+ import sys
44+ import time
45+
46+ app = Flask(__name__)
47+
48+ @app.route('/')
49+ def hello():
50+ print("Backend stdout: Hello from Flask!")
51+ sys.stderr.write("Backend stderr: This is an error message.\\n")
52+ return jsonify({"message": "Backend API is running!"})
53+
54+ if __name__ == '__main__':
55+ # Simulate a startup error for a moment, then recover
56+ print("Backend starting...")
57+ time.sleep(2) # Simulate some startup time
58+ # This will cause an error if a non-existent module is imported
59+ # try:
60+ # import non_existent_module
61+ # except ImportError:
62+ # sys.stderr.write("Backend stderr: Failed to import non_existent_module.\\n")
63+ app.run(debug=True, host='0.0.0.0', port=5000)
64+ ` ,
65+ ) ;
66+
67+ // Create a frontend file that makes a request to the backend
68+ await createFrontendFile (
69+ page ,
70+ appId ,
71+ "src/App.tsx" ,
72+ `
73+ import React, { useEffect, useState } from 'react';
74+
75+ function App() {
76+ const [message, setMessage] = useState('Loading...');
77+
78+ useEffect(() => {
79+ console.log("Frontend stdout: App started.");
80+ fetch('http://localhost:5000/')
81+ .then(res => res.json())
82+ .then(data => {
83+ setMessage(data.message);
84+ console.log("Frontend stdout: Backend message received.");
85+ })
86+ .catch(error => {
87+ console.error("Frontend stderr: Error fetching from backend:", error);
88+ setMessage('Error: ' + error.message);
89+ });
90+ }, []);
91+
92+ return (
93+ <div className="App">
94+ <h1>Todo App</h1>
95+ <p>{message}</p>
96+ </div>
97+ );
98+ }
99+
100+ export default App;
101+ ` ,
102+ ) ;
103+
104+ // Start the app in FullStack mode
105+ await startApp ( page , appId , "main" ) ;
106+
107+ // Wait for some output to appear in the system messages
108+ await page . waitForSelector ( ".system-messages-container" , { state : "visible" } ) ;
109+ await page . waitForTimeout ( 10000 ) ; // Give time for logs to accumulate
110+
111+ // Check if logs appear in the system console (Playwright can't directly access Node.js console,
112+ // but we can check the UI's system messages which should reflect console logs)
113+ const systemMessages = await getAppOutput ( page , appId ) ;
114+ expect ( systemMessages ) . toContain ( "Backend stdout: Hello from Flask!" ) ;
115+ expect ( systemMessages ) . toContain ( "Backend stderr: This is an error message." ) ;
116+ expect ( systemMessages ) . toContain ( "Frontend stdout: App started." ) ;
117+ expect ( systemMessages ) . toContain ( "Frontend stdout: Backend message received." ) ;
118+
119+ // Switch to backend terminal and check logs
120+ await switchTerminal ( page , "backend" ) ;
121+ const backendTerminalOutput = await getTerminalOutput ( page , appId , "backend" ) ;
122+ expect ( backendTerminalOutput ) . toContain ( "Backend stdout: Hello from Flask!" ) ;
123+ expect ( backendTerminalOutput ) . toContain ( "Backend stderr: This is an error message." ) ;
124+
125+ // Switch to frontend terminal and check logs
126+ await switchTerminal ( page , "frontend" ) ;
127+ const frontendTerminalOutput = await getTerminalOutput ( page , appId , "frontend" ) ;
128+ expect ( frontendTerminalOutput ) . toContain ( "Frontend stdout: App started." ) ;
129+ expect ( frontendTerminalOutput ) . toContain ( "Frontend stdout: Backend message received." ) ;
130+ expect ( frontendTerminalOutput ) . toContain ( "Backend stdout: Hello from Flask!" ) ; // Should also see backend logs in frontend for fullstack
131+ expect ( frontendTerminalOutput ) . toContain ( "Backend stderr: This is an error message." ) ; // Should also see backend errors in frontend for fullstack
132+
133+ await stopApp ( page , appId ) ;
134+ } ) ;
135+
136+ test ( "should stream logs to system terminal and frontend terminal in Frontend mode" , async ( {
137+ page,
138+ } ) => {
139+ test . setTimeout ( 60000 ) ;
140+
141+ // Start the app in Frontend mode
142+ await startApp ( page , appId , "frontend" ) ;
143+ await page . waitForTimeout ( 5000 ) ; // Give time for logs
144+
145+ const systemMessages = await getAppOutput ( page , appId ) ;
146+ expect ( systemMessages ) . toContain ( "Frontend stdout: App started." ) ;
147+ expect ( systemMessages ) . not . toContain ( "Backend stdout:" ) ; // Should not contain backend logs
148+
149+ await switchTerminal ( page , "frontend" ) ;
150+ const frontendTerminalOutput = await getTerminalOutput ( page , appId , "frontend" ) ;
151+ expect ( frontendTerminalOutput ) . toContain ( "Frontend stdout: App started." ) ;
152+ expect ( frontendTerminalOutput ) . not . toContain ( "Backend stdout:" ) ;
153+
154+ await stopApp ( page , appId ) ;
155+ } ) ;
156+
157+ test ( "should stream logs to system terminal and backend terminal in Backend mode" , async ( {
158+ page,
159+ } ) => {
160+ test . setTimeout ( 60000 ) ;
161+
162+ // Start the app in Backend mode
163+ await startApp ( page , appId , "backend" ) ;
164+ await page . waitForTimeout ( 5000 ) ; // Give time for logs
165+
166+ const systemMessages = await getAppOutput ( page , appId ) ;
167+ expect ( systemMessages ) . toContain ( "Backend stdout: Hello from Flask!" ) ;
168+ expect ( systemMessages ) . toContain ( "Backend stderr: This is an error message." ) ;
169+ expect ( systemMessages ) . not . toContain ( "Frontend stdout:" ) ; // Should not contain frontend logs
170+
171+ await switchTerminal ( page , "backend" ) ;
172+ const backendTerminalOutput = await getTerminalOutput ( page , appId , "backend" ) ;
173+ expect ( backendTerminalOutput ) . toContain ( "Backend stdout: Hello from Flask!" ) ;
174+ expect ( backendTerminalOutput ) . toContain ( "Backend stderr: This is an error message." ) ;
175+ expect ( backendTerminalOutput ) . not . toContain ( "Frontend stdout:" ) ;
176+
177+ await stopApp ( page , appId ) ;
178+ } ) ;
179+ } ) ;
0 commit comments