mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-11 07:34:41 +08:00
Merge branch 'ur-SCI-2924' (Refactor generate_workflow_image into service)
This commit is contained in:
commit
30d0fcdf00
18 changed files with 215 additions and 211 deletions
5
.overcommit.yml
Normal file
5
.overcommit.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
PreCommit:
|
||||
RuboCop:
|
||||
enabled: true
|
||||
on_warn: fail
|
||||
problem_on_unmodified_line: ignore
|
1
Gemfile
1
Gemfile
|
@ -109,6 +109,7 @@ group :development, :test do
|
|||
gem 'byebug'
|
||||
gem 'factory_bot_rails'
|
||||
gem 'listen', '~> 3.0'
|
||||
gem 'overcommit'
|
||||
gem 'pry'
|
||||
gem 'pry-byebug'
|
||||
gem 'pry-rails'
|
||||
|
|
|
@ -156,6 +156,8 @@ GEM
|
|||
mail
|
||||
case_transform (0.2)
|
||||
activesupport
|
||||
childprocess (0.9.0)
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
climate_control (0.2.0)
|
||||
cliver (0.3.2)
|
||||
coderay (1.1.2)
|
||||
|
@ -241,6 +243,7 @@ GEM
|
|||
concurrent-ruby (~> 1.0)
|
||||
i18n-js (3.0.3)
|
||||
i18n (~> 0.6, >= 0.6.6)
|
||||
iniparse (1.4.4)
|
||||
jaro_winkler (1.5.1)
|
||||
jbuilder (2.7.0)
|
||||
activesupport (>= 4.2.0)
|
||||
|
@ -330,6 +333,9 @@ GEM
|
|||
oauth2 (~> 1.1)
|
||||
omniauth (~> 1.2)
|
||||
orm_adapter (0.5.0)
|
||||
overcommit (0.46.0)
|
||||
childprocess (~> 0.6, >= 0.6.3)
|
||||
iniparse (~> 1.4)
|
||||
paperclip (5.3.0)
|
||||
activemodel (>= 4.2.0)
|
||||
activesupport (>= 4.2.0)
|
||||
|
@ -590,6 +596,7 @@ DEPENDENCIES
|
|||
nokogiri (~> 1.8.1)
|
||||
omniauth
|
||||
omniauth-linkedin-oauth2
|
||||
overcommit
|
||||
paperclip (~> 5.3)
|
||||
pg (~> 0.18)
|
||||
phantomjs
|
||||
|
@ -637,4 +644,4 @@ RUBY VERSION
|
|||
ruby 2.4.4p296
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.6
|
||||
1.17.1
|
||||
|
|
|
@ -98,12 +98,6 @@ class Experiment < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def modules_without_group
|
||||
MyModule.where(experiment_id: id)
|
||||
.where(my_module_group: nil)
|
||||
.where(archived: false)
|
||||
end
|
||||
|
||||
def active_module_groups
|
||||
my_module_groups.joins(:my_modules)
|
||||
.where('my_modules.archived = ?', false)
|
||||
|
@ -227,125 +221,8 @@ class Experiment < ApplicationRecord
|
|||
true
|
||||
end
|
||||
|
||||
# This method generate the workflow image and saves it as
|
||||
# experiment attachment
|
||||
def generate_workflow_img
|
||||
require 'graphviz'
|
||||
|
||||
graph = GraphViz.new(:G,
|
||||
type: :digraph,
|
||||
use: :neato)
|
||||
|
||||
graph[:size] = '4,4'
|
||||
graph.node[color: Constants::COLOR_ALTO,
|
||||
style: :filled,
|
||||
fontcolor: Constants::COLOR_EMPEROR,
|
||||
shape: 'circle',
|
||||
fontname: 'Arial',
|
||||
fontsize: '16.0']
|
||||
|
||||
graph.edge[color: Constants::COLOR_ALTO]
|
||||
|
||||
label = ''
|
||||
subg = {}
|
||||
|
||||
# Draw orphan modules
|
||||
if modules_without_group
|
||||
modules_without_group.each do |my_module|
|
||||
graph
|
||||
.subgraph(rank: 'same')
|
||||
.add_nodes("Orphan-#{my_module.id}",
|
||||
label: label,
|
||||
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
|
||||
end
|
||||
end
|
||||
|
||||
# Draw grouped modules
|
||||
if my_module_groups.many?
|
||||
my_module_groups.each_with_index do |group, gindex|
|
||||
subgraph_name = "cluster-#{gindex}"
|
||||
subg[subgraph_name] = graph.subgraph(rank: 'same')
|
||||
group.ordered_modules.each_with_index do |my_module, index|
|
||||
if my_module.outputs.any?
|
||||
parent = subg[subgraph_name]
|
||||
.add_nodes("#{subgraph_name}-#{index}",
|
||||
label: label,
|
||||
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
|
||||
|
||||
my_module.outputs.each_with_index do |output, i|
|
||||
child_mod = MyModule.find_by_id(output.input_id)
|
||||
child_node = subg[subgraph_name]
|
||||
.add_nodes("#{subgraph_name}-O#{child_mod.id}-#{i}",
|
||||
label: label,
|
||||
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
|
||||
|
||||
subg[subgraph_name].add_edges(parent, child_node)
|
||||
end
|
||||
elsif my_module.inputs.any?
|
||||
parent = subg[subgraph_name]
|
||||
.add_nodes("#{subgraph_name}-#{index}",
|
||||
label: label,
|
||||
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
|
||||
|
||||
my_module.inputs.each_with_index do |input, i|
|
||||
child_mod = MyModule.find_by_id(input.output_id)
|
||||
child_node = subg[subgraph_name]
|
||||
.add_nodes("#{subgraph_name}-I#{child_mod.id}-#{i}",
|
||||
label: label,
|
||||
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
|
||||
|
||||
subg[subgraph_name].add_edges(child_node, parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
my_module_groups.each do |group|
|
||||
group.ordered_modules.each_with_index do |my_module, index|
|
||||
if my_module.outputs.any?
|
||||
parent = graph.add_nodes("N-#{index}",
|
||||
label: label,
|
||||
pos: "#{my_module.x / 10},-#{ my_module.y / 10}!")
|
||||
|
||||
my_module.outputs.each_with_index do |output, i|
|
||||
child_mod = MyModule.find_by_id(output.input_id)
|
||||
child_node = graph
|
||||
.add_nodes("N-O#{child_mod.id}-#{i}",
|
||||
label: label,
|
||||
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
|
||||
graph.add_edges(parent, child_node)
|
||||
end
|
||||
elsif my_module.inputs.any?
|
||||
parent = graph.add_nodes("N-#{index}",
|
||||
label: label,
|
||||
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
|
||||
my_module.inputs.each_with_index do |input, i|
|
||||
child_mod = MyModule.find_by_id(input.output_id)
|
||||
child_node = graph
|
||||
.add_nodes("N-I#{child_mod.id}-#{i}",
|
||||
label: label,
|
||||
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
|
||||
graph.add_edges(child_node, parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
file_location = Tempfile.open(['wimg', '.png'],
|
||||
Rails.root.join('tmp'))
|
||||
|
||||
graph.output(png: file_location.path)
|
||||
|
||||
begin
|
||||
file = File.open(file_location)
|
||||
self.workflowimg = file
|
||||
file.close
|
||||
save
|
||||
touch(:workflowimg_updated_at)
|
||||
rescue => ex
|
||||
logger.error ex.message
|
||||
end
|
||||
Experiments::GenerateWorkflowImageService.call(experiment_id: id)
|
||||
end
|
||||
|
||||
# Clone this experiment to given project
|
||||
|
@ -371,7 +248,7 @@ class Experiment < ApplicationRecord
|
|||
end
|
||||
|
||||
# Copy modules without group
|
||||
clone.my_modules << modules_without_group.map do |m|
|
||||
clone.my_modules << my_modules.without_group.map do |m|
|
||||
m.deep_clone_to_experiment(current_user, clone)
|
||||
end
|
||||
clone.save
|
||||
|
|
|
@ -68,11 +68,13 @@ class MyModule < ApplicationRecord
|
|||
scope :is_archived, ->(is_archived) { where('archived = ?', is_archived) }
|
||||
scope :active, -> { where(archived: false) }
|
||||
scope :overdue, -> { where('my_modules.due_date < ?', Time.current.utc) }
|
||||
scope :without_group, -> { active.where(my_module_group: nil) }
|
||||
scope :one_day_prior, (lambda do
|
||||
where('my_modules.due_date > ? AND my_modules.due_date < ?',
|
||||
Time.current.utc,
|
||||
Time.current.utc + 1.day)
|
||||
end)
|
||||
scope :workflow_ordered, -> { order(workflow_order: :asc) }
|
||||
|
||||
# A module takes this much space in canvas (x, y) in database
|
||||
WIDTH = 30
|
||||
|
|
|
@ -10,10 +10,6 @@ class MyModuleGroup < ApplicationRecord
|
|||
optional: true
|
||||
has_many :my_modules, inverse_of: :my_module_group, dependent: :nullify
|
||||
|
||||
def ordered_modules
|
||||
my_modules.order(workflow_order: :asc)
|
||||
end
|
||||
|
||||
def deep_clone_to_experiment(current_user, experiment)
|
||||
clone = MyModuleGroup.new(
|
||||
created_by: created_by,
|
||||
|
@ -21,12 +17,12 @@ class MyModuleGroup < ApplicationRecord
|
|||
)
|
||||
|
||||
# Get clones of modules from this group, save them as hash
|
||||
cloned_modules = ordered_modules.each_with_object({}) do |m, hash|
|
||||
hash[m.id] = m.deep_clone_to_experiment(current_user, experiment)
|
||||
hash
|
||||
cloned_modules = my_modules.workflow_ordered.each_with_object({}) do |m, h|
|
||||
h[m.id] = m.deep_clone_to_experiment(current_user, experiment)
|
||||
h
|
||||
end
|
||||
|
||||
ordered_modules.each do |m|
|
||||
my_modules.workflow_ordered.each do |m|
|
||||
# Copy connections
|
||||
m.inputs.each do |inp|
|
||||
Connection.create(
|
||||
|
|
87
app/services/experiments/generate_workflow_image_service.rb
Normal file
87
app/services/experiments/generate_workflow_image_service.rb
Normal file
|
@ -0,0 +1,87 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Experiments
|
||||
class GenerateWorkflowImageService
|
||||
extend Service
|
||||
require 'graphviz'
|
||||
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(experiment_id:)
|
||||
@exp = Experiment.find experiment_id
|
||||
@graph = GraphViz.new(:G, type: :digraph, use: :neato)
|
||||
|
||||
@graph[:size] = '4,4'
|
||||
@graph.node[color: Constants::COLOR_ALTO,
|
||||
style: :filled,
|
||||
fontcolor: Constants::COLOR_EMPEROR,
|
||||
shape: 'circle',
|
||||
fontname: 'Arial',
|
||||
fontsize: '16.0']
|
||||
|
||||
@graph.edge[color: Constants::COLOR_ALTO]
|
||||
@errors = []
|
||||
end
|
||||
|
||||
def call
|
||||
draw_diagram
|
||||
save_file
|
||||
self
|
||||
end
|
||||
|
||||
def succeed?
|
||||
@errors.none?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def draw_diagram
|
||||
# Draw orphan nodes
|
||||
@exp.my_modules.without_group.each do |my_module|
|
||||
@graph.subgraph(rank: 'same').add_nodes(
|
||||
"Orphan-#{my_module.id}",
|
||||
label: '',
|
||||
pos: "#{my_module.x / 10},-#{my_module.y / 10}!"
|
||||
)
|
||||
end
|
||||
|
||||
# Draw grouped modules
|
||||
subg = {}
|
||||
@exp.my_module_groups.each_with_index do |group, gindex|
|
||||
subgraph_id = "cluster-#{gindex}"
|
||||
subg[subgraph_id] = @graph.subgraph(rank: 'same')
|
||||
nodes = {}
|
||||
|
||||
group.my_modules.workflow_ordered.each_with_index do |my_module, index|
|
||||
# draw nodes
|
||||
node = subg[subgraph_id].add_nodes(
|
||||
"#{subgraph_id}-#{index}",
|
||||
label: '',
|
||||
pos: "#{my_module.x / 10},-#{my_module.y / 10}!"
|
||||
)
|
||||
nodes[my_module.id] = node
|
||||
end
|
||||
|
||||
# draw edges
|
||||
group.my_modules.workflow_ordered.each do |m|
|
||||
m.outputs.each do |output|
|
||||
parent_node = nodes[m.id]
|
||||
child_node = nodes[output.input_id]
|
||||
subg[subgraph_id].add_edges(parent_node, child_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def save_file
|
||||
file = Tempfile.open(%w(wimg .png), Rails.root.join('tmp'))
|
||||
@graph.output(png: file.path)
|
||||
@exp.workflowimg = file
|
||||
file.close
|
||||
@exp.save
|
||||
@exp.touch(:workflowimg_updated_at)
|
||||
rescue StandardError => ex
|
||||
logger.error ex.message
|
||||
end
|
||||
end
|
||||
end
|
7
app/services/service.rb
Normal file
7
app/services/service.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Service
|
||||
def call(*args)
|
||||
new(*args).call
|
||||
end
|
||||
end
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<% experiment.my_module_groups.each do |my_module_group| %>
|
||||
<% if my_module_group.my_modules.exists? then %>
|
||||
<% my_module_group.ordered_modules.each do |my_module| %>
|
||||
<% my_module_group.my_modules.workflow_ordered.each do |my_module| %>
|
||||
<li>
|
||||
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
|
||||
</li>
|
||||
|
@ -22,13 +22,10 @@
|
|||
<% end %>
|
||||
|
||||
<!-- Tasks without groups -->
|
||||
<% modules_without_group = experiment.modules_without_group %>
|
||||
<% if modules_without_group.exists? %>
|
||||
<% modules_without_group.each do |my_module| %>
|
||||
<li>
|
||||
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% experiment.my_modules.without_group.each do |my_module| %>
|
||||
<li>
|
||||
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
</ul>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<% experiment.my_module_groups.each do |my_module_group| %>
|
||||
<% next unless my_module_group.my_modules.is_archived(false).exists? %>
|
||||
<% my_module_group.ordered_modules.is_archived(false).each do |my_module| %>
|
||||
<% my_module_group.my_modules.workflow_ordered.is_archived(false).each do |my_module| %>
|
||||
<li>
|
||||
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
|
||||
</li>
|
||||
|
@ -27,13 +27,10 @@
|
|||
<% end %>
|
||||
|
||||
<!-- Tasks without groups -->
|
||||
<% modules_without_group = experiment.modules_without_group %>
|
||||
<% if modules_without_group.exists? %>
|
||||
<% modules_without_group.each do |my_module| %>
|
||||
<li>
|
||||
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% experiment.my_modules.without_group.each do |my_module| %>
|
||||
<li>
|
||||
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
</ul>
|
||||
|
|
|
@ -1,26 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :experiment do
|
||||
name { Faker::Name.unique.name }
|
||||
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
|
||||
end
|
||||
|
||||
factory :experiment_one, class: Experiment do
|
||||
name 'My Experiment One'
|
||||
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
|
||||
association :project, factory: :project
|
||||
association :created_by, factory: :user, email: Faker::Internet.email
|
||||
association :last_modified_by,
|
||||
factory: :user,
|
||||
email: Faker::Internet.email
|
||||
end
|
||||
|
||||
factory :experiment_two, class: Experiment do
|
||||
name Faker::Name.name
|
||||
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
|
||||
association :project, factory: :project
|
||||
association :created_by, factory: :user, email: Faker::Internet.email
|
||||
association :last_modified_by,
|
||||
factory: :user,
|
||||
email: Faker::Internet.email
|
||||
factory :experiment, class: Experiment do
|
||||
transient do
|
||||
user { create :user }
|
||||
end
|
||||
sequence(:name) { |n| "Experiment-#{n}" }
|
||||
description { Faker::Lorem.sentence }
|
||||
created_by { user }
|
||||
last_modified_by { user }
|
||||
project { create :project, created_by: user }
|
||||
factory :experiment_with_tasks do
|
||||
after(:create) do |e|
|
||||
create_list :my_module, 3, experiment: e
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :my_module_group do
|
||||
experiment { Experiment.first || create(:experiment_two) }
|
||||
experiment
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :my_module do
|
||||
name 'My first module'
|
||||
x 0
|
||||
y 0
|
||||
workflow_order 0
|
||||
experiment { Experiment.first || create(:experiment_one) }
|
||||
my_module_group { MyModuleGroup.first || create(:my_module_group) }
|
||||
sequence(:name) { |n| "Task-#{n}" }
|
||||
x { Faker::Number.between(1, 100) }
|
||||
y { Faker::Number.between(1, 100) }
|
||||
workflow_order { MyModule.where(experiment_id: experiment.id).count + 1 }
|
||||
experiment
|
||||
my_module_group { create :my_module_group, experiment: experiment }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :project do
|
||||
created_by { User.first || association(:project_user) }
|
||||
team { Team.first || association(:project_team) }
|
||||
archived false
|
||||
name 'My project'
|
||||
visibility 'hidden'
|
||||
sequence(:name) { |n| "My project-#{n}" }
|
||||
association :created_by, factory: :user
|
||||
team { create :team, created_by: created_by }
|
||||
archived { false }
|
||||
visibility { 'hidden' }
|
||||
end
|
||||
|
||||
factory :project_user, class: User do
|
||||
|
@ -14,11 +16,4 @@ FactoryBot.define do
|
|||
password 'asdf1243'
|
||||
password_confirmation 'asdf1243'
|
||||
end
|
||||
|
||||
factory :project_team, class: Team do
|
||||
created_by { User.first || association(:project_user) }
|
||||
name 'My team'
|
||||
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing eli.'
|
||||
space_taken 1048576
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :team do
|
||||
created_by { User.first || create(:user) }
|
||||
name 'My team'
|
||||
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing eli.'
|
||||
space_taken 1048576
|
||||
association :created_by, factory: :user
|
||||
sequence(:name) { |n| "My team-#{n}" }
|
||||
description { Faker::Lorem.sentence }
|
||||
space_taken { 1048576 }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :user do
|
||||
full_name 'admin'
|
||||
initials 'AD'
|
||||
email Faker::Internet.unique.email
|
||||
sequence(:email) { |n| "user-#{n}@example.com" }
|
||||
password 'asdf1243'
|
||||
password_confirmation 'asdf1243'
|
||||
current_sign_in_at DateTime.now
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Project, type: :model do
|
||||
|
@ -39,22 +41,30 @@ describe Project, type: :model do
|
|||
it { should have_many :report_elements }
|
||||
end
|
||||
|
||||
describe 'Should be a valid object' do
|
||||
let(:user) { create :user }
|
||||
let(:team) { create :team, created_by: user }
|
||||
it { should validate_presence_of :visibility }
|
||||
it { should validate_presence_of :team }
|
||||
it do
|
||||
should validate_length_of(:name).is_at_least(Constants::NAME_MIN_LENGTH)
|
||||
.is_at_most(Constants::NAME_MAX_LENGTH)
|
||||
describe 'Validations' do
|
||||
describe '#visibility' do
|
||||
it { should validate_presence_of :visibility }
|
||||
end
|
||||
|
||||
it 'should have a unique name scoped to team' do
|
||||
create :project, created_by: user, last_modified_by: user, team: team
|
||||
project_two = build :project, created_by: user,
|
||||
last_modified_by: user,
|
||||
team: team
|
||||
expect(project_two).to_not be_valid
|
||||
describe '#team' do
|
||||
it { should validate_presence_of :team }
|
||||
end
|
||||
|
||||
describe '#name' do
|
||||
it 'should be at least 2 long and max 255 long' do
|
||||
should validate_length_of(:name)
|
||||
.is_at_least(Constants::NAME_MIN_LENGTH)
|
||||
.is_at_most(Constants::NAME_MAX_LENGTH)
|
||||
end
|
||||
|
||||
it 'should be uniq per project and team' do
|
||||
first_project = create :project
|
||||
second_project = build :project,
|
||||
name: first_project.name,
|
||||
team: first_project.team
|
||||
|
||||
expect(second_project).to_not be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Experiments::GenerateWorkflowImageService do
|
||||
let(:experiment) { create :experiment_with_tasks }
|
||||
let(:params) { { experiment_id: experiment.id } }
|
||||
|
||||
context 'when succeed' do
|
||||
it 'succeed? returns true' do
|
||||
expect(described_class.call(params).succeed?).to be_truthy
|
||||
end
|
||||
|
||||
it 'worklfow image of experiment is updated' do
|
||||
old_filename = experiment.workflowimg_file_name
|
||||
described_class.call(params)
|
||||
experiment.reload
|
||||
|
||||
expect(experiment.workflowimg_file_name).not_to be == old_filename
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue