diff --git a/doc/smart-answer-flow-development/creating-a-new-smart-answer.md b/doc/smart-answer-flow-development/creating-a-new-smart-answer.md index b9237604221..814ed4d9246 100644 --- a/doc/smart-answer-flow-development/creating-a-new-smart-answer.md +++ b/doc/smart-answer-flow-development/creating-a-new-smart-answer.md @@ -43,7 +43,7 @@ Create a new file for our landing page template. ``` $ mkdir lib/smart_answer_flows/example-smart-answer -$ touch lib/smart_answer_flows/example-smart-answer/example_smart_answer.govspeak.erb +$ touch lib/smart_answer_flows/example-smart-answer/example_smart_answer.erb ``` Although the landing page template needs to exist, it doesn't actually need to contain anything! @@ -53,11 +53,11 @@ Assuming you're still running `rails server`, visit [http://localhost:3000/examp Open the new landing page template your editor and copy/paste the following content: ```erb -<% render_content_for :title do %> +<% text_for :title do %> Smart Answer title <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Landing page body. <% end %> ``` @@ -74,7 +74,7 @@ Create a new file for our question page template. ``` $ mkdir lib/smart_answer_flows/example-smart-answer/questions -$ touch lib/smart_answer_flows/example-smart-answer/questions/question_1.govspeak.erb +$ touch lib/smart_answer_flows/example-smart-answer/questions/question_1.erb ``` Although the question page template needs to exist, it doesn't actually need to contain anything! @@ -84,11 +84,11 @@ Assuming you're still running `rails server`, visit [http://localhost:3000/examp Open the new question page template in your editor and copy/paste the following content: ```erb -<% render_content_for :title do %> +<% text_for :title do %> Question page title <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Question page body. <% end %> ``` @@ -105,7 +105,7 @@ Create a new file for our outcome page template. ``` $ mkdir lib/smart_answer_flows/example-smart-answer/outcomes -$ touch lib/smart_answer_flows/example-smart-answer/outcomes/outcome_1.govspeak.erb +$ touch lib/smart_answer_flows/example-smart-answer/outcomes/outcome_1.erb ``` Although the question page template needs to exist, it doesn't actually need to contain anything! @@ -115,11 +115,11 @@ Assuming you're still running `rails server`, visit [http://localhost:3000/examp Open the new outcome page template in your editor and copy/paste the following content: ```erb -<% render_content_for :title do %> +<% text_for :title do %> Outcome page title <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Outcome page body. <% end %> ``` diff --git a/doc/smart-answers/erb-templates.md b/doc/smart-answers/erb-templates.md index 506c8577f1f..e7ab4d1e01a 100644 --- a/doc/smart-answers/erb-templates.md +++ b/doc/smart-answers/erb-templates.md @@ -1,27 +1,30 @@ # ERB templates -Content is defined in `render_content_for` blocks and with the name of the intent of the content: +Content is defined using one of three helpers to indicate the format with an argument to indicate the intent: ```erb -<% render_content_for :title do %> - Some amazing title +<% text_for :title do %> + This is plain text, any HTML characters used will be espaced. Any indentation is automatically removed. <% end %> ``` -The type of content can be explicitly set with the `format:` option: +```erb +<% govspeak_for :body do %> + This uses the GOV.UK markdown dialect, [govspeak](https://github.com/alphagov/govspeak), + and will be converted to HTML. Any indentation is automatically removed. +<% end %> +``` ```erb -<% render_content_for :title, format: :html do %> -

Some amazing title

+<% html_for :body do %> +

This is HTML, used when we need fine grained control over content

<% end %> ``` -We support Govspeak (`:govspeak`), plain text (`:text`) and HTML (`:html`). See docs for template pages for the default formats of different content blocks. +See the template page documentation for the available contexts and their allowed formats: * [Landing page templates](erb-templates/landing-page-template.md) * [Question templates](erb-templates/question-templates.md) * [Outcome templates](erb-templates/outcome-templates.md) -We remove all leading spaces from the content in the `render_content_for` blocks for Govspeak and Text formats. This allows us to indent the content in the `render_content_for` blocks without having to worry about it affecting the generated HTML when it's processed using Govspeak. - Any state variable defined in the flow is available to be used in the ERB template. See [storing data](storing-data.md) for the various ways that you can set state variables. diff --git a/doc/smart-answers/erb-templates/landing-page-template.md b/doc/smart-answers/erb-templates/landing-page-template.md index f2af3f6165e..f6f2186ce9b 100644 --- a/doc/smart-answers/erb-templates/landing-page-template.md +++ b/doc/smart-answers/erb-templates/landing-page-template.md @@ -1,6 +1,6 @@ # Landing page template -Landing page templates live in `lib/smart_answer_flows//.govspeak.erb`. +Landing page templates live in `lib/smart_answer_flows//.erb`. ## Content types @@ -8,37 +8,46 @@ The templates can contain content for any of the following keys: ### `:title` -* Default format is `:text` -* Used as the heading (currently "h1") +Used as the h1 heading and can only be text. Example: -### `:meta_description` - -* Default format is `:text` -* Used as the content for the [meta description tag][meta-description] +```erb +<% text_for :title do %> + Look up Meursing code +<% end %> +``` -### `:body` +### `:meta_description` -* Default format is `:govspeak` -* Used to generate the main content (appearing above the start button) +Used as the content for the [meta description tag][meta-description]. Can only be text. Example: -### `:post_body` +```erb +<% text_for :meta_description do %> + Look up the additional code (Meursing code) required for import or export of goods containing certain types of milk and sugars +<% end %> +``` -* Default format is `:govspeak` -* Used to generate supplementary content (appearing below the start button) +### `:body` -## Example +Used to generate the main content (appearing above the start button). Expected to be govspeak or HTML. Example: ```erb -<% render_content_for :title do %> - Look up Meursing code +<% govspeak_for :body do %> + Use this tool to look up the additional code (Meursing code) for import or export of goods containing certain types of milk and sugars covered Regulation (EC) No. 1216/09. <% end %> +``` -<% render_content_for :meta_description do %> - Look up the additional code (Meursing code) required for import or export of goods containing certain types of milk and sugars +```erb +<% html_for :body do %> +

Use this tool to look up the additional code (Meursing code) for import or export of goods containing certain types of milk and sugars covered Regulation (EC) No. 1216/09.

<% end %> +``` +### `:post_body` -<% render_content_for :body do %> - Use this tool to look up the additional code (Meursing code) for import or export of goods containing certain types of milk and sugars covered Regulation (EC) No. 1216/09. +Used to generate supplementary content (appearing below the start button). Expected to be govspeak or HTML. Example: + +```erb +<% govspeak_for :post_body do %> + Code of measuring practice became globally effective in May 2015. <% end %> ``` diff --git a/doc/smart-answers/erb-templates/outcome-templates.md b/doc/smart-answers/erb-templates/outcome-templates.md index 6621c709692..d5be8bde0a3 100644 --- a/doc/smart-answers/erb-templates/outcome-templates.md +++ b/doc/smart-answers/erb-templates/outcome-templates.md @@ -1,6 +1,6 @@ # Outcome templates -Outcome templates live in `lib/smart_answer_flows//outcomes/.govspeak.erb`. +Outcome templates live in `lib/smart_answer_flows//outcomes/.erb`. ## Content types @@ -8,33 +8,36 @@ The templates can contain content for any of the following keys: ### `:title` -* Default format is `:text` -* Used as the heading (currently "h1") - -### `:body` - -* Default format is `:govspeak` -* Used as the main text - -### `next_steps(govspeak)` - -* Default format is `:govspeak` -* Used to generate "next steps" content (at top of a right-hand sidebar) - -## Example +Used as the h1 heading and can only be text. Example: ```erb -<% render_content_for :title do %> +<% text_for :title do %> <% unless calculator.has_commodity_code? %> The product composition you indicated is not possible. <% else %> The Meursing code for a product with this composition is 7<%= calculator.commodity_code %>. <% end %> <% end %> +``` + +### `:body` -<% render_content_for :body do %> +Used to generate the main content. Expected to be govspeak or HTML. Example: + +```erb +<% govspeak_for :body do %> <% if calculator.has_commodity_code? %> Use these four digits together with the ten-digit commodity code from Trade Tariff. <% end %> <% end %> ``` + +### `next_steps` + +Used to generate the "next steps" content (at the top of the right-hand sidebar). Expected to be govspeak or HTML. Example: + +```erb +<% govspeak_for :next_steps do %> + Find out what happens to [ownerless property](/unclaimed-estates-bona-vacantia "Ownerless property (bona vacantia)") +<% end %> +``` diff --git a/doc/smart-answers/erb-templates/question-templates.md b/doc/smart-answers/erb-templates/question-templates.md index 06fde9bf190..16657c88a6c 100644 --- a/doc/smart-answers/erb-templates/question-templates.md +++ b/doc/smart-answers/erb-templates/question-templates.md @@ -1,6 +1,6 @@ # Question templates -Question templates live in `lib/smart_answer_flows//questions/.govspeak.erb`. +Question templates live in `lib/smart_answer_flows//questions/.erb`. ## Content types @@ -8,93 +8,104 @@ The templates can contain content for any of the following keys: ### `:title` -* Valid for all question types -* Default format is `:text` -* Used as the heading (currently "h1") -* [Example](#example) of how it's used +Used as the h1 heading and can only be text. Example: + +```erb +<% text_for :title do %> + How much milk proteins does the product contain? +<% end %> +``` ### `:hint` -* Valid for all question types -* Default format is `:text` -* Used as a "hint" paragraph -* [Example](#example) of how it's used +Used as a "hint" paragraph and can only be text. Example: + +```erb +<% text_for :hint do %> + The values represent % by weight +<% end %> +``` ### `:label` -* Valid for value questions -* Default format is `:text` -* Used as a label (preceding the input control) +Used as a label (preceding the input control) for value questions. Can only be text. Example: + +```erb +<% text_for :label do %> + Hours per shift +<% end %> +``` + +Note: As of May 2020 this option may not be working correctly. Please check and amend this documentation. ### `:suffix_label` -* Valid for [value questions](../question-types.md#value_question) & [money questions](../question-types.md#money_question) -* Default format is `:text` -* Used as the label (following the input control) +Valid for [value questions](../question-types.md#value_question) & [money questions](../question-types.md#money_question). Can only be text. Example: + +```erb +<% text_for :suffix_label do %> + years old +<% end %> +``` ### `:body` -* Valid for all question types -* Default format is `:govspeak` -* Used to generate the main content (appearing above the input control, e.g. text input element) +Used to generate the main content (appearing above the input control, e.g. text input element). +It is valid for all questions types and can be govspeak or HTML. Example: + +```erb +<% govspeak_for :body do %> + An introduction to a question. +<% end %> +``` ### `:post_body` -* Valid for all question types -* Default format is `:govspeak` -* Used to generate supplementary content (appearing below the input control) +Used to generate supplementary content (appearing below the input control). +It is valid for all question types and can be govspeak or HTML. Example: + +```erb +<% html_for :post_body do %> +

A conclusion to a question

+<% end %> +``` ### `:error_message` -* Valid for all question types -* Default format is `:text` -* Error message for the default validation error key +Error message for the default validation error key. Can only be text. Example: -### `:error_*` +```erb +<% text_for :error_message do %> + Try again +<% end %> +``` -* Valid for all question types -* Default format is `:text` -* Error message for a custom validation error key -* Any key can be used, but needs to have the `error_` prefix +Note you can specify error messages for a custom validation error key. These +can be specified with a prefix of `:error_`, -## Specifying options +Example: -This is done using custom syntax, not with the `render_content_for` block. +```erb +<% text_for :error_for_a_specific_scenario do %> + Try again +<% end %> +``` -### `options(hash)` +## Specifying options -* Valid for [multiple choice](../question-types.md#multiple_choice) & [checkbox question](../question-types.md#checkbox_question) types -* `hash` argument is a `Hash` of option keys (strings) and text values (also strings) -* Used to "translate" options keys for multiple choice & checkbox questions into human-friendly text -* [Example](#example) of how it's used with a Flow class +This is done using a call to the `options` method. +### `options(hash)` -## Example +Valid for [multiple choice](../question-types.md#multiple_choice) and [checkbox question](../question-types.md#checkbox_question) types. `hash` argument is a `Hash` of option keys (strings) and text values (also strings). +It is used to "translate" options keys for multiple choice and checkbox questions into human-friendly text. -```ruby -class CheckboxSampleFlow < Flow - def define - multiple_choice :how_much_milk_protein? do - option "0" - option "2" - option "12" - end - end -end -``` +Example: ```erb -<% render_content_for :title do %> - How much milk proteins does the product contain? -<% end %> - <% options( "0": "0-2.49", "2": "2.5-11.99", "12": "12 or more" ) %> - -<% render_content_for :hint do %> - The values represent % by weight -<% end %> ``` diff --git a/doc/smart-answers/file-structure.md b/doc/smart-answers/file-structure.md index 18563fd639d..92a06836288 100644 --- a/doc/smart-answers/file-structure.md +++ b/doc/smart-answers/file-structure.md @@ -10,15 +10,15 @@ lib |__ smart_answer_flows |__ .rb (Required: Flow and question logic) |__ - | |__ .govspeak.erb (Optional: Content for the landing page) + | |__ .erb (Optional: Content for the landing page) | |__ outcomes - | | |__ .govspeak.erb (Optional: Content for each outcome page) - | | |__ _.govspeak.erb (Optional: Useful when you need to share content between outcome templates) + | | |__ .erb (Optional: Content for each outcome page) + | | |__ _.erb (Optional: Useful when you need to share content between outcome templates) | |__ questions - | | |__ .govspeak.erb (Optional: Data used to build questions e.g. question and option text) + | | |__ .erb (Optional: Data used to build questions e.g. question and option text) |__ shared | |__ - | |__ _.govspeak.erb (Optional: Useful when you need to share content between Smart Answers) + | |__ _.erb (Optional: Useful when you need to share content between Smart Answers) |__ shared_logic |__ .rb (Optional: Useful when you need to share flow and question logic between Smart Answers) ``` diff --git a/lib/smart_answer/erb_renderer.rb b/lib/smart_answer/erb_renderer.rb index f7d9c1bed4e..7b39fc6981d 100644 --- a/lib/smart_answer/erb_renderer.rb +++ b/lib/smart_answer/erb_renderer.rb @@ -9,6 +9,8 @@ def initialize(template_directory:, template_name:, locals: {}, helpers: []) [@template_directory, FlowRegistry.instance.load_path] + default_view_paths, ) @view = ActionView::Base.with_empty_template_cache.new(lookup_context) + # This is required to continue supporting .govspeak.erb templates + @view.formats = %i[govspeak html] helpers.each { |helper| @view.extend(helper) } @view.extend(ErbRenderer::QuestionOptionsHelper) @view.extend(ErbRenderer::FormatCaptureHelper) @@ -19,12 +21,10 @@ def option_text(key) @view.options.fetch(key).html_safe end - def erb_template_path - @template_directory.join(erb_template_name) - end - def relative_erb_template_path - erb_template_path.relative_path_from(Rails.root).to_s + template = @view.lookup_context.find_template(@template_name) + path = Pathname.new(template.identifier) + path.relative_path_from(Rails.root).to_s end def content_for(name) @@ -33,13 +33,9 @@ def content_for(name) private - def erb_template_name - "#{@template_name}.govspeak.erb" - end - def rendered_view @rendered_view ||= @view.tap do |view| - view.render(template: erb_template_name, locals: @locals) + view.render(template: @template_name, locals: @locals) end end end diff --git a/lib/smart_answer/erb_renderer/format_capture_helper.rb b/lib/smart_answer/erb_renderer/format_capture_helper.rb index e8c9e559f5e..a28ad59abbe 100644 --- a/lib/smart_answer/erb_renderer/format_capture_helper.rb +++ b/lib/smart_answer/erb_renderer/format_capture_helper.rb @@ -2,60 +2,80 @@ module SmartAnswer module ErbRenderer::FormatCaptureHelper class InvalidFormatType < RuntimeError; end - DEFAULT_FORMATS = { - govspeak: [/^body$/, /^post_body$/, /^next_steps$/], - text: [/^title$/, /^meta_description$/, /^hint$/, /^label$/, /^suffix_label$/, /^error_*./], - }.freeze + TEXT_CONTENT = [ + :title, + :meta_description, + :hint, + :label, + :suffix_label, + /^error_/, + ].freeze def render_content_for(name, options = {}, &block) - if block_given? - content = capture(&block) || "" + format = options.fetch(:format, default_format(name)) - format = options.delete(:format) || default_format(name) - content = render_content(format, content) - - content_for(name, content, options, &nil) - end - end - - private - - def default_format(name) - DEFAULT_FORMATS.each do |format, patterns| - return format if patterns.any? { |pattern| pattern.match?(name) } - end - - :govspeak - end - - def render_content(format, content) case format when :govspeak - render_govspeak(content) + govspeak_for(name, &block) when :html - render_html(content) + html_for(name, &block) when :text - render_text(content) + text_for(name, &block) else raise InvalidFormatType end end - def render_govspeak(content) + def text_for(name, &block) + content = capture_content(&block) content = strip_leading_spaces(content) - content = Govspeak::Document.new(content, sanitize: false).to_html - content = content.chomp.html_safe + content = normalize_blank_lines(content) + content_for(name, content.strip) + end + + def govspeak_for(name, &block) + raise ArgumentError, text_only_error_message(name) if text_only?(name) + + content_for(name, render_govspeak(capture_content(&block))) + end - content.present? ? render("govuk_publishing_components/components/govspeak") { content } : "" + def html_for(name, &block) + raise ArgumentError, text_only_error_message(name) if text_only?(name) + + content_for(name, capture_content(&block).html_safe) end - def render_html(content) - content.html_safe + private + + def capture_content(&block) + raise "Expected a block" unless block + + capture(&block) || "" end - def render_text(content) + def default_format(name) + text_only?(name) ? :text : :govspeak + end + + def text_only?(name) + TEXT_CONTENT.any? do |item| + item.is_a?(Regexp) ? name.match?(item) : name == item + end + end + + def text_only_error_message(name) + "#{name} can only be used to display text. Please use #text_for" + end + + def render_govspeak(content) content = strip_leading_spaces(content) - normalize_blank_lines(content).strip + content = Govspeak::Document.new(content, sanitize: false).to_html + + if content.present? + render("govuk_publishing_components/components/govspeak") { content.html_safe } + else + "" + end end def strip_leading_spaces(string) diff --git a/lib/smart_answer_flows/all-smart-answer-questions/all_smart_answer_questions.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/all_smart_answer_questions.erb similarity index 74% rename from lib/smart_answer_flows/all-smart-answer-questions/all_smart_answer_questions.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/all_smart_answer_questions.erb index d4c1a1f0fe1..7796dd1e2b8 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/all_smart_answer_questions.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/all_smart_answer_questions.erb @@ -1,16 +1,16 @@ -<% render_content_for :meta_description do %> +<% text_for :meta_description do %> Do SEO magic here. <% end %> -<% render_content_for :title do %> +<% text_for :title do %> All Smart Answer questions <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> This flow shows all the different question types for Smart Answers. You can [peek at the results](/all-smart-answer-questions/y/mithrandir,olorin,tharkun/mordor/2019-01-01/1900-01-01/2020-02-29/0000-12-25/9999999.0/four/yes/WC2B%206NH/500000.0-month/world/0/0.5) and access all the different question types individually via changing the previous answers. <% end %> -<% render_content_for :post_body do %> +<% govspeak_for :post_body do %> Enjoy! <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/outcomes/outcome.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/outcomes/outcome.erb similarity index 56% rename from lib/smart_answer_flows/all-smart-answer-questions/outcomes/outcome.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/outcomes/outcome.erb index 496502ae373..deb0e096a3c 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/outcomes/outcome.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/outcomes/outcome.erb @@ -1,11 +1,11 @@ -<% render_content_for :title do %> +<% text_for :title do %> Congratulations <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> You managed to get through all the questions. <% end %> -<% render_content_for :next_steps do %> +<% govspeak_for :next_steps do %> Now you can close the browser. Or not. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_money.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_money.erb similarity index 53% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_money.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_money.erb index 0f0c58fd1c1..08c29708615 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_money.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_money.erb @@ -1,15 +1,15 @@ -<% render_content_for :title do %> +<% text_for :title do %> Money question: How much does the world cost? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. <% end %> -<% render_content_for :suffix_label do %> +<% text_for :suffix_label do %> this year <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> It's gotta be more than that! <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_salary.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_salary.erb similarity index 57% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_salary.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_salary.erb index ac1b67818ce..f436b5c83aa 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_salary.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/how_much_salary.erb @@ -1,17 +1,17 @@ -<% render_content_for :title do %> +<% text_for :title do %> Salary question: What would you like your salary to be? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and govspeak <% end %> -<% render_content_for :hint do %> +<% text_for :hint do %> This is a hint <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> Really, not more? <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_boolean_choice.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_boolean_choice.erb similarity index 64% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_boolean_choice.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_boolean_choice.erb index 1d2b03815c4..5f26e7d96f1 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_boolean_choice.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_boolean_choice.erb @@ -1,14 +1,14 @@ -<% render_content_for :title do %> +<% text_for :title do %> Multiple choice (yes/no): Would you like to see the other questions? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and govspeak <% end %> -<% render_content_for :hint do %> +<% text_for :hint do %> This is a hint <% end %> @@ -17,6 +17,6 @@ "no": "No" ) %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> Of course you would! <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_checkboxes.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_checkboxes.erb similarity index 71% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_checkboxes.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_checkboxes.erb index c568eae51d5..11702b568f3 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_checkboxes.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_checkboxes.erb @@ -1,15 +1,15 @@ -<% render_content_for :title do %> +<% text_for :title do %> Checkbox question: What are other names for Gandalf? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - also formatting in a govspeak style - like this <% end %> -<% render_content_for :post_body do %> +<% govspeak_for :post_body do %> Post body can contain less important information. <% end %> @@ -21,10 +21,10 @@ "elrohir": "Elrohir" ) %> -<% render_content_for :hint do %> +<% text_for :hint do %> This is a hint <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> It's neither Elrohir nor Radagast. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_choice.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_choice.erb similarity index 66% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_choice.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_choice.erb index 8de39f0e7d3..9c082b1c894 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_choice.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_choice.erb @@ -1,14 +1,14 @@ -<% render_content_for :title do %> +<% text_for :title do %> Multiple choice: Which of these numbers is not a prime number? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and govspeak <% end %> -<% render_content_for :hint do %> +<% text_for :hint do %> This is a hint <% end %> @@ -19,6 +19,6 @@ "four": "Four" ) %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> 4 is divisible by 2. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_country.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_country.erb similarity index 61% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_country.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_country.erb index e0172fb9f31..0080e055336 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_country.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_country.erb @@ -1,13 +1,13 @@ -<% render_content_for :title do %> +<% text_for :title do %> Country select: Where are you now? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and also govspeak <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> You are currently in a fictional country? <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date.erb similarity index 58% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_date.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_date.erb index 867c3f36415..c3180f087e4 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date.erb @@ -1,13 +1,13 @@ -<% render_content_for :title do %> +<% text_for :title do %> Date question: What date is tomorrow? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and maybe govspeak <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> That's not tomorrow. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_of_birth.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_of_birth.erb similarity index 59% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_of_birth.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_of_birth.erb index 876c850ebcf..ca8e129bf45 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_of_birth.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_of_birth.erb @@ -1,13 +1,13 @@ -<% render_content_for :title do %> +<% text_for :title do %> Date question: What is your date of birth? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and govspeak <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> You haven't been born yet. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_this_year.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_this_year.erb similarity index 58% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_this_year.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_this_year.erb index eccf06ba83a..a66f854dbf5 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_this_year.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_this_year.erb @@ -1,13 +1,13 @@ -<% render_content_for :title do %> +<% text_for :title do %> Date question: When is Christmas this year? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and govspeak <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> That's not Christmas. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_within_range.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_within_range.erb similarity index 60% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_within_range.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_within_range.erb index 0ed6bf1cd3a..d277d613ea8 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_within_range.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_date_within_range.erb @@ -1,13 +1,13 @@ -<% render_content_for :title do %> +<% text_for :title do %> Date question: When will be the next 29 February? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. - and govspeak <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> That's not a leap year. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_float.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_float.erb new file mode 100644 index 00000000000..6414dfe5e2b --- /dev/null +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_float.erb @@ -0,0 +1,15 @@ +<% text_for :title do %> + Value/float question: What is 1/2? +<% end %> + +<% govspeak_for :body do %> + Body can contain further explanations. +<% end %> + +<% text_for :label do %> + Number +<% end %> + +<% text_for :error_message do %> + 0.5 +<% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_float.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_float.govspeak.erb deleted file mode 100644 index 6f16d4374f8..00000000000 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_float.govspeak.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% render_content_for :title do %> - Value/float question: What is 1/2? -<% end %> - -<% render_content_for :body do %> - Body can contain further explanations. -<% end %> - -<% render_content_for :label do %> - Number -<% end %> - -<% render_content_for :error_message do %> - 0.5 -<% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_integer.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_integer.erb similarity index 72% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_integer.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_integer.erb index 740bd0568e3..82055808baf 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_integer.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_integer.erb @@ -1,11 +1,11 @@ -<% render_content_for :title do %> +<% text_for :title do %> Value/integer question: How many software engineers does it take to change a light bulb? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> None. That's a hardware problem. Or: The light bulb works fine on the system in my office. Or: Darkness is working as intended. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_postcode.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_postcode.erb similarity index 52% rename from lib/smart_answer_flows/all-smart-answer-questions/questions/which_postcode.govspeak.erb rename to lib/smart_answer_flows/all-smart-answer-questions/questions/which_postcode.erb index 9b40b0860e5..bf19eb741fd 100644 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_postcode.govspeak.erb +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_postcode.erb @@ -1,15 +1,15 @@ -<% render_content_for :title do %> +<% text_for :title do %> Postcode question: Where is Aviation House? <% end %> -<% render_content_for :body do %> +<% govspeak_for :body do %> Body can contain further explanations. <% end %> -<% render_content_for :hint do %> +<% text_for :hint do %> This is a hint <% end %> -<% render_content_for :error_message do %> +<% text_for :error_message do %> It's WC2B 6NH. <% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_value.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_value.erb new file mode 100644 index 00000000000..1210188f1b4 --- /dev/null +++ b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_value.erb @@ -0,0 +1,15 @@ +<% text_for :title do %> + Value question: "Hello ..."? +<% end %> + +<% govspeak_for :body do %> + Body can contain further explanations. +<% end %> + +<% text_for :suffix_label do %> + ! +<% end %> + +<% text_for :error_message do %> + "world" +<% end %> diff --git a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_value.govspeak.erb b/lib/smart_answer_flows/all-smart-answer-questions/questions/which_value.govspeak.erb deleted file mode 100644 index b1bcd130191..00000000000 --- a/lib/smart_answer_flows/all-smart-answer-questions/questions/which_value.govspeak.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% render_content_for :title do %> - Value question: "Hello ..."? -<% end %> - -<% render_content_for :body do %> - Body can contain further explanations. -<% end %> - -<% render_content_for :suffix_label do %> - ! -<% end %> - -<% render_content_for :error_message do %> - "world" -<% end %> diff --git a/test/unit/erb_renderer_test.rb b/test/unit/erb_renderer_test.rb index cfcee9c1f06..b8018b6895f 100644 --- a/test/unit/erb_renderer_test.rb +++ b/test/unit/erb_renderer_test.rb @@ -2,27 +2,33 @@ module SmartAnswer class ErbRendererTest < ActiveSupport::TestCase - test "#erb_template_path returns the combination of the template directory and name" do - erb_template = "" + test "can render a template" do + erb_template = render_content_for(:key, "content") with_erb_template_file("template-name", erb_template) do |erb_template_directory| - renderer = ErbRenderer.new(template_directory: erb_template_directory, template_name: "template-name") + renderer = ErbRenderer.new( + template_directory: erb_template_directory, + template_name: "template-name", + ) + assert_match("content", renderer.content_for(:key)) + end + end - expected_path = erb_template_directory.join("template-name.govspeak.erb") - assert_equal expected_path, renderer.erb_template_path + test "can render a template with a .govspeak name" do + erb_template = render_content_for(:key, "content") + with_erb_template_file("template-name.govspeak", erb_template) do |erb_template_directory| + renderer = ErbRenderer.new( + template_directory: erb_template_directory, + template_name: "template-name", + ) + assert_match("content", renderer.content_for(:key)) end end - test "#relative_erb_template_path returns a relative version of erb_template_path" do - erb_template = "" - with_erb_template_file("template-name", erb_template) do |erb_template_directory| + test "#relative_erb_template_path returns a template path relative to Rails.root" do + with_erb_template_file("template-name", "") do |erb_template_directory| renderer = ErbRenderer.new(template_directory: erb_template_directory, template_name: "template-name") - - erb_template_path = stub("erb-template-path") - relative_erb_template_path = Pathname.new("relative-erb-template-path") - erb_template_path.stubs(:relative_path_from).returns(relative_erb_template_path) - renderer.stubs(:erb_template_path).returns(erb_template_path) - - assert_equal relative_erb_template_path.to_s, renderer.relative_erb_template_path + Rails.stubs(:root).returns(erb_template_directory) + assert_equal "template-name.erb", renderer.relative_erb_template_path end end @@ -34,21 +40,6 @@ class ErbRendererTest < ActiveSupport::TestCase end end - test "#content_for trims newlines by default" do - erb_template = render_content_for( - :key, - '<% if true %> -Hello world -<% end %>', - ) - - with_erb_template_file("template-name", erb_template) do |erb_template_directory| - renderer = ErbRenderer.new(template_directory: erb_template_directory, template_name: "template-name") - - assert_match(/

