diff --git a/app/graphql/mutations/saved_replies/base.rb b/app/graphql/mutations/saved_replies/base.rb
index 6fd9e03171c719a346e2ae61b21eb8e424f66680..6320d242beb248d3c00c6bda2afcdc6213ec8a25 100644
--- a/app/graphql/mutations/saved_replies/base.rb
+++ b/app/graphql/mutations/saved_replies/base.rb
@@ -3,10 +3,6 @@
 module Mutations
   module SavedReplies
     class Base < BaseMutation
-      field :saved_reply, ::Types::Users::SavedReplyType,
-            null: true,
-            description: 'Saved reply after mutation.'
-
       private
 
       def present_result(result)
diff --git a/app/graphql/mutations/saved_replies/create.rb b/app/graphql/mutations/saved_replies/create.rb
index 1e71688af3fe1b4750cdf6e7b007ef156ee40aab..ad9815e8f0bc11e1f63fa0d500eca30f2edf15e0 100644
--- a/app/graphql/mutations/saved_replies/create.rb
+++ b/app/graphql/mutations/saved_replies/create.rb
@@ -3,22 +3,15 @@
 module Mutations
   module SavedReplies
     class Create < Base
-      graphql_name 'SavedReplyCreate'
-
       authorize :create_saved_replies
 
       argument :name, GraphQL::Types::String,
                required: true,
-               description: copy_field_description(Types::SavedReplyType, :name)
+               description: copy_field_description(::Types::SavedReplyType, :name)
 
       argument :content, GraphQL::Types::String,
                required: true,
-               description: copy_field_description(Types::SavedReplyType, :content)
-
-      def resolve(name:, content:)
-        result = ::SavedReplies::CreateService.new(object: current_user, name: name, content: content).execute
-        present_result(result)
-      end
+               description: copy_field_description(::Types::SavedReplyType, :content)
     end
   end
 end
diff --git a/app/graphql/mutations/saved_replies/destroy.rb b/app/graphql/mutations/saved_replies/destroy.rb
index b67bd11e0cbb139d7a39c7b54c02178df9c1ad52..c9aded6fbe13509c67b566684d2124499b517ffd 100644
--- a/app/graphql/mutations/saved_replies/destroy.rb
+++ b/app/graphql/mutations/saved_replies/destroy.rb
@@ -3,14 +3,8 @@
 module Mutations
   module SavedReplies
     class Destroy < Base
-      graphql_name 'SavedReplyDestroy'
-
       authorize :destroy_saved_replies
 
-      argument :id, Types::GlobalIDType[::Users::SavedReply],
-               required: true,
-               description: copy_field_description(::Types::Users::SavedReplyType, :id)
-
       def resolve(id:)
         saved_reply = authorized_find!(id: id)
         result = ::SavedReplies::DestroyService.new(saved_reply: saved_reply).execute
diff --git a/app/graphql/mutations/saved_replies/update.rb b/app/graphql/mutations/saved_replies/update.rb
index 6acbdd8d770ac8f635e71904a074cf1657fd9c1d..a58633c178bf8324d63c6bac2f420a124657b0a0 100644
--- a/app/graphql/mutations/saved_replies/update.rb
+++ b/app/graphql/mutations/saved_replies/update.rb
@@ -3,14 +3,8 @@
 module Mutations
   module SavedReplies
     class Update < Base
-      graphql_name 'SavedReplyUpdate'
-
       authorize :update_saved_replies
 
-      argument :id, Types::GlobalIDType[::Users::SavedReply],
-               required: true,
-               description: copy_field_description(::Types::Users::SavedReplyType, :id)
-
       argument :name, GraphQL::Types::String,
                required: true,
                description: copy_field_description(::Types::SavedReplyType, :name)
