-
1
require 'rails_helper'
-
1
require 'simplecov'
-
1
SimpleCov.start
-
-
-
1
describe Questionnaire, type: :model do
-
# Creating dummy objects for the test with the help of let statement
-
36
let(:role) {Role.create(name: 'Instructor', parent_id: nil, id: 2, default_page_id: nil)}
-
36
let(:instructor) { Instructor.create(name: 'testinstructor', email: 'test@test.com', full_name: 'Test Instructor', password: '123456', role: role) }
-
19
let(:questionnaire) { FactoryBot.build(:questionnaire, { id: 1, name: 'abc', instructor_id: instructor.id }) }
-
3
let(:questionnaire1) { FactoryBot.build(:questionnaire, { id: 2, name: 'xyz', max_question_score: 20, instructor_id: instructor.id }) }
-
3
let(:questionnaire3) { FactoryBot.build(:review_questionnaire, { id: 3, name: 'pqr', instructor_id: instructor.id }) }
-
3
let(:question1) { questionnaire.questions.build(weight: 1, id: 1, seq: 1, txt: "que 1", question_type: "Scale", break_before: true) }
-
3
let(:question2) { questionnaire.questions.build(weight: 10, id: 2, seq: 2, txt: "que 2", question_type: "Checkbox", break_before: true) }
-
-
-
1
describe '#name' do
-
# Test validates the name of the questionnaire
-
1
it 'returns the name of the Questionnaire' do
-
# Act Assert
-
1
expect(questionnaire.name).to eq('abc')
-
1
expect(questionnaire1.name).to eq('xyz')
-
1
expect(questionnaire3.name).to eq('pqr')
-
end
-
-
# Test ensures that the name field of the questionnaire is not blank
-
1
it 'Validate presence of name which cannot be blank' do
-
# Arrange
-
1
questionnaire.name = ' '
-
-
# Act Assert
-
1
expect(questionnaire).not_to be_valid
-
end
-
-
# Test ensures that the name field of the questionnaire is unique per instructor
-
1
it 'Validate name field must be unique per instructor' do
-
# Arrange Act
-
1
questionnaire.save!
-
1
questionnaire1.name = questionnaire.name
-
1
questionnaire3.name = questionnaire.name
-
1
instructor2 = Instructor.create(name: 'testinstructortwo', email: 'test2@test.com', full_name: 'Test Instructor 2', password: '123456', role: role)
-
1
instructor2.save!
-
1
questionnaire3.instructor_id = instructor2.id
-
# Assert
-
1
expect(questionnaire).to be_valid
-
1
expect(questionnaire1).not_to be_valid
-
1
expect(questionnaire3).to be_valid
-
end
-
end
-
-
1
describe '#instructor_id' do
-
# Test validates the instructor id in the questionnaire
-
1
it 'returns the instructor id' do
-
1
expect(questionnaire.instructor_id).to eq(instructor.id)
-
end
-
end
-
-
1
describe '#maximum_score' do
-
# Test validates the maximum score in the questionnaire
-
1
it 'validate maximum score' do
-
1
expect(questionnaire.max_question_score).to eq(10)
-
end
-
-
# Test ensures maximum score is an integer
-
1
it 'validate maximum score is integer' do
-
1
expect(questionnaire.max_question_score).to eq(10)
-
1
questionnaire.max_question_score = 'a'
-
1
expect(questionnaire).not_to be_valid
-
1
questionnaire.max_question_score = 1.1
-
1
expect(questionnaire).not_to be_valid
-
end
-
-
# Test ensures maximum score is positive
-
1
it 'validate maximum score should be positive' do
-
1
expect(questionnaire.max_question_score).to eq(10)
-
1
questionnaire.max_question_score = -10
-
1
expect(questionnaire).not_to be_valid
-
1
questionnaire.max_question_score = 0
-
1
expect(questionnaire).not_to be_valid
-
end
-
-
# Test ensures maximum score is greater than the minimum score
-
1
it 'validate maximum score should be bigger than minimum score' do
-
-
1
expect(questionnaire).to be_valid
-
1
questionnaire.max_question_score = 0
-
1
expect(questionnaire).not_to be_valid
-
1
questionnaire.max_question_score = 2
-
1
questionnaire.min_question_score = 3
-
1
expect(questionnaire).not_to be_valid
-
end
-
end
-
-
1
describe '#minimum_score' do
-
# Test validates minimum score of a questionnaire
-
1
it 'validate minimum score' do
-
1
questionnaire.min_question_score = 5
-
1
expect(questionnaire.min_question_score).to eq(5)
-
end
-
-
# Test ensures minimum score is smaller than maximum score
-
1
it 'validate minimum should be smaller than maximum' do
-
1
expect(questionnaire.min_question_score).to eq(0)
-
1
questionnaire.min_question_score = 10
-
1
expect(questionnaire).not_to be_valid
-
1
questionnaire.min_question_score = 0
-
end
-
-
# Test ensures minimum score is an integer
-
1
it 'validate minimum score is integer' do
-
1
expect(questionnaire.min_question_score).to eq(0)
-
1
questionnaire.min_question_score = 'a'
-
1
expect(questionnaire).not_to be_valid
-
end
-
-
end
-
-
-
1
describe 'associations' do
-
# Test validates the association that a questionnaire comprises of several questions
-
1
it 'has many questions' do
-
1
expect(questionnaire.questions).to include(question1, question2)
-
end
-
end
-
-
1
describe '.copy_questionnaire_details' do
-
# Test ensures calls from the method copy_questionnaire_details
-
1
it 'allowing calls from copy_questionnaire_details' do
-
1
allow(Questionnaire).to receive(:find).with('1').and_return(questionnaire)
-
1
allow(Question).to receive(:where).with(questionnaire_id: '1').and_return([Question])
-
end
-
# Test ensures creation of a copy of given questionnaire
-
# Combined two tests into one to avoid performing the same functionalities again to test another feature.
-
1
it 'creates a copy of the questionnaire' do
-
1
instructor.save!
-
1
questionnaire.save!
-
1
question1.save!
-
1
question2.save!
-
-
# Stub the where method to return the questions associated with the original questionnaire
-
1
allow(questionnaire).to receive_message_chain(:questions, :each).and_yield(question1).and_yield(question2)
-
-
# Call the copy_questionnaire_details method
-
1
copied_questionnaire = Questionnaire.copy_questionnaire_details({ id: questionnaire.id })
-
-
# Assertions
-
1
expect(copied_questionnaire.instructor_id).to eq(questionnaire.instructor_id)
-
1
expect(copied_questionnaire.name).to eq("Copy of #{questionnaire.name}")
-
1
expect(copied_questionnaire.created_at).to be_within(1.second).of(Time.zone.now)
-
-
# Verify that the copied questionnaire has associated questions
-
1
expect(copied_questionnaire.questions.count).to eq(2)
-
1
expect(copied_questionnaire.questions.first.txt).to eq(question1.txt)
-
1
expect(copied_questionnaire.questions.second.txt).to eq(question2.txt)
-
end
-
end
-
-
# This is the beginning of the skeleton implementation
-
1
describe '#get_weighted_score' do
-
1
before :each do
-
4
@questionnaire = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
4
@assignment = FactoryBot.create(:assignment)
-
end
-
1
context 'when the assignment has a round' do
-
1
it 'computes the weighted score using the questionnaire symbol with the round appended' do
-
# Test case 1
-
# Arrange
-
1
FactoryBot.create(:assignment_questionnaire, { assignment_id: @assignment.id, questionnaire_id: @questionnaire.id, used_in_round: 1 })
-
1
scores = { "#{@questionnaire.symbol}#{1}".to_sym => { scores: { avg: 100 } } }
-
# Act Assert
-
1
expect(@questionnaire.get_weighted_score(@assignment, scores)).to eq(100)
-
# Test case 2
-
# Arrange
-
1
scores = { "#{@questionnaire.symbol}#{1}".to_sym => { scores: { avg: 75 } } }
-
# Act Assert
-
1
expect(@questionnaire.get_weighted_score(@assignment, scores)).to eq(75)
-
end
-
end
-
-
1
context 'when the assignment does not have a round' do
-
1
it 'computes the weighted score using the questionnaire symbol' do
-
# Test case 3
-
# Arrange
-
1
FactoryBot.create(:assignment_questionnaire, { assignment_id: @assignment.id, questionnaire_id: @questionnaire.id })
-
1
scores = { @questionnaire.symbol => { scores: { avg: 100 } } }
-
# Act Assert
-
1
expect(@questionnaire.get_weighted_score(@assignment, scores)).to eq(100)
-
# Test case 4
-
# Arrange
-
1
scores = { @questionnaire.symbol => { scores: { avg: 75 } } }
-
# Act Assert
-
1
expect(@questionnaire.get_weighted_score(@assignment, scores)).to eq(75)
-
end
-
end
-
1
describe "#compute_weighted_score" do
-
1
before :each do
-
2
@questionnaire = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
2
@assignment = FactoryBot.create(:assignment)
-
2
FactoryBot.create(:assignment_questionnaire, { assignment_id: @assignment.id, questionnaire_id: @questionnaire.id, questionnaire_weight: 50 })
-
end
-
1
context "when the average score is nil" do
-
1
it "returns 0" do
-
# Test scenario
-
# Arrange
-
1
scores = { @questionnaire.symbol => { scores: { avg: nil } } }
-
-
# Act Assert
-
1
expect(@questionnaire.compute_weighted_score(@questionnaire.symbol, @assignment, scores)).to eq(0)
-
end
-
end
-
1
context "when the average score is not nil" do
-
1
it "calculates the weighted score based on the questionnaire weight" do
-
# Test scenario
-
# Arrange
-
1
scores = { @questionnaire.symbol => { scores: { avg: 75 } } }
-
-
# Act Assert
-
1
expect(@questionnaire.compute_weighted_score(@questionnaire.symbol, @assignment, scores)).to eq(75 * 0.5)
-
end
-
end
-
end
-
end
-
1
describe "#true_false_questions?" do
-
1
before :each do
-
2
@questionnaire = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
end
-
1
context "when there are true/false questions" do
-
1
it "returns true" do
-
# Test scenario 2: Single question with type 'Checkbox'
-
# Arrange
-
1
@questionnaire.questions.create(weight: 1, id: 1, seq: 1, txt: "que 1", question_type: "Checkbox", break_before: true)
-
-
# Act Assert
-
1
expect(@questionnaire.true_false_questions?).to eq(true)
-
-
# Test scenario 1: Multiple questions with type 'Checkbox'
-
# Arrange
-
1
@questionnaire.questions.create(weight: 1, id: 2, seq: 1, txt: "que 1", question_type: "Checkbox", break_before: true)
-
1
@questionnaire.questions.create(weight: 1, id: 3, seq: 1, txt: "que 1", question_type: "Checkbox", break_before: true)
-
-
# Act Assert
-
1
expect(@questionnaire.true_false_questions?).to eq(true)
-
end
-
end
-
-
1
context "when there are no true/false questions" do
-
1
it "returns false" do
-
# Test scenario 2: Single question with no 'Checkbox' type
-
# Arrange
-
1
@questionnaire.questions.create(weight: 1, id: 1, seq: 1, txt: "que 1", question_type: "Scale", break_before: true)
-
-
# Act Assert
-
1
expect(@questionnaire.true_false_questions?).to eq(false)
-
-
# Test scenario 1: Multiple questions with no 'Checkbox' type
-
# Arrange
-
1
@questionnaire.questions.create(weight: 1, id: 2, seq: 1, txt: "que 1", question_type: "Scale", break_before: true)
-
1
@questionnaire.questions.create(weight: 1, id: 3, seq: 1, txt: "que 1", question_type: "Scale", break_before: true)
-
-
# Act Assert
-
1
expect(@questionnaire.true_false_questions?).to eq(false)
-
end
-
end
-
end
-
1
describe "#delete" do
-
1
context "when there are assignments using the questionnaire" do
-
1
it "raises an error with a message asking if the user wants to delete the assignment" do
-
# Arrange
-
1
questionnaire_single_assignment = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
1
single_assignment = FactoryBot.create(:assignment)
-
1
FactoryBot.create(:assignment_questionnaire, { assignment_id: single_assignment.id, questionnaire_id: questionnaire_single_assignment.id})
-
1
questionnaire_multi_assignment = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
1
multi_assignment1 = FactoryBot.create(:assignment)
-
1
FactoryBot.create(:assignment_questionnaire, { assignment_id: multi_assignment1.id, questionnaire_id: questionnaire_multi_assignment.id})
-
1
multi_assignment2 = FactoryBot.create(:assignment)
-
1
FactoryBot.create(:assignment_questionnaire, { assignment_id: multi_assignment2.id, questionnaire_id: questionnaire_multi_assignment.id})
-
-
# Test scenario 1
-
# Given: There are assignments using the questionnaire
-
# When: The delete method is called
-
# Then: An error is raised with a message asking if the user wants to delete the assignment
-
2
expect { questionnaire_single_assignment.delete }.to raise_exception(RuntimeError) do |error|
-
1
expect(error.message).to match(/^The assignment .* uses this questionnaire/)
-
end
-
-
# Test scenario 2
-
1
assignment1_pattern = /^The assignment #{Regexp.escape(multi_assignment1.name)} uses this questionnaire/
-
1
assignment2_pattern = /^The assignment #{Regexp.escape(multi_assignment2.name)} uses this questionnaire/
-
# Given: There are multiple assignments using the questionnaire
-
# When: The delete method is called
-
# Then: An error is raised for each assignment with a message asking if the user wants to delete the assignment
-
2
expect { questionnaire_multi_assignment.delete }.to raise_exception(RuntimeError) do |error|
-
1
expect(error.message).to match(assignment1_pattern)
-
end
-
1
multi_assignment1.destroy!
-
2
expect { questionnaire_multi_assignment.delete }.to raise_exception(RuntimeError) do |error|
-
1
expect(error.message).to match(assignment2_pattern)
-
end
-
end
-
end
-
-
1
context "when there are no assignments using the questionnaire" do
-
1
it "deletes all the questions associated with the questionnaire" do
-
# Test scenario 1
-
# Given: There are no assignments using the questionnaire
-
# When: The delete method is called
-
# Then: All the questions associated with the questionnaire are deleted
-
# Arrange
-
1
questionnaire_one_question = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
1
question1 = questionnaire_one_question.questions.build(weight: 1, id: 1, seq: 1, txt: "que 1", question_type: "Scale", break_before: true)
-
1
question1.save!
-
-
# Act
-
1
questionnaire_one_question.delete
-
-
# Assert
-
1
expect(Question.find_by(id: question1.id)).to be_nil
-
-
# Test scenario 2
-
# Given: There are no assignments using the questionnaire and there are multiple questions
-
# When: The delete method is called
-
# Then: All the questions associated with the questionnaire are deleted
-
# Arrange
-
1
questionnaire_multi_question = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
1
question1 = questionnaire_multi_question.questions.build(weight: 1, id: 1, seq: 1, txt: "que 1", question_type: "Scale", break_before: true)
-
1
question1.save!
-
1
question2 = questionnaire_multi_question.questions.build(weight: 1, id: 2, seq: 1, txt: "que 1", question_type: "Scale", break_before: true)
-
1
question2.save!
-
-
# Act
-
1
questionnaire_multi_question.delete
-
-
# Assert
-
1
expect(Question.find_by(id: question1.id)).to be_nil
-
1
expect(Question.find_by(id: question2.id)).to be_nil
-
end
-
-
1
it "deletes the questionnaire node if it exists" do
-
# Test scenario 1
-
# Given: There are no assignments using the questionnaire and the questionnaire node exists
-
# When: The delete method is called
-
# Then: The questionnaire node is deleted
-
1
questionnaire = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
1
q_node = QuestionnaireNode.create(parent_id: 0, node_object_id: questionnaire.id, type: 'QuestionnaireNode')
-
# Act
-
1
questionnaire.delete
-
-
# Assert
-
1
expect(QuestionnaireNode.find_by(id: q_node.id)).to be_nil
-
-
# Test scenario 2
-
# Given: There are no assignments using the questionnaire and the questionnaire node does not exist
-
# When: The delete method is called
-
# Then: No error is raised and the method completes successfully
-
1
questionnaire = FactoryBot.create(:review_questionnaire, { instructor_id: instructor.id })
-
-
# Act Assert
-
2
expect { questionnaire.delete }.not_to raise_error
-
1
expect(Questionnaire.find_by(id: questionnaire.id)).to be_nil
-
end
-
-
# The below tests were redundant
-
# it "deletes the questionnaire" do
-
# Test scenario 1
-
# Given: There are no assignments using the questionnaire
-
# When: The delete method is called
-
# Then: The questionnaire is deleted
-
-
# Test scenario 2
-
# Given: There are no assignments using the questionnaire and there are multiple questionnaires
-
# When: The delete method is called
-
# Then: The questionnaire is deleted
-
# end
-
end
-
end
-
-
1
describe '#name_is_unique' do
-
1
context 'when no other questionnaire with the same name exists for the same instructor' do
-
1
it 'does not add error' do
-
1
questionnaire.name_is_unique
-
1
expect(questionnaire.errors[:name]).to_not include('must be unique')
-
end
-
end
-
-
1
context 'when two questionnaires with the same name exists for the same instructor' do
-
1
it 'adds error' do
-
1
existing_questionnaire = FactoryBot.create(:questionnaire, instructor: instructor)
-
1
duplicate_question = FactoryBot.create(:questionnaire, instructor: instructor)
-
1
duplicate_question.name_is_unique
-
1
expect(duplicate_question.errors[:name]).to include('must be unique')
-
end
-
end
-
-
1
context 'when two questionnaires have the same name for different instructors' do
-
1
it 'does not throw an error' do
-
## Creating a different instructor for this test.
-
1
instructor2 = Instructor.create(name: 'testinstructortwo', email: 'test2@test.com', full_name: 'Test Instructor 2', password: '123456', role: role)
-
-
1
original_questionnaire = FactoryBot.create(:questionnaire, instructor: instructor)
-
1
new_questionnaire = FactoryBot.create(:questionnaire, instructor: instructor2)
-
1
new_questionnaire.name_is_unique
-
1
expect(new_questionnaire.errors[:name]).to_not include('must be unique')
-
end
-
end
-
-
1
context 'when two questionnaires have different names for the same instructor' do
-
1
it 'does not throw an error' do
-
1
original_questionnaire = FactoryBot.create(:questionnaire, instructor: instructor)
-
1
new_questionnaire = FactoryBot.create(:questionnaire, instructor: instructor, name: "Super cool new questionnaire")
-
-
1
new_questionnaire.name_is_unique
-
1
expect(new_questionnaire.errors[:name]).to_not include('must be unique')
-
end
-
end
-
-
1
context 'when any of the required values is missing' do
-
1
it 'returns nothing if id is nil' do
-
1
questionnaire.id = nil
-
1
result = questionnaire.name_is_unique
-
1
expect(result).to be_nil
-
end
-
-
1
it 'returns nothing if name is nil' do
-
1
questionnaire.name = nil
-
1
result = questionnaire.name_is_unique
-
1
expect(result).to be_nil
-
end
-
-
1
it 'returns nothing if instructor_id is nil' do
-
1
questionnaire.instructor_id = nil
-
1
result = questionnaire.name_is_unique
-
1
expect(result).to be_nil
-
end
-
end
-
end
-
-
1
describe '#min_less_than_max' do
-
1
context 'when either value is not there' do
-
1
it 'returns nil if min_score is nil.' do
-
1
questionnaire = FactoryBot.create( :questionnaire, instructor: instructor)
-
## Must be added here or it will not pass validation when being created.
-
1
questionnaire.min_question_score = nil
-
1
result = questionnaire.min_less_than_max
-
1
expect(result).to be_nil
-
end
-
end
-
1
it 'returns nil if max_score is nil.' do
-
1
questionnaire = FactoryBot.create( :questionnaire, instructor: instructor)
-
## Must be added here or it will not pass validation when being created.
-
1
questionnaire.max_question_score = nil
-
1
result = questionnaire.min_less_than_max
-
1
expect(result).to be_nil
-
end
-
1
context 'when it is given two integers' do
-
1
it 'adds an error if min is greater than max' do
-
1
questionnaire = FactoryBot.create( :questionnaire, instructor: instructor)
-
1
questionnaire.max_question_score = 20
-
1
questionnaire.min_question_score = 25 ## min is now greater than max.
-
1
questionnaire.min_less_than_max
-
1
expect(questionnaire.errors[:min_question_score]).to include('must be less than max question score')
-
end
-
1
it 'adds an error if min is equal to max' do
-
1
questionnaire = FactoryBot.create( :questionnaire, instructor: instructor)
-
1
questionnaire.max_question_score = 25
-
1
questionnaire.min_question_score = 25 ## min is now equal to max.
-
1
questionnaire.min_less_than_max
-
1
expect(questionnaire.errors[:min_question_score]).to include('must be less than max question score')
-
end
-
-
1
it 'does not add an error if min is less than max' do
-
1
questionnaire = FactoryBot.create( :questionnaire, instructor: instructor)
-
1
questionnaire.max_question_score = 25
-
1
questionnaire.min_question_score = 20 ## min is now less than max.
-
1
questionnaire.min_less_than_max
-
1
expect(questionnaire.errors[:min_question_score]).to be_empty
-
end
-
end
-
end
-
-
end