From f3e04d025281b5090ddd708b3da14d829b0734a7 Mon Sep 17 00:00:00 2001 From: Dayne Date: Wed, 18 Dec 2019 23:37:03 -0800 Subject: [PATCH] Adding Blockly blocks to Content levels. In Content levels, such as External levels, level creators were taking screenshots of Blockly blocks and adding them to the instructions in order to give a preview to the student of what the blocks look like. This has become a problem because screenshots are not translatable and we are expanding our content to be used internationally. * Added common, maze, and turtle CDO blocks to Content levels. * blocks in Markdown content render as Blockly blocks. --- TESTING.md | 6 +- .../src/sites/studio/pages/levels/_content.js | 32 ++++++++- apps/src/templates/instructions/utils.js | 1 + dashboard/app/views/levels/_content.html.haml | 9 ++- .../scripts/test_external_markdown.external | 71 ++++++++++++++----- .../ui/features/markdown_rendering.feature | 9 +++ 6 files changed, 103 insertions(+), 25 deletions(-) diff --git a/TESTING.md b/TESTING.md index 1f0c5462f49a5..20ed710c71059 100644 --- a/TESTING.md +++ b/TESTING.md @@ -84,9 +84,9 @@ See [the apps readme](./apps/README.md) for more details. If you get a bunch of complaints about database, like missing tables or how some tables haven't been seeded, here are some things you can try in order from least to most drastic before running your tests again: -1. `rake seed:secret_pictures seed:secret_words` to seed the missing data, or +1. `bundle exec rake seed:secret_pictures seed:secret_words` to seed the missing data, or -2. `RAILS_ENV=test rake db:reset db:test:prepare` to recreate your local dashboard test db and reseed the data. +2. `RAILS_ENV=test bundle exec rake db:reset db:test:prepare` to recreate your local dashboard test db and reseed the data. If you just want to run a single file of tests, you can run `bundle exec spring testunit ./path/to/your/test.rb` @@ -106,7 +106,7 @@ If you get an error about missing db fields, try migrating your test database: We have a set of integration tests, divided into "UI tests" (Selenium+Cucumber) and "Eyes tests" (Selenium+Cucumber+Applitools). These tests live in [dashboard/test/ui](dashboard/test/ui) - for information on setting up and running these tests, see [the README in that directory](dashboard/test/ui) and our [guide to adding an eyes test](docs/testing-with-applitools-eyes.md). Or you can just use this shortcut (after you've installed chromedriver): -`rake test:ui feature=dashboard/test/ui/features/sometest.feature` +`bundle exec rake test:ui feature=dashboard/test/ui/features/sometest.feature` ### Pegasus Tests `cd pegasus && rake test` will run all of our pegasus Ruby tests. This usually takes ~20 seconds to run. diff --git a/apps/src/sites/studio/pages/levels/_content.js b/apps/src/sites/studio/pages/levels/_content.js index dc3b16e56a002..2206a420cc274 100644 --- a/apps/src/sites/studio/pages/levels/_content.js +++ b/apps/src/sites/studio/pages/levels/_content.js @@ -1,19 +1,47 @@ import $ from 'jquery'; +import assetUrl from '@cdo/apps/code-studio/assetUrl'; import React from 'react'; import ReactDom from 'react-dom'; - import SafeMarkdown from '@cdo/apps/templates/SafeMarkdown'; +import {convertXmlToBlockly} from '@cdo/apps/templates/instructions/utils'; +import commonBlocks from '@cdo/apps/blocksCommon'; $(document).ready(() => { + // Content levels don't have a particular 'app' associated with them so make + // available all the different app specific Blockly blocks as they are needed + // by level creators. This will enable them to write Blockly XML and render + // the blocks directly in the level text. + Blockly.assetUrl = assetUrl; + Blockly.Css.inject(document); + // Install the common Blockly blocks + commonBlocks.install(window.Blockly, {}); + // Install the custom CDO blocks for the following level/app types. + var options = [{skin: {id: 'birds'}, app: 'maze'}, {skin: {}, app: 'turtle'}]; + for (var i = 0; i < options.length; i++) { + var option = options[i]; + try { + const appBlocks = require('@cdo/apps/' + option.app + '/blocks'); + appBlocks.install(window.Blockly, option); + } catch (error) { + console.warn(`Unable to load blockly blocks for ${option.app}: ${error}`); + } + } + // Render Markdown $('.content-level > .markdown-container').each(function() { if (!this.dataset.markdown) { return; } + var container = this; ReactDom.render( React.createElement(SafeMarkdown, this.dataset, null), - this + this, + function() { + // After the Markdown is rendered, render any Blockly blocks defined in + // blocks. + convertXmlToBlockly(container); + } ); }); }); diff --git a/apps/src/templates/instructions/utils.js b/apps/src/templates/instructions/utils.js index f5b0bdbce9248..0e5ad9111bd1b 100644 --- a/apps/src/templates/instructions/utils.js +++ b/apps/src/templates/instructions/utils.js @@ -1,4 +1,5 @@ import ReactDOM from 'react-dom'; +import Blockly from '@code-dot-org/blockly'; import $ from 'jquery'; /** diff --git a/dashboard/app/views/levels/_content.html.haml b/dashboard/app/views/levels/_content.html.haml index 413a2ecc60ec0..49050c6c51814 100644 --- a/dashboard/app/views/levels/_content.html.haml +++ b/dashboard/app/views/levels/_content.html.haml @@ -3,8 +3,15 @@ / Note that content_class, source_level, hide_header, and postcontent are optional. - app, data, content_class, source_level, hide_header, postcontent = %i(app data content_class source_level hide_header postcontent).map{ |x| local_assigns[x] } - level = source_level || @level - - content_for(:head) do + %script{src: webpack_asset_path('js/common.js')} + / Import Blockly assets in order to render them in the Markdown section of + / content levels. + %script{src: webpack_asset_path('js/blockly.js')} + %script{src: webpack_asset_path("js/#{js_locale}/blockly_locale.js")} + %script{src: webpack_asset_path("js/#{js_locale}/maze_locale.js")} + %script{src: webpack_asset_path("js/#{js_locale}/turtle_locale.js")} + %script{src: webpack_asset_path('js/levels/_content.js')} - unless data['title'].blank? || hide_header diff --git a/dashboard/config/scripts/test_external_markdown.external b/dashboard/config/scripts/test_external_markdown.external index 932457ca20fcd..6ff1cad702f54 100644 --- a/dashboard/config/scripts/test_external_markdown.external +++ b/dashboard/config/scripts/test_external_markdown.external @@ -1,21 +1,54 @@ name 'Test External Markdown' -encrypted 'B0ygOUMJGSbJt//EhCuQ9IQWHFaBkFiAYyc6/Ofqr7e6aAVP5I/9vyNE2i/a -pQZ87yKg88VHPYwTbspyyqV2ujotqoGrti1spBuf8CXeggp6vSJWqJD+7yEa -6cqmILEYKjyWXydmAhnXI9qiV/kmiuW+QmtWZy6hpFp6MhuLo0GK5NxbTq4j -8mHoBJetXL3Wku4RSSzs7t1uO5cMd6tnkVR8mYqGpI33xdrf4ETM1oOP9izd -+g4cKGBIYuFvfDB/QoscuYDU3y1zo6KjU0p8coR8Nel6CtxSQwHS8cMul41x -uJlulBq4A+QGkAYnjQpfxpz12knmdUSdfr36qyFd2gCiuVLAvSJbguyAKyNw -R538meX8OvbpR/yaLCxi5osQhZ0rPrkTRe//5E2Cajz7OYXX4Z+1kR0RhOG0 -EJDXXzzlN8W5yh1FnOUr+Us10IP/2JPoe3pVoVf7xWarsrEwdnZnDmaZSmb5 -v9HmeDxZe5Ly7xD0k6bFHrlM+XUUB5Gj78k+n0h2TGdD2CTtzxbpzQlQjx1s -bW5jIhk5n8hOhpoQLYzd+xOCJmwGh8/5lyEPfCgpO5Y+1bJAti2swBShnRlL -FhDnTlEVWKfgWLQCoHcPlzJaXjByZu0shbJKQthSbl9dk4Gkh+gXAgYEqZqp -ETV7odDBeskVDjxxS2s5p+xJLM+1su5dzlUcU9uAiC4icn5+CqujNUA46tu2 -z1t4bJ8P/zIViK1/1LmU2EEpgqzk5VZAOddZfK1GoKO8s6LXgF1rtVm1J1JH -+p2rpl2s0fmRbu1ovPlIBDv5W7tKOeAxYpDpuBPQ95ikVXyAHgh5hru+rnkN -5vZe8kB6NbhnIAsJWSGHgQGtf6loiHbSIHcpXT283/ipCxD1htJLypuDQpIM -uzNdO/liix2ycgqCCezdSAzXD0lGskwRwfQozr6YT+uSMGuqDDP3VK/5wH01 -fCIBt2p9D9T4KWfTpOiDThkR06Jeunl1nXmixnRCkucx7Moktunq6PnkW/GZ -JrrmrUU5pM9kGT1W0MiHkI10vCzCumCgdShPF3qMBCRhJMBwc3QcP99jNY2w -x5CqLu7Hlmr3Q3uJwJTBhniDOBrb8MxdXkYKjBddvlzLJQGLeOA= +encrypted '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 ' \ No newline at end of file diff --git a/dashboard/test/ui/features/markdown_rendering.feature b/dashboard/test/ui/features/markdown_rendering.feature index 66a5147e578fa..645d1083349aa 100644 --- a/dashboard/test/ui/features/markdown_rendering.feature +++ b/dashboard/test/ui/features/markdown_rendering.feature @@ -23,3 +23,12 @@ Feature: Markdown rendering across the website And I wait for the page to fully load Then I see no difference for "K1 embedded blockly" And I close my eyes + + @eyes + Scenario: Visiting an External level with blockly xml in the Markdown + When I open my eyes to test "Blockly in External level" + And I am on "http://studio.code.org/s/allthethings/stage/21/puzzle/1?noautoplay=true" + And I rotate to landscape + And I wait to see ".blocklySvg" + Then I see no difference for "blockly on External level" + And I close my eyes