diff --git a/core/spec/models/spree/permission_set_spec.rb b/core/spec/models/spree/permission_set_spec.rb
new file mode 100644
index 00000000000..6a29d2f6136
--- /dev/null
+++ b/core/spec/models/spree/permission_set_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+RSpec.describe Spree::PermissionSet, type: :model do
+  describe "associations" do
+    it "has many role_permissions" do
+      association = described_class.reflect_on_association(:role_permissions)
+      expect(association.macro).to eq(:has_many)
+    end
+
+    it "has many roles through role_permissions" do
+      association = described_class.reflect_on_association(:roles)
+      expect(association.macro).to eq(:has_many)
+      expect(association.options[:through]).to eq(:role_permissions)
+    end
+  end
+
+  describe "validations" do
+    it "is invalid without a name" do
+      permission_set = described_class.new(set: "Spree::PermissionSet::OrderDisplay", category: "order", privilege: "display")
+      expect(permission_set).not_to be_valid
+      expect(permission_set.errors[:name]).to include("can't be blank")
+    end
+
+    it "is invalid without a set" do
+      permission_set = described_class.new(name: "OrderDisplay", category: "order", privilege: "display")
+      expect(permission_set).not_to be_valid
+      expect(permission_set.errors[:set]).to include("can't be blank")
+    end
+
+    it "is invalid without a privilege" do
+      permission_set = described_class.new(name: "OrderDisplay", set: "Spree::PermissionSet::OrderDisplay", category: "display")
+      expect(permission_set).not_to be_valid
+      expect(permission_set.errors[:privilege]).to include("can't be blank")
+    end
+
+    it "is invalid without a category" do
+      permission_set = described_class.new(name: "OrderDisplay", set: "Spree::PermissionSet::OrderDisplay", privilege: "order")
+      expect(permission_set).not_to be_valid
+      expect(permission_set.errors[:category]).to include("can't be blank")
+    end
+  end
+
+  describe "scopes" do
+    let!(:display_permission) { described_class.create(name: "OrderDisplay", set: "Spree::PermissionSet::OrderDisplay", category: "order", privilege: "display") }
+    let!(:management_permission) { described_class.create(name: "OrderManagement", set: "Spree::PermissionSet::OrderManagement", category: "order", privilege: "management") }
+    let!(:other_permission) { described_class.create(name: "Shipping", set: "Spree::PermissionSet::Shipping", category: "shipping", privilege: "other") }
+
+    it 'returns permission sets with privilege: display for display_permissions scope' do
+      expect(Spree::PermissionSet.display_permissions).to include(display_permission)
+      expect(Spree::PermissionSet.display_permissions).not_to include(management_permission, other_permission)
+    end
+
+    it 'returns permission sets with privilege: management for management_permissions scope' do
+      expect(Spree::PermissionSet.management_permissions).to include(management_permission)
+      expect(Spree::PermissionSet.management_permissions).not_to include(display_permission, other_permission)
+    end
+
+    it 'returns permission sets with privilege: other for other_permissions scope' do
+      expect(Spree::PermissionSet.management_permissions).to include(management_permission)
+      expect(Spree::PermissionSet.management_permissions).not_to include(display_permission, other_permission)
+    end
+  end
+end
diff --git a/core/spec/models/spree/role_permission_spec.rb b/core/spec/models/spree/role_permission_spec.rb
new file mode 100644
index 00000000000..5f6665b7600
--- /dev/null
+++ b/core/spec/models/spree/role_permission_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+RSpec.describe Spree::RolePermission, type: :model do
+  describe "associations" do
+    it "belongs to a role" do
+      association = described_class.reflect_on_association(:role)
+      expect(association.macro).to eq(:belongs_to)
+    end
+
+    it "belongs to a permission_set" do
+      association = described_class.reflect_on_association(:permission_set)
+      expect(association.macro).to eq(:belongs_to)
+    end
+  end
+end
diff --git a/core/spec/models/spree/role_spec.rb b/core/spec/models/spree/role_spec.rb
new file mode 100644
index 00000000000..7d44706c019
--- /dev/null
+++ b/core/spec/models/spree/role_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+RSpec.describe Spree::Role, type: :model do
+  describe "associations" do
+    it "has many role_users" do
+      association = described_class.reflect_on_association(:role_users)
+      expect(association.macro).to eq(:has_many)
+      expect(association.options[:dependent]).to eq(:destroy)
+    end
+
+    it "has many users through role_users" do
+      association = described_class.reflect_on_association(:users)
+      expect(association.macro).to eq(:has_many)
+      expect(association.options[:through]).to eq(:role_users)
+    end
+
+    it "has many role_permissions" do
+      association = described_class.reflect_on_association(:role_permissions)
+      expect(association.macro).to eq(:has_many)
+      expect(association.options[:dependent]).to eq(:destroy)
+    end
+
+    it "has many permission_sets through role_permissions" do
+      association = described_class.reflect_on_association(:permission_sets)
+      expect(association.macro).to eq(:has_many)
+      expect(association.options[:through]).to eq(:role_permissions)
+    end
+  end
+
+  describe "validations" do
+    it "is invalid without a name" do
+      role = described_class.new
+      expect(role).not_to be_valid
+      expect(role.errors[:name]).to include("can't be blank")
+    end
+
+    it "validates uniqueness of name" do
+      described_class.create!(name: "admin")
+      duplicate_role = described_class.new(name: "admin")
+      expect(duplicate_role).not_to be_valid
+      expect(duplicate_role.errors[:name]).to include("has already been taken")
+    end
+  end
+
+  describe "#admin?" do
+    it "returns true if the role name is 'admin'" do
+      role = described_class.new(name: "admin")
+      expect(role.admin?).to be true
+    end
+
+    it "returns false if the role name is not 'admin'" do
+      role = described_class.new(name: "user")
+      expect(role.admin?).to be false
+    end
+  end
+
+  describe "#destroy" do
+    let(:role) { create(:role) }
+    let(:display_permission) { Spree::PermissionSet.create!(name: "OrderDisplay", set: "Spree::PermissionSet::OrderDisplay", category: "order", privilege: "display") }
+
+    before do
+      role.permission_sets << display_permission
+      role.save
+    end
+
+    it "destroys all associated role permissions" do
+      role_permission = role.role_permissions.first
+
+      role.destroy
+      aggregate_failures do
+        expect{ described_class.find(role.id) }.to raise_error(ActiveRecord::RecordNotFound)
+        expect{ Spree::RolePermission.find(role_permission.id) }.to raise_error(ActiveRecord::RecordNotFound)
+      end
+    end
+  end
+end