add outcomes export
closes OUT-1837 Basic test plan: - Create account outcomes in an account - From the Account Settings/Reports tab, export outcomes - Verify the exported CSV matches expectations Variations: - nested outcome groups - outcomes in multiple outcome groups - global outcomes in account groups - exporting outcomes from subaccount - including account outcomes in subaccount and exporting subaccount Change-Id: I03c6e4b7b69e91a4e1c68f4242a596719ac12858 Reviewed-on: https://gerrit.instructure.com/140209 Tested-by: Jenkins Reviewed-by: Augusto Callejas <acallejas@instructure.com> QA-Review: Andrew Porter <hporter-c@instructure.com> Product-Review: Sidharth Oberoi <soberoi@instructure.com>
This commit is contained in:
parent
264d4f46c4
commit
b861e06122
|
@ -0,0 +1,107 @@
|
|||
<p><%= t(%{This report shows all learning outcomes that exist within this account.
|
||||
The resulting csv file will have one row per outcome, and will show the details of
|
||||
all associated attributes with each outcome.}) %></p>
|
||||
|
||||
<h3><%= t(%{Example}) %></h3>
|
||||
|
||||
<table class="report_example">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>canvas_id</th>
|
||||
<th>vendor_guid</th>
|
||||
<th>object_type</th>
|
||||
<th>title</th>
|
||||
<th>description</th>
|
||||
<th>display_name</th>
|
||||
<th>calculation_method</th>
|
||||
<th>calculation_int</th>
|
||||
<th>parent_guids</th>
|
||||
<th>workflow_state</th>
|
||||
<th>mastery_points</th>
|
||||
<th>ratings</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1001</td>
|
||||
<td>a00201</td>
|
||||
<td>outcome_group</td>
|
||||
<td>Mathematics</td>
|
||||
<td>Standards related to mathematics</td>
|
||||
<td>MATH</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>active</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1002</td>
|
||||
<td>a00202</td>
|
||||
<td>outcome_group</td>
|
||||
<td>Mathematics Grade 2</td>
|
||||
<td>Standards related to mathematics, grade 2</td>
|
||||
<td>MATH-2</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>a00201</td>
|
||||
<td>active</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>51</td>
|
||||
<td>g0333</td>
|
||||
<td>outcome</td>
|
||||
<td>Order of Operations, +/-</td>
|
||||
<td>Students will be able add and subtract using parentheses to define order of operations</td>
|
||||
<td>MATH-2-OO</td>
|
||||
<td>decaying_average</td>
|
||||
<td>40</td>
|
||||
<td>a00201 a00202</td>
|
||||
<td>deleted</td>
|
||||
<td>3.0</td>
|
||||
<td>0.80</td>
|
||||
<td>Excellent</td>
|
||||
<td>0.40</td>
|
||||
<td>Fair</td>
|
||||
<td>0.0</td>
|
||||
<td>Needs Improvement</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>53</td>
|
||||
<td>g0335</td>
|
||||
<td>outcome</td>
|
||||
<td>Order of Operations, ×/÷</td>
|
||||
<td>Students will be able multiply and divide using parentheses to define order of operations</td>
|
||||
<td>MATH-2-O1</td>
|
||||
<td>n_mastery</td>
|
||||
<td>4</td>
|
||||
<td>a00201</td>
|
||||
<td>active</td>
|
||||
<td>5.0</td>
|
||||
<td>0.60</td>
|
||||
<td>Pass</td>
|
||||
<td>0.0</td>
|
||||
<td>Fail</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
|
@ -30,6 +30,10 @@ module AccountReports
|
|||
OutcomeReports.new(account_report).outcome_results
|
||||
end
|
||||
|
||||
def self.outcome_export_csv(account_report)
|
||||
OutcomeExport.new(account_report).outcome_export
|
||||
end
|
||||
|
||||
def self.grade_export_csv(account_report)
|
||||
GradeReports.new(account_report).grade_export
|
||||
end
|
||||
|
|
|
@ -22,6 +22,7 @@ module AccountReports
|
|||
require 'account_reports/course_reports'
|
||||
require 'account_reports/default'
|
||||
require 'account_reports/grade_reports'
|
||||
require 'account_reports/outcome_export'
|
||||
require 'account_reports/outcome_reports'
|
||||
require 'account_reports/report_helper'
|
||||
require 'account_reports/sis_exporter'
|
||||
|
@ -89,6 +90,12 @@ module AccountReports
|
|||
}
|
||||
}
|
||||
},
|
||||
'outcome_export_csv' => {
|
||||
title: proc { I18n.t('Outcome Export')},
|
||||
parameters_partial: false,
|
||||
description_partial: true,
|
||||
parameters: {}
|
||||
},
|
||||
'outcome_results_csv' => {
|
||||
:title => proc { I18n.t(:outcome_results_title, 'Outcome Results') },
|
||||
:parameters_partial => true,
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
#
|
||||
# Copyright (C) 2012 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'account_reports/report_helper'
|
||||
|
||||
module AccountReports
|
||||
class OutcomeExport
|
||||
include ReportHelper
|
||||
|
||||
def initialize(account_report)
|
||||
@account_report = account_report
|
||||
include_deleted_objects
|
||||
end
|
||||
|
||||
OUTCOME_EXPORT_SCALAR_HEADERS = [
|
||||
'canvas_id',
|
||||
'vendor_guid',
|
||||
'object_type',
|
||||
'title',
|
||||
'description',
|
||||
'display_name',
|
||||
'calculation_method',
|
||||
'calculation_int',
|
||||
'parent_guids',
|
||||
'workflow_state',
|
||||
'mastery_points'
|
||||
].freeze
|
||||
OUTCOME_EXPORT_HEADERS = (OUTCOME_EXPORT_SCALAR_HEADERS + ['ratings']).freeze
|
||||
|
||||
def outcome_export
|
||||
write_report OUTCOME_EXPORT_HEADERS do |csv|
|
||||
export_outcome_groups(csv)
|
||||
export_outcomes(csv)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def vendor_guid_field(table, prefix: 'canvas_outcome_group')
|
||||
guid_field, backup_field = %i[vendor_guid vendor_guid_2]
|
||||
guid_field, backup_field = backup_field, guid_field if AcademicBenchmark.use_new_guid_columns?
|
||||
|
||||
"COALESCE(
|
||||
#{table}.#{guid_field},
|
||||
#{table}.#{backup_field},
|
||||
CONCAT('#{prefix}:', #{table}.id)
|
||||
)"
|
||||
end
|
||||
|
||||
def outcome_group_scope
|
||||
LearningOutcomeGroup.connection.execute(<<~SQL)
|
||||
WITH RECURSIVE outcome_tree AS (
|
||||
SELECT
|
||||
root_group.id AS canvas_id,
|
||||
root_group.learning_outcome_group_id,
|
||||
root_group.workflow_state,
|
||||
#{vendor_guid_field('root_group')} AS vendor_guid,
|
||||
CAST('' AS bpchar) AS parent_guid,
|
||||
root_group.description,
|
||||
root_group.title,
|
||||
0 AS generation
|
||||
FROM #{LearningOutcomeGroup.quoted_table_name} root_group
|
||||
WHERE root_group.learning_outcome_group_id IS NULL
|
||||
AND root_group.context_id = '#{account.id}'
|
||||
AND root_group.context_type = 'Account'
|
||||
AND root_group.workflow_state <> 'deleted'
|
||||
UNION ALL
|
||||
SELECT
|
||||
child_group.id AS canvas_id,
|
||||
child_group.learning_outcome_group_id,
|
||||
child_group.workflow_state,
|
||||
#{vendor_guid_field('child_group')} AS vendor_guid,
|
||||
ot.vendor_guid AS parent_guid,
|
||||
child_group.description,
|
||||
child_group.title,
|
||||
ot.generation + 1 as generation
|
||||
FROM #{LearningOutcomeGroup.quoted_table_name} child_group
|
||||
JOIN outcome_tree ot ON child_group.learning_outcome_group_id = ot.canvas_id
|
||||
WHERE child_group.workflow_state <> 'deleted'
|
||||
)
|
||||
SELECT *,
|
||||
CASE WHEN generation = 1 THEN NULL
|
||||
ELSE parent_guid
|
||||
END AS parent_guids
|
||||
FROM outcome_tree
|
||||
WHERE generation > 0
|
||||
ORDER BY generation ASC
|
||||
SQL
|
||||
end
|
||||
|
||||
def export_outcome_groups(csv)
|
||||
outcome_group_scope.each do |row|
|
||||
row['object_type'] = 'group'
|
||||
csv << OUTCOME_EXPORT_SCALAR_HEADERS.map { |h| row[h] }
|
||||
end
|
||||
end
|
||||
|
||||
def simple_outcome_scope
|
||||
ContentTag.active.where(
|
||||
context: account,
|
||||
tag_type: 'learning_outcome_association'
|
||||
).joins(:learning_outcome_content)
|
||||
end
|
||||
|
||||
def outcome_scope
|
||||
simple_outcome_scope.joins(<<~SQL).
|
||||
JOIN #{LearningOutcomeGroup.quoted_table_name} learning_outcome_groups
|
||||
ON learning_outcome_groups.id = content_tags.associated_asset_id
|
||||
SQL
|
||||
where("learning_outcomes.workflow_state <> 'deleted'").
|
||||
order('learning_outcomes.id').
|
||||
group('learning_outcomes.id').
|
||||
select(<<~SQL)
|
||||
learning_outcomes.id AS canvas_id,
|
||||
learning_outcomes.workflow_state,
|
||||
#{vendor_guid_field('learning_outcomes', prefix: 'canvas_outcome')} AS vendor_guid,
|
||||
learning_outcomes.short_description AS title,
|
||||
learning_outcomes.description,
|
||||
learning_outcomes.data,
|
||||
learning_outcomes.workflow_state,
|
||||
learning_outcomes.display_name,
|
||||
learning_outcomes.calculation_method,
|
||||
learning_outcomes.calculation_int,
|
||||
STRING_AGG(
|
||||
CASE WHEN learning_outcome_groups.learning_outcome_group_id IS NULL THEN NULL
|
||||
ELSE #{vendor_guid_field('learning_outcome_groups')}
|
||||
END,
|
||||
' ' ORDER BY learning_outcome_groups.id
|
||||
) AS parent_guids
|
||||
SQL
|
||||
end
|
||||
|
||||
def export_outcomes(csv)
|
||||
outcome_scope.find_each do |row|
|
||||
outcome = row.attributes.dup
|
||||
outcome['object_type'] = 'outcome'
|
||||
outcome_data = YAML.safe_load(outcome['data'])
|
||||
outcome['mastery_points'] = outcome_data.dig(:rubric_criterion, :mastery_points)
|
||||
|
||||
csv_row = OUTCOME_EXPORT_SCALAR_HEADERS.map { |h| outcome[h] }
|
||||
ratings = outcome_data.dig(:rubric_criterion, :ratings)
|
||||
if ratings.present?
|
||||
csv_row += ratings.flat_map { |r| r.values_at(:points, :description) }
|
||||
end
|
||||
csv << csv_row
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,305 @@
|
|||
#
|
||||
# Copyright (C) 2013 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/report_spec_helper')
|
||||
|
||||
describe "Outcome Reports" do
|
||||
include ReportSpecHelper
|
||||
|
||||
RATING_INDEX = AccountReports::OutcomeExport::OUTCOME_EXPORT_HEADERS.find_index('ratings')
|
||||
|
||||
describe 'outcome export' do
|
||||
def match_row(attrs)
|
||||
satisfy("match row #{attrs}") { |row| include(attrs).matches?(row.to_h) }
|
||||
end
|
||||
|
||||
def match_outcome(outcome)
|
||||
match_row('canvas_id' => outcome.id.to_s)
|
||||
end
|
||||
|
||||
def include_outcome(outcome)
|
||||
include(match_outcome(outcome))
|
||||
end
|
||||
|
||||
def row_index(outcome)
|
||||
report.find_index { |row| match_outcome(outcome).matches?(row) }
|
||||
end
|
||||
|
||||
def have_n_ratings(n)
|
||||
satisfy("have #{n} ratings") do |row|
|
||||
row.length - RATING_INDEX == 2 * n
|
||||
end
|
||||
end
|
||||
|
||||
let_once(:account) { account_model }
|
||||
let(:report_options) { {} }
|
||||
let(:report) do
|
||||
read_report(
|
||||
'outcome_export_csv',
|
||||
parse_header: true,
|
||||
account: account,
|
||||
order: [2,0],
|
||||
**report_options
|
||||
)
|
||||
end
|
||||
|
||||
it 'includes the correct headers' do
|
||||
report_options[:header] = true
|
||||
expect(report[0].headers).to eq AccountReports::OutcomeExport::OUTCOME_EXPORT_HEADERS
|
||||
end
|
||||
|
||||
context 'with outcome groups' do
|
||||
before(:once) do
|
||||
@root_group_1 = outcome_group_model(context: account, vendor_guid: 'monkey')
|
||||
@root_group_2 = outcome_group_model(context: account)
|
||||
@child_group_1_1 = outcome_group_model(context: account, outcome_group_id: @root_group_1.id)
|
||||
@child_group_2_1 = outcome_group_model(context: account, outcome_group_id: @root_group_2.id)
|
||||
end
|
||||
|
||||
it 'includes outcome groups' do
|
||||
expect(report.length).to eq 4
|
||||
expect(report).to all(match_row('object_type' => 'group'))
|
||||
expect(report[0]).to match_outcome(@root_group_1)
|
||||
expect(report[3]).to match_outcome(@child_group_2_1)
|
||||
end
|
||||
|
||||
it 'includes only outcome groups in current account' do
|
||||
other_account = account_model(parent_account: account)
|
||||
other_account_group = outcome_group_model(context: other_account)
|
||||
expect(report).not_to include_outcome(other_account_group)
|
||||
end
|
||||
|
||||
it 'includes relevant fields' do
|
||||
expect(report[0]['canvas_id']).to eq @root_group_1.id.to_s
|
||||
expect(report[0]['object_type']).to eq 'group'
|
||||
expect(report[0]['title']).to eq 'new outcome group'
|
||||
expect(report[0]['description']).to match(/outcome group description/)
|
||||
expect(report[0]['workflow_state']).to eq 'active'
|
||||
end
|
||||
|
||||
it 'does not include deleted outcome groups' do
|
||||
@child_group_2_1.destroy!
|
||||
expect(report.length).to eq 3
|
||||
expect(report).not_to include_outcome(@child_group_2_1)
|
||||
end
|
||||
|
||||
context 'with vendor guids' do
|
||||
before(:once) do
|
||||
@root_group_1.update! vendor_guid: 'lion', vendor_guid_2: 'tiger'
|
||||
@root_group_2.update! vendor_guid: 'bear'
|
||||
@child_group_1_1.update! vendor_guid_2: 'monkey'
|
||||
end
|
||||
|
||||
it 'defaults to vendor_guid field when AcademicBenchmark.use_new_guid_columns? not set' do
|
||||
allow(AcademicBenchmark).to receive(:use_new_guid_columns?).and_return false
|
||||
expect(report[0]['vendor_guid']).to eq 'lion'
|
||||
expect(report[1]['vendor_guid']).to eq 'bear'
|
||||
expect(report[2]['vendor_guid']).to eq 'monkey'
|
||||
end
|
||||
|
||||
it 'defaults to vendor_guid_2 field when AcademicBenchmark.use_new_guid_columns? set' do
|
||||
allow(AcademicBenchmark).to receive(:use_new_guid_columns?).and_return true
|
||||
expect(report[0]['vendor_guid']).to eq 'tiger'
|
||||
expect(report[1]['vendor_guid']).to eq 'bear'
|
||||
expect(report[2]['vendor_guid']).to eq 'monkey'
|
||||
end
|
||||
|
||||
it 'uses canvas id for vendor_guid if and only if vendor_guid is not present' do
|
||||
expect(report[3]['vendor_guid']).to eq "canvas_outcome_group:#{@child_group_2_1.id}"
|
||||
end
|
||||
end
|
||||
|
||||
it 'has empty parent_guids if parent is root outcome group' do
|
||||
expect(report[0]['parent_guids']).to eq nil
|
||||
expect(report[1]['parent_guids']).to eq nil
|
||||
end
|
||||
|
||||
it 'includes parent of outcome groups' do
|
||||
expect(report[2]['parent_guids']).to eq 'monkey'
|
||||
expect(report[3]['parent_guids']).to eq "canvas_outcome_group:#{@root_group_2.id}"
|
||||
end
|
||||
|
||||
it 'includes parent before children' do
|
||||
report_options[:order] = 'skip'
|
||||
expect(row_index(@root_group_1)).to be < row_index(@child_group_1_1)
|
||||
expect(row_index(@root_group_2)).to be < row_index(@child_group_2_1)
|
||||
end
|
||||
|
||||
it 'does not include root outcome group' do
|
||||
expect(report).not_to include_outcome(account.root_outcome_group)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with outcomes' do
|
||||
before(:once) do
|
||||
@root_outcome_1 = outcome_model(
|
||||
context: account,
|
||||
vendor_guid: 'giraffe',
|
||||
calculation_method: 'highest'
|
||||
)
|
||||
@root_outcome_2 = outcome_model(
|
||||
context: account,
|
||||
calculation_method: 'n_mastery',
|
||||
calculation_int: 5
|
||||
)
|
||||
@root_outcome_3 = outcome_model(
|
||||
context: account
|
||||
)
|
||||
@root_outcome_4 = outcome_model(
|
||||
context: account
|
||||
)
|
||||
end
|
||||
|
||||
it 'includes outcomes' do
|
||||
expect(report.length).to eq 4
|
||||
expect(report).to all(match_row('object_type' => 'outcome'))
|
||||
expect(report[0]).to match_outcome(@root_outcome_1)
|
||||
expect(report[1]).to match_outcome(@root_outcome_2)
|
||||
end
|
||||
|
||||
it 'includes only outcomes linked in current account' do
|
||||
other_account = account_model(parent_account: @account)
|
||||
other_outcome = outcome_model(context: other_account)
|
||||
expect(report).not_to include_outcome(other_outcome)
|
||||
end
|
||||
|
||||
it 'includes outcomes from another context linked in current account' do
|
||||
other_account = account_model
|
||||
other_outcome = outcome_model(context: other_account)
|
||||
account.root_outcome_group.add_outcome(other_outcome)
|
||||
expect(report.length).to eq 5
|
||||
expect(report).to include_outcome(other_outcome)
|
||||
end
|
||||
|
||||
it 'includes global outcomes' do
|
||||
@root_outcome_1.update! context: nil
|
||||
expect(report).to include_outcome(@root_outcome_1)
|
||||
end
|
||||
|
||||
it 'includes relevant fields' do
|
||||
expect(report[0]['canvas_id']).to eq @root_outcome_1.id.to_s
|
||||
expect(report[0]['object_type']).to eq 'outcome'
|
||||
expect(report[0]['title']).to eq @root_outcome_1.title
|
||||
expect(report[0]['description']).to eq @root_outcome_1.description
|
||||
expect(report[0]['display_name']).to eq @root_outcome_1.display_name
|
||||
expect(report[0]['calculation_method']).to eq 'highest'
|
||||
expect(report[0]['calculation_int']).to eq nil
|
||||
expect(report[0]['workflow_state']).to eq @root_outcome_1.workflow_state
|
||||
expect(report[0]['mastery_points']).to eq '3.0'
|
||||
|
||||
expect(report[1]['calculation_method']).to eq 'n_mastery'
|
||||
expect(report[1]['calculation_int']).to eq '5'
|
||||
end
|
||||
|
||||
it 'does not include deleted outcomes' do
|
||||
@root_outcome_2.destroy!
|
||||
expect(report.length).to eq 3
|
||||
expect(report).not_to include_outcome(@root_outcome_2)
|
||||
end
|
||||
|
||||
context 'with vendor guids' do
|
||||
before(:once) do
|
||||
@root_outcome_1.update! vendor_guid: 'lion', vendor_guid_2: 'tiger'
|
||||
@root_outcome_2.update! vendor_guid: 'bear'
|
||||
@root_outcome_3.update! vendor_guid: 'llama'
|
||||
end
|
||||
|
||||
it 'defaults to vendor_guid field when AcademicBenchmark.use_new_guid_columns? not set' do
|
||||
allow(AcademicBenchmark).to receive(:use_new_guid_columns?).and_return false
|
||||
expect(report[0]['vendor_guid']).to eq 'lion'
|
||||
expect(report[1]['vendor_guid']).to eq 'bear'
|
||||
expect(report[2]['vendor_guid']).to eq 'llama'
|
||||
end
|
||||
|
||||
it 'defaults to vendor_guid_2 field when AcademicBenchmark.use_new_guid_columns? set' do
|
||||
allow(AcademicBenchmark).to receive(:use_new_guid_columns?).and_return true
|
||||
expect(report[0]['vendor_guid']).to eq 'tiger'
|
||||
expect(report[1]['vendor_guid']).to eq 'bear'
|
||||
expect(report[2]['vendor_guid']).to eq 'llama'
|
||||
end
|
||||
|
||||
it 'uses canvas id for vendor_guid if vendor_guid is not present' do
|
||||
expect(report[3]['vendor_guid']).to eq "canvas_outcome:#{@root_outcome_4.id}"
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not contain parent guids for the root outcome group' do
|
||||
expect(report[0]['parent_guids']).to be_blank
|
||||
end
|
||||
|
||||
context 'and groups' do
|
||||
before do
|
||||
@root_group_1 = outcome_group_model(context: account)
|
||||
@group_1_1 = outcome_group_model(context: account, outcome_group_id: @root_group_1.id)
|
||||
@group_1_1_1 = outcome_group_model(context: account, outcome_group_id: @group_1_1.id)
|
||||
@nested_outcome = outcome_model(context: account, outcome_group: @group_1_1_1)
|
||||
end
|
||||
|
||||
it 'includes groups before outcomes' do
|
||||
report_options[:order] = 'skip'
|
||||
LearningOutcomeGroup.where.not(learning_outcome_group_id: nil).to_a.
|
||||
product(LearningOutcome.all).
|
||||
each do |group, outcome|
|
||||
expect(row_index(group)).to be < row_index(outcome)
|
||||
end
|
||||
end
|
||||
|
||||
it 'includes parents for outcome group links' do
|
||||
expect(report[row_index(@nested_outcome)]['parent_guids']).to eq "canvas_outcome_group:#{@group_1_1_1.id}"
|
||||
end
|
||||
|
||||
it 'includes multiple parents if group is linked to multiple outcome groups' do
|
||||
@root_group_1.add_outcome(@nested_outcome)
|
||||
expect(report[7]['parent_guids']).
|
||||
to eq "canvas_outcome_group:#{@root_group_1.id} canvas_outcome_group:#{@group_1_1_1.id}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with ratings' do
|
||||
it 'includes all ratings' do
|
||||
expect(report[0]).to have_n_ratings(2)
|
||||
expect(report[0][RATING_INDEX]).to eq '3.0'
|
||||
expect(report[0][RATING_INDEX + 1]).to eq 'Rockin'
|
||||
expect(report[0][RATING_INDEX + 2]).to eq '0.0'
|
||||
expect(report[0][RATING_INDEX + 3]).to eq 'Lame'
|
||||
end
|
||||
|
||||
it 'includes different number of fields depending on how many ratings are present' do
|
||||
@root_outcome_1.rubric_criterion = {
|
||||
ratings: [
|
||||
{ points: 0, description: 'I know' },
|
||||
{ points: 1, description: 'an old' },
|
||||
{ points: 2, description: 'woman' },
|
||||
{ points: 3, description: 'who' },
|
||||
{ points: 4, description: 'swallowed' },
|
||||
{ points: 10, description: 'a fly' }
|
||||
]
|
||||
}
|
||||
@root_outcome_1.save!
|
||||
expect(report[0]).to have_n_ratings(6)
|
||||
expect(report[0][RATING_INDEX]).to eq '10.0'
|
||||
expect(report[0][RATING_INDEX + 1]).to eq 'a fly'
|
||||
expect(report[0][RATING_INDEX + 10]).to eq '0.0'
|
||||
expect(report[0][RATING_INDEX + 11]).to eq 'I know'
|
||||
expect(report[0][RATING_INDEX + 12]).to be_nil
|
||||
expect(report[0][RATING_INDEX + 13]).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,14 +18,14 @@
|
|||
|
||||
module Factories
|
||||
def outcome_model(opts={})
|
||||
@context ||= opts.delete(:context) || course_model(:reusable => true)
|
||||
outcome_context = opts.delete(:outcome_context) || @context
|
||||
@outcome_group ||= @context.root_outcome_group
|
||||
context = opts.delete(:context) || @context || course_model(:reusable => true)
|
||||
outcome_context = opts.delete(:outcome_context) || context
|
||||
outcome_group = opts.delete(:outcome_group) || context.root_outcome_group
|
||||
@outcome = outcome_context.created_learning_outcomes.build(valid_outcome_attributes.merge(opts))
|
||||
@outcome.rubric_criterion = valid_outcome_data
|
||||
@outcome.save!
|
||||
@outcome_group.add_outcome(@outcome)
|
||||
@outcome_group.save!
|
||||
outcome_group.add_outcome(@outcome)
|
||||
outcome_group.save!
|
||||
@outcome
|
||||
end
|
||||
|
||||
|
@ -50,7 +50,7 @@ module Factories
|
|||
context = opts[:context] || @context
|
||||
@parent_outcome_group =
|
||||
if opts[:outcome_group_id]
|
||||
LearningOutcomeGroup.for_context(context).active.find(opts[:outcome_group_id])
|
||||
LearningOutcomeGroup.for_context(context).active.find(opts.delete(:outcome_group_id))
|
||||
else
|
||||
context.root_outcome_group
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue