Merge pull request #33868 from overleaf/dk-package-loading-tests

[web] Add tests for pyodide worker streams and output pane rendering

GitOrigin-RevId: 41ffc25230be23d68d50c61980cfaf1260a0247d
This commit is contained in:
Chris Dryden
2026-06-03 12:04:08 +01:00
committed by Copybot
parent f1282ee5cd
commit e38f4e18e4
2 changed files with 153 additions and 0 deletions
@@ -302,6 +302,62 @@ describe('<PythonOutputPane />', function () {
)
})
it('renders stdout, stderr, and info lines with visually distinct CSS classes', function () {
const executablePythonFileContents = [
'import sys',
"print('hello!')",
"sys.stderr.write('boom\\n')",
'while True:',
' pass',
].join('\n')
const projectFiles = {
[pythonExecutableScript.filename]: executablePythonFileContents,
}
const ProjectProvider = makeProjectProvider(projectFiles)
cy.mount(
<EditorProviders
scope={{
editor: {
sharejs_doc: {
doc_id: pythonExecutableScript.file_id,
getSnapshot: () => executablePythonFileContents,
},
currentDocumentId: pythonExecutableScript.file_id,
openDocName: pythonExecutableScript.filename,
},
}}
providers={{ FileTreePathProvider, ProjectProvider }}
>
<PythonExecutionProvider>
<PythonOutputPane />
</PythonExecutionProvider>
</EditorProviders>
)
cy.findByRole('button', { name: 'Run Python code' })
.should('not.be.disabled')
.click()
cy.findByText('hello!')
.should('have.class', 'ide-redesign-python-output-pane-line-stdout')
.and('not.have.class', 'ide-redesign-python-output-pane-line-stderr')
.and('not.have.class', 'ide-redesign-python-output-pane-line-info')
cy.findByText('boom')
.should('have.class', 'ide-redesign-python-output-pane-line-stderr')
.and('not.have.class', 'ide-redesign-python-output-pane-line-stdout')
.and('not.have.class', 'ide-redesign-python-output-pane-line-info')
cy.findByRole('button', { name: 'Stop Python execution' })
.should('not.be.disabled')
.click()
cy.findByText('Execution interrupted')
.should('have.class', 'ide-redesign-python-output-pane-line-info')
.and('not.have.class', 'ide-redesign-python-output-pane-line-stdout')
.and('not.have.class', 'ide-redesign-python-output-pane-line-stderr')
})
it('can load common python data analysis packages on code execution', function () {
const executablePythonFileContents = [
'import tomli',
@@ -587,6 +587,103 @@ describe('PyodideWorkerClient', function () {
})
})
describe('output-line forwarding', function () {
function setupClientWithOutputTracking() {
const outputCalls: Parameters<OutputCallback>[] = []
const client = new PyodideWorkerClient({
baseAssetPath: BASE_ASSET_PATH,
createWorker,
onOutput: (...args) => {
outputCalls.push(args)
},
fileUploader: fileUploaderStub,
})
const worker = WorkerMock.instances[0]
worker.emitMessage({ type: 'listening' })
return { client, worker, outputCalls }
}
it('forwards stdout output-line events to the output callback', function () {
const { worker, outputCalls } = setupClientWithOutputTracking()
worker.emitMessage({
type: 'output-line',
stream: 'stdout',
line: 'hello!',
fileId: 'main.py',
executionId: 'exec-stdout',
})
expect(outputCalls).to.deep.equal([
['stdout', 'hello!', 'main.py', 'exec-stdout'],
])
})
it('forwards stderr output-line events to the output callback', function () {
const { worker, outputCalls } = setupClientWithOutputTracking()
worker.emitMessage({
type: 'output-line',
stream: 'stderr',
line: 'boom',
fileId: 'main.py',
executionId: 'exec-stderr',
})
expect(outputCalls).to.deep.equal([
['stderr', 'boom', 'main.py', 'exec-stderr'],
])
})
it('forwards info output-line events to the output callback', function () {
const { worker, outputCalls } = setupClientWithOutputTracking()
worker.emitMessage({
type: 'output-line',
stream: 'info',
line: 'Loading numpy from package index',
fileId: 'main.py',
executionId: 'exec-info',
})
expect(outputCalls).to.deep.equal([
['info', 'Loading numpy from package index', 'main.py', 'exec-info'],
])
})
it('preserves stream type when forwarding stdout, stderr, and info in sequence', function () {
const { worker, outputCalls } = setupClientWithOutputTracking()
worker.emitMessage({
type: 'output-line',
stream: 'info',
line: 'Loading package',
fileId: 'main.py',
executionId: 'exec-mixed',
})
worker.emitMessage({
type: 'output-line',
stream: 'stdout',
line: 'result',
fileId: 'main.py',
executionId: 'exec-mixed',
})
worker.emitMessage({
type: 'output-line',
stream: 'stderr',
line: 'warning',
fileId: 'main.py',
executionId: 'exec-mixed',
})
expect(outputCalls.map(call => call[0])).to.deep.equal([
'info',
'stdout',
'stderr',
])
})
})
describe('reset', function () {
it('terminates the current worker and creates a new one', function () {
const client = new PyodideWorkerClient({