diff --git a/mobile-app/lib/service/learn/learn_file_service.dart b/mobile-app/lib/service/learn/learn_file_service.dart index 077d0c5d6..ab9e8dee2 100644 --- a/mobile-app/lib/service/learn/learn_file_service.dart +++ b/mobile-app/lib/service/learn/learn_file_service.dart @@ -274,7 +274,12 @@ class LearnFileService { if (babelRes?.error != null) { throw Exception('Babel transpilation failed: ${babelRes?.error}'); } - fileContents = babelRes?.value; + + final result = babelRes?.value as Map?; + if (result?['success'] == false) { + throw Exception('Babel transpilation failed: ${result?['error']}'); + } + fileContents = result?['code']; Document document = parse(challengeContent); diff --git a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart index aa9f1b285..4bf12c0fb 100644 --- a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart +++ b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart @@ -702,13 +702,34 @@ class ChallengeViewModel extends BaseViewModel { _userConsoleMessages = []; setTestConsoleMessages = ['

// running tests

']; - // Get user code console messages + String userCode; + try { + userCode = await builder.buildUserCode( + challenge!, + _babelWebView.webViewController, + ); + } catch (e) { + String errorMessage = e.toString(); + if (errorMessage.contains('Babel transpilation failed')) { + errorMessage = errorMessage.replaceFirst('Exception: ', ''); + } + String userFriendlyMessage = parseSyntaxError(errorMessage); + + setPanelType = PanelType.hint; + setHint = '

$userFriendlyMessage

'; + setTestConsoleMessages = [ + ...testConsoleMessages, + '

$userFriendlyMessage

', + '

// tests completed

', + ]; + setIsRunningTests = false; + _scaffoldKey.currentState?.openEndDrawer(); + return; + } + if ([1, 26, 28].contains(challenge!.challengeType)) { final evalResult = await testController!.callAsyncJavaScript( - functionBody: await builder.buildUserCode( - challenge!, - _babelWebView.webViewController, - ), + functionBody: userCode, ); if (evalResult != null && evalResult.error != null) { setUserConsoleMessages = [ @@ -724,10 +745,7 @@ class ChallengeViewModel extends BaseViewModel { final updateTestRunnerRes = await testController!.callAsyncJavaScript( functionBody: ScriptBuilder.runnerScript, arguments: { - 'userCode': await builder.buildUserCode( - challenge!, - _babelWebView.webViewController, - ), + 'userCode': userCode, 'workerType': builder.getWorkerType(challenge!.challengeType), 'combinedCode': await builder.combinedCode(challenge!), 'editableRegionContent': editableRegionContent, diff --git a/mobile-app/lib/ui/views/learn/test_runner.dart b/mobile-app/lib/ui/views/learn/test_runner.dart index fbd63b0c0..dada20590 100644 --- a/mobile-app/lib/ui/views/learn/test_runner.dart +++ b/mobile-app/lib/ui/views/learn/test_runner.dart @@ -7,8 +7,17 @@ import 'package:freecodecamp/service/learn/learn_file_service.dart'; class ScriptBuilder { final LearnFileService fileService = locator(); - static const transpileScript = - 'return Babel.transform(code, { presets: ["env"] }).code'; + static const transpileScript = ''' +try { + return { success: true, code: Babel.transform(code, { presets: ["env"] }).code }; +} catch (e) { + let errorMsg = e.message || e.toString(); + if (e.loc) { + errorMsg = "SyntaxError: " + e.message + " (" + e.loc.line + ":" + e.loc.column + ")"; + } + return { success: false, error: errorMsg }; +} +'''; static const hideFccHeaderStyle = '''