Hello world<\/p>/, renderer.content_for(:key)) - end - end - test "#content_for makes local variables available to the ERB template" do erb_template = render_content_for(:key, "<%= state_variable %>") @@ -72,47 +63,6 @@ class ErbRendererTest < ActiveSupport::TestCase end end - test "#content_for makes the ActionView::Helpers::NumberHelper methods available to the ERB template" do - erb_template = render_content_for(:key, "<%= number_with_delimiter(123456789) %>") - - with_erb_template_file("template-name", erb_template) do |erb_template_directory| - renderer = ErbRenderer.new(template_directory: erb_template_directory, template_name: "template-name") - - assert_match "123,456,789", renderer.content_for(:key) - end - end - - test "#content_for passes output of ERB template through Govspeak by default" do - erb_template = render_content_for(:key, "^information^") - - with_erb_template_file("template-name", erb_template) do |erb_template_directory| - renderer = ErbRenderer.new(template_directory: erb_template_directory, template_name: "template-name") - - nodes = Capybara.string(renderer.content_for(:key)) - assert nodes.has_css?(".application-notice", text: "information"), "Does not have information callout" - end - end - - test "#content_for returns an HTML-safe string when passed through Govspeak" do - erb_template = render_content_for(:body, "html-unsafe-string") - - with_erb_template_file("template-name", erb_template) do |erb_template_directory| - renderer = ErbRenderer.new(template_directory: erb_template_directory, template_name: "template-name") - - assert renderer.content_for(:body).html_safe? - end - end - - test "#content_for returns an HTML-safe string" do - erb_template = render_content_for(:key, "html-unsafe-string") - - with_erb_template_file("template-name", erb_template) do |erb_template_directory| - renderer = ErbRenderer.new(template_directory: erb_template_directory, template_name: "template-name") - - assert renderer.content_for(:key).html_safe? - end - end - test "#content_for returns an empty string when content is missing" do erb_template = "" @@ -175,7 +125,7 @@ def render_content_for(key, template) end def with_erb_template_file(outcome_name, erb_template) - erb_template_filename = "#{outcome_name}.govspeak.erb" + erb_template_filename = "#{outcome_name}.erb" Dir.mktmpdir do |directory| erb_template_directory = Pathname.new(directory) diff --git a/test/unit/format_capture_helper_test.rb b/test/unit/format_capture_helper_test.rb index b95603b2dc4..e2b3c3e25c1 100644 --- a/test/unit/format_capture_helper_test.rb +++ b/test/unit/format_capture_helper_test.rb @@ -2,103 +2,131 @@ module SmartAnswer class FormatCaptureHelperTest < ActiveSupport::TestCase - def assert_captured_content(content, format, expected) - options = format.present? ? { format: format } : {} - args = [:name, expected, options] - - @test_obj.expects(:content_for).with(*args) - - @test_obj.render_content_for(:name, options) { content } - end - - context "actionview class is extended by helper" do - setup do - mock_actionview_class = Class.new do - def content_for(_name, content, _options, &_block) - content + setup do + mock_actionview_class = Class.new do + def content_for(name, content = nil, _options = {}, &_block) + @content_for ||= {} + if content + @content_for[name] = content + else + @content_for[name] end + end - def capture(&block) - block.call - end + def capture(&block) + block.call + end - def render(component, &block) - if component == "govuk_publishing_components/components/govspeak" - "#{block.call}" - else - block.call - end + def render(component, &block) + if component == "govuk_publishing_components/components/govspeak" + "#{block.call}" + else + block.call end end - - @test_obj = mock_actionview_class.new - @test_obj.extend(SmartAnswer::ErbRenderer::FormatCaptureHelper) end - should "ignore missing blocks" do - @test_obj.expects(:content_for).never + @test_obj = mock_actionview_class.new + @test_obj.extend(SmartAnswer::ErbRenderer::FormatCaptureHelper) + end - @test_obj.render_content_for(:title) + context "#text_for" do + should "remove leading spaces on content" do + @test_obj.text_for(:name) { " content" } + assert_match @test_obj.content_for(:name), "content" end - should "return empty string for empty blocks" do - @test_obj.expects(:content_for).with(:title, "", {}) + should "remove more than 2 newlines from text" do + @test_obj.text_for(:name) { "content\n\n\n\nmore content" } + assert_match @test_obj.content_for(:name), "content\n\nmore content" + end - @test_obj.render_content_for(:title) {} + should "trim newlines from text" do + @test_obj.text_for(:name) { "\ncontent\n" } + assert_match @test_obj.content_for(:name), "content" end - should "pass all arguments to content_for" do - @test_obj.expects(:content_for).with(:title, "contents", { option: :option }) + should "not be HTML safe" do + @test_obj.text_for(:name) { "Text" } + assert_not @test_obj.content_for(:name).html_safe? + end + end - @test_obj.render_content_for(:title, { option: :option }) { "contents" } + context "#govspeak_for" do + should "render govspeak and wrap it in the govspeak component" do + @test_obj.govspeak_for(:name) { "content" } + assert_match @test_obj.content_for(:name), "

content

\n" end - should "remove format key from options when calling content_for" do - @test_obj.expects(:content_for).with(:name, "contents", { key: :value }) + should "not wrap empty content in the govspeak component" do + @test_obj.govspeak_for(:name) { "" } + assert_match @test_obj.content_for(:name), "" + end - @test_obj.render_content_for(:name, { format: :text, key: :value }) { "contents" } + should "strip leading spaces" do + @test_obj.govspeak_for(:name) { " content" } + assert_match @test_obj.content_for(:name), "

content

\n
" end - should "render govspeak by default" do - assert_captured_content("content", nil, "

content

") + should "raise an error when rendering a text only field" do + error = assert_raises ArgumentError do + @test_obj.govspeak_for(:title) { "Text" } + end + assert_match "title can only be used to display text. Please use #text_for", + error.message end + end - should "render plain text when format set" do - assert_captured_content("content", :text, "content") + context "#html_for" do + should "not alter the html passed in" do + @test_obj.html_for(:name) { "

content

" } + assert_match @test_obj.content_for(:name), "

content

" end - should "render html when format set" do - assert_captured_content("

content

", :html, "

content

") + should "be set set as HTML safe" do + @test_obj.html_for(:name) { "

content

" } + assert @test_obj.content_for(:name).html_safe? end - should "does not modify content when unknown format set" do - assert_raises SmartAnswer::ErbRenderer::FormatCaptureHelper::InvalidFormatType do - @test_obj.render_content_for(:title, { format: :invalid }) { "contents" } + should "raise an error when rendering a text only field" do + error = assert_raises ArgumentError do + @test_obj.html_for(:title) { "Text" } end + assert_match "title can only be used to display text. Please use #text_for", + error.message end + end - should "remove leading spaces on content for text" do - assert_captured_content(" content", :text, "content") + context "#render_content_for" do + should "render govspeak when specified" do + @test_obj.render_content_for(:name, format: :govspeak) { "content" } + assert_match @test_obj.content_for(:name), "

