@robotical/martyblocksjr 3.5.30 → 3.5.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/editions/free/src/app.bundle.js +1 -1
  2. package/editions/free/src/css/lobby.css +46 -24
  3. package/editions/free/src/home.html +4 -0
  4. package/editions/free/src/inapp/style/tutorials.css +110 -0
  5. package/editions/free/src/inapp/tutorials.html +16 -0
  6. package/editions/free/src/localizations/bg.json +19 -18
  7. package/editions/free/src/localizations/ca.json +19 -18
  8. package/editions/free/src/localizations/cs.json +19 -18
  9. package/editions/free/src/localizations/cy.json +19 -18
  10. package/editions/free/src/localizations/da.json +19 -18
  11. package/editions/free/src/localizations/de.json +19 -18
  12. package/editions/free/src/localizations/el.json +19 -18
  13. package/editions/free/src/localizations/en.json +19 -18
  14. package/editions/free/src/localizations/es.json +19 -18
  15. package/editions/free/src/localizations/fi.json +19 -18
  16. package/editions/free/src/localizations/fr.json +19 -18
  17. package/editions/free/src/localizations/it.json +19 -18
  18. package/editions/free/src/localizations/ja.json +19 -18
  19. package/editions/free/src/localizations/ko.json +19 -18
  20. package/editions/free/src/localizations/nl.json +19 -18
  21. package/editions/free/src/localizations/no.json +19 -18
  22. package/editions/free/src/localizations/pl.json +19 -18
  23. package/editions/free/src/localizations/pt-br.json +19 -18
  24. package/editions/free/src/localizations/pt.json +19 -18
  25. package/editions/free/src/localizations/sv.json +19 -18
  26. package/editions/free/src/localizations/th.json +19 -18
  27. package/editions/free/src/localizations/tr.json +19 -18
  28. package/editions/free/src/localizations/uk.json +19 -18
  29. package/editions/free/src/localizations/zh-cn.json +19 -18
  30. package/editions/free/src/localizations/zh-tw.json +19 -18
  31. package/package.json +1 -1
  32. package/tests/e2e/chromium-79-smoke.test.js +172 -15
  33. package/tests/tutorial/TutorialFetcher.test.js +91 -0
@@ -6,6 +6,7 @@
6
6
  "INTERFACE_GUIDE": "界面指南",
7
7
  "PAINT_EDITOR_GUIDE": "绘图编辑器指南",
8
8
  "BLOCKS_GUIDE": "积木指南",
9
+ "TUTORIALS": "Tutorials",
9
10
  "PRIVACY_POLICY": "隐私政策",
10
11
  "ABOUT_WHAT_IS": "ScratchJr 是什么?",
11
12
  "ABOUT_DESCRIPTION": "ScratchJr 是一个入门级的编程语言,它可以让幼儿 ( 5-7岁 ) 创建互动的故事和游戏,孩子利用图形化的程序积木让角色移动、跳跃、舞蹈、唱歌。孩子也可以利用绘图编辑器绘制自己的角色、用麦克风录制自己声音、用照相机加入自己拍摄的照片。最后用拼积木的方法组合成程序,让他们心中的角色动起来。",
@@ -575,7 +576,7 @@
575
576
  "COG_AND_MARTY_TUTORIAL_MARTY_MOTION_BLOCKS": "现在,让我们选择 Marty 的运动积木。点击 Marty 积木的“运动”类别。",
576
577
  "COG_AND_MARTY_TUTORIAL_MARTY_DANCE_BLOCK": "快完成了!将“Marty Dance”积木拖到脚本区域。这个积木会让 Marty 在收到消息时跳舞。",
577
578
  "COG_AND_MARTY_TUTORIAL_END": "太棒了!你成功编写了 Cog 和 Marty 之间的交互代码。现在点击 Cog 的按钮,就能看到 Marty 跳舞啦!",
578
- "COG_JRBLOCKS1_TITLE": "创作一首曲子",
579
+ "COG_JRBLOCKS1_TITLE": "1. 创作一首曲子",
579
580
  "COG_JRBLOCKS1_STEP_1_TEXT": "让我们让 Cog 演奏一段曲子吧!",
580
581
  "COG_JRBLOCKS1_STEP_2_TEXT": "选择 Cog Events 类别",
581
582
  "COG_JRBLOCKS1_STEP_3_TEXT": "添加按钮按下块",
@@ -602,7 +603,7 @@
602
603
  "COG_JRBLOCKS1_STEP_24_TEXT": "将节奏设置为 180 bpm",
603
604
  "COG_JRBLOCKS1_STEP_25_TEXT": "按下按钮!",
604
605
  "COG_JRBLOCKS1_STEP_26_TEXT": "<b>做得好!</b><br />现在看看你是否能创作出属于自己的曲子🎵",
605
- "COG_JRBLOCKS2_TITLE": "做一场灯光秀",
606
+ "COG_JRBLOCKS2_TITLE": "2. 做一场灯光秀",
606
607
  "COG_JRBLOCKS2_STEP_1_TEXT": "让我们做一场灯光秀吧!✨",
607
608
  "COG_JRBLOCKS2_STEP_2_TEXT": "选择<i><u>Cog Events</u></i>类别",
608
609
  "COG_JRBLOCKS2_STEP_3_TEXT": "添加<i><u>按下按钮</u></i>块",
@@ -633,7 +634,7 @@
633
634
  "COG_JRBLOCKS2_STEP_28_TEXT": "添加<i><u>关灯</u></i>块",
634
635
  "COG_JRBLOCKS2_STEP_29_TEXT": "按下按钮!",
635
636
  "COG_JRBLOCKS2_STEP_30_TEXT": "<b>做得好!</b> </br>现在制作您自己的颜色和图案!",
636
- "COG_JRBLOCKS3_TITLE": "制作声光秀",
637
+ "COG_JRBLOCKS3_TITLE": "3. 制作声光秀",
637
638
  "COG_JRBLOCKS3_STEP_1_TEXT": "让我们来一场声光秀吧!🎵✨",
638
639
  "COG_JRBLOCKS3_STEP_2_TEXT": "选择<i><u>cog event</u></i>块",
639
640
  "COG_JRBLOCKS3_STEP_3_TEXT": "添加<i><u>按下按钮</u></i>块",
@@ -660,7 +661,7 @@
660
661
  "COG_JRBLOCKS3_STEP_24_TEXT": "按下按钮!",
661
662
  "COG_JRBLOCKS3_STEP_25_TEXT": "按下按钮!",
662
663
  "COG_JRBLOCKS3_STEP_26_TEXT": "做得好!</br>下一步:- 尝试改变颜色和图案。尝试创作另一首歌曲。看看能否让颜色随着每个音符而变化。看看能否使用循环来缩短代码长度。小组活动:- 向全班同学演示你的声光表演",
663
- "COG_JRBLOCKS4_TITLE": "制作蚀刻画",
664
+ "COG_JRBLOCKS4_TITLE": "4. 制作蚀刻画",
664
665
  "COG_JRBLOCKS4_STEP_1_TEXT": "让我们来制作蚀刻素描吧!",
665
666
  "COG_JRBLOCKS4_STEP_2_TEXT": "选择<i><u>Cog Events</u></i>类别",
666
667
  "COG_JRBLOCKS4_STEP_3_TEXT": "添加<i><u>倾斜</u></i>块",
@@ -687,7 +688,7 @@
687
688
  "COG_JRBLOCKS4_STEP_24_TEXT": "运行设定速度块",
688
689
  "COG_JRBLOCKS4_STEP_25_TEXT": "画点东西!",
689
690
  "COG_JRBLOCKS4_STEP_26_TEXT": "做得好!</br>现在看看你还能画什么!",
690
- "COG_JRBLOCKS5_TITLE": "制作迷宫游戏",
691
+ "COG_JRBLOCKS5_TITLE": "5. 制作迷宫游戏",
691
692
  "COG_JRBLOCKS5_DESCRIPTION": "我们将制作一个迷宫游戏,使用齿轮引导精灵绕过迷宫",
692
693
  "COG_JRBLOCKS5_STEP_1_TEXT": "让我们做一个迷宫游戏吧!",
693
694
  "COG_JRBLOCKS5_STEP_2_TEXT": "选择<i><u>Cog Events</u></i>类别",
@@ -735,7 +736,7 @@
735
736
  "COG_JRBLOCKS5_STEP_44_TEXT": "添加“转到第 2 页”块",
736
737
  "COG_JRBLOCKS5_STEP_45_TEXT": "尝试引导马蒂达到目标!",
737
738
  "COG_JRBLOCKS5_STEP_46_TEXT": "做得好!</br>现在看看你是否可以为迷宫添加更多关卡!",
738
- "COG_JRBLOCKS6_TITLE": "让我们制作一个停车传感器!",
739
+ "COG_JRBLOCKS6_TITLE": "6. 让我们制作一个停车传感器!",
739
740
  "COG_JRBLOCKS6_STEP_1_TEXT": "让我们制作一个停车传感器!",
740
741
  "COG_JRBLOCKS6_STEP_2_TEXT": "选择<i><u>Cog Events</u></i>类别",
741
742
  "COG_JRBLOCKS6_STEP_3_TEXT": "添加<i><u>物体感知</u></i>区块",
@@ -776,7 +777,7 @@
776
777
  "COG_JRBLOCKS6_STEP_39_TEXT": "尝试一下!",
777
778
  "COG_JRBLOCKS6_STEP_39_FULLSCREEN_TEXT": "在全屏模式下尝试",
778
779
  "COG_JRBLOCKS6_STEP_40_TEXT": "做得好!</br>现在尝试让你的灯光和声音更令人兴奋!",
779
- "COG_JRBLOCKS7_TITLE": "让我们做一个计数器!",
780
+ "COG_JRBLOCKS7_TITLE": "7. 让我们做一个计数器!",
780
781
  "COG_JRBLOCKS7_STEP_1_TEXT": "让我们做一个计数器!",
781
782
  "COG_JRBLOCKS7_STEP_2_TEXT": "添加<b>物体感应到</b>块",
782
783
  "COG_JRBLOCKS7_STEP_3_TEXT": "将其更改为在<b>正确</b>物体传感器上触发",
@@ -802,7 +803,7 @@
802
803
  "COG_JRBLOCKS7_STEP_23_TEXT": "添加<b>按下按钮</b>和<b>重置计数器</b>块",
803
804
  "COG_JRBLOCKS7_STEP_24_TEXT": "按下 Cog 上的按钮来重置计数器",
804
805
  "COG_JRBLOCKS7_STEP_25_TEXT": "<p><b>做得好!</b>您已将 cog 制作成一个<b>里程表</b> - 一种测量旋转次数的装置!</p> <p>&nbsp;</p><ul><li>当您反向旋转 cog 时,您可以让它倒计时吗?</li><li>制作一个滚轮并使用 cog 测量距离</li></ul>",
805
- "COG_JRBLOCKS8_TITLE": "制作一盏小夜灯",
806
+ "COG_JRBLOCKS8_TITLE": "8. 制作一盏小夜灯",
806
807
  "COG_JRBLOCKS8_STEP_1_TEXT": "我们来做一盏小夜灯吧!",
807
808
  "COG_JRBLOCKS8_STEP_2_TEXT": "选择<b>Cog Events</b>类别",
808
809
  "COG_JRBLOCKS8_STEP_3_TEXT": "添加<b>从灯亮处开始</b>块",
@@ -834,7 +835,7 @@
834
835
  "COG_JRBLOCKS8_STEP_29_TEXT": "返回第 1 页",
835
836
  "COG_JRBLOCKS8_STEP_30_TEXT": "试试吧!现在天黑时就会出现星空",
836
837
  "COG_JRBLOCKS8_STEP_31_TEXT": "<p><b>做得好!</b><br /> 你把 cog 做成了夜灯!</p><p>&nbsp;</p><p>现在试着和你的朋友一起做一场灯光秀</p>",
837
- "COG_JRBLOCKS9_TITLE": "让我们来玩躲避球游戏吧!",
838
+ "COG_JRBLOCKS9_TITLE": "9. 让我们来玩躲避球游戏吧!",
838
839
  "COG_JRBLOCKS9_STEP_1_TEXT": "让我们来玩躲避球游戏吧!",
839
840
  "COG_JRBLOCKS9_STEP_2_TEXT": "使用背景按钮添加<b>健身房背景</b>",
840
841
  "COG_JRBLOCKS9_STEP_3_TEXT": "使用<i><u>文本</u></i>按钮添加文本“<b>摇一摇开始</b>”",
@@ -879,7 +880,7 @@
879
880
  "COG_JRBLOCKS9_STEP_42_TEXT": "尝试一下!",
880
881
  "COG_JRBLOCKS9_STEP_43_TEXT": "现在看看你能获得多高的分数!",
881
882
  "COG_JRBLOCKS9_STEP_44_TEXT": "<p><b>干得好!</b><br /> 你成功制作了一款游戏!</p><p>&nbsp;</p><p>你能制作一个获胜画面或其他关卡吗?你会如何使用上面的代码?</p><p>&nbsp;</p><p>你能让齿轮在收集星星时亮起来吗?</p>",
882
- "COG_JRBLOCKS10_TITLE": "和 Marty 一起制作形状",
883
+ "COG_JRBLOCKS10_TITLE": "10. 和 Marty 一起制作形状",
883
884
  "COG_JRBLOCKS10_STEP_1_TEXT": "让我们和机器人马蒂一起制作一些形状吧!",
884
885
  "COG_JRBLOCKS10_STEP_2_TEXT": "开启<b>Marty 模式</b>!",
885
886
  "COG_JRBLOCKS10_STEP_3_TEXT": "添加 <b>On Flag</b> 块",
