diff --git a/tests/python/bl_animation_keyframing.py b/tests/python/bl_animation_keyframing.py index af26c39e425..75188cc8cb5 100644 --- a/tests/python/bl_animation_keyframing.py +++ b/tests/python/bl_animation_keyframing.py @@ -42,6 +42,29 @@ def _create_animation_object(): return anim_object +_BONE_NAME = "bone" + + +def _create_armature(): + armature = bpy.data.armatures.new("anim_armature") + armature_obj = bpy.data.objects.new("anim_object", armature) + bpy.context.scene.collection.objects.link(armature_obj) + bpy.context.view_layer.objects.active = armature_obj + armature_obj.select_set(True) + + bpy.ops.object.mode_set(mode='EDIT') + edit_bone = armature.edit_bones.new(_BONE_NAME) + edit_bone.head = (1, 0, 0) + bpy.ops.object.mode_set(mode='POSE') + armature_obj.pose.bones[_BONE_NAME].rotation_mode = "XYZ" + armature_obj.pose.bones[_BONE_NAME].bone.select = True + armature_obj.pose.bones[_BONE_NAME].bone.select_head = True + armature_obj.pose.bones[_BONE_NAME].bone.select_tail = True + bpy.ops.object.mode_set(mode='OBJECT') + + return armature_obj + + def _insert_by_name_test(insert_key: str, expected_paths: list): keyed_object = _create_animation_object() with bpy.context.temp_override(**_get_view3d_context()): @@ -240,6 +263,59 @@ class CycleAwareKeyingTest(AbstractKeyframingTest, unittest.TestCase): bpy.data.objects.remove(keyed_object, do_unlink=True) +class AutoKeyframingTest(AbstractKeyframingTest, unittest.TestCase): + + def test_autokey_basic(self): + keyed_object = _create_animation_object() + bpy.context.scene.tool_settings.use_keyframe_insert_auto = True + bpy.context.preferences.edit.use_keyframe_insert_available = False + with bpy.context.temp_override(**_get_view3d_context()): + bpy.ops.transform.translate(value=(1, 0, 0)) + + action = keyed_object.animation_data.action + self.assertTrue(_fcurve_paths_match(action.fcurves, ["location", "rotation_euler", "scale"])) + bpy.data.objects.remove(keyed_object, do_unlink=True) + + def test_autokey_available(self): + keyed_object = _create_animation_object() + + bpy.context.scene.tool_settings.use_keyframe_insert_auto = True + bpy.context.preferences.edit.use_keyframe_insert_available = True + + with bpy.context.temp_override(**_get_view3d_context()): + bpy.context.scene.frame_set(1) + bpy.ops.anim.keyframe_insert_by_name(type="Location") + bpy.context.scene.frame_set(5) + bpy.ops.transform.translate(value=(1, 0, 0)) + + action = keyed_object.animation_data.action + self.assertTrue(_fcurve_paths_match(action.fcurves, ["location"])) + + for fcurve in action.fcurves: + self.assertEqual(len(fcurve.keyframe_points), 2) + + bpy.context.preferences.edit.use_keyframe_insert_available = False + bpy.data.objects.remove(keyed_object, do_unlink=True) + + def test_autokey_bone(self): + armature_obj = _create_armature() + bpy.context.scene.tool_settings.use_keyframe_insert_auto = True + bpy.context.preferences.edit.use_keyframe_insert_available = False + + bpy.ops.object.mode_set(mode='POSE') + # Not overriding the context because it would mean context.selected_pose_bones is empty + # resulting in a failure to move/key the bone + bpy.ops.transform.translate(value=(1, 0, 0)) + bpy.ops.object.mode_set(mode='OBJECT') + + action = armature_obj.animation_data.action + bone_path = f"pose.bones[\"{_BONE_NAME}\"]" + expected_paths = [f"{bone_path}.location", f"{bone_path}.rotation_euler", f"{bone_path}.scale"] + self.assertTrue(_fcurve_paths_match(action.fcurves, expected_paths)) + + bpy.data.objects.remove(armature_obj, do_unlink=True) + + def main(): global args import argparse