# frozen_string_literal: true require "spec_helper" require "rack/test" require "split/dashboard" describe Split::Dashboard do include Rack::Test::Methods class TestDashboard < Split::Dashboard include Split::Helper get "/my_experiment" do ab_test(params[:experiment], "blue", "red") end end def app @app ||= TestDashboard end def link(color) Split::Alternative.new(color, experiment.name) end let(:experiment) { Split::ExperimentCatalog.find_or_create("link_color", "blue", "red") } let(:experiment_with_goals) { Split::ExperimentCatalog.find_or_create({ "link_color" => ["goal_1", "goal_2"] }, "blue", "red") } let(:metric) { Split::Metric.find_or_create(name: "testmetric", experiments: [experiment, experiment_with_goals]) } let(:red_link) { link("red") } let(:blue_link) { link("blue") } before(:each) do Split.configuration.beta_probability_simulations = 1 end it "should respond to /" do get "/" expect(last_response).to be_ok end context "start experiment manually" do before do Split.configuration.start_manually = true end context "experiment without goals" do it "should display a Start button" do experiment get "/" expect(last_response.body).to include("Start") post "/start?experiment=#{experiment.name}" get "/" expect(last_response.body).to include("Reset Data") expect(last_response.body).not_to include("Metrics:") end end context "experiment with metrics" do it "should display the names of associated metrics" do metric get "/" expect(last_response.body).to include("Metrics:testmetric") end end context "with goals" do it "should display a Start button" do experiment_with_goals get "/" expect(last_response.body).to include("Start") post "/start?experiment=#{experiment.name}" get "/" expect(last_response.body).to include("Reset Data") end end end describe "force alternative" do context "initial version" do let!(:user) do Split::User.new(@app, { experiment.name => "red" }) end before do allow(Split::User).to receive(:new).and_return(user) end it "should set current user's alternative" do blue_link.participant_count = 7 post "/force_alternative?experiment=#{experiment.name}", alternative: "blue" get "/my_experiment?experiment=#{experiment.name}" expect(last_response.body).to include("blue") end it "should not modify an existing user" do blue_link.participant_count = 7 post "/force_alternative?experiment=#{experiment.name}", alternative: "blue" expect(user[experiment.key]).to eq("red") expect(blue_link.participant_count).to eq(7) end end context "incremented version" do let!(:user) do experiment.increment_version Split::User.new(@app, { "#{experiment.name}:#{experiment.version}" => "red" }) end before do allow(Split::User).to receive(:new).and_return(user) end it "should set current user's alternative" do blue_link.participant_count = 7 post "/force_alternative?experiment=#{experiment.name}", alternative: "blue" get "/my_experiment?experiment=#{experiment.name}" expect(last_response.body).to include("blue") end end end describe "index page" do context "with winner" do before { experiment.winner = "red" } it "displays `Reopen Experiment` button" do get "/" expect(last_response.body).to include("Reopen Experiment") end end context "without winner" do it "should not display `Reopen Experiment` button" do get "/" expect(last_response.body).to_not include("Reopen Experiment") end end end describe "reopen experiment" do before { experiment.winner = "red" } it "redirects" do post "/reopen?experiment=#{experiment.name}" expect(last_response).to be_redirect end it "removes winner" do post "/reopen?experiment=#{experiment.name}" expect(Split::ExperimentCatalog.find(experiment.name)).to_not have_winner end it "keeps existing stats" do red_link.participant_count = 5 blue_link.participant_count = 7 experiment.winner = "blue" post "/reopen?experiment=#{experiment.name}" expect(red_link.participant_count).to eq(5) expect(blue_link.participant_count).to eq(7) end end describe "update cohorting" do it "calls enable of cohorting when action is enable" do post "/update_cohorting?experiment=#{experiment.name}", { "cohorting_action": "enable" } expect(experiment.cohorting_disabled?).to eq false end it "calls disable of cohorting when action is disable" do post "/update_cohorting?experiment=#{experiment.name}", { "cohorting_action": "disable" } expect(experiment.cohorting_disabled?).to eq true end it "calls neither enable or disable cohorting when passed invalid action" do previous_value = experiment.cohorting_disabled? post "/update_cohorting?experiment=#{experiment.name}", { "cohorting_action": "other" } expect(experiment.cohorting_disabled?).to eq previous_value end end describe "initialize experiment" do before do Split.configuration.experiments = { my_experiment: { alternatives: [ "control", "alternative" ], } } end it "initializes the experiment when the experiment is given" do expect(Split::ExperimentCatalog.find("my_experiment")).to be nil post "/initialize_experiment", { experiment: "my_experiment" } experiment = Split::ExperimentCatalog.find("my_experiment") expect(experiment).to be_a(Split::Experiment) end it "does not attempt to intialize the experiment when empty experiment is given" do post "/initialize_experiment", { experiment: "" } expect(Split::ExperimentCatalog).to_not receive(:find_or_create) end it "does not attempt to intialize the experiment when no experiment is given" do post "/initialize_experiment" expect(Split::ExperimentCatalog).to_not receive(:find_or_create) end end it "should reset an experiment" do red_link.participant_count = 5 blue_link.participant_count = 7 experiment.winner = "blue" post "/reset?experiment=#{experiment.name}" expect(last_response).to be_redirect new_red_count = red_link.participant_count new_blue_count = blue_link.participant_count expect(new_blue_count).to eq(0) expect(new_red_count).to eq(0) expect(experiment.winner).to be_nil end it "should delete an experiment" do delete "/experiment?experiment=#{experiment.name}" expect(last_response).to be_redirect expect(Split::ExperimentCatalog.find(experiment.name)).to be_nil end it "should mark an alternative as the winner" do expect(experiment.winner).to be_nil post "/experiment?experiment=#{experiment.name}", alternative: "red" expect(last_response).to be_redirect expect(experiment.winner.name).to eq("red") end it "should display the start date" do experiment.start get "/" expect(last_response.body).to include("#{experiment.start_time.strftime('%Y-%m-%d')}") end it "should handle experiments without a start date" do Split.redis.hdel(:experiment_start_times, experiment.name) get "/" expect(last_response.body).to include("Unknown") end end