live coder seeding - completes #16

This commit is contained in:
Mark Moser 2016-08-23 21:54:53 -05:00
parent 393fd15ab5
commit 2b55fed1bc
12 changed files with 79 additions and 27 deletions

View File

@ -10,7 +10,9 @@ $(function(){
$("#question_input_type").on('change', function(){ $("#question_input_type").on('change', function(){
var qid = $(this).attr('data-qid') === undefined ? '' : "/" + $(this).attr('data-qid'); var qid = $(this).attr('data-qid') === undefined ? '' : "/" + $(this).attr('data-qid');
// /admin/question(/:question_id)/options/:input_type // /admin/question(/:question_id)/options/:input_type
$("[data-id=input-options-wrapper]").load("/admin/question" + qid + "/options/" + $(this).val()); $("[data-id=input-options-wrapper]").load("/admin/question" + qid + "/options/" + $(this).val(), function(){
$(".code-input textarea").linedtextarea();
});
}); });
}); });

View File

@ -60,9 +60,9 @@ module Admin
def process_question_params def process_question_params
question = question_params question = question_params
question[:input_options] = question_params[:multi_choice] unless question_params[:multi_choice].nil? question[:input_options] = question_params[:multi_choice] unless question_params[:multi_choice].nil?
question[:input_options] = question_params[:live_coder] unless question_params[:live_coder].nil? question[:input_options] = question_params[:live_code] unless question_params[:live_code].nil?
question.delete(:multi_choice) question.delete(:multi_choice)
question.delete(:live_coder) question.delete(:live_code)
question question
end end
end end

View File

@ -1,9 +1,10 @@
class Question < ApplicationRecord class Question < ApplicationRecord
serialize :input_options, Array serialize :input_options
has_many :answers has_many :answers
belongs_to :quiz belongs_to :quiz
after_initialize :prepare_input_options
before_validation :compact_input_options before_validation :compact_input_options
validates :quiz_id, presence: true validates :quiz_id, presence: true
@ -15,6 +16,11 @@ class Question < ApplicationRecord
private private
def compact_input_options def compact_input_options
self.input_options = input_options.reject(&:blank?) self.input_options = input_options.reject { |_k, v| v.blank? } if input_options.class == Hash
self.input_options = input_options.reject(&:blank?) if input_options.class == Array
end
def prepare_input_options
self.input_options = input_options || {}
end end
end end

View File

@ -31,7 +31,9 @@ class AnswerFormatValidator < ActiveModel::EachValidator
end end
def live_code record, attribute, value def live_code record, attribute, value
return unless value.nil? || value.values.join.blank? seed = (Question.find_by(id: record.question_id) || Question.new).input_options
return unless value.nil? || value.values.join.blank? || !match_seed?(value, seed)
record.errors[attribute] << (options[:message] || live_code_error_message(value)) record.errors[attribute] << (options[:message] || live_code_error_message(value))
end end
@ -44,4 +46,16 @@ class AnswerFormatValidator < ActiveModel::EachValidator
end end
"You must write comments or code in one of the textareas to progress." "You must write comments or code in one of the textareas to progress."
end end
def match_seed? value, seed
s_value = value.stringify_keys
s_seed = seed.stringify_keys
keys = s_value.merge(s_seed).keys.uniq
matches = keys.inject([]) do |memo, k|
memo << (s_value[k].to_s.strip == s_seed[k].to_s.strip)
end
matches.include? false
end
end end

View File

@ -1,29 +1,18 @@
<%
return nil
# don't load this partial yet. Will finish in issue #16
# https://gitlab.perficientxd.com/pdr/skill-assessment-app/issues/16
options = { 'text' => '', 'html' => '', 'css' => '', 'js' => '' }
%>
<div data-id="live-coder-answer"> <div data-id="live-coder-answer">
<div class="code-input"> <div class="code-input">
<label for="question_input_options_html">HTML</label> <label for="question_input_options_html">HTML</label>
<%= text_area_tag 'question[live_code][html]', options['html'], { data: {id: 'code-html', last: options['html']}, class: 'code-answer code-html' } %> <%= text_area_tag 'question[live_code][html]', question.input_options['html'], { data: {id: 'code-html', last: question.input_options['html']}, class: 'code-answer code-html' } %>
</div> </div>
<div class="code-input"> <div class="code-input">
<label for="question_input_options_css">CSS</label> <label for="question_input_options_css">CSS</label>
<%= text_area_tag 'question[live_code][css]', options['css'], { data: {id: 'code-css', last: options['css']}, class: 'code-answer code-css' } %> <%= text_area_tag 'question[live_code][css]', question.input_options['css'], { data: {id: 'code-css', last: question.input_options['css']}, class: 'code-answer code-css' } %>
</div> </div>
<div class="code-input"> <div class="code-input">
<label for="question_input_options_js">JS</label> <label for="question_input_options_js">JS</label>
<%= text_area_tag 'question[live_code][js]', options['js'], { data: {id: 'code-js', last: options['js']}, class: 'code-answer code-js' } %> <%= text_area_tag 'question[live_code][js]', question.input_options['js'], { data: {id: 'code-js', last: question.input_options['js']}, class: 'code-answer code-js' } %>
</div> </div>
<div class="results" data-id="results"></div> <div class="results" data-id="results"></div>
</div> </div>

View File