@@ -916,7 +917,7 @@
916
917
  "COG_JRBLOCKS10_STEP_34_TEXT": "添加方块让 Marty <b>转身</b>",
917
918
  "COG_JRBLOCKS10_STEP_35_TEXT": "试试看!使用<b>物体传感器</b>来转动 Marty",
918
919
  "COG_JRBLOCKS10_STEP_44_TEXT": "<p><b>做得好!</b><br />您了解了<b>相对方向</b>,而不是<b>绝对方向</b>。<br /><br />您还可以画什么?",
919
- "COG_JRBLOCKS11_TITLE": "太空游戏",
920
+ "COG_JRBLOCKS11_TITLE": "11. 太空游戏",
920
921
  "COG_JRBLOCKS11_STEP_1_TEXT": "让我们制作一款以太空为背景的游戏吧!",
921
922
  "COG_JRBLOCKS11_STEP_2_TEXT": "添加<b>太空背景</b>",
922
923
  "COG_JRBLOCKS11_STEP_3_TEXT": "添加<b>火箭精灵</B>",
@@ -956,7 +957,7 @@
956
957
  "COG_JRBLOCKS11_STEP_37_TEXT": "添加<b>转到第 2 页</b>块",
957
958
  "COG_JRBLOCKS11_STEP_38_TEXT": "试试吧!按一下绿旗即可开始,然后摇动齿轮即可重新启动",
958
959
  "COG_JRBLOCKS11_STEP_44_TEXT": "<p><b>做得好!</b><br />您制作了一个太空游戏!<br /><br />您能添加更多星星来收集吗?",
959
- "COG_JRBLOCKS12_TITLE": "让我们做一个反应测试游戏吧!",
960
+ "COG_JRBLOCKS12_TITLE": "12. 让我们做一个反应测试游戏吧!",
960
961
  "COG_JRBLOCKS12_STEP_1_TEXT": "让我们做一个反应测试游戏吧!",
961
962
  "COG_JRBLOCKS12_STEP_2_TEXT": "让马蒂永远下台",
962
963
  "COG_JRBLOCKS12_STEP_3_TEXT": "当 Marty 触碰另一个精灵时<b>发送消息</b>",
@@ -994,7 +995,7 @@
994
995
  "COG_JRBLOCKS12_STEP_35_TEXT": "<b>增加节奏</b>以在中途加速游戏!",
995
996
  "COG_JRBLOCKS12_STEP_36_TEXT": "尝试一下!",
996
997
  "COG_JRBLOCKS12_STEP_47_TEXT": "<p><b>做得好!</b><br />您制作了一个反应测试游戏!<br /><br />您能让它变得更快吗?<br /><Br />与朋友配对,同时使用两个齿轮尝试!",
997
- "COG_JRBLOCKS13_TITLE": "冒险故事",
998
+ "COG_JRBLOCKS13_TITLE": "13. 冒险故事",
998
999
  "COG_JRBLOCKS13_STEP_1_TEXT": "让我们来创作一个冒险故事吧!",
999
1000
  "COG_JRBLOCKS13_STEP_2_TEXT": "添加背景",
1000
1001
  "COG_JRBLOCKS13_STEP_3_TEXT": "为 Marty 添加<b>移动控制</b>",
@@ -1043,7 +1044,7 @@
1043
1044
  "COG_JRBLOCKS13_STEP_46_TEXT": "添加<b>摇晃后转到第 3 页</b>块",
1044
1045
  "COG_JRBLOCKS13_STEP_47_TEXT": "试试看!<br /><Br />摇动齿轮敲门",
1045
1046
  "COG_JRBLOCKS13_STEP_48_TEXT": "<p><b>做得好!</b><br />现在,使用你之前学到的所有知识,继续这个故事,为马蒂和独角兽创造一次冒险",
1046
- "MARTY_JRBLOCKS1_TITLE": "让马蒂动起来",
1047
+ "MARTY_JRBLOCKS1_TITLE": "1. 让马蒂动起来",
1047
1048
  "MARTY_JRBLOCKS1_STEP_1_TEXT": "在本教程中,我们将学习如何在 BlocksJr 中使用基本函数。",
1048
1049
  "MARTY_JRBLOCKS1_STEP_2_TEXT": "首先,我们来连接马蒂。点击马蒂按钮连接马蒂。",
1049
1050
  "MARTY_JRBLOCKS1_STEP_3_TEXT": "这些拼图块形状的模块叫做<b/>函数</b>。<br/><br/>函数就像动作一样,是一段告诉 Marty“嘿,做这个!”的代码。",
@@ -1060,7 +1061,7 @@
1060
1061
  "MARTY_JRBLOCKS1_STEP_14_TEXT": "现在我们来移动马蒂!首先,让他向前走四步。<br/><br/>在“准备”和“停止”之间放置四个这样的<b/>",
1061
1062
  "MARTY_JRBLOCKS1_STEP_15_TEXT": "他向前走之后,我们让马蒂向左走!如图所示,在红色“停止”方块前放置<b/>3个向左滑动的方块</b>。",
1062
1063
  "MARTY_JRBLOCKS1_END": "你成功了!你可以在 BlocksJr 里让 Marty 动起来!<br/><br/>不妨探索一下这款应用,看看你还能让 Marty 做什么,然后再回来学习教程 2!",
1063
- "MARTY_JRBLOCKS2_TITLE": "代码清理:参数",
1064
+ "MARTY_JRBLOCKS2_TITLE": "2. 代码清理:参数",
1064
1065
  "MARTY_JRBLOCKS2_STEP_1_TEXT": "在本教程中,我们将学习如何使用参数来简化和缩小代码。",
1065
1066
  "MARTY_JRBLOCKS2_STEP_2_TEXT": "首先,我们来连接马蒂。点击马蒂按钮连接马蒂。",
1066
1067
  "MARTY_JRBLOCKS2_STEP_3_TEXT": "这是我们之前让马蒂向前走四步的代码。你能看出有什么方法可以简化我们的指令吗?",
@@ -1072,7 +1073,7 @@
1072
1073
  "MARTY_JRBLOCKS2_STEP_9_TEXT": "现在添加一个类似示例代码的<b/>向左滑动</b>代码块——总共有多少个向左滑动代码块?你应该在向左滑动代码块中放入什么参数?",
1073
1074
  "MARTY_JRBLOCKS2_STEP_10_TEXT": "快完成了!添加一个类似示例代码的<b/>向后走</b>代码块,并添加正确的参数。",
1074
1075
  "MARTY_JRBLOCKS2_END": "你做到了!你既是论证专家,又是代码简化天才!",
1075
- "MARTY_JRBLOCKS3_TITLE": "交通灯马蒂",
1076
+ "MARTY_JRBLOCKS3_TITLE": "3. 交通灯马蒂",
1076
1077
  "MARTY_JRBLOCKS3_STEP_1_TEXT": "在本教程中,我们将学习如何在 BlocksJr 中使用等待函数。",