diff --git a/app/graphql/mutations/users/saved_replies/create.rb b/app/graphql/mutations/users/saved_replies/create.rb
new file mode 100644
index 0000000000000000000000000000000000000000..67b7733a750c16aedaffc357d6aa46a0bf4f40ed
--- /dev/null
+++ b/app/graphql/mutations/users/saved_replies/create.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Users
+    module SavedReplies
+      class Create < ::Mutations::SavedReplies::Create
+        graphql_name 'SavedReplyCreate'
+
+        field :saved_reply, ::Types::Users::SavedReplyType,
+          null: true,
+          description: 'Saved reply after mutation.'
+
+        def resolve(name:, content:)
+          result = ::SavedReplies::CreateService.new(object: current_user, name: name, content: content).execute
+          present_result(result)
+        end
+      end
+    end
+  end
+end
diff --git a/app/graphql/mutations/users/saved_replies/destroy.rb b/app/graphql/mutations/users/saved_replies/destroy.rb
new file mode 100644
index 0000000000000000000000000000000000000000..35693f24cc038c1db36301f5e51cf1c8499ab7f5
--- /dev/null
+++ b/app/graphql/mutations/users/saved_replies/destroy.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Users
+    module SavedReplies
+      class Destroy < ::Mutations::SavedReplies::Destroy
+        graphql_name 'SavedReplyDestroy'
+
+        field :saved_reply, ::Types::Users::SavedReplyType,
+          null: true,
+          description: 'Saved reply after mutation.'
+
+        argument :id, Types::GlobalIDType[::Users::SavedReply],
+          required: true,
+          description: copy_field_description(::Types::Users::SavedReplyType, :id)
+      end
+    end
+  end
+end
diff --git a/app/graphql/mutations/users/saved_replies/update.rb b/app/graphql/mutations/users/saved_replies/update.rb
new file mode 100644
index 0000000000000000000000000000000000000000..65a1777afd48453caf8b2f18488cf1b272063980
--- /dev/null
+++ b/app/graphql/mutations/users/saved_replies/update.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Users
+    module SavedReplies
+      class Update < ::Mutations::SavedReplies::Update
+        graphql_name 'SavedReplyUpdate'
+
+        field :saved_reply, ::Types::Users::SavedReplyType,
+          null: true,
+          description: 'Saved reply after mutation.'
+
+        argument :id, Types::GlobalIDType[::Users::SavedReply],
+          required: true,
+          description: copy_field_description(::Types::Users::SavedReplyType, :id)
+      end
+    end
+  end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index ab4e78435f19cee7b4fb54222f97963da2b46a77..21e9c76249b89cdc073378c6a04d50a0d8f67cef 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -197,10 +197,10 @@ class MutationType < BaseObject
     mount_mutation Mutations::WorkItems::Convert, alpha: { milestone: '15.11' }
     mount_mutation Mutations::WorkItems::LinkedItems::Add, alpha: { milestone: '16.3' }
     mount_mutation Mutations::WorkItems::LinkedItems::Remove, alpha: { milestone: '16.3' }
-    mount_mutation Mutations::SavedReplies::Create
-    mount_mutation Mutations::SavedReplies::Update
+    mount_mutation Mutations::Users::SavedReplies::Create
+    mount_mutation Mutations::Users::SavedReplies::Update
+    mount_mutation Mutations::Users::SavedReplies::Destroy
     mount_mutation Mutations::Pages::MarkOnboardingComplete
-    mount_mutation Mutations::SavedReplies::Destroy
     mount_mutation Mutations::Uploads::Delete
     mount_mutation Mutations::Users::SetNamespaceCommitEmail
     mount_mutation Mutations::WorkItems::Subscribe, alpha: { milestone: '16.3' }
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index b4c29f41922d493deee38303d552908ba2d7435d..b1a1e88e15ab336709309c4fd48c00e97f5297c8 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -4565,6 +4565,79 @@ Input type: `GroupMemberBulkUpdateInput`
 | <a id="mutationgroupmemberbulkupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
 | <a id="mutationgroupmemberbulkupdategroupmembers"></a>`groupMembers` | [`[GroupMember!]`](#groupmember) | Group members after mutation. |
 
+### `Mutation.groupSavedReplyCreate`
+
+NOTE:
+**Introduced** in 16.10.
+**Status**: Experiment.
+
+Input type: `GroupSavedReplyCreateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgroupsavedreplycreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgroupsavedreplycreatecontent"></a>`content` | [`String!`](#string) | Content of the saved reply. |
+| <a id="mutationgroupsavedreplycreategroupid"></a>`groupId` | [`GroupID!`](#groupid) | Group for the save reply. |
+| <a id="mutationgroupsavedreplycreatename"></a>`name` | [`String!`](#string) | Name of the saved reply. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgroupsavedreplycreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgroupsavedreplycreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationgroupsavedreplycreatesavedreply"></a>`savedReply` | [`GroupSavedReply`](#groupsavedreply) | Saved reply after mutation. |
+
+### `Mutation.groupSavedReplyDestroy`
+
+NOTE:
+**Introduced** in 16.10.
+**Status**: Experiment.
+
+Input type: `GroupSavedReplyDestroyInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgroupsavedreplydestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgroupsavedreplydestroyid"></a>`id` | [`GroupsSavedReplyID!`](#groupssavedreplyid) | Global ID of the group-level saved reply. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgroupsavedreplydestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgroupsavedreplydestroyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationgroupsavedreplydestroysavedreply"></a>`savedReply` | [`GroupSavedReply`](#groupsavedreply) | Saved reply after mutation. |
+
+### `Mutation.groupSavedReplyUpdate`
+
+NOTE:
+**Introduced** in 16.10.
+**Status**: Experiment.
+
+Input type: `GroupSavedReplyUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgroupsavedreplyupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgroupsavedreplyupdatecontent"></a>`content` | [`String!`](#string) | Content of the saved reply. |
+| <a id="mutationgroupsavedreplyupdateid"></a>`id` | [`GroupsSavedReplyID!`](#groupssavedreplyid) | Global ID of the group-level saved reply. |
+| <a id="mutationgroupsavedreplyupdatename"></a>`name` | [`String!`](#string) | Name of the saved reply. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgroupsavedreplyupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgroupsavedreplyupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationgroupsavedreplyupdatesavedreply"></a>`savedReply` | [`GroupSavedReply`](#groupsavedreply) | Saved reply after mutation. |
+
 ### `Mutation.groupUpdate`
 
 Input type: `GroupUpdateInput`
diff --git a/ee/app/graphql/ee/types/mutation_type.rb b/ee/app/graphql/ee/types/mutation_type.rb
index 1b666c3d6280bfec863375db6e85dabbb73473b1..f48f49d78989497d439bb274a88c4cab7394ff72 100644
--- a/ee/app/graphql/ee/types/mutation_type.rb
+++ b/ee/app/graphql/ee/types/mutation_type.rb
@@ -153,6 +153,9 @@ module MutationType
         mount_mutation ::Mutations::AuditEvents::Streaming::HTTP::NamespaceFilters::Delete
         mount_mutation ::Mutations::Ai::Agents::Create, alpha: { milestone: '16.8' }
         mount_mutation ::Mutations::ComplianceManagement::Standards::RefreshAdherenceChecks
+        mount_mutation ::Mutations::Groups::SavedReplies::Create, alpha: { milestone: '16.10' }
+        mount_mutation ::Mutations::Groups::SavedReplies::Update, alpha: { milestone: '16.10' }
+        mount_mutation ::Mutations::Groups::SavedReplies::Destroy, alpha: { milestone: '16.10' }
 
         prepend(Types::DeprecatedMutations)
       end
diff --git a/ee/app/graphql/mutations/groups/saved_replies/create.rb b/ee/app/graphql/mutations/groups/saved_replies/create.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c745041fc3a95f2e4346e50710f89d9d244eabcb
--- /dev/null
+++ b/ee/app/graphql/mutations/groups/saved_replies/create.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Groups
+    module SavedReplies
+      class Create < ::Mutations::SavedReplies::Create
+        graphql_name 'GroupSavedReplyCreate'
+
+        field :saved_reply, ::Types::Groups::SavedReplyType,
+          null: true,
+          description: 'Saved reply after mutation.'
+
+        argument :group_id, ::Types::GlobalIDType[::Group],
+          required: true,
+          description: 'Group for the save reply.'
+
+        def resolve(group_id:, name:, content:)
+          group = authorized_find!(id: group_id)
+
+          result = ::SavedReplies::CreateService.new(object: group, name: name, content: content).execute
+          present_result(result)
+        end
+      end
+    end
+  end
+end
diff --git a/ee/app/graphql/mutations/groups/saved_replies/destroy.rb b/ee/app/graphql/mutations/groups/saved_replies/destroy.rb
new file mode 100644
index 0000000000000000000000000000000000000000..950466f19d7f9110f6be4e332a54116096f19dfd
--- /dev/null
+++ b/ee/app/graphql/mutations/groups/saved_replies/destroy.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Groups
+    module SavedReplies
+      class Destroy < ::Mutations::SavedReplies::Destroy
+        graphql_name 'GroupSavedReplyDestroy'
+
+        field :saved_reply, ::Types::Groups::SavedReplyType,
+          null: true,
+          description: 'Saved reply after mutation.'
+
+        argument :id, Types::GlobalIDType[::Groups::SavedReply],
+          required: true,
+          description: copy_field_description(::Types::Groups::SavedReplyType, :id)
+      end
+    end
+  end
+end
diff --git a/ee/app/graphql/mutations/groups/saved_replies/update.rb b/ee/app/graphql/mutations/groups/saved_replies/update.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7ab10d55a131fbc97a6cbc7d8853fec598200be6
--- /dev/null
+++ b/ee/app/graphql/mutations/groups/saved_replies/update.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Groups
+    module SavedReplies
+      class Update < ::Mutations::SavedReplies::Update
+        graphql_name 'GroupSavedReplyUpdate'
+
+        field :saved_reply, ::Types::Groups::SavedReplyType,
+          null: true,
+          description: 'Saved reply after mutation.'
+
+        argument :id, Types::GlobalIDType[::Groups::SavedReply],
+          required: true,
+          description: copy_field_description(::Types::Groups::SavedReplyType, :id)
+      end
+    end
+  end
+end
diff --git a/ee/app/policies/ee/group_policy.rb b/ee/app/policies/ee/group_policy.rb
index 992154ec5acbd75b3c6dac71607fd325e2e04529..010ec03a4d4e73b942aa32ec68fa71947724c36f 100644
--- a/ee/app/policies/ee/group_policy.rb
+++ b/ee/app/policies/ee/group_policy.rb
@@ -695,6 +695,9 @@ module GroupPolicy
 
       rule { supports_saved_replies & developer }.policy do
         enable :read_saved_replies
+        enable :create_saved_replies
+        enable :destroy_saved_replies
+        enable :update_saved_replies
       end
     end
 
diff --git a/ee/spec/policies/group_policy_spec.rb b/ee/spec/policies/group_policy_spec.rb
index 3b9cfe59ffa32ba9872c8dcf2e2fbd6e206c7a80..a13ed1bfc2b2a8d7fc4cfbf51c2be8f92256f924 100644
--- a/ee/spec/policies/group_policy_spec.rb
+++ b/ee/spec/policies/group_policy_spec.rb
@@ -3300,7 +3300,7 @@ def create_member_role(member, abilities = member_role_abilities)
     end
   end
 
-  context 'for :read_saved_replies' do
+  context 'saved replies permissions' do
     let(:current_user) { owner }
 
     context 'when group_saved_replies_flag feature flag is disabled' do
@@ -3308,7 +3308,7 @@ def create_member_role(member, abilities = member_role_abilities)
         stub_feature_flags(group_saved_replies_flag: false)
       end
 
-      it { is_expected.to be_disallowed(:read_saved_replies) }
+      it { is_expected.to be_disallowed(:read_saved_replies, :create_saved_replies, :update_saved_replies, :destroy_saved_replies) }
     end
 
     context 'when no license is present' do
@@ -3316,7 +3316,7 @@ def create_member_role(member, abilities = member_role_abilities)
         stub_licensed_features(group_saved_replies: false)
       end
 
-      it { is_expected.to be_disallowed(:read_saved_replies) }
+      it { is_expected.to be_disallowed(:read_saved_replies, :create_saved_replies, :update_saved_replies, :destroy_saved_replies) }
     end
 
     context 'with correct license' do
@@ -3324,18 +3324,18 @@ def create_member_role(member, abilities = member_role_abilities)
         stub_licensed_features(group_saved_replies: true)
       end
 
-      it { is_expected.to be_allowed(:read_saved_replies) }
+      it { is_expected.to be_allowed(:read_saved_replies, :create_saved_replies, :update_saved_replies, :destroy_saved_replies) }
 
       context 'when the user is a developer' do
         let(:current_user) { developer }
 
-        it { is_expected.to be_allowed(:read_saved_replies) }
+        it { is_expected.to be_allowed(:read_saved_replies, :create_saved_replies, :update_saved_replies, :destroy_saved_replies) }
       end
 
       context 'when the user is a guest member of the group' do
         let(:current_user) { guest }
 
-        it { is_expected.to be_disallowed(:read_saved_replies) }
+        it { is_expected.to be_disallowed(:read_saved_replies, :create_saved_replies, :update_saved_replies, :destroy_saved_replies) }
       end
     end
   end
diff --git a/ee/spec/requests/api/graphql/groups/saved_replies/create_spec.rb b/ee/spec/requests/api/graphql/groups/saved_replies/create_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d4ebb70613853ec090c89b42bb5656253912ca8c
--- /dev/null
+++ b/ee/spec/requests/api/graphql/groups/saved_replies/create_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Create group saved reply', feature_category: :code_review_workflow do
+  include GraphqlHelpers
+
+  let_it_be(:group) { create(:group) }
+  let_it_be(:current_user) { create(:user) }
+
+  let(:input) { { group_id: group.to_global_id, name: 'Test name', content: 'Test content' } }
+
+  let(:mutation) { graphql_mutation(:group_saved_reply_create, input) }
+  let(:mutation_response) { graphql_mutation_response(:group_saved_reply_create) }
+
+  before_all do
+    group.add_maintainer(current_user)
+  end
+
+  context 'with group_saved_replies_flag disabled' do
+    before do
+      stub_feature_flags(group_saved_replies_flag: false)
+      stub_licensed_features(group_saved_replies: true)
+    end
+
+    it 'returns null' do
+      post_graphql_mutation(mutation, current_user: current_user)
+
+      expect(mutation_response).to be_nil
+    end
+  end
+
+  context 'when license is invalid' do
+    before do
+      stub_licensed_features(group_saved_replies: false)
+    end
+
+    it 'returns null' do
+      post_graphql_mutation(mutation, current_user: current_user)
+
+      expect(mutation_response).to be_nil
+    end
+  end
+
+  context 'when license is valid' do
+    before do
+      stub_licensed_features(group_saved_replies: true)
+    end
+
+    it 'creates a saved reply' do
+      expect do
+        post_graphql_mutation(mutation, current_user: current_user)
+
+        expect(mutation_response['savedReply']).to include(
+          'name' => 'Test name',
+          'content' => 'Test content'
+        )
+      end.to change { ::Groups::SavedReply.count }.by(1)
+    end
+
+    context 'when saved reply exists' do
+      let_it_be(:saved_reply) { create(:group_saved_reply, group: group, name: 'Test name') }
+
+      it_behaves_like 'a mutation that returns errors in the response', errors: ["Name has already been taken"]
+    end
+  end
+end
diff --git a/ee/spec/requests/api/graphql/groups/saved_replies/destroy_spec.rb b/ee/spec/requests/api/graphql/groups/saved_replies/destroy_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..05574765d5907d1993d9ac9d917031ea8efbf4e6
--- /dev/null
+++ b/ee/spec/requests/api/graphql/groups/saved_replies/destroy_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Destroy group saved reply', feature_category: :code_review_workflow do
+  include GraphqlHelpers
+
+  let_it_be(:group) { create(:group) }
+  let_it_be(:current_user) { create(:user) }
+  let_it_be(:saved_reply) { create(:group_saved_reply, group: group) }
+
+  let(:input) { { id: saved_reply.to_global_id } }
+
+  let(:mutation) { graphql_mutation(:group_saved_reply_destroy, input) }
+  let(:mutation_response) { graphql_mutation_response(:group_saved_reply_destroy) }
+
+  before_all do
+    group.add_maintainer(current_user)
+  end
+
+  context 'with group_saved_replies_flag disabled' do
+    before do
+      stub_feature_flags(group_saved_replies_flag: false)
+      stub_licensed_features(group_saved_replies: true)
+    end
+
+    it 'returns null' do
+      post_graphql_mutation(mutation, current_user: current_user)
+
+      expect(mutation_response).to be_nil
+    end
+  end
+
+  context 'when license is invalid' do
+    before do
+      stub_licensed_features(group_saved_replies: false)
+    end
+
+    it 'returns null' do
+      post_graphql_mutation(mutation, current_user: current_user)
+
+      expect(mutation_response).to be_nil
+    end
+  end
+
+  context 'when license is valid' do
+    before do
+      stub_licensed_features(group_saved_replies: true)
+    end
+
+    it 'deletes the saved reply' do
+      expect do
+        post_graphql_mutation(mutation, current_user: current_user)
+      end.to change { ::Groups::SavedReply.count }.by(-1)
+    end
+  end
+end
diff --git a/ee/spec/requests/api/graphql/groups/saved_replies/update_spec.rb b/ee/spec/requests/api/graphql/groups/saved_replies/update_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..77da54ff6dec037b6e6a327fc18add3e4776757f
--- /dev/null
+++ b/ee/spec/requests/api/graphql/groups/saved_replies/update_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Update group saved reply', feature_category: :code_review_workflow do
+  include GraphqlHelpers
+
+  let_it_be(:group) { create(:group) }
+  let_it_be(:current_user) { create(:user) }
+  let_it_be(:saved_reply) { create(:group_saved_reply, group: group, name: 'Old name', content: 'Old content') }
+
+  let(:input) { { id: saved_reply.to_global_id, name: 'New name', content: 'New content' } }
+
+  let(:mutation) { graphql_mutation(:group_saved_reply_update, input) }
+  let(:mutation_response) { graphql_mutation_response(:group_saved_reply_update) }
+
+  before_all do
+    group.add_maintainer(current_user)
+  end
+
+  context 'with group_saved_replies_flag disabled' do
+    before do
+      stub_feature_flags(group_saved_replies_flag: false)
+      stub_licensed_features(group_saved_replies: true)
+    end
+
+    it 'returns null' do
+      post_graphql_mutation(mutation, current_user: current_user)
+
+      expect(mutation_response).to be_nil
+    end
+  end
+
+  context 'when license is invalid' do
+    before do
+      stub_licensed_features(group_saved_replies: false)
+    end
+
+    it 'returns null' do
+      post_graphql_mutation(mutation, current_user: current_user)
+
+      expect(mutation_response).to be_nil
+    end
+  end
+
+  context 'when license is valid' do
+    before do
+      stub_licensed_features(group_saved_replies: true)
+    end
+
+    it 'updates the saved reply' do
+      post_graphql_mutation(mutation, current_user: current_user)
+
+      expect(mutation_response['savedReply']).to include(
+        'name' => 'New name',
+        'content' => 'New content'
+      )
+    end
+  end
+end
diff --git a/spec/graphql/mutations/saved_replies/create_spec.rb b/spec/graphql/mutations/users/saved_replies/create_spec.rb
similarity index 64%
rename from spec/graphql/mutations/saved_replies/create_spec.rb
rename to spec/graphql/mutations/users/saved_replies/create_spec.rb
index 9db23ab5345f2ef6fb2d34b156a5ff78e752dfc0..a2530e6653185492560643023b6c03e419a73d65 100644
--- a/spec/graphql/mutations/saved_replies/create_spec.rb
+++ b/spec/graphql/mutations/users/saved_replies/create_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Mutations::SavedReplies::Create do
+RSpec.describe Mutations::Users::SavedReplies::Create, feature_category: :code_review_workflow do
   let_it_be(:current_user) { create(:user) }
 
   let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
@@ -17,14 +17,14 @@
     context 'when service fails to create a new saved reply' do
       let(:mutation_arguments) { { name: '', content: '' } }
 
-      it { expect(subject[:saved_reply]).to be_nil }
-      it { expect(subject[:errors]).to match_array(["Content can't be blank", "Name can't be blank"]) }
+      it { expect(resolve[:saved_reply]).to be_nil }
+      it { expect(resolve[:errors]).to match_array(["Content can't be blank", "Name can't be blank"]) }
     end
 
     context 'when service successfully creates a new saved reply' do
-      it { expect(subject[:saved_reply].name).to eq(mutation_arguments[:name]) }
-      it { expect(subject[:saved_reply].content).to eq(mutation_arguments[:content]) }
-      it { expect(subject[:errors]).to be_empty }
+      it { expect(resolve[:saved_reply].name).to eq(mutation_arguments[:name]) }
+      it { expect(resolve[:saved_reply].content).to eq(mutation_arguments[:content]) }
+      it { expect(resolve[:errors]).to be_empty }
     end
   end
 end
diff --git a/spec/graphql/mutations/saved_replies/destroy_spec.rb b/spec/graphql/mutations/users/saved_replies/destroy_spec.rb
similarity index 76%
rename from spec/graphql/mutations/saved_replies/destroy_spec.rb
rename to spec/graphql/mutations/users/saved_replies/destroy_spec.rb
index 84efd9ee0b8c7648911aba1961b232443450377c..dad237d1e2bc221ae670492c702651b71a3c6e07 100644
--- a/spec/graphql/mutations/saved_replies/destroy_spec.rb
+++ b/spec/graphql/mutations/users/saved_replies/destroy_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Mutations::SavedReplies::Destroy do
+RSpec.describe Mutations::Users::SavedReplies::Destroy, feature_category: :code_review_workflow do
   let_it_be(:current_user) { create(:user) }
   let_it_be(:saved_reply) { create(:saved_reply, user: current_user) }
 
@@ -19,12 +19,12 @@
       end
 
       it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do
-        expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+        expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
       end
     end
 
     context 'when service successfully deletes the saved reply' do
-      it { expect(subject[:errors]).to be_empty }
+      it { expect(resolve[:errors]).to be_empty }
     end
   end
 end
diff --git a/spec/graphql/mutations/saved_replies/update_spec.rb b/spec/graphql/mutations/users/saved_replies/update_spec.rb
similarity index 67%
rename from spec/graphql/mutations/saved_replies/update_spec.rb
rename to spec/graphql/mutations/users/saved_replies/update_spec.rb
index cc358d946a5f4893b501f704ae0a3c5a149848ea..4b5b9fef46b048b2b762f8a6956e92a9bb1b4429 100644
--- a/spec/graphql/mutations/saved_replies/update_spec.rb
+++ b/spec/graphql/mutations/users/saved_replies/update_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Mutations::SavedReplies::Update do
+RSpec.describe Mutations::Users::SavedReplies::Update, feature_category: :code_review_workflow do
   let_it_be(:current_user) { create(:user) }
   let_it_be(:saved_reply) { create(:saved_reply, user: current_user) }
 
@@ -18,14 +18,14 @@
     context 'when service fails to update a new saved reply' do
       let(:mutation_arguments) { { name: '', content: '' } }
 
-      it { expect(subject[:saved_reply]).to be_nil }
-      it { expect(subject[:errors]).to match_array(["Content can't be blank", "Name can't be blank"]) }
+      it { expect(resolve[:saved_reply]).to be_nil }
+      it { expect(resolve[:errors]).to match_array(["Content can't be blank", "Name can't be blank"]) }
     end
 
     context 'when service successfully updates the saved reply' do
-      it { expect(subject[:saved_reply].name).to eq(mutation_arguments[:name]) }
-      it { expect(subject[:saved_reply].content).to eq(mutation_arguments[:content]) }
-      it { expect(subject[:errors]).to be_empty }
+      it { expect(resolve[:saved_reply].name).to eq(mutation_arguments[:name]) }
+      it { expect(resolve[:saved_reply].content).to eq(mutation_arguments[:content]) }
+      it { expect(resolve[:errors]).to be_empty }
     end
   end
 end