Skip to content

Commit 9bd915d

Browse files
committed
DEV: Add specs
1 parent 556fe2f commit 9bd915d

File tree

5 files changed

+220
-5
lines changed

5 files changed

+220
-5
lines changed

admin/assets/javascripts/discourse/templates/admin-plugins/show/discourse-ai-features/index.gjs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ export default RouteTemplate(
6161

6262
<tbody>
6363
{{#each this.configuredFeatures as |feature|}}
64-
<tr class="ai-feature-list__row d-admin-row__content">
64+
<tr
65+
class="ai-feature-list__row d-admin-row__content"
66+
data-feature-name={{feature.name}}
67+
>
6568
<td class="d-admin-row__overview ai-feature-list__row-item">
6669
<span class="ai-feature-list__row-item-name">
6770
<strong>
@@ -72,15 +75,19 @@ export default RouteTemplate(
7275
{{feature.description}}
7376
</span>
7477
</td>
75-
<td class="d-admin-row__detail ai-feature-list__row-item">
78+
<td
79+
class="d-admin-row__detail ai-feature-list__row-item ai-feature-list__persona"
80+
>
7681
<DButton
7782
class="btn-flat btn-small ai-feature-list__row-item-persona"
7883
@translatedLabel={{feature.persona.name}}
7984
@route="adminPlugins.show.discourse-ai-personas.edit"
8085
@routeModels={{feature.persona.id}}
8186
/>
8287
</td>
83-
<td class="d-admin-row__detail ai-feature-list__row-item">
88+
<td
89+
class="d-admin-row__detail ai-feature-list__row-item ai-feature-list__groups"
90+
>
8491
{{#if (gt feature.persona.allowed_groups.length 0)}}
8592
<ul class="ai-feature-list__row-item-groups">
8693
{{#each feature.persona.allowed_groups as |group|}}
@@ -91,7 +98,7 @@ export default RouteTemplate(
9198
</td>
9299
<td class="d-admin-row_controls">
93100
<DButton
94-
class="btn-small"
101+
class="btn-small edit"
95102
@label="discourse_ai.features.list.edit"
96103
@route="adminPlugins.show.discourse-ai-features.edit"
97104
@routeModels={{feature.id}}
@@ -105,7 +112,7 @@ export default RouteTemplate(
105112
{{/if}}
106113

107114
{{#if (gt this.unconfiguredFeatures.length 0)}}
108-
<div class="ai-feature-list-editor__unconfigured-features">
115+
<div class="ai-feature-list__unconfigured-features">
109116
<h3>{{i18n "discourse_ai.features.list.unconfigured_features"}}</h3>
110117

111118
<table class="d-admin-table">
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe DiscourseAi::Admin::AiFeaturesController do
4+
let(:controller) { described_class.new }
5+
fab!(:admin)
6+
fab!(:group)
7+
fab!(:llm_model)
8+
fab!(:summarizer_persona) { Fabricate(:ai_persona) }
9+
fab!(:alternate_summarizer_persona) { Fabricate(:ai_persona) }
10+
11+
before do
12+
sign_in(admin)
13+
SiteSetting.ai_bot_enabled = true
14+
SiteSetting.discourse_ai_enabled = true
15+
end
16+
17+
describe "#index" do
18+
it "lists all features backed by personas" do
19+
get "/admin/plugins/discourse-ai/ai-features.json"
20+
21+
expect(response.status).to eq(200)
22+
expect(response.parsed_body["ai_features"].count).to eq(4)
23+
end
24+
end
25+
26+
describe "#edit" do
27+
it "returns a success response" do
28+
get "/admin/plugins/discourse-ai/ai-features/1/edit.json"
29+
expect(response.parsed_body["name"]).to eq(I18n.t "discourse_ai.features.summarization.name")
30+
end
31+
end
32+
33+
describe "#update" do
34+
before do
35+
SiteSetting.ai_summarization_persona = summarizer_persona.id
36+
SiteSetting.ai_summarization_enabled = true
37+
end
38+
39+
it "updates the feature" do
40+
expect(SiteSetting.ai_summarization_persona).to eq(summarizer_persona.id.to_s)
41+
expect(SiteSetting.ai_summarization_enabled).to eq(true)
42+
43+
put "/admin/plugins/discourse-ai/ai-features/1.json",
44+
params: {
45+
ai_feature: {
46+
enabled: false,
47+
persona_id: alternate_summarizer_persona.id,
48+
},
49+
}
50+
51+
expect(SiteSetting.ai_summarization_persona).to eq(alternate_summarizer_persona.id.to_s)
52+
expect(SiteSetting.ai_summarization_enabled).to eq(false)
53+
end
54+
end
55+
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe AiFeaturesPersonaSerializer do
4+
fab!(:admin)
5+
fab!(:ai_persona)
6+
fab!(:group)
7+
fab!(:group_2) { Fabricate(:group) }
8+
9+
describe "serialized attributes" do
10+
before do
11+
ai_persona.allowed_group_ids = [group.id, group_2.id]
12+
ai_persona.save!
13+
end
14+
15+
context "when there is a persona with allowed groups" do
16+
let(:allowed_groups) do
17+
Group
18+
.where(id: ai_persona.allowed_group_ids)
19+
.pluck(:id, :name)
20+
.map { |id, name| { id: id, name: name } }
21+
end
22+
23+
it "display every participant" do
24+
serialized = described_class.new(ai_persona, scope: Guardian.new(admin), root: nil)
25+
expect(serialized.id).to eq(ai_persona.id)
26+
expect(serialized.name).to eq(ai_persona.name)
27+
expect(serialized.system_prompt).to eq(ai_persona.system_prompt)
28+
expect(serialized.allowed_groups).to eq(allowed_groups)
29+
expect(serialized.enabled).to eq(ai_persona.enabled)
30+
end
31+
end
32+
end
33+
end

spec/system/admin_ai_features_spec.rb

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe "Admin AI features configuration", type: :system, js: true do
4+
fab!(:admin)
5+
fab!(:llm_model)
6+
fab!(:summarization_persona) { Fabricate(:ai_persona) }
7+
fab!(:group_1) { Fabricate(:group) }
8+
fab!(:group_2) { Fabricate(:group) }
9+
let(:page_header) { PageObjects::Components::DPageHeader.new }
10+
let(:form) { PageObjects::Components::FormKit.new("form") }
11+
let(:ai_features_page) { PageObjects::Pages::AdminAiFeatures.new }
12+
13+
before do
14+
summarization_persona.allowed_group_ids = [group_1.id, group_2.id]
15+
summarization_persona.save!
16+
assign_fake_provider_to(:ai_summarization_model)
17+
SiteSetting.ai_summarization_enabled = true
18+
SiteSetting.ai_summarization_persona = summarization_persona.id
19+
sign_in(admin)
20+
end
21+
22+
it "lists all persona backed AI features separated by configured/unconfigured" do
23+
ai_features_page.visit
24+
expect(
25+
ai_features_page
26+
.configured_features_table
27+
.find(".ai-feature-list__row-item .ai-feature-list__row-item-name")
28+
.text,
29+
).to eq(I18n.t("discourse_ai.features.summarization.name"))
30+
31+
expect(ai_features_page).to have_configured_feature_items(1)
32+
expect(ai_features_page).to have_unconfigured_feature_items(3)
33+
end
34+
35+
it "lists the persona used for the corresponding AI feature" do
36+
ai_features_page.visit
37+
expect(ai_features_page).to have_feature_persona(summarization_persona.name)
38+
end
39+
40+
it "lists the groups allowed to use the AI feature" do
41+
ai_features_page.visit
42+
expect(ai_features_page).to have_feature_groups([group_1.name, group_2.name])
43+
end
44+
45+
it "can navigate the AI plugin with breadcrumbs" do
46+
visit "/admin/plugins/discourse-ai/ai-features"
47+
expect(page).to have_css(".d-breadcrumbs")
48+
expect(page).to have_css(".d-breadcrumbs__item", count: 4)
49+
find(".d-breadcrumbs__item", text: I18n.t("admin_js.admin.plugins.title")).click
50+
expect(page).to have_current_path("/admin/plugins")
51+
end
52+
53+
it "can edit the AI feature" do
54+
ai_features_page.visit
55+
ai_features_page.click_edit_feature(I18n.t("discourse_ai.features.summarization.name"))
56+
expect(page).to have_current_path("/admin/plugins/discourse-ai/ai-features/1/edit")
57+
expect(page).to have_css(
58+
".ai-feature-editor__header h2",
59+
text: I18n.t("discourse_ai.features.summarization.name"),
60+
)
61+
62+
form.field("persona_id").select(-6)
63+
form.submit
64+
expect(page).to have_current_path("/admin/plugins/discourse-ai/ai-features")
65+
expect(ai_features_page).to have_feature_persona(
66+
I18n.t("discourse_ai.ai_bot.personas.creative.name"),
67+
)
68+
end
69+
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# frozen_string_literal: true
2+
3+
module PageObjects
4+
module Pages
5+
class AdminAiFeatures < PageObjects::Pages::Base
6+
CONFIGURED_FEATURES_TABLE = ".ai-feature-list__configured-features .d-admin-table"
7+
UNCONFIGURED_FEATURES_TABLE = ".ai-feature-list__unconfigured-features .d-admin-table"
8+
9+
def visit
10+
page.visit("/admin/plugins/discourse-ai/ai-features")
11+
self
12+
end
13+
14+
def configured_features_table
15+
page.find(CONFIGURED_FEATURES_TABLE)
16+
end
17+
18+
def unconfigured_features_table
19+
page.find(UNCONFIGURED_FEATURES_TABLE)
20+
end
21+
22+
def has_configured_feature_items?(count)
23+
page.has_css?("#{CONFIGURED_FEATURES_TABLE} .ai-feature-list__row", count: count)
24+
end
25+
26+
def has_unconfigured_feature_items?(count)
27+
page.has_css?("#{UNCONFIGURED_FEATURES_TABLE} .ai-feature-list__row", count: count)
28+
end
29+
30+
def has_feature_persona?(name)
31+
page.has_css?(
32+
"#{CONFIGURED_FEATURES_TABLE} .ai-feature-list__persona .d-button-label ",
33+
text: name,
34+
)
35+
end
36+
37+
def has_feature_groups?(groups)
38+
listed_groups = page.find("#{CONFIGURED_FEATURES_TABLE} .ai-feature-list__groups")
39+
list_items = listed_groups.all("li", visible: true).map(&:text)
40+
41+
list_items.sort == groups.sort
42+
end
43+
44+
def click_edit_feature(feature_name)
45+
page.find(
46+
"#{CONFIGURED_FEATURES_TABLE} .ai-feature-list__row[data-feature-name='#{feature_name}'] .edit",
47+
).click
48+
end
49+
end
50+
end
51+
end

0 commit comments

Comments
 (0)