1077
1078
  "MARTY_JRBLOCKS3_STEP_2_TEXT": "首先,我们来连接马蒂。点击马蒂按钮连接马蒂。",
1078
1079
  "MARTY_JRBLOCKS3_STEP_3_TEXT": "现在添加一个绿色旗帜代码块来开始我们的代码。",
@@ -1085,7 +1086,7 @@
1085
1086
  "MARTY_JRBLOCKS3_STEP_10_TEXT": "在绿色 LED 眼睛模块之前添加一个<b/>准备</b>模块,以便 Marty 可以在“开始!”之前做好准备。",
1086
1087
  "MARTY_JRBLOCKS3_STEP_11_TEXT": "绿色表示通行——你会让你的马蒂在绿色区域做什么呢?我们说过,当马蒂的眼睛变成绿色时,就庆祝吧!",
1087
1088
  "MARTY_JRBLOCKS3_END": "你做到了!点击绿旗,注意交通信号灯,马蒂!",
1088
- "MARTY_JRBLOCKS4_TITLE": "清理代码:重复",
1089
+ "MARTY_JRBLOCKS4_TITLE": "4. 清理代码:重复",
1089
1090
  "MARTY_JRBLOCKS4_STEP_1_TEXT": "马蒂想跳舞!让我们来试试他的跳舞功能,并学习如何使用重复功能来创作我们自己的马蒂舞蹈!",
1090
1091
  "MARTY_JRBLOCKS4_STEP_2_TEXT": "首先,我们来连接马蒂。点击马蒂按钮连接马蒂。",
1091
1092
  "MARTY_JRBLOCKS4_STEP_3_TEXT": "现在添加一个绿色旗帜代码块来开始我们的代码。",
@@ -1097,7 +1098,7 @@
1097
1098
  "MARTY_JRBLOCKS4_STEP_9_TEXT": "如果马蒂一直跳舞,他会累的!如果我们让他一直跳舞,他可能会累!如果我们只想让马蒂跳5次舞呢?我们可以在5次循环后按下停止按钮——但还有更简单的方法。",
1098
1099
  "MARTY_JRBLOCKS4_STEP_10_TEXT": "移除红色的重复代码块,并用这个闭环重复函数替换它。我们可以在这个代码块中放入代码片段,并根据需要重复执行任意次数。让马蒂重复你的舞蹈动作 5 次!",
1099
1100
  "MARTY_JRBLOCKS4_END": "你做到了!马蒂现在是舞蹈高手了!",
1100
- "MARTY_JRBLOCKS5_TITLE": "马蒂射门游戏",
1101
+ "MARTY_JRBLOCKS5_TITLE": "5. 马蒂射门游戏",
1101
1102
  "MARTY_JRBLOCKS5_STEP_1_TEXT": "在本教程中,我们将使用精灵图制作一个马蒂射门游戏!",
1102
1103
  "MARTY_JRBLOCKS5_STEP_2_TEXT": "首先,我们给马蒂小人找个踢足球的场地。进入背景菜单,选择“农场”。",
1103
1104
  "MARTY_JRBLOCKS5_STEP_3_TEXT": "为了进球,马蒂需要两样东西:一个足球和一个球网!点击加号选择两个新的角色:足球和球网。",
@@ -6,6 +6,7 @@
6
6
  "INTERFACE_GUIDE": "介面指南",
7
7
  "PAINT_EDITOR_GUIDE": "繪圖編輯器指南",
8
8
  "BLOCKS_GUIDE": "積木指南",
9
+ "TUTORIALS": "Tutorials",
9
10
  "PRIVACY_POLICY": "隱私權政策",
10
11
  "ABOUT_WHAT_IS": "ScratchJr 是什麼?",
11
12
  "ABOUT_DESCRIPTION": "ScratchJr 是個入門級程式語言,可以讓幼童( 5-7 歲) 建立自己的互動式媒體,像是故事和遊戲。孩子透過圖像化的程式方塊,像組合積木般來讓所建立的角色移動、跳躍、跳舞、唱歌。也可以利用繪圖編輯器來描繪出心目中的角色人物,使用麥克風錄製自己的聲音或其他音效,利用照像機來拍攝自己的照片或放入其他圖片-- 然後組合它們,將孩子心中的想像帶到真實世界。",
@@ -575,7 +576,7 @@
575
576
  "COG_AND_MARTY_TUTORIAL_MARTY_MOTION_BLOCKS": "現在,讓我們選擇 Marty 的運動積木。點選 Marty 積木的「運動」類別。",
576
577
  "COG_AND_MARTY_TUTORIAL_MARTY_DANCE_BLOCK": "快完成了!將“Marty Dance”積木拖到腳本區域。這個積木會讓 Marty 在收到消息時跳舞。",
577
578
  "COG_AND_MARTY_TUTORIAL_END": "太棒了!你成功寫了 Cog 和 Marty 之間的互動程式碼。現在點擊 Cog 的按鈕,就能看到 Marty 跳舞啦!",
578
- "COG_JRBLOCKS1_TITLE": "創作一首曲子",
579
+ "COG_JRBLOCKS1_TITLE": "1. 創作一首曲子",
579
580
  "COG_JRBLOCKS1_STEP_1_TEXT": "讓我們讓 Cog 演奏一段曲子吧!",
580
581
  "COG_JRBLOCKS1_STEP_2_TEXT": "選擇 Cog Events 類別",
581
582
  "COG_JRBLOCKS1_STEP_3_TEXT": "新增按鈕按下區塊",
@@ -602,7 +603,7 @@
602
603
  "COG_JRBLOCKS1_STEP_24_TEXT": "將節奏設定為 180 bpm",
603
604
  "COG_JRBLOCKS1_STEP_25_TEXT": "按下按鈕!",
604
605
  "COG_JRBLOCKS1_STEP_26_TEXT": "<b>做得好! </b><br />現在看看你是否能創作出屬於自己的曲子🎵",
605
- "COG_JRBLOCKS2_TITLE": "做一場燈光秀",
606
+ "COG_JRBLOCKS2_TITLE": "2. 做一場燈光秀",
606
607
  "COG_JRBLOCKS2_STEP_1_TEXT": "讓我們來做一場燈光秀吧! ✨",
607
608
  "COG_JRBLOCKS2_STEP_2_TEXT": "選擇<i><u>Cog Events</u></i>類別",
608
609
  "COG_JRBLOCKS2_STEP_3_TEXT": "加<i><u>按下按鈕</u></i>區塊",
@@ -633,7 +634,7 @@
633
634
  "COG_JRBLOCKS2_STEP_28_TEXT": "加<i><u>關燈</u></i>塊",
634
635
  "COG_JRBLOCKS2_STEP_29_TEXT": "按下按鈕!",
635
636
  "COG_JRBLOCKS2_STEP_30_TEXT": "<b>做得好! </b> </br>現在製作自己的顏色和圖案!",
636
- "COG_JRBLOCKS3_TITLE": "製作聲光秀",
637
+ "COG_JRBLOCKS3_TITLE": "3. 製作聲光秀",
637
638
  "COG_JRBLOCKS3_STEP_1_TEXT": "讓我們來一場聲光秀吧! 🎵✨",
638
639
  "COG_JRBLOCKS3_STEP_2_TEXT": "選擇<i><u>cog event</u></i>區塊",
639
640
  "COG_JRBLOCKS3_STEP_3_TEXT": "加<i><u>按下按鈕</u></i>區塊",
@@ -660,7 +661,7 @@
660
661
  "COG_JRBLOCKS3_STEP_24_TEXT": "按下按鈕!",
661
662
  "COG_JRBLOCKS3_STEP_25_TEXT": "按下按鈕!",
662
663
  "COG_JRBLOCKS3_STEP_26_TEXT": "做得好! </br>下一步:- 嘗試改變顏色和圖案。嘗試創作另一首歌曲。看看能否讓顏色隨著每個音符而改變。看看能否使用循環來縮短程式碼長度。團體活動:- 向全班示範你的聲光錶演",
663
- "COG_JRBLOCKS4_TITLE": "製作蝕刻畫",
664
+ "COG_JRBLOCKS4_TITLE": "4. 製作蝕刻畫",
664
665
  "COG_JRBLOCKS4_STEP_1_TEXT": "讓我們來製作蝕刻素描吧!",
665
666
  "COG_JRBLOCKS4_STEP_2_TEXT": "選擇<i><u>Cog Events</u></i>類別",
666
667
  "COG_JRBLOCKS4_STEP_3_TEXT": "加入<i><u>傾斜</u></i>塊",
@@ -687,7 +688,7 @@
687
688
  "COG_JRBLOCKS4_STEP_24_TEXT": "運行設定速度塊",
688
689
  "COG_JRBLOCKS4_STEP_25_TEXT": "畫點東西!",
689
690
  "COG_JRBLOCKS4_STEP_26_TEXT": "做得好! </br>現在看看你還能畫什麼!",
690
- "COG_JRBLOCKS5_TITLE": "製作迷宮遊戲",
691
+ "COG_JRBLOCKS5_TITLE": "5. 製作迷宮遊戲",
691
692
  "COG_JRBLOCKS5_DESCRIPTION": "我們將製作一個迷宮遊戲,使用齒輪引導精靈繞過迷宮",
692
693
  "COG_JRBLOCKS5_STEP_1_TEXT": "讓我們來做一個迷宮遊戲吧!",
693
694
  "COG_JRBLOCKS5_STEP_2_TEXT": "選擇<i><u>Cog Events</u></i>類別",
@@ -735,7 +736,7 @@
735
736
  "COG_JRBLOCKS5_STEP_44_TEXT": "新增「轉到第 2 頁」區塊",
736
737
  "COG_JRBLOCKS5_STEP_45_TEXT": "試著引導馬蒂達到目標!",
737
738
  "COG_JRBLOCKS5_STEP_46_TEXT": "做得好! </br>現在看看你是否可以為迷宮添加更多關卡!",
738
- "COG_JRBLOCKS6_TITLE": "讓我們製作一個停車感應器!",
739
+ "COG_JRBLOCKS6_TITLE": "6. 讓我們製作一個停車感應器!",
739
740
  "COG_JRBLOCKS6_STEP_1_TEXT": "讓我們製作一個停車感應器!",
740
741
  "COG_JRBLOCKS6_STEP_2_TEXT": "選擇<i><u>Cog Events</u></i>類別",
741
742
  "COG_JRBLOCKS6_STEP_3_TEXT": "加<i><u>物體感知</u></i>區塊",
@@ -776,7 +777,7 @@
776
777
  "COG_JRBLOCKS6_STEP_39_TEXT": "嘗試一下!",
777
778
  "COG_JRBLOCKS6_STEP_39_FULLSCREEN_TEXT": "在全螢幕模式下嘗試",
778
779
  "COG_JRBLOCKS6_STEP_40_TEXT": "做得好! </br>現在嘗試讓你的燈光和聲音更令人興奮!",
779
- "COG_JRBLOCKS7_TITLE": "讓我們來做一個計數器!",
780
+ "COG_JRBLOCKS7_TITLE": "7. 讓我們來做一個計數器!",
780
781
  "COG_JRBLOCKS7_STEP_1_TEXT": "讓我們來做一個計數器!",
781
782
  "COG_JRBLOCKS7_STEP_2_TEXT": "加入<b>物體感應到</b>塊",
782
783
  "COG_JRBLOCKS7_STEP_3_TEXT": "將其變更為在<b>正確</b>物體感測器上觸發",
@@ -802,7 +803,7 @@
802
803
  "COG_JRBLOCKS7_STEP_23_TEXT": "新增<b>按下按鈕</b>和<b>重置計數器</b>區塊",
803
804
  "COG_JRBLOCKS7_STEP_24_TEXT": "按下 Cog 上的按鈕來重設計數器",
804
805
  "COG_JRBLOCKS7_STEP_25_TEXT": "<p><b>做得好! </b>您已將 cog 製作成一個<b>里程表</b> - 測量旋轉次數的裝置! </p> <p>&nbsp;</p><ul><li>當您反向旋轉 cog 時,您可以讓它倒數嗎? </li><li>製作一個滾輪並使用 cog 測量距離</li></ul>",
805
- "COG_JRBLOCKS8_TITLE": "製作一盞小夜燈",
806
+ "COG_JRBLOCKS8_TITLE": "8. 製作一盞小夜燈",
806
807
  "COG_JRBLOCKS8_STEP_1_TEXT": "我們來做一盞小夜燈吧!",
807
808
  "COG_JRBLOCKS8_STEP_2_TEXT": "選擇<b>Cog Events</b>類別",
808
809
  "COG_JRBLOCKS8_STEP_3_TEXT": "加入<b>從燈亮處開始</b>塊",
@@ -834,7 +835,7 @@
834
835
  "COG_JRBLOCKS8_STEP_29_TEXT": "回第 1 頁",
835
836
  "COG_JRBLOCKS8_STEP_30_TEXT": "試試吧!現在天黑時就會出現星空",
836
837
  "COG_JRBLOCKS8_STEP_31_TEXT": "<p><b>做得好! </b><br /> 你把 cog 做成了夜燈! </p><p>&nbsp;</p><p>現在試著和你的朋友一起做一場燈光秀</p>",
837
- "COG_JRBLOCKS9_TITLE": "讓我們來玩躲避球遊戲吧!",
838
+ "COG_JRBLOCKS9_TITLE": "9. 讓我們來玩躲避球遊戲吧!",
838
839
  "COG_JRBLOCKS9_STEP_1_TEXT": "讓我們來玩躲避球遊戲吧!",
839
840
  "COG_JRBLOCKS9_STEP_2_TEXT": "使用背景按鈕新增<b>健身房背景</b>",