content

\n
" end - should "remove more than 2 newlines from text" do - assert_captured_content("content\n\n\n\nmore content", :text, "content\n\nmore content") + should "render html when specified" do + @test_obj.render_content_for(:name, format: :html) { "

content

" } + assert_equal @test_obj.content_for(:name), "

content

" end - should "trim newlines from text" do - assert_captured_content("\n\n\n\ncontent\n\n\n\n", :text, "content") + should "render text when specified" do + @test_obj.render_content_for(:name, format: :text) { "text" } + assert_equal @test_obj.content_for(:name), "text" end - should "remove leading spaces from govspeak" do - assert_captured_content(" content", :govspeak, "

content

") + should "default to rendering govspeak" do + @test_obj.render_content_for(:name) { "content" } + assert_match @test_obj.content_for(:name), "

content

\n
" end - should "remove extra trailing newlines from govspeak" do - assert_captured_content("content\n\n\n\n", :govspeak, "

content

\n
") + should "render text when the field defaults to text" do + @test_obj.render_content_for(:title) { "content" } + assert_match @test_obj.content_for(:title), "content" end - should "not wrap empty content with govspeak html tags" do - assert_captured_content(" ", :govspeak, "") + should "raise an error when given an unknown format" do + assert_raises SmartAnswer::ErbRenderer::FormatCaptureHelper::InvalidFormatType do + @test_obj.render_content_for(:title, { format: :invalid }) { "content" } + end end end end