@ -5,7 +5,12 @@
name: "answer[#{question.input_type}][later]", name: "answer[#{question.input_type}][later]",
checked: Array(question.answer).include?('finish-later') checked: Array(question.answer).include?('finish-later')
} }
answers = answer.try(:answer) || answer answers = answer.try(:answer) || answer
value_text = answers['text'] || question.input_options['text']
value_html = answers['html'] || question.input_options['html']
value_css = answers['css'] || question.input_options['css']
value_js = answers['js'] || question.input_options['js']
%> %>
<%= render partial: "quiz/answer_errors", locals: {question: question, answer: answer} %> <%= render partial: "quiz/answer_errors", locals: {question: question, answer: answer} %>
@ -38,21 +43,21 @@
<div id="answer<%= question.question_id %>" data-id="live-coder-answer" style="display: none;"> <div id="answer<%= question.question_id %>" data-id="live-coder-answer" style="display: none;">
<label for="answer_live_code_text">Enter answer here</label> <label for="answer_live_code_text">Enter answer here</label>
<%= text_area_tag 'answer[live_code][text]', (answers['text']), { disabled: true, data: {last: answers['text']}} %> <%= text_area_tag 'answer[live_code][text]', value_text, { disabled: true, data: {last: answers['text']}} %>
<div class="code-input"> <div class="code-input">
<label for="answer_live_code_html">HTML</label> <label for="answer_live_code_html">HTML</label>
<%= text_area_tag 'answer[live_code][html]', (answers['html']), { disabled: true, data: {id: 'code-html', last: answers['html']}, class: 'code-answer code-html' } %> <%= text_area_tag 'answer[live_code][html]', value_html, { disabled: true, data: {id: 'code-html', last: answers['html']}, class: 'code-answer code-html' } %>
</div> </div>
<div class="code-input"> <div class="code-input">
<label for="answer_live_code_css">CSS</label> <label for="answer_live_code_css">CSS</label>
<%= text_area_tag 'answer[live_code][css]', (answers['css']), { disabled: true, data: {id: 'code-css', last: answers['css']}, class: 'code-answer code-css' } %> <%= text_area_tag 'answer[live_code][css]', value_css, { disabled: true, data: {id: 'code-css', last: answers['css']}, class: 'code-answer code-css' } %>
</div> </div>
<div class="code-input"> <div class="code-input">
<label for="answer_live_code_js">JS</label> <label for="answer_live_code_js">JS</label>
<%= text_area_tag 'answer[live_code][js]', (answers['js']), { disabled: true, data: {id: 'code-js', last: answers['js']}, class: 'code-answer code-js' } %> <%= text_area_tag 'answer[live_code][js]', value_js, { disabled: true, data: {id: 'code-js', last: answers['js']}, class: 'code-answer code-js' } %>
</div> </div>
<div class="results" data-id="results"></div> <div class="results" data-id="results"></div>

View File

@ -39,7 +39,7 @@ class CandidateQuizQuestion
end end
def input_options def input_options
YAML.load(row["input_options"].to_s) YAML.load(row["input_options"].to_s) || {}
end end
def answer def answer

View File

@ -68,6 +68,8 @@ fed7:
category: Javascript category: Javascript
input_type: live_code input_type: live_code
input_options: input_options:
:html: "<p>sample seed html</p>"
:css: "body { color: #644; }"
sort: 6 sort: 6
active: true active: true

View File

@ -15,4 +15,13 @@ class QuestionLiveCoderTest < ActionDispatch::IntegrationTest
# TODO: add in capybara and test form post # TODO: add in capybara and test form post
# assert_redirected summary_path # assert_redirected summary_path
end end
test "should load seed data into live coder" do
setup_auth candidates(:juan)
question = questions(:fed7)
get question_path(question.id)
assert_response :success
assert_select '#answer_live_code_html', question.input_options['html']
end
end end

View File

@ -11,4 +11,11 @@ class QuestionTest < ActiveSupport::TestCase
assert_equal 2, question.input_options.count assert_equal 2, question.input_options.count
end end
test 'should have seed input for live_coder' do
question = Question.find questions(:fed7).to_i
assert_kind_of Hash, question.input_options
assert question.input_options.keys.include? :html
end
end end

View File

@ -3,13 +3,15 @@ class AnswerValidatable
attr_accessor :answer attr_accessor :answer
attr_accessor :question attr_accessor :question
attr_accessor :question_id
validates :answer, answer_format: true validates :answer, answer_format: true
MockQuestion = Struct.new(:input_type) MockQuestion = Struct.new(:input_type)
def initialize input_type def initialize input_type, qid = nil
@input_type = input_type @input_type = input_type
@question_id = qid
end end
def question def question

View File

@ -48,4 +48,20 @@ class AnswerFormatValidatorTest < ActiveSupport::TestCase
assert obj.valid? assert obj.valid?
assert obj.errors.messages.empty? assert obj.errors.messages.empty?
end end
test "live_code should PASS using seed data" do
obj = AnswerValidatable.new('live_code', questions(:fed7).id)
obj.answer = { text: "no thanks", html: "<p>sample seed html</p>", css: "body { color: #644; }", js: "" }
assert obj.valid?
assert obj.errors.messages.empty?
end
test "live_code should FAIL with seed data only" do
obj = AnswerValidatable.new('live_code', questions(:fed7).id)
obj.answer = { text: "", html: "<p>sample seed html</p>", css: "body { color: #644; }", js: "" }
refute obj.valid?
assert_match(/write.*code/, obj.errors.messages[:answer][0])
end
end end