840
841
  "COG_JRBLOCKS9_STEP_3_TEXT": "使用<i><u>文字</u></i>按鈕新增文字“<b>搖一搖開始</b>”",
@@ -879,7 +880,7 @@
879
880
  "COG_JRBLOCKS9_STEP_42_TEXT": "嘗試一下!",
880
881
  "COG_JRBLOCKS9_STEP_43_TEXT": "現在看看你能獲得多高的分數!",
881
882
  "COG_JRBLOCKS9_STEP_44_TEXT": "<p><b>幹得好! </b><br /> 你成功製作了一款遊戲! </p><p>&nbsp;</p><p>你能製作一個獲勝畫面或其他關卡嗎?你會如何使用上面的程式碼? </p><p>&nbsp;</p><p>你能讓齒輪在收集星星時亮起來嗎? </p>",
882
- "COG_JRBLOCKS10_TITLE": "和 Marty 一起製作形狀",
883
+ "COG_JRBLOCKS10_TITLE": "10. 和 Marty 一起製作形狀",
883
884
  "COG_JRBLOCKS10_STEP_1_TEXT": "讓我們來和機器人馬蒂一起製作一些形狀吧!",
884
885
  "COG_JRBLOCKS10_STEP_2_TEXT": "開啟<b>Marty 模式</b>!",
885
886
  "COG_JRBLOCKS10_STEP_3_TEXT": "新增 <b>On Flag</b> 區塊",
@@ -916,7 +917,7 @@
916
917
  "COG_JRBLOCKS10_STEP_34_TEXT": "加入方塊讓 Marty <b>轉身</b>",
917
918
  "COG_JRBLOCKS10_STEP_35_TEXT": "試試看!使用<b>物體感測器</b>來轉動 Marty",
918
919
  "COG_JRBLOCKS10_STEP_44_TEXT": "<p><b>做得好! </b><br />您了解了<b>相對方向</b>,而不是<b>絕對方向</b>。 <br /><br />您還可以畫什麼?",
919
- "COG_JRBLOCKS11_TITLE": "太空遊戲",
920
+ "COG_JRBLOCKS11_TITLE": "11. 太空遊戲",
920
921
  "COG_JRBLOCKS11_STEP_1_TEXT": "讓我們來製作一款以太空為背景的遊戲吧!",
921
922
  "COG_JRBLOCKS11_STEP_2_TEXT": "新增<b>太空背景</b>",
922
923
  "COG_JRBLOCKS11_STEP_3_TEXT": "加入<b>火箭精靈</B>",
@@ -956,7 +957,7 @@
956
957
  "COG_JRBLOCKS11_STEP_37_TEXT": "新增<b>到第 2 頁</b>區塊",
957
958
  "COG_JRBLOCKS11_STEP_38_TEXT": "試試吧!按一下綠旗即可開始,然後搖動齒輪即可重新啟動",
958
959
  "COG_JRBLOCKS11_STEP_44_TEXT": "<p><b>做得好! </b><br />您製作了一個太空遊戲! <br /><br />您能增加更多星星來收集嗎?",
959
- "COG_JRBLOCKS12_TITLE": "讓我們來做一個反應測試遊戲吧!",
960
+ "COG_JRBLOCKS12_TITLE": "12. 讓我們來做一個反應測試遊戲吧!",
960
961
  "COG_JRBLOCKS12_STEP_1_TEXT": "讓我們來做一個反應測試遊戲吧!",
961
962
  "COG_JRBLOCKS12_STEP_2_TEXT": "讓馬蒂永遠下台",
962
963
  "COG_JRBLOCKS12_STEP_3_TEXT": "當 Marty 觸碰另一個精靈<b>發送訊息</b>",
@@ -994,7 +995,7 @@
994
995
  "COG_JRBLOCKS12_STEP_35_TEXT": "<b>增加節奏</b>以在中途加速遊戲!",
995
996
  "COG_JRBLOCKS12_STEP_36_TEXT": "嘗試一下!",
996
997
  "COG_JRBLOCKS12_STEP_47_TEXT": "<p><b>做得好! </b><br />您製作了一個反應測試遊戲! <br /><br />您能讓它變得更快嗎? <br /><Br />與朋友配對,同時使用兩個齒輪嘗試!",
997
- "COG_JRBLOCKS13_TITLE": "冒險故事",
998
+ "COG_JRBLOCKS13_TITLE": "13. 冒險故事",
998
999
  "COG_JRBLOCKS13_STEP_1_TEXT": "讓我們來創作一個冒險故事吧!",
999
1000
  "COG_JRBLOCKS13_STEP_2_TEXT": "新增背景",
1000
1001
  "COG_JRBLOCKS13_STEP_3_TEXT": "為 Marty 增加<b>移動控制</b>",
@@ -1043,7 +1044,7 @@
1043
1044
  "COG_JRBLOCKS13_STEP_46_TEXT": "加入<b>搖晃後轉到第 3 頁</b>塊",
1044
1045
  "COG_JRBLOCKS13_STEP_47_TEXT": "試試看! <br /><Br />搖動齒輪敲門",
1045
1046
  "COG_JRBLOCKS13_STEP_48_TEXT": "<p><b>做得好! </b><br />現在,運用你之前學到的所有知識,繼續這個故事,為馬蒂和獨角獸創造一次冒險",
1046
- "MARTY_JRBLOCKS1_TITLE": "讓馬蒂動起來",
1047
+ "MARTY_JRBLOCKS1_TITLE": "1. 讓馬蒂動起來",
1047
1048
  "MARTY_JRBLOCKS1_STEP_1_TEXT": "在本教程中,我們將學習如何在 BlocksJr 中使用基本函數。",
1048
1049
  "MARTY_JRBLOCKS1_STEP_2_TEXT": "首先,我們來連接馬蒂。點擊馬蒂按鈕連接馬蒂。",
1049
1050
  "MARTY_JRBLOCKS1_STEP_3_TEXT": "這些拼圖塊形狀的模組叫做<b/>函數</b>。 <br/><br/>函數就像動作一樣,是一段告訴 Marty「嘿,做這個!」的程式碼。",
@@ -1060,7 +1061,7 @@
1060
1061
  "MARTY_JRBLOCKS1_STEP_14_TEXT": "現在我們來移動馬蒂!首先,讓他向前走四步。 <br/><br/>在「準備」與「停止」之間放置四個這樣的<b/>",
1061
1062
  "MARTY_JRBLOCKS1_STEP_15_TEXT": "他向前走之後,我們讓馬蒂向左走!如圖所示,在紅色「停止」方塊前方放置<b/>3個向左滑動的方塊</b>。",
1062
1063
  "MARTY_JRBLOCKS1_END": "你成功了!你可以在 BlocksJr 讓 Marty 動起來! <br/><br/>不妨探索這款應用,看看你還能讓 Marty 做什麼,然後再回來學習教學 2!",
1063
- "MARTY_JRBLOCKS2_TITLE": "程式碼清理:參數",
1064
+ "MARTY_JRBLOCKS2_TITLE": "2. 程式碼清理:參數",
1064
1065
  "MARTY_JRBLOCKS2_STEP_1_TEXT": "在本教程中,我們將學習如何使用參數來簡化和縮小程式碼。",
1065
1066
  "MARTY_JRBLOCKS2_STEP_2_TEXT": "首先,我們來連接馬蒂。點擊馬蒂按鈕連接馬蒂。",
1066
1067
  "MARTY_JRBLOCKS2_STEP_3_TEXT": "這是我們之前讓馬蒂向前走四步的程式碼。看得出來有什麼方法可以簡化我們的指令嗎?",
@@ -1072,7 +1073,7 @@
1072
1073
  "MARTY_JRBLOCKS2_STEP_9_TEXT": "現在加入一個類似範例程式碼的<b/>向左滑動</b>程式碼區塊-總共有多少個向左滑動程式碼區塊?你應該在向左滑動程式碼區塊中放入什麼參數?",
1073
1074
  "MARTY_JRBLOCKS2_STEP_10_TEXT": "快完成了!新增一個類似範例程式碼的<b/>向後走</b>程式碼區塊,並加入正確的參數。",
1074
1075
  "MARTY_JRBLOCKS2_END": "你做到了!你既是論證專家,也是程式碼簡化天才!",
1075
- "MARTY_JRBLOCKS3_TITLE": "交通燈馬蒂",
1076
+ "MARTY_JRBLOCKS3_TITLE": "3. 交通燈馬蒂",
1076
1077
  "MARTY_JRBLOCKS3_STEP_1_TEXT": "在本教程中,我們將學習如何在 BlocksJr 中使用等待函數。",
1077
1078
  "MARTY_JRBLOCKS3_STEP_2_TEXT": "首先,我們來連接馬蒂。點擊馬蒂按鈕連接馬蒂。",
1078
1079
  "MARTY_JRBLOCKS3_STEP_3_TEXT": "現在加入一個綠色旗幟代碼區塊來開始我們的程式碼。",
@@ -1085,7 +1086,7 @@
1085
1086
  "MARTY_JRBLOCKS3_STEP_10_TEXT": "在綠色 LED 眼睛模組之前添加一個<b/>準備</b>模組,以便 Marty 可以在「開始!」之前做好準備。",
1086
1087
  "MARTY_JRBLOCKS3_STEP_11_TEXT": "綠色表示通行-你會讓你的馬蒂在綠色區域做什麼?我們說過,當馬蒂的眼睛變成綠色時,就慶祝吧!",
1087
1088
  "MARTY_JRBLOCKS3_END": "你做到了!點擊綠旗,注意交通號誌燈,馬蒂!",
1088
- "MARTY_JRBLOCKS4_TITLE": "清理程式碼:重複",
1089
+ "MARTY_JRBLOCKS4_TITLE": "4. 清理程式碼:重複",
1089
1090
  "MARTY_JRBLOCKS4_STEP_1_TEXT": "馬蒂想跳舞!讓我們來試試他的跳舞功能,並學習如何使用重複功能來創作我們自己的馬蒂舞蹈!",
1090
1091
  "MARTY_JRBLOCKS4_STEP_2_TEXT": "首先,我們來連接馬蒂。點擊馬蒂按鈕連接馬蒂。",
1091
1092
  "MARTY_JRBLOCKS4_STEP_3_TEXT": "現在加入一個綠色旗幟代碼區塊來開始我們的程式碼。",
@@ -1097,7 +1098,7 @@
1097
1098
  "MARTY_JRBLOCKS4_STEP_9_TEXT": "如果馬蒂一直跳舞,他會累的!如果我們讓他一直跳舞,他可能會累!如果我們只想讓馬蒂跳5次舞呢?我們可以在5次循環後按下停止按鈕——但還有更簡單的方法。",
1098
1099
  "MARTY_JRBLOCKS4_STEP_10_TEXT": "移除紅色的重複程式碼區塊,並用這個閉環重複函數取代它。我們可以在這個程式碼區塊中放入程式碼片段,並根據需要重複執行任意次數。讓馬蒂重複你的舞蹈動作 5 次!",
1099
1100
  "MARTY_JRBLOCKS4_END": "你做到了!馬蒂現在是舞蹈高手了!",
1100
- "MARTY_JRBLOCKS5_TITLE": "馬蒂射門遊戲",
1101
+ "MARTY_JRBLOCKS5_TITLE": "5. 馬蒂射門遊戲",
1101
1102
  "MARTY_JRBLOCKS5_STEP_1_TEXT": "在本教程中,我們將使用精靈圖製作一個馬蒂射門遊戲!",
1102
1103
  "MARTY_JRBLOCKS5_STEP_2_TEXT": "首先,我們給馬蒂小人找個踢足球的場地。進入背景選單,選擇“農場”。",
1103
1104
  "MARTY_JRBLOCKS5_STEP_3_TEXT": "為了進球,馬蒂需要兩樣東西:一個足球和一個球網!點擊加號選擇兩個新的角色:足球和球網。",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robotical/martyblocksjr",
3
- "version": "3.5.30",
3
+ "version": "3.5.32",
4
4
  "description": "ScratchJr",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -38,32 +38,189 @@ afterAll(() => {
38
38
  }
39
39
  });
40
40
 
41
+ async function openPage(pathname) {
42
+ const browser = await puppeteer.launch({
43
+ headless: true,
44
+ args: ["--no-sandbox"],
45
+ });
46
+ const page = await browser.newPage();
47
+ const errors = [];
48
+
49
+ page.on("pageerror", (err) => errors.push(err.message || String(err)));
50
+ page.on("console", (msg) => {
51
+ if (msg.type() === "error") {
52
+ errors.push(msg.text());
53
+ }
54
+ });
55
+
56
+ await page.goto(`${HOST}${pathname}`, { waitUntil: "networkidle2", timeout: 30_000 });
57
+
58
+ return { browser, page, errors };
59
+ }
60
+
61
+ async function getTutorialFrame(page) {
62
+ await page.waitForFunction(() => {
63
+ const iframe = document.getElementById("htmlcontents");
64
+ return iframe && iframe.tagName === "IFRAME" && iframe.src.includes("inapp/tutorials.html");
65
+ });
66
+
67
+ const frame = page.frames().find((entry) => entry.url().includes("/inapp/tutorials.html"));
68
+ if (!frame) {
69
+ throw new Error("Tutorial frame not found");
70
+ }
71
+
72
+ await frame.waitForSelector(".tutorial-card", { timeout: 30_000 });
73
+ return frame;
74
+ }
75
+
76
+ async function assertTutorialOpened(page, tutorialId) {
77
+ await page.waitFor(3_000);
78
+
79
+ const tutorialState = await page.evaluate(() => ({
80
+ tutorialEngineId:
81
+ window.tutorialEngine && window.tutorialEngine.tutorial
82
+ ? window.tutorialEngine.tutorial.id
83
+ : null,
84
+ hasTutorialMenuBar: Boolean(document.getElementById("tutorialMenuBar")),
85
+ hasCloseTutorialButton: Boolean(document.getElementById("closeTutorial")),
86
+ hasTutorialProgressBar: Boolean(document.getElementById("tutorialProgressBar")),
87
+ hasTutorialInstructor: Boolean(document.getElementById("tutorialInstructor")),
88
+ tutorialTitle: (
89
+ document.getElementById("tutorialTitle") &&
90
+ document.getElementById("tutorialTitle").textContent
91
+ ? document.getElementById("tutorialTitle").textContent
92
+ : ""
93
+ ).trim(),
94
+ }));
95
+
96
+ expect(tutorialState.tutorialEngineId).toBe(tutorialId);
97
+ expect(tutorialState.hasTutorialMenuBar).toBe(true);
98
+ expect(tutorialState.hasCloseTutorialButton).toBe(true);
99
+ expect(tutorialState.hasTutorialProgressBar).toBe(true);
100
+ expect(tutorialState.hasTutorialInstructor).toBe(true);
101
+ expect(tutorialState.tutorialTitle.length).toBeGreaterThan(0);
102
+ }
103
+
41
104
  describe("Chromium 79 smoke test", () => {
42
105
  it(
43
106
  "loads home page without console errors",
44
107
  async () => {
45
- const browser = await puppeteer.launch({
46
- headless: true,
47
- args: ["--no-sandbox"],
108
+ const { browser, page, errors } = await openPage("/home.html");
109
+ const title = await page.title();
110
+
111
+ await browser.close();
112
+ expect(title.toLowerCase()).toContain("scratch");
113
+ expect(errors).toEqual([]);
114
+ },
115
+ 60_000
116
+ );
117
+
118
+ it(
119
+ "opens tutorials from the book tab and returns there from tutorial mode",
120
+ async () => {
121
+ const { browser, page, errors } = await openPage("/home.html?place=book&submenu=tutorials");
122
+
123
+ const frame = await getTutorialFrame(page);
124
+ const tutorialCount = await frame.$$eval(".tutorial-card", (cards) => cards.length);
125
+
126
+ expect(tutorialCount).toBe(19);
127
+
128
+ await Promise.all([
129
+ page.waitForNavigation({ waitUntil: "networkidle2", timeout: 30_000 }),
130
+ frame.click('[data-tutorial-id="marty-jr-blocks-1"]'),
131
+ ]);
132
+
133
+ expect(page.url()).toContain("/editor.html");
134
+ expect(page.url()).toContain("tutorial=marty-jr-blocks-1");
135
+ expect(page.url()).toContain("tutorialReturnPlace=book");
136
+ expect(page.url()).toContain("tutorialReturnSubmenu=tutorials");
137
+
138
+ await assertTutorialOpened(page, "marty-jr-blocks-1");
139
+
140
+ await page.evaluate(() => {
141
+ document.getElementById("closeTutorial").click();
48
142
  });
49
- const page = await browser.newPage();
50
- const errors = [];
51
-
52
- page.on("pageerror", (err) => errors.push(err.message || String(err)));
53
- page.on("console", (msg) => {
54
- if (msg.type() === "error") {
55
- errors.push(msg.text());
56
- }
143
+ await page.waitForFunction(
144
+ () => window.location.href.includes("home.html?place=book&submenu=tutorials"),
145
+ { timeout: 30_000 }
146
+ );
147
+
148
+ expect(page.url()).toContain("/home.html?place=book&submenu=tutorials");
149
+
150
+ const returnedFrame = await getTutorialFrame(page);
151
+ const returnedCount = await returnedFrame.$$eval(".tutorial-card", (cards) => cards.length);
152
+
153
+ await browser.close();
154
+
155
+ expect(returnedCount).toBe(19);
156
+ expect(errors).toEqual([]);
157
+ },
158
+ 90_000
159
+ );
160
+
161
+ it(
162
+ "opens a tutorial when the tutorials page is loaded standalone",
163
+ async () => {
164
+ const { browser, page, errors } = await openPage("/inapp/tutorials.html");
165
+
166
+ await page.waitForSelector('.tutorial-card[data-tutorial-id="marty-jr-blocks-1"]', {
167
+ timeout: 30_000,
57
168
  });
58
169
 
59
- await page.goto(`${HOST}/home.html`, { waitUntil: "networkidle2", timeout: 30_000 });
60
- const title = await page.title();
170
+ await Promise.all([
171
+ page.waitForNavigation({ waitUntil: "networkidle2", timeout: 30_000 }),
172
+ page.click('.tutorial-card[data-tutorial-id="marty-jr-blocks-1"]'),
173
+ ]);
174
+
175
+ expect(page.url()).toContain("/editor.html");
176
+ expect(page.url()).toContain("tutorial=marty-jr-blocks-1");
177
+ expect(page.url()).toContain("tutorialReturnPlace=book");
178
+ expect(page.url()).toContain("tutorialReturnSubmenu=tutorials");
179
+
180
+ await assertTutorialOpened(page, "marty-jr-blocks-1");
61
181
 
62
182
  await browser.close();
63
183
 
64
- expect(title.toLowerCase()).toContain("scratch");
65
184
  expect(errors).toEqual([]);
66
185
  },
67
- 60_000
186
+ 90_000
187
+ );
188
+
189
+ it(
190
+ "returns to the in-app tutorials page when a tutorial was launched from the host-style entry route",
191
+ async () => {
192
+ const { browser, page, errors } = await openPage("/index.html?tutorial=marty-jr-blocks-1");
193
+
194
+ await page.waitForFunction(
195
+ () => window.location.href.includes("editor.html") && window.location.href.includes("tutorial=marty-jr-blocks-1"),
196
+ { timeout: 30_000 }
197
+ );
198
+
199
+ expect(page.url()).toContain("/editor.html");
200
+ expect(page.url()).toContain("tutorialReturnPlace=book");
201
+ expect(page.url()).toContain("tutorialReturnSubmenu=tutorials");
202
+
203
+ await assertTutorialOpened(page, "marty-jr-blocks-1");
204
+
205
+ await page.evaluate(() => {
206
+ document.getElementById("closeTutorial").click();
207
+ });
208
+
209
+ await page.waitForFunction(
210
+ () => window.location.href.includes("home.html?place=book&submenu=tutorials"),
211
+ { timeout: 30_000 }
212
+ );
213
+
214
+ expect(page.url()).toContain("/home.html?place=book&submenu=tutorials");
215
+
216
+ const frame = await getTutorialFrame(page);
217
+ const tutorialCount = await frame.$$eval(".tutorial-card", (cards) => cards.length);
218
+
219
+ await browser.close();
220
+
221
+ expect(tutorialCount).toBe(19);
222
+ expect(errors).toEqual([]);
223
+ },
224
+ 90_000
68
225
  );
69
226
  });