[analysis_server] Move CodeActions tests to shared mixins

The next CL will make CodeActions a shared handler (so it can run for both LSP and legacy servers). This moves the tests to a shared mixin (without any changes) to keep that change smaller and easier to review if the tests do end up requiring changes.

Not all tests are moved yet - plugins are not (because the plugin code is not the same across server types), not "Fix All" (because it will require some additional changes to not be LSP-specific compared to others).

Change-Id: Ib4727ef1b1cc5b96d98cdbd6e17bf4b7b2791e3e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/428003
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/test/lsp/code_actions_assists_test.dart b/pkg/analysis_server/test/lsp/code_actions_assists_test.dart
index 12dab69..5568c5a 100644
--- a/pkg/analysis_server/test/lsp/code_actions_assists_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_assists_test.dart
@@ -3,11 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:convert';
 
 import 'package:analysis_server/lsp_protocol/protocol.dart';
 import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/extensions/code_action.dart';
 import 'package:analysis_server/src/services/correction/assist_internal.dart';
 import 'package:analyzer/src/test_utilities/test_code_format.dart';
@@ -18,7 +16,7 @@
 
 import '../lsp/code_actions_mixin.dart';
 import '../lsp/server_abstract.dart';
-import '../utils/lsp_protocol_extensions.dart';
+import '../shared/shared_code_actions_assists_tests.dart';
 import '../utils/test_code_extensions.dart';
 
 void main() {
@@ -29,7 +27,10 @@
 
 @reflectiveTest
 class AssistsCodeActionsTest extends AbstractLspAnalysisServerTest
-    with LspSharedTestMixin, CodeActionsTestMixin {
+    with
+        LspSharedTestMixin,
+        CodeActionsTestMixin,
+        SharedAssistsCodeActionsTests {
   @override
   void setUp() {
     super.setUp();
@@ -43,229 +44,6 @@
     writeTestPackageConfig(flutter: true);
   }
 
-  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
-    // This code should get an assist to add a show combinator.
-    const content = '''
-import '[!dart:async!]';
-
-Future? f;
-''';
-
-    const expectedContent = '''
-import 'dart:async' show Future;
-
-Future? f;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('refactor.add.showCombinator'),
-      title: "Add explicit 'show' combinator",
-    );
-  }
-
-  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
-    // This code should get an assist to add a show combinator.
-    const content = '''
-import '[!dart:async!]';
-
-Future? f;
-''';
-
-    const expectedContent = '''
-import 'dart:async' show Future;
-
-Future? f;
-''';
-
-    setDocumentChangesSupport(false);
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('refactor.add.showCombinator'),
-      title: "Add explicit 'show' combinator",
-    );
-  }
-
-  Future<void> test_codeActionLiterals_supported() async {
-    setSnippetTextEditSupport();
-    setSupportedCodeActionKinds([CodeActionKind.Refactor]);
-
-    var code = TestCode.parse('''
-import 'package:flutter/widgets.dart';
-Widget build() {
-  return Te^xt('');
-}
-''');
-
-    var action = await expectCodeAction(
-      code,
-      kind: CodeActionKind('refactor.flutter.wrap.center'),
-      title: 'Wrap with Center',
-    );
-
-    // Ensure we are a CodeAction literal.
-    expect(action.isCodeActionLiteral, true);
-
-    await verifyCodeActionEdits(action, r'''
->>>>>>>>>> lib/test.dart
-import 'package:flutter/widgets.dart';
-Widget build() {
-  return Center($0child: Text(''));
-}
-''');
-  }
-
-  Future<void> test_codeActionLiterals_unsupported() async {
-    setSnippetTextEditSupport();
-    setSupportedCodeActionKinds(null); // no codeActionLiteralSupport
-
-    var code = TestCode.parse('''
-import 'package:flutter/widgets.dart';
-Widget build() {
-  return Te[!!]xt('');
-}
-''');
-
-    var action = await expectCodeAction(
-      openTargetFile: true, // Open document to verify we get a version back.
-      code,
-      title: 'Wrap with Center',
-      command: Commands.applyCodeAction,
-      commandArgs: [
-        {
-          'textDocument': {'uri': testFileUri.toString(), 'version': 1},
-          'range': code.range.range.toJson(),
-          'kind': 'refactor.flutter.wrap.center',
-          'loggedAction': 'dart.assist.flutter.wrap.center',
-        },
-      ],
-    );
-
-    // We don't support literals, so we expect the raw command instead.
-    expect(action.isCommand, true);
-    var command = action.asCommand;
-
-    // Verify that executing the command produces the correct edits (which will
-    // come back via `workspace/applyEdit`).
-    await verifyCommandEdits(command, r'''
->>>>>>>>>> lib/test.dart
-import 'package:flutter/widgets.dart';
-Widget build() {
-  return Center($0child: Text(''));
-}
-''');
-
-    expectCommandLogged(Commands.applyCodeAction);
-    expectCommandLogged('dart.assist.flutter.wrap.center');
-  }
-
-  Future<void> test_errorMessage_invalidIntegers() async {
-    // A VS Code code coverage extension has been seen to use Number.MAX_VALUE
-    // for the character position and resulted in:
-    //
-    //     type 'double' is not a subtype of type 'int'
-    //
-    // This test ensures the error message for these invalid params is clearer,
-    // indicating this is not a valid (Dart) int.
-    // https://github.com/dart-lang/sdk/issues/42786
-
-    createFile(testFilePath, '');
-    await initializeServer();
-
-    var request = makeRequest(
-      Method.textDocument_codeAction,
-      _RawParams('''
-      {
-        "textDocument": {
-          "uri": "$testFileUri"
-        },
-        "context": {
-          "diagnostics": []
-        },
-        "range": {
-          "start": {
-            "line": 3,
-            "character": 2
-          },
-          "end": {
-            "line": 3,
-            "character": 1.7976931348623157e+308
-          }
-        }
-      }
-'''),
-    );
-    var resp = await sendRequestToServer(request);
-    var error = resp.error!;
-    expect(error.code, equals(ErrorCodes.InvalidParams));
-    expect(
-      error.message,
-      allOf([
-        contains('Invalid params for textDocument/codeAction'),
-        contains('params.range.end.character must be of type int'),
-      ]),
-    );
-  }
-
-  Future<void> test_flutterWrap_selection() async {
-    const content = '''
-import 'package:flutter/widgets.dart';
-Widget build() {
-  return Te^xt('');
-}
-''';
-
-    // For testing, the snippet will be inserted literally into the text, as
-    // this requires some magic on the client. The expected text should
-    // therefore contain '$0' at the location of the selection/final tabstop.
-    const expectedContent = r'''
-import 'package:flutter/widgets.dart';
-Widget build() {
-  return Center($0child: Text(''));
-}
-''';
-
-    setSnippetTextEditSupport();
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('refactor.flutter.wrap.center'),
-      title: 'Wrap with Center',
-    );
-  }
-
-  Future<void> test_logsExecution() async {
-    const content = '''
-import '[!dart:async!]';
-
-Future? f;
-''';
-
-    var action = await expectCodeActionLiteral(
-      content,
-      kind: CodeActionKind('refactor.add.showCombinator'),
-      title: "Add explicit 'show' combinator",
-    );
-
-    await executeCommand(action.command!);
-    expectCommandLogged('dart.assist.add.showCombinator');
-  }
-
-  Future<void> test_nonDartFile() async {
-    setSupportedCodeActionKinds([CodeActionKind.Refactor]);
-
-    createFile(pubspecFilePath, simplePubspecContent);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      pubspecFileUri,
-      range: startOfDocRange,
-    );
-    expect(codeActions, isEmpty);
-  }
-
   Future<void> test_plugin() async {
     failTestOnErrorDiagnostic = false;
 
@@ -345,242 +123,4 @@
       containsAllInOrder(['High', 'Convert to single quoted string', 'Low']),
     );
   }
-
-  Future<void> test_snippetTextEdits_multiEditGroup() async {
-    // As test_snippetTextEdits_singleEditGroup, but uses an assist that
-    // produces multiple linked edit groups.
-
-    const content = '''
-import 'package:flutter/widgets.dart';
-build() {
-  return Container(
-    child: Ro^w(
-      children: [
-        Text('111'),
-        Text('222'),
-        Container(),
-      ],
-    ),
-  );
-}
-''';
-
-    const expectedContent = r'''
-import 'package:flutter/widgets.dart';
-build() {
-  return Container(
-    child: ${1:widget}(
-      ${2:child}: Row(
-        children: [
-          Text('111'),
-          Text('222'),
-          Container(),
-        ],
-      ),
-    ),
-  );
-}
-''';
-
-    setSnippetTextEditSupport();
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('refactor.flutter.wrap.generic'),
-      title: 'Wrap with widget...',
-    );
-  }
-
-  Future<void> test_snippetTextEdits_singleEditGroup() async {
-    // This tests experimental support for including Snippets in TextEdits.
-    // https://github.com/rust-analyzer/rust-analyzer/blob/b35559a2460e7f0b2b79a7029db0c5d4e0acdb44/docs/dev/lsp-extensions.md#snippet-textedit
-    //
-    // This allows setting the cursor position/selection in TextEdits included
-    // in CodeActions, for example Flutter's "Wrap with widget" assist that
-    // should select the text "widget".
-
-    const content = '''
-import 'package:flutter/widgets.dart';
-build() {
-  return Container(
-    child: Row(
-      children: [^
-        Text('111'),
-        Text('222'),
-        Container(),
-      ],
-    ),
-  );
-}
-''';
-
-    // For testing, the snippet will be inserted literally into the text, as
-    // this requires some magic on the client. The expected text should
-    // therefore contain the snippets in the standard format.
-    const expectedContent = r'''
-import 'package:flutter/widgets.dart';
-build() {
-  return Container(
-    child: Row(
-      children: [
-        ${0:widget}(
-          children: [
-            Text('111'),
-            Text('222'),
-            Container(),
-          ],
-        ),
-      ],
-    ),
-  );
-}
-''';
-
-    setSnippetTextEditSupport();
-    var verifier = await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('refactor.flutter.wrap.generic'),
-      title: 'Wrap with widget...',
-    );
-
-    // Also ensure there was a single edit that was correctly marked
-    // as a SnippetTextEdit.
-    var textEdits =
-        extractTextDocumentEdits(verifier.edit.documentChanges!)
-            .expand((tde) => tde.edits)
-            .map(
-              (edit) => edit.map(
-                (e) => throw 'Expected SnippetTextEdit, got AnnotatedTextEdit',
-                (e) => e,
-                (e) => throw 'Expected SnippetTextEdit, got TextEdit',
-              ),
-            )
-            .toList();
-    expect(textEdits, hasLength(1));
-    expect(textEdits.first.insertTextFormat, equals(InsertTextFormat.Snippet));
-  }
-
-  Future<void> test_snippetTextEdits_unsupported() async {
-    // This tests experimental support for including Snippets in TextEdits
-    // is not active when the client capabilities do not advertise support for it.
-    // https://github.com/rust-analyzer/rust-analyzer/blob/b35559a2460e7f0b2b79a7029db0c5d4e0acdb44/docs/dev/lsp-extensions.md#snippet-textedit
-
-    const content = '''
-import 'package:flutter/widgets.dart';
-build() {
-  return Container(
-    child: Row(
-      children: [^
-        Text('111'),
-        Text('222'),
-        Container(),
-      ],
-    ),
-  );
-}
-''';
-
-    var assist = await expectCodeActionLiteral(
-      content,
-      kind: CodeActionKind('refactor.flutter.wrap.generic'),
-      title: 'Wrap with widget...',
-    );
-
-    // Extract just TextDocumentEdits, create/rename/delete are not relevant.
-    var edit = assist.edit!;
-    var textDocumentEdits = extractTextDocumentEdits(edit.documentChanges!);
-    var textEdits =
-        textDocumentEdits
-            .expand((tde) => tde.edits)
-            .map((edit) => edit.map((e) => e, (e) => e, (e) => e))
-            .toList();
-
-    // Ensure the edit does _not_ have a format of Snippet, nor does it include
-    // any $ characters that would indicate snippet text.
-    for (var edit in textEdits) {
-      expect(edit, isNot(TypeMatcher<SnippetTextEdit>()));
-      expect(edit.newText, isNot(contains(r'$')));
-    }
-  }
-
-  Future<void> test_sort() async {
-    setDocumentChangesSupport();
-    setSupportedCodeActionKinds([CodeActionKind.Refactor]);
-
-    var code = TestCode.parse('''
-import 'package:flutter/widgets.dart';
-
-build() => Contai^ner(child: Container());
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      position: code.position.position,
-    );
-    var codeActionTitles = codeActions.map((action) => action.title);
-
-    expect(
-      codeActionTitles,
-      containsAllInOrder([
-        // Check the ordering for two well-known assists that should always be
-        // sorted this way.
-        // https://github.com/Dart-Code/Dart-Code/issues/3646
-        'Wrap with widget...',
-        'Remove this widget',
-      ]),
-    );
-  }
-
-  Future<void> test_surround_editGroupsAndSelection() async {
-    const content = '''
-void f() {
-  [!print(0);!]
-}
-''';
-
-    const expectedContent = r'''
-void f() {
-  if (${1:condition}) {
-    print(0);
-  }$0
-}
-''';
-
-    setSnippetTextEditSupport();
-    var verifier = await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('refactor.surround.if'),
-      title: "Surround with 'if'",
-    );
-
-    // Also ensure there was a single edit that was correctly marked
-    // as a SnippetTextEdit.
-    var textEdits =
-        extractTextDocumentEdits(verifier.edit.documentChanges!)
-            .expand((tde) => tde.edits)
-            .map(
-              (edit) => edit.map(
-                (e) => throw 'Expected SnippetTextEdit, got AnnotatedTextEdit',
-                (e) => e,
-                (e) => throw 'Expected SnippetTextEdit, got TextEdit',
-              ),
-            )
-            .toList();
-    expect(textEdits, hasLength(1));
-    expect(textEdits.first.insertTextFormat, equals(InsertTextFormat.Snippet));
-  }
-}
-
-class _RawParams extends ToJsonable {
-  final String _json;
-
-  _RawParams(this._json);
-
-  @override
-  Object toJson() => jsonDecode(_json) as Object;
 }
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index 2c63d00..b4cfe67 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -2,25 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:async';
-
 import 'package:analysis_server/lsp_protocol/protocol.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/lsp/extensions/code_action.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
-import 'package:analyzer/src/dart/error/lint_codes.dart';
-import 'package:analyzer/src/lint/linter.dart';
-import 'package:analyzer/src/lint/registry.dart';
 import 'package:analyzer/src/test_utilities/test_code_format.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
-import 'package:linter/src/rules.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../lsp/code_actions_mixin.dart';
-import '../lsp/server_abstract.dart';
+import '../shared/shared_code_actions_fixes_tests.dart';
 import '../utils/test_code_extensions.dart';
+import 'code_actions_mixin.dart';
+import 'server_abstract.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -28,34 +22,21 @@
   });
 }
 
-/// A version of `camel_case_types` that is deprecated.
-class DeprecatedCamelCaseTypes extends LintRule {
-  static const LintCode code = LintCode(
-    'camel_case_types',
-    "The type name '{0}' isn't an UpperCamelCase identifier.",
-    correctionMessage:
-        'Try changing the name to follow the UpperCamelCase style.',
-    hasPublishedDocs: true,
-  );
-
-  DeprecatedCamelCaseTypes()
-    : super(
-        name: 'camel_case_types',
-        state: State.deprecated(),
-        description: '',
-      );
-
-  @override
-  LintCode get lintCode => code;
-}
-
 @reflectiveTest
 class FixesCodeActionsTest extends AbstractLspAnalysisServerTest
-    with LspSharedTestMixin, CodeActionsTestMixin {
+    with
+        LspSharedTestMixin,
+        CodeActionsTestMixin,
+        // Most tests are defined in a shared mixin.
+        SharedFixesCodeActionsTests {
   /// Helper to check plugin fixes for [filePath].
   ///
   /// Used to ensure that both Dart and non-Dart files fixes are returned.
   Future<void> checkPluginResults(String filePath) async {
+    // TODO(dantup): Abstract plugin support to the shared test interface so
+    //  that the plugin tests can also move to the shared mixins and run for
+    //  both servers.
+
     // This code should get a fix to replace 'foo' with 'bar'.'
     const content = '''
 [!foo!]
@@ -110,626 +91,6 @@
     );
   }
 
-  @override
-  void setUp() {
-    super.setUp();
-
-    // Fix tests are likely to have diagnostics that need fixing.
-    failTestOnErrorDiagnostic = false;
-
-    setApplyEditSupport();
-    setDocumentChangesSupport();
-    setSupportedCodeActionKinds([CodeActionKind.QuickFix]);
-
-    registerBuiltInFixGenerators();
-  }
-
-  Future<void> test_addImport_noPreference() async {
-    createFile(
-      pathContext.join(projectFolderPath, 'lib', 'class.dart'),
-      'class MyClass {}',
-    );
-
-    var code = TestCode.parse('''
-MyCla^ss? a;
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      position: code.position.position,
-    );
-    var codeActionTitles = codeActions.map((action) => action.title);
-
-    expect(
-      codeActionTitles,
-      // With no preference, server defaults to absolute.
-      containsAllInOrder([
-        "Import library 'package:test/class.dart'",
-        "Import library 'class.dart'",
-      ]),
-    );
-  }
-
-  Future<void> test_addImport_preferAbsolute() async {
-    _enableLints(['always_use_package_imports']);
-
-    createFile(
-      pathContext.join(projectFolderPath, 'lib', 'class.dart'),
-      'class MyClass {}',
-    );
-
-    var code = TestCode.parse('''
-MyCla^ss? a;
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      position: code.position.position,
-    );
-    var codeActionTitles = codeActions.map((action) => action.title);
-
-    expect(
-      codeActionTitles,
-      containsAllInOrder(["Import library 'package:test/class.dart'"]),
-    );
-  }
-
-  Future<void> test_addImport_preferRelative() async {
-    _enableLints(['prefer_relative_imports']);
-
-    createFile(
-      pathContext.join(projectFolderPath, 'lib', 'class.dart'),
-      'class MyClass {}',
-    );
-
-    var code = TestCode.parse('''
-MyCla^ss? a;
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      position: code.position.position,
-    );
-    var codeActionTitles = codeActions.map((action) => action.title);
-
-    expect(
-      codeActionTitles,
-      containsAllInOrder(["Import library 'class.dart'"]),
-    );
-  }
-
-  Future<void> test_analysisOptions() async {
-    registerLintRules();
-
-    // To ensure there's an associated code action, we manually deprecate an
-    // existing lint (`camel_case_types`) for the duration of this test.
-
-    // Fetch the "actual" lint so we can restore it after the test.
-    var camelCaseTypes = Registry.ruleRegistry.getRule('camel_case_types')!;
-
-    // Overwrite it.
-    Registry.ruleRegistry.registerLintRule(DeprecatedCamelCaseTypes());
-
-    // Now we can assume it will have an action associated...
-
-    try {
-      const content = r'''
-linter:
-  rules:
-    - prefer_is_empty
-    - [!camel_case_types!]
-    - lines_longer_than_80_chars
-''';
-
-      const expectedContent = r'''
-linter:
-  rules:
-    - prefer_is_empty
-    - lines_longer_than_80_chars
-''';
-
-      await verifyCodeActionLiteralEdits(
-        filePath: analysisOptionsPath,
-        content,
-        expectedContent,
-        kind: CodeActionKind('quickfix.removeLint'),
-        title: "Remove 'camel_case_types'",
-      );
-    } finally {
-      // Restore the "real" `camel_case_types`.
-      Registry.ruleRegistry.registerLintRule(camelCaseTypes);
-    }
-  }
-
-  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
-    // This code should get a fix to remove the unused import.
-    const content = '''
-import 'dart:async';
-[!import!] 'dart:convert';
-
-Future foo;
-''';
-
-    const expectedContent = '''
-import 'dart:async';
-
-Future foo;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.remove.unusedImport'),
-      title: 'Remove unused import',
-    );
-  }
-
-  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
-    // This code should get a fix to remove the unused import.
-    const content = '''
-import 'dart:async';
-[!import!] 'dart:convert';
-
-Future foo;
-''';
-
-    const expectedContent = '''
-import 'dart:async';
-
-Future foo;
-''';
-
-    setDocumentChangesSupport(false);
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.remove.unusedImport'),
-      title: 'Remove unused import',
-    );
-  }
-
-  Future<void> test_createFile() async {
-    const content = '''
-import '[!createFile.dart!]';
-''';
-
-    const expectedContent = '''
->>>>>>>>>> lib/createFile.dart created
-// TODO Implement this library.<<<<<<<<<<
-''';
-
-    setFileCreateSupport();
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.create.file'),
-      title: "Create file 'createFile.dart'",
-    );
-  }
-
-  Future<void> test_filtersCorrectly() async {
-    setSupportedCodeActionKinds([
-      CodeActionKind.QuickFix,
-      CodeActionKind.Refactor,
-    ]);
-
-    var code = TestCode.parse('''
-import 'dart:async';
-[!import!] 'dart:convert';
-
-Future foo;
-''');
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    ofKind(CodeActionKind kind) =>
-        getCodeActions(testFileUri, range: code.range.range, kinds: [kind]);
-
-    // The code above will return a 'quickfix.remove.unusedImport'.
-    expect(await ofKind(CodeActionKind.QuickFix), isNotEmpty);
-    expect(await ofKind(CodeActionKind('quickfix.remove')), isNotEmpty);
-    expect(await ofKind(CodeActionKind('quickfix.remove.foo')), isEmpty);
-    expect(await ofKind(CodeActionKind('quickfix.other')), isEmpty);
-    expect(await ofKind(CodeActionKind.Refactor), isEmpty);
-  }
-
-  Future<void> test_fixAll_logsExecution() async {
-    const content = '''
-void f(String a) {
-  [!print(a!!)!];
-  print(a!!);
-}
-''';
-
-    var action = await expectCodeActionLiteral(
-      content,
-      kind: CodeActionKind('quickfix.remove.nonNullAssertion.multi'),
-      title: "Remove '!'s in file",
-    );
-
-    await executeCommand(action.command!);
-    expectCommandLogged('dart.fix.remove.nonNullAssertion.multi');
-  }
-
-  Future<void> test_fixAll_notWhenNoBatchFix() async {
-    // Some fixes (for example 'create function foo') are not available in the
-    // batch processor, so should not generate fix-all-in-file fixes even if there
-    // are multiple instances.
-    var code = TestCode.parse('''
-var a = [!foo!]();
-var b = bar();
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var allFixes = await getCodeActions(testFileUri, range: code.range.range);
-
-    // Expect only the single-fix, there should be no apply-all.
-    expect(allFixes, hasLength(1));
-    var fixTitle = allFixes.first.map((f) => f.title, (f) => f.title);
-    expect(fixTitle, equals("Create function 'foo'"));
-  }
-
-  Future<void> test_fixAll_notWhenSingle() async {
-    const content = '''
-void f(String a) {
-  [!print(a!)!];
-}
-''';
-
-    await expectNoAction(
-      content,
-      kind: CodeActionKind('quickfix'),
-      title: "Remove '!'s in file",
-    );
-  }
-
-  /// Ensure the "fix all in file" action doesn't appear against an unfixable
-  /// item just because the diagnostic is also reported in a location that
-  /// is fixable.
-  ///
-  /// https://github.com/dart-lang/sdk/issues/53021
-  Future<void> test_fixAll_unfixable() async {
-    registerLintRules();
-    createFile(analysisOptionsPath, '''
-linter:
-  rules:
-    - non_constant_identifier_names
-    ''');
-
-    const content = '''
-/// This is unfixable because it's a top-level. It should not have a "fix all
-/// in file" action.
-var aaa_a^aa = '';
-
-void f() {
-  /// These are here to ensure there's > 1 instance of this diagnostic to
-  /// allow "fix all in file" to appear.
-  final bbb_bbb = 0;
-  final ccc_ccc = 0;
-}
-''';
-
-    await expectNoAction(
-      content,
-      kind: CodeActionKind('quickfix.rename.toCamelCase.multi'),
-      title: 'Rename to camel case everywhere in file',
-    );
-  }
-
-  Future<void> test_fixAll_whenMultiple() async {
-    const content = '''
-void f(String a) {
-  [!print(a!!)!];
-  print(a!!);
-}
-''';
-
-    const expectedContent = '''
-void f(String a) {
-  print(a);
-  print(a);
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.remove.nonNullAssertion.multi'),
-      title: "Remove '!'s in file",
-    );
-  }
-
-  Future<void> test_ignoreDiagnostic_afterOtherFixes() async {
-    var code = TestCode.parse('''
-void main() {
-  Uint8List inputBytes = Uin^t8List.fromList(List.filled(100000000, 0));
-}
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var position = code.position.position;
-    var range = Range(start: position, end: position);
-    var codeActions = await getCodeActions(testFileUri, range: range);
-    var codeActionKinds = codeActions.map(
-      (item) =>
-          item.map((literal) => literal.kind?.toString(), (command) => null),
-    );
-
-    expect(
-      codeActionKinds,
-      containsAllInOrder([
-        // Non-ignore fixes (order doesn't matter here, but this is what
-        // server produces).
-        'quickfix.create.class',
-        'quickfix.create.mixin',
-        'quickfix.create.localVariable',
-        'quickfix.remove.unusedLocalVariable',
-        // Ignore fixes last, with line sorted above file.
-        'quickfix.ignore.line',
-        'quickfix.ignore.file',
-      ]),
-    );
-  }
-
-  Future<void> test_ignoreDiagnosticForFile() async {
-    const content = '''
-// Header comment
-// Header comment
-// Header comment
-
-// This comment is attached to the below import
-import 'dart:async';
-[!import!] 'dart:convert';
-
-Future foo;
-''';
-
-    const expectedContent = '''
-// Header comment
-// Header comment
-// Header comment
-
-// ignore_for_file: unused_import
-
-// This comment is attached to the below import
-import 'dart:async';
-import 'dart:convert';
-
-Future foo;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.ignore.file'),
-      title: "Ignore 'unused_import' for the whole file",
-    );
-  }
-
-  Future<void> test_ignoreDiagnosticForLine() async {
-    const content = '''
-import 'dart:async';
-[!import!] 'dart:convert';
-
-Future foo;
-''';
-
-    const expectedContent = '''
-import 'dart:async';
-// ignore: unused_import
-import 'dart:convert';
-
-Future foo;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.ignore.line'),
-      title: "Ignore 'unused_import' for this line",
-    );
-  }
-
-  Future<void> test_logsExecution() async {
-    var code = TestCode.parse('''
-[!import!] 'dart:convert';
-''');
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      range: code.range.range,
-    );
-    var fixAction =
-        findCodeActionLiteral(
-          codeActions,
-          title: 'Remove unused import',
-          kind: CodeActionKind('quickfix.remove.unusedImport'),
-        )!;
-
-    await executeCommand(fixAction.command!);
-    expectCommandLogged('dart.fix.remove.unusedImport');
-  }
-
-  /// Repro for https://github.com/Dart-Code/Dart-Code/issues/4462.
-  ///
-  /// Original code only included a fix on its first error (which in this sample
-  /// is the opening brace) and not the whole range of the error.
-  Future<void> test_multilineError() async {
-    registerLintRules();
-    createFile(analysisOptionsPath, '''
-linter:
-  rules:
-    - prefer_expression_function_bodies
-    ''');
-
-    var code = TestCode.parse('''
-int foo() {
-  [!return!] 1;
-}
-    ''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      range: code.range.range,
-    );
-    var fixAction = findCodeActionLiteral(
-      codeActions,
-      title: 'Convert to expression body',
-      kind: CodeActionKind('quickfix.convert.toExpressionBody'),
-    );
-    expect(fixAction, isNotNull);
-  }
-
-  Future<void> test_noDuplicates_differentFix() async {
-    // For convenience, quick-fixes are usually returned for the entire line,
-    // though this can lead to duplicate entries (by title) when multiple
-    // diagnostics have their own fixes of the same type.
-    //
-    // Expect only the only one nearest to the start of the range to be returned.
-    var code = TestCode.parse('''
-void f() {
-  var a = [];
-  print(a!!);^
-}
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      position: code.position.position,
-    );
-    var removeNnaAction =
-        findCodeActionLiteral(
-          codeActions,
-          title: "Remove the '!'",
-          kind: CodeActionKind('quickfix.remove.nonNullAssertion'),
-        )!;
-
-    // Ensure the action is for the diagnostic on the second bang which was
-    // closest to the range requested.
-    var diagnostics = removeNnaAction.diagnostics;
-    var secondBangPos = positionFromOffset(code.code.indexOf('!);'), code.code);
-    expect(diagnostics, hasLength(1));
-    var diagStart = diagnostics!.first.range.start;
-    expect(diagStart, equals(secondBangPos));
-  }
-
-  Future<void> test_noDuplicates_sameFix() async {
-    var code = TestCode.parse('''
-var a = [Test, Test, Te[!!]st];
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      range: code.range.range,
-    );
-    var createClassAction =
-        findCodeActionLiteral(
-          codeActions,
-          title: "Create class 'Test'",
-          kind: CodeActionKind('quickfix.create.class'),
-        )!;
-
-    expect(createClassAction.diagnostics, hasLength(3));
-  }
-
-  Future<void> test_noDuplicates_withDocumentChangesSupport() async {
-    setApplyEditSupport();
-    setDocumentChangesSupport();
-    setSupportedCodeActionKinds([CodeActionKind.QuickFix]);
-
-    var code = TestCode.parse('''
-var a = [Test, Test, Te[!!]st];
-''');
-
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      testFileUri,
-      range: code.range.range,
-    );
-    var createClassActions =
-        findCodeActionLiteral(
-          codeActions,
-          title: "Create class 'Test'",
-          kind: CodeActionKind('quickfix.create.class'),
-        )!;
-
-    expect(createClassActions.diagnostics, hasLength(3));
-  }
-
-  Future<void> test_organizeImportsFix_namedOrganizeImports() async {
-    registerLintRules();
-    createFile(analysisOptionsPath, '''
-linter:
-  rules:
-    - directives_ordering
-    ''');
-
-    // This code should get a fix to sort the imports.
-    const content = '''
-import 'dart:io';
-[!import 'dart:async'!];
-
-Completer a;
-ProcessInfo b;
-''';
-
-    const expectedContent = '''
-import 'dart:async';
-import 'dart:io';
-
-Completer a;
-ProcessInfo b;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.organize.imports'),
-      title: 'Organize Imports',
-    );
-  }
-
-  Future<void> test_outsideRoot() async {
-    var otherFilePath = pathContext.normalize(
-      pathContext.join(projectFolderPath, '..', 'otherProject', 'foo.dart'),
-    );
-    var otherFileUri = pathContext.toUri(otherFilePath);
-    createFile(otherFilePath, 'bad code to create error');
-    await initializeServer();
-
-    var codeActions = await getCodeActions(
-      otherFileUri,
-      position: startOfDocPos,
-    );
-    expect(codeActions, isEmpty);
-  }
-
   Future<void> test_plugin_dart() async {
     if (!AnalysisServer.supportsPlugins) return;
     return await checkPluginResults(testFilePath);
@@ -784,117 +145,4 @@
       containsAllInOrder(['High', 'Remove unused import', 'Low']),
     );
   }
-
-  Future<void> test_pubspec() async {
-    const content = '^';
-
-    const expectedContent = r'''
-name: my_project
-''';
-
-    await verifyCodeActionLiteralEdits(
-      filePath: pubspecFilePath,
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.add.name'),
-      title: "Add 'name' key",
-    );
-  }
-
-  Future<void> test_snippets_createMethod_functionTypeNestedParameters() async {
-    const content = '''
-class A {
-  void a() => c^((cell) => cell.south);
-  void b() => c((cell) => cell.west);
-}
-''';
-
-    const expectedContent = r'''
-class A {
-  void a() => c((cell) => cell.south);
-  void b() => c((cell) => cell.west);
-
-  ${1:void} ${2:c}(${3:Function(dynamic cell)} ${4:param0}) {}
-}
-''';
-
-    setSnippetTextEditSupport();
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.create.method'),
-      title: "Create method 'c'",
-    );
-  }
-
-  /// Ensure braces aren't over-escaped in snippet choices.
-  /// https://github.com/dart-lang/sdk/issues/54403
-  Future<void> test_snippets_createMissingOverrides_recordBraces() async {
-    const content = '''
-abstract class A {
-  void m(Iterable<({int a, int b})> r);
-}
-
-class ^B extends A {}
-''';
-
-    const expectedContent = r'''
-abstract class A {
-  void m(Iterable<({int a, int b})> r);
-}
-
-class B extends A {
-  @override
-  void m(${1|Iterable<({int a\, int b})>,Object|} ${2:r}) {
-    // TODO: implement m$0
-  }
-}
-''';
-
-    setSnippetTextEditSupport();
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.create.missingOverrides'),
-      title: 'Create 1 missing override',
-    );
-  }
-
-  Future<void>
-  test_snippets_extractVariable_functionTypeNestedParameters() async {
-    const content = '''
-void f() {
-  useFunction(te^st);
-}
-
-useFunction(int g(a, b)) {}
-''';
-
-    const expectedContent = r'''
-void f() {
-  ${1:int Function(dynamic a, dynamic b)} ${2:test};
-  useFunction(test);
-}
-
-useFunction(int g(a, b)) {}
-''';
-
-    setSnippetTextEditSupport();
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      kind: CodeActionKind('quickfix.create.localVariable'),
-      title: "Create local variable 'test'",
-    );
-  }
-
-  void _enableLints(List<String> lintNames) {
-    registerLintRules();
-    var lintsYaml = lintNames.map((name) => '    - $name\n').join();
-    createFile(analysisOptionsPath, '''
-linter:
-  rules:
-$lintsYaml
-''');
-  }
 }
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index 5291422..024fa78 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -2,17 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:async';
-
 import 'package:analysis_server/lsp_protocol/protocol.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
-import 'package:analysis_server/src/lsp/handlers/commands/perform_refactor.dart';
-import 'package:analyzer/src/test_utilities/test_code_format.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../tool/lsp_spec/matchers.dart';
-import '../utils/test_code_extensions.dart';
+import '../shared/shared_code_actions_refactor_tests.dart';
 import 'code_actions_mixin.dart';
 import 'request_helpers_mixin.dart';
 import 'server_abstract.dart';
@@ -30,444 +25,23 @@
 }
 
 @reflectiveTest
-class ConvertGetterToMethodCodeActionsTest extends RefactorCodeActionsTest {
-  final refactorTitle = 'Convert Getter to Method';
-
-  Future<void> test_refactor() async {
-    const content = '''
-int get ^test => 42;
-void f() {
-  var a = test;
-  var b = test;
-}
-''';
-    const expectedContent = '''
-int test() => 42;
-void f() {
-  var a = test();
-  var b = test();
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: refactorTitle,
-    );
-  }
-
-  Future<void> test_setter_notAvailable() async {
-    const content = '''
-set ^a(String value) {}
-''';
-
-    await expectNoAction(
-      content,
-      command: Commands.performRefactor,
-      title: refactorTitle,
-    );
-  }
-}
+class ConvertGetterToMethodCodeActionsTest extends RefactorCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedConvertGetterToMethodRefactorCodeActionsTests {}
 
 @reflectiveTest
-class ConvertMethodToGetterCodeActionsTest extends RefactorCodeActionsTest {
-  final refactorTitle = 'Convert Method to Getter';
-
-  Future<void> test_constructor_notAvailable() async {
-    const content = '''
-class A {
-  ^A();
-}
-''';
-
-    await expectNoAction(
-      content,
-      command: Commands.performRefactor,
-      title: refactorTitle,
-    );
-  }
-
-  Future<void> test_refactor() async {
-    const content = '''
-int ^test() => 42;
-void f() {
-  var a = test();
-  var b = test();
-}
-''';
-    const expectedContent = '''
-int get test => 42;
-void f() {
-  var a = test;
-  var b = test;
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: refactorTitle,
-    );
-  }
-}
+class ConvertMethodToGetterCodeActionsTest extends RefactorCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedConvertMethodToGetterRefactorCodeActionsTests {}
 
 @reflectiveTest
 class ExtractMethodRefactorCodeActionsTest extends RefactorCodeActionsTest
-    with LspProgressNotificationsMixin {
-  final extractMethodTitle = 'Extract Method';
-
-  Future<void> test_appliesCorrectEdits() async {
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-    const expectedContent = '''
-void f() {
-  print('Test!');
-  newMethod();
-}
-
-void newMethod() {
-  print('Test!');
-}
-''';
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-  }
-
-  Future<void> test_cancelsInProgress() async {
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-    const expectedContent = '''
->>>>>>>>>> lib/test.dart
-void f() {
-  print('Test!');
-  newMethod();
-}
-
-void newMethod() {
-  print('Test!');
-}
-''';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-
-    // Respond to any applyEdit requests from the server with successful responses
-    // and capturing the last edit.
-    late WorkspaceEdit edit;
-    requestsFromServer.listen((request) {
-      if (request.method == Method.workspace_applyEdit) {
-        var params = ApplyWorkspaceEditParams.fromJson(
-          request.params as Map<String, Object?>,
-        );
-        edit = params.edit;
-        respondTo(request, ApplyWorkspaceEditResult(applied: true));
-      }
-    });
-
-    // Send two requests together.
-    var req1 = executeCommand(codeAction.command!);
-    var req2 = executeCommand(codeAction.command!);
-
-    // Expect the first will have cancelled the second.
-    await expectLater(
-      req1,
-      throwsA(
-        isResponseError(
-          ErrorCodes.RequestCancelled,
-          message:
-              'Another workspace/executeCommand request for a refactor was started',
-        ),
-      ),
-    );
-    await req2;
-
-    // Ensure applying the changes will give us the expected content.
-    verifyEdit(edit, expectedContent);
-  }
-
-  Future<void> test_contentModified() async {
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-      openTargetFile: true,
-    );
-
-    // Use a Completer to control when the refactor handler starts computing.
-    var completer = Completer<void>();
-    PerformRefactorCommandHandler.delayAfterResolveForTests = completer.future;
-    try {
-      // Send an edit request immediately after the refactor request.
-      var req1 = executeCommand(codeAction.command!);
-      var req2 = replaceFile(100, testFileUri, '// new test content');
-      completer.complete();
-
-      // Expect the first to fail because of the modified content.
-      await expectLater(
-        req1,
-        throwsA(isResponseError(ErrorCodes.ContentModified)),
-      );
-      await req2;
-    } finally {
-      // Ensure we never leave an incomplete future if anything above throws.
-      PerformRefactorCommandHandler.delayAfterResolveForTests = null;
-    }
-  }
-
-  Future<void> test_filtersCorrectly() async {
-    // Support everything (empty prefix matches all)
-    setSupportedCodeActionKinds([CodeActionKind.Empty]);
-
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-    var code = TestCode.parse(content);
-    createFile(testFilePath, code.code);
-    await initializeServer();
-
-    ofKind(CodeActionKind kind) =>
-        getCodeActions(testFileUri, range: code.range.range, kinds: [kind]);
-
-    // The code above will return a 'refactor.extract' (as well as some other
-    // refactors, but not rewrite).
-    expect(await ofKind(CodeActionKind.Refactor), isNotEmpty);
-    expect(await ofKind(CodeActionKind.RefactorExtract), isNotEmpty);
-    expect(await ofKind(CodeActionKind('refactor.extract.foo')), isEmpty);
-    expect(await ofKind(CodeActionKind.RefactorRewrite), isEmpty);
-  }
-
-  Future<void> test_generatesNames() async {
-    const content = '''
-Object? F() {
-  return Container([!Text('Test!')!]);
-}
-
-Object? Container(Object? text) => null;
-Object? Text(Object? text) => null;
-''';
-    const expectedContent = '''
-Object? F() {
-  return Container(text());
-}
-
-Object? text() => Text('Test!');
-
-Object? Container(Object? text) => null;
-Object? Text(Object? text) => null;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-  }
-
-  Future<void> test_invalidLocation() async {
-    const content = '''
-import 'dart:convert';
-^
-void f() {}
-''';
-
-    await expectNoAction(
-      content,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-  }
-
-  Future<void> test_invalidLocation_importPrefix() async {
-    const content = '''
-import 'dart:io' as io;
-
-i^o.File? a;
-''';
-
-    await expectNoAction(
-      content,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-  }
-
-  Future<void> test_logsAction() async {
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-
-    setDocumentChangesSupport(false);
-    var action = await expectCodeActionLiteral(
-      content,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-
-    await executeCommandForEdits(action.command!);
-    expectCommandLogged('dart.refactor.extract_method');
-  }
-
-  Future<void> test_progress_clientProvided() async {
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-    const expectedContent = '''
-void f() {
-  print('Test!');
-  newMethod();
-}
-
-void newMethod() {
-  print('Test!');
-}
-''';
-
-    // Expect begin/end progress updates without a create, since the
-    // token was supplied by us (the client).
-    expect(progressUpdates, emitsInOrder(['BEGIN', 'END']));
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-      commandWorkDoneToken: clientProvidedTestWorkDoneToken,
-    );
-  }
-
-  Future<void> test_progress_notSupported() async {
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-    const expectedContent = '''
-void f() {
-  print('Test!');
-  newMethod();
-}
-
-void newMethod() {
-  print('Test!');
-}
-''';
-
-    var didGetProgressNotifications = false;
-    progressUpdates.listen((_) => didGetProgressNotifications = true);
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-
-    expect(didGetProgressNotifications, isFalse);
-  }
-
-  Future<void> test_progress_serverGenerated() async {
-    const content = '''
-void f() {
-  print('Test!');
-  [!print('Test!');!]
-}
-''';
-    const expectedContent = '''
-void f() {
-  print('Test!');
-  newMethod();
-}
-
-void newMethod() {
-  print('Test!');
-}
-''';
-
-    // Expect create/begin/end progress updates, because in this case the server
-    // generates the token.
-    expect(progressUpdates, emitsInOrder(['CREATE', 'BEGIN', 'END']));
-
-    setWorkDoneProgressSupport();
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-  }
-
-  Future<void> test_validLocation_failsInitialValidation() async {
-    const content = '''
-f() {
-  var a = 0;
-  doFoo([!() => print(a)!]);
-  print(a);
-}
-
-void doFoo(void Function() a) => a();
-
-''';
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-    var command = codeAction.command!;
-
-    // Call the `refactor.validate` command with the same arguments.
-    // Clients that want validation behaviour will need to implement this
-    // themselves (via middleware).
-    var response = await executeCommand(
-      Command(
-        title: command.title,
-        command: Commands.validateRefactor,
-        arguments: command.arguments,
-      ),
-      decoder: ValidateRefactorResult.fromJson,
-    );
-
-    expect(response.valid, isFalse);
-    expect(
-      response.message,
-      contains('Cannot extract the closure as a method'),
-    );
-  }
-
+    with
+        LspProgressNotificationsMixin,
+        // Most tests are defined in a shared mixin.
+        SharedExtractMethodRefactorCodeActionsTests {
   /// Test if the client does not call refactor.validate it still gets a
   /// sensible `showMessage` call and not a failed request.
   Future<void> test_validLocation_failsInitialValidation_noValidation() async {
@@ -505,476 +79,37 @@
       contains('Cannot extract the closure as a method'),
     );
   }
-
-  Future<void> test_validLocation_passesInitialValidation() async {
-    const content = '''
-f() {
-  doFoo([!() => print(1)!]);
-}
-
-void doFoo(void Function() a) => a();
-
-''';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.performRefactor,
-      title: extractMethodTitle,
-    );
-    var command = codeAction.command!;
-
-    // Call the `Commands.validateRefactor` command with the same arguments.
-    // Clients that want validation behaviour will need to implement this
-    // themselves (via middleware).
-    var response = await executeCommand(
-      Command(
-        title: command.title,
-        command: Commands.validateRefactor,
-        arguments: command.arguments,
-      ),
-      decoder: ValidateRefactorResult.fromJson,
-    );
-
-    expect(response.valid, isTrue);
-    expect(response.message, isNull);
-  }
 }
 
 @reflectiveTest
-class ExtractVariableRefactorCodeActionsTest extends RefactorCodeActionsTest {
-  final convertMethodToGetterTitle = 'Convert Method to Getter';
-  final extractVariableTitle = 'Extract Local Variable';
-  final inlineMethodTitle = 'Inline Method';
-
-  Future<void> test_appliesCorrectEdits() async {
-    const content = '''
-void f() {
-  foo([!1 + 2!]);
-}
-
-void foo(int arg) {}
-''';
-    const expectedContent = '''
-void f() {
-  var arg = 1 + 2;
-  foo(arg);
-}
-
-void foo(int arg) {}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractVariableTitle,
-    );
-  }
-
-  Future<void> test_doesNotCreateNameConflicts() async {
-    const content = '''
-void f() {
-  var arg = "test";
-  foo([!1 + 2!]);
-}
-
-void foo(int arg) {}
-''';
-    const expectedContent = '''
-void f() {
-  var arg = "test";
-  var arg2 = 1 + 2;
-  foo(arg2);
-}
-
-void foo(int arg) {}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractVariableTitle,
-    );
-  }
-
-  Future<void> test_inlineMethod_function_startOfParameterList() async {
-    const content = '''
-test^(a, b) {
-  print(a);
-  print(b);
-}
-void f() {
-  test(1, 2);
-}
-''';
-    const expectedContent = '''
-void f() {
-  print(1);
-  print(2);
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: inlineMethodTitle,
-    );
-  }
-
-  Future<void> test_inlineMethod_function_startOfTypeParameterList() async {
-    const content = '''
-test^<T>(T a, T b) {
-  print(a);
-  print(b);
-}
-void f() {
-  test(1, 2);
-}
-''';
-    const expectedContent = '''
-void f() {
-  print(1);
-  print(2);
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: inlineMethodTitle,
-    );
-  }
-
-  Future<void> test_inlineMethod_method_startOfParameterList() async {
-    const content = '''
-class A {
-  test^(a, b) {
-    print(a);
-    print(b);
-  }
-  void f() {
-    test(1, 2);
-  }
-}
-''';
-    const expectedContent = '''
-class A {
-  void f() {
-    print(1);
-    print(2);
-  }
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: inlineMethodTitle,
-    );
-  }
-
-  Future<void> test_inlineMethod_method_startOfTypeParameterList() async {
-    const content = '''
-class A {
-  test^<T>(T a, T b) {
-    print(a);
-    print(b);
-  }
-  void f() {
-    test(1, 2);
-  }
-}
-''';
-    const expectedContent = '''
-class A {
-  void f() {
-    print(1);
-    print(2);
-  }
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: inlineMethodTitle,
-    );
-  }
-
-  Future<void> test_methodToGetter_function_startOfParameterList() async {
-    const content = '''
-int test^() => 42;
-''';
-    const expectedContent = '''
-int get test => 42;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: convertMethodToGetterTitle,
-    );
-  }
-
-  Future<void> test_methodToGetter_function_startOfTypeParameterList() async {
-    const content = '''
-int test^<T>() => 42;
-''';
-    const expectedContent = '''
-int get test<T> => 42;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: convertMethodToGetterTitle,
-    );
-  }
-
-  Future<void> test_methodToGetter_method_startOfParameterList() async {
-    const content = '''
-class A {
-  int test^() => 42;
-}
-''';
-    const expectedContent = '''
-class A {
-  int get test => 42;
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: convertMethodToGetterTitle,
-    );
-  }
-
-  Future<void> test_methodToGetter_method_startOfTypeParameterList() async {
-    const content = '''
-class A {
-  int test^<T>() => 42;
-}
-''';
-    const expectedContent = '''
-class A {
-  int get test<T> => 42;
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: convertMethodToGetterTitle,
-    );
-  }
-}
+class ExtractVariableRefactorCodeActionsTest extends RefactorCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedExtractVariableRefactorCodeActionsTests {}
 
 @reflectiveTest
-class ExtractWidgetRefactorCodeActionsTest extends RefactorCodeActionsTest {
-  final extractWidgetTitle = 'Extract Widget';
-
-  String get expectedNewWidgetConstructorDeclaration => '''
-const NewWidget({
-    super.key,
-  });
-''';
-
+class ExtractWidgetRefactorCodeActionsTest extends RefactorCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedExtractWidgetRefactorCodeActionsTests {
   @override
   void setUp() {
     super.setUp();
     writeTestPackageConfig(flutter: true);
   }
-
-  Future<void> test_appliesCorrectEdits() async {
-    const content = '''
-import 'package:flutter/material.dart';
-
-class MyWidget extends StatelessWidget {
-  @override
-  Widget build(BuildContext context) {
-    return new Row(
-      children: <Widget>[
-        new [!Column!](
-          children: <Widget>[
-            new Text('AAA'),
-            new Text('BBB'),
-          ],
-        ),
-        new Text('CCC'),
-        new Text('DDD'),
-      ],
-    );
-  }
-}
-''';
-    var expectedContent = '''
-import 'package:flutter/material.dart';
-
-class MyWidget extends StatelessWidget {
-  @override
-  Widget build(BuildContext context) {
-    return new Row(
-      children: <Widget>[
-        NewWidget(),
-        new Text('CCC'),
-        new Text('DDD'),
-      ],
-    );
-  }
-}
-
-class NewWidget extends StatelessWidget {
-  $expectedNewWidgetConstructorDeclaration
-  @override
-  Widget build(BuildContext context) {
-    return new Column(
-      children: <Widget>[
-        new Text('AAA'),
-        new Text('BBB'),
-      ],
-    );
-  }
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: extractWidgetTitle,
-      openTargetFile: true,
-    );
-  }
-
-  Future<void> test_invalidLocation() async {
-    const content = '''
-import 'dart:convert';
-^
-void f() {}
-''';
-
-    await expectNoAction(
-      content,
-      command: Commands.performRefactor,
-      title: extractWidgetTitle,
-    );
-  }
 }
 
 @reflectiveTest
-class InlineLocalVariableRefactorCodeActionsTest
-    extends RefactorCodeActionsTest {
-  final inlineVariableTitle = 'Inline Local Variable';
-
-  Future<void> test_appliesCorrectEdits() async {
-    const content = '''
-void f() {
-  var a^ = 1;
-  print(a);
-  print(a);
-  print(a);
-}
-''';
-    const expectedContent = '''
-void f() {
-  print(1);
-  print(1);
-  print(1);
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: inlineVariableTitle,
-      openTargetFile: true,
-    );
-  }
-}
+class InlineLocalVariableRefactorCodeActionsTest extends RefactorCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedInlineLocalVariableRefactorCodeActionsTests {}
 
 @reflectiveTest
-class InlineMethodRefactorCodeActionsTest extends RefactorCodeActionsTest {
-  final inlineMethodTitle = 'Inline Method';
-
-  Future<void> test_inlineAtCallSite() async {
-    const content = '''
-void foo1() {
-  ba^r();
-}
-
-void foo2() {
-  bar();
-}
-
-void bar() {
-  print('test');
-}
-''';
-    const expectedContent = '''
-void foo1() {
-  print('test');
-}
-
-void foo2() {
-  bar();
-}
-
-void bar() {
-  print('test');
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: inlineMethodTitle,
-    );
-  }
-
-  Future<void> test_inlineAtMethod() async {
-    const content = '''
-void foo1() {
-  bar();
-}
-
-void foo2() {
-  bar();
-}
-
-void ba^r() {
-  print('test');
-}
-''';
-    const expectedContent = '''
-void foo1() {
-  print('test');
-}
-
-void foo2() {
-  print('test');
-}
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.performRefactor,
-      title: inlineMethodTitle,
-    );
-  }
-}
+class InlineMethodRefactorCodeActionsTest extends RefactorCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedInlineMethodRefactorCodeActionsTests {}
 
 abstract class RefactorCodeActionsTest extends AbstractLspAnalysisServerTest
     with LspSharedTestMixin, CodeActionsTestMixin {
diff --git a/pkg/analysis_server/test/lsp/code_actions_source_test.dart b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
index 3e0e806..06ec5c0 100644
--- a/pkg/analysis_server/test/lsp/code_actions_source_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
@@ -11,7 +11,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../tool/lsp_spec/matchers.dart';
+import '../shared/shared_code_actions_source_tests.dart';
 import 'code_actions_mixin.dart';
 import 'server_abstract.dart';
 
@@ -360,308 +360,13 @@
 }
 
 @reflectiveTest
-class OrganizeImportsSourceCodeActionsTest
-    extends AbstractSourceCodeActionsTest {
-  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
-    const content = '''
-import 'dart:math';
-import 'dart:async';
-import 'dart:convert';
-
-Completer? foo;
-int minified(int x, int y) => min(x, y);
-''';
-    const expectedContent = '''
-import 'dart:async';
-import 'dart:math';
-
-Completer? foo;
-int minified(int x, int y) => min(x, y);
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.organizeImports,
-    );
-  }
-
-  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
-    const content = '''
-import 'dart:math';
-import 'dart:async';
-import 'dart:convert';
-
-Completer? foo;
-int minified(int x, int y) => min(x, y);
-''';
-    const expectedContent = '''
-import 'dart:async';
-import 'dart:math';
-
-Completer? foo;
-int minified(int x, int y) => min(x, y);
-''';
-
-    setDocumentChangesSupport(false);
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.organizeImports,
-    );
-  }
-
-  Future<void> test_availableAsCodeActionLiteral() async {
-    const content = '';
-
-    await expectCodeActionLiteral(content, command: Commands.organizeImports);
-  }
-
-  Future<void> test_availableAsCommand() async {
-    createFile(testFilePath, '');
-    setSupportedCodeActionKinds(null); // no codeActionLiteralSupport
-    await initializeServer();
-
-    var actions = await getCodeActions(testFileUri);
-    var action = findCommand(actions, Commands.organizeImports)!;
-    action.map(
-      (codeActionLiteral) => throw 'Expected command, got codeActionLiteral',
-      (command) {},
-    );
-  }
-
-  Future<void> test_fileHasErrors_failsSilentlyForAutomatic() async {
-    failTestOnErrorDiagnostic = false;
-    var content = 'invalid dart code';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.organizeImports,
-      triggerKind: CodeActionTriggerKind.Automatic,
-    );
-    var command = codeAction.command!;
-
-    // Expect a valid null result.
-    var response = await executeCommand(command);
-    expect(response, isNull);
-  }
-
-  Future<void> test_fileHasErrors_failsWithErrorForManual() async {
-    failTestOnErrorDiagnostic = false;
-    var content = 'invalid dart code';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.organizeImports,
-    );
-    var command = codeAction.command!;
-
-    // Ensure the request returned an error (error responses are thrown by
-    // the test helper to make consuming success results simpler).
-    await expectLater(
-      executeCommand(command),
-      throwsA(isResponseError(ServerErrorCodes.FileHasErrors)),
-    );
-  }
-
-  Future<void> test_filtersCorrectly() async {
-    createFile(testFilePath, '');
-    await initializeServer();
-
-    ofKind(CodeActionKind kind) => getCodeActions(testFileUri, kinds: [kind]);
-
-    expect(await ofKind(CodeActionKind.Source), hasLength(3));
-    expect(await ofKind(CodeActionKind.SourceOrganizeImports), hasLength(1));
-    expect(await ofKind(DartCodeActionKind.SortMembers), hasLength(1));
-    expect(await ofKind(DartCodeActionKind.FixAll), hasLength(1));
-    expect(await ofKind(CodeActionKind('source.foo')), isEmpty);
-    expect(await ofKind(CodeActionKind.Refactor), isEmpty);
-  }
-
-  Future<void> test_noEdits() async {
-    const content = '''
-import 'dart:async';
-import 'dart:math';
-
-Completer? foo;
-int minified(int x, int y) => min(x, y);
-''';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.organizeImports,
-    );
-    var command = codeAction.command!;
-
-    // Execute the command and it should return without needing us to process
-    // a workspace/applyEdit command because there were no edits.
-    var commandResponse = await executeCommand(command);
-    // Successful edits return an empty success() response.
-    expect(commandResponse, isNull);
-  }
-
-  Future<void> test_unavailableWhenNotRequested() async {
-    var content = '';
-
-    setSupportedCodeActionKinds([CodeActionKind.Refactor]); // not Source
-    await expectNoAction(content, command: Commands.organizeImports);
-  }
-
-  Future<void> test_unavailableWithoutApplyEditSupport() async {
-    var content = '';
-
-    setApplyEditSupport(false);
-    await expectNoAction(content, command: Commands.organizeImports);
-  }
-}
+class OrganizeImportsSourceCodeActionsTest extends AbstractSourceCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedOrganizeImportsSourceCodeActionsTests {}
 
 @reflectiveTest
-class SortMembersSourceCodeActionsTest extends AbstractSourceCodeActionsTest {
-  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
-    const content = '''
-String? b;
-String? a;
-''';
-    const expectedContent = '''
-String? a;
-String? b;
-''';
-
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.sortMembers,
-    );
-  }
-
-  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
-    const content = '''
-String? b;
-String? a;
-''';
-    const expectedContent = '''
-String? a;
-String? b;
-''';
-
-    setDocumentChangesSupport(false);
-    await verifyCodeActionLiteralEdits(
-      content,
-      expectedContent,
-      command: Commands.sortMembers,
-    );
-  }
-
-  Future<void> test_availableAsCodeActionLiteral() async {
-    const content = '';
-
-    await expectCodeActionLiteral(content, command: Commands.sortMembers);
-  }
-
-  Future<void> test_availableAsCommand() async {
-    createFile(testFilePath, '');
-    setSupportedCodeActionKinds(null); // no codeActionLiteralSupport
-    await initializeServer();
-
-    var actions = await getCodeActions(testFileUri);
-    var action = findCommand(actions, Commands.sortMembers)!;
-    action.map(
-      (codeActionLiteral) => throw 'Expected command, got codeActionLiteral',
-      (command) {},
-    );
-  }
-
-  Future<void> test_failsIfClientDoesntApplyEdits() async {
-    const content = '''
-String? b;
-String? a;
-''';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.sortMembers,
-    );
-    var command = codeAction.command!;
-
-    var commandResponse = handleExpectedRequest<
-      Object?,
-      ApplyWorkspaceEditParams,
-      ApplyWorkspaceEditResult
-    >(
-      Method.workspace_applyEdit,
-      ApplyWorkspaceEditParams.fromJson,
-      () => executeCommand(command),
-      // Claim that we failed tpo apply the edits. This is what the client
-      // would do if the edits provided were for an old version of the
-      // document.
-      handler:
-          (edit) => ApplyWorkspaceEditResult(
-            applied: false,
-            failureReason: 'Document changed',
-          ),
-    );
-
-    // Ensure the request returned an error (error responses are thrown by
-    // the test helper to make consuming success results simpler).
-    await expectLater(
-      commandResponse,
-      throwsA(isResponseError(ServerErrorCodes.ClientFailedToApplyEdit)),
-    );
-  }
-
-  Future<void> test_fileHasErrors_failsSilentlyForAutomatic() async {
-    failTestOnErrorDiagnostic = false;
-    var content = 'invalid dart code';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.sortMembers,
-      triggerKind: CodeActionTriggerKind.Automatic,
-    );
-    var command = codeAction.command!;
-
-    // Expect a valid null result.
-    var response = await executeCommand(command);
-    expect(response, isNull);
-  }
-
-  Future<void> test_fileHasErrors_failsWithErrorForManual() async {
-    failTestOnErrorDiagnostic = false;
-    var content = 'invalid dart code';
-
-    var codeAction = await expectCodeActionLiteral(
-      content,
-      command: Commands.sortMembers,
-    );
-    var command = codeAction.command!;
-
-    // Ensure the request returned an error (error responses are thrown by
-    // the test helper to make consuming success results simpler).
-    await expectLater(
-      executeCommand(command),
-      throwsA(isResponseError(ServerErrorCodes.FileHasErrors)),
-    );
-  }
-
-  Future<void> test_nonDartFile() async {
-    await expectNoAction(
-      filePath: pubspecFilePath,
-      simplePubspecContent,
-      command: Commands.sortMembers,
-    );
-  }
-
-  Future<void> test_unavailableWhenNotRequested() async {
-    var content = '';
-
-    setSupportedCodeActionKinds([CodeActionKind.Refactor]); // not Source
-    await expectNoAction(content, command: Commands.sortMembers);
-  }
-
-  Future<void> test_unavailableWithoutApplyEditSupport() async {
-    var content = '';
-
-    setApplyEditSupport(false);
-    await expectNoAction(content, command: Commands.sortMembers);
-  }
-}
+class SortMembersSourceCodeActionsTest extends AbstractSourceCodeActionsTest
+    with
+        // Most tests are defined in a shared mixin.
+        SharedSortMembersSourceCodeActionsTests {}
diff --git a/pkg/analysis_server/test/shared/shared_code_actions_assists_tests.dart b/pkg/analysis_server/test/shared/shared_code_actions_assists_tests.dart
new file mode 100644
index 0000000..3a4eb79
--- /dev/null
+++ b/pkg/analysis_server/test/shared/shared_code_actions_assists_tests.dart
@@ -0,0 +1,490 @@
+// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/extensions/code_action.dart';
+import 'package:analyzer/src/test_utilities/test_code_format.dart';
+import 'package:test/test.dart';
+
+import '../lsp/code_actions_mixin.dart';
+import '../lsp/request_helpers_mixin.dart';
+import '../lsp/server_abstract.dart';
+import '../utils/lsp_protocol_extensions.dart';
+import '../utils/test_code_extensions.dart';
+import 'shared_test_interface.dart';
+
+/// Shared tests used by both LSP + Legacy server tests and/or integration.
+mixin SharedAssistsCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
+    // This code should get an assist to add a show combinator.
+    const content = '''
+import '[!dart:async!]';
+
+Future? f;
+''';
+
+    const expectedContent = '''
+import 'dart:async' show Future;
+
+Future? f;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('refactor.add.showCombinator'),
+      title: "Add explicit 'show' combinator",
+    );
+  }
+
+  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
+    // This code should get an assist to add a show combinator.
+    const content = '''
+import '[!dart:async!]';
+
+Future? f;
+''';
+
+    const expectedContent = '''
+import 'dart:async' show Future;
+
+Future? f;
+''';
+
+    setDocumentChangesSupport(false);
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('refactor.add.showCombinator'),
+      title: "Add explicit 'show' combinator",
+    );
+  }
+
+  Future<void> test_codeActionLiterals_supported() async {
+    setSnippetTextEditSupport();
+    setSupportedCodeActionKinds([CodeActionKind.Refactor]);
+
+    var code = TestCode.parse('''
+import 'package:flutter/widgets.dart';
+Widget build() {
+  return Te^xt('');
+}
+''');
+
+    var action = await expectCodeAction(
+      code,
+      kind: CodeActionKind('refactor.flutter.wrap.center'),
+      title: 'Wrap with Center',
+    );
+
+    // Ensure we are a CodeAction literal.
+    expect(action.isCodeActionLiteral, true);
+
+    await verifyCodeActionEdits(action, r'''
+>>>>>>>>>> lib/test.dart
+import 'package:flutter/widgets.dart';
+Widget build() {
+  return Center($0child: Text(''));
+}
+''');
+  }
+
+  Future<void> test_codeActionLiterals_unsupported() async {
+    setSnippetTextEditSupport();
+    setSupportedCodeActionKinds(null); // no codeActionLiteralSupport
+
+    var code = TestCode.parse('''
+import 'package:flutter/widgets.dart';
+Widget build() {
+  return Te[!!]xt('');
+}
+''');
+
+    var action = await expectCodeAction(
+      openTargetFile: true, // Open document to verify we get a version back.
+      code,
+      title: 'Wrap with Center',
+      command: Commands.applyCodeAction,
+      commandArgs: [
+        {
+          'textDocument': {'uri': testFileUri.toString(), 'version': 1},
+          'range': code.range.range.toJson(),
+          'kind': 'refactor.flutter.wrap.center',
+          'loggedAction': 'dart.assist.flutter.wrap.center',
+        },
+      ],
+    );
+
+    // We don't support literals, so we expect the raw command instead.
+    expect(action.isCommand, true);
+    var command = action.asCommand;
+
+    // Verify that executing the command produces the correct edits (which will
+    // come back via `workspace/applyEdit`).
+    await verifyCommandEdits(command, r'''
+>>>>>>>>>> lib/test.dart
+import 'package:flutter/widgets.dart';
+Widget build() {
+  return Center($0child: Text(''));
+}
+''');
+
+    expectCommandLogged(Commands.applyCodeAction);
+    expectCommandLogged('dart.assist.flutter.wrap.center');
+  }
+
+  Future<void> test_errorMessage_invalidIntegers() async {
+    // A VS Code code coverage extension has been seen to use Number.MAX_VALUE
+    // for the character position and resulted in:
+    //
+    //     type 'double' is not a subtype of type 'int'
+    //
+    // This test ensures the error message for these invalid params is clearer,
+    // indicating this is not a valid (Dart) int.
+    // https://github.com/dart-lang/sdk/issues/42786
+
+    createFile(testFilePath, '');
+    await initializeServer();
+
+    var request = makeRequest(
+      Method.textDocument_codeAction,
+      _RawParams('''
+      {
+        "textDocument": {
+          "uri": "$testFileUri"
+        },
+        "context": {
+          "diagnostics": []
+        },
+        "range": {
+          "start": {
+            "line": 3,
+            "character": 2
+          },
+          "end": {
+            "line": 3,
+            "character": 1.7976931348623157e+308
+          }
+        }
+      }
+'''),
+    );
+    var resp = await sendRequestToServer(request);
+    var error = resp.error!;
+    expect(error.code, equals(ErrorCodes.InvalidParams));
+    expect(
+      error.message,
+      allOf([
+        contains('Invalid params for textDocument/codeAction'),
+        contains('params.range.end.character must be of type int'),
+      ]),
+    );
+  }
+
+  Future<void> test_flutterWrap_selection() async {
+    const content = '''
+import 'package:flutter/widgets.dart';
+Widget build() {
+  return Te^xt('');
+}
+''';
+
+    // For testing, the snippet will be inserted literally into the text, as
+    // this requires some magic on the client. The expected text should
+    // therefore contain '$0' at the location of the selection/final tabstop.
+    const expectedContent = r'''
+import 'package:flutter/widgets.dart';
+Widget build() {
+  return Center($0child: Text(''));
+}
+''';
+
+    setSnippetTextEditSupport();
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('refactor.flutter.wrap.center'),
+      title: 'Wrap with Center',
+    );
+  }
+
+  Future<void> test_logsExecution() async {
+    const content = '''
+import '[!dart:async!]';
+
+Future? f;
+''';
+
+    var action = await expectCodeActionLiteral(
+      content,
+      kind: CodeActionKind('refactor.add.showCombinator'),
+      title: "Add explicit 'show' combinator",
+    );
+
+    await executeCommand(action.command!);
+    expectCommandLogged('dart.assist.add.showCombinator');
+  }
+
+  Future<void> test_nonDartFile() async {
+    setSupportedCodeActionKinds([CodeActionKind.Refactor]);
+
+    createFile(pubspecFilePath, simplePubspecContent);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      pubspecFileUri,
+      range: startOfDocRange,
+    );
+    expect(codeActions, isEmpty);
+  }
+
+  Future<void> test_snippetTextEdits_multiEditGroup() async {
+    // As test_snippetTextEdits_singleEditGroup, but uses an assist that
+    // produces multiple linked edit groups.
+
+    const content = '''
+import 'package:flutter/widgets.dart';
+build() {
+  return Container(
+    child: Ro^w(
+      children: [
+        Text('111'),
+        Text('222'),
+        Container(),
+      ],
+    ),
+  );
+}
+''';
+
+    const expectedContent = r'''
+import 'package:flutter/widgets.dart';
+build() {
+  return Container(
+    child: ${1:widget}(
+      ${2:child}: Row(
+        children: [
+          Text('111'),
+          Text('222'),
+          Container(),
+        ],
+      ),
+    ),
+  );
+}
+''';
+
+    setSnippetTextEditSupport();
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('refactor.flutter.wrap.generic'),
+      title: 'Wrap with widget...',
+    );
+  }
+
+  Future<void> test_snippetTextEdits_singleEditGroup() async {
+    // This tests experimental support for including Snippets in TextEdits.
+    // https://github.com/rust-analyzer/rust-analyzer/blob/b35559a2460e7f0b2b79a7029db0c5d4e0acdb44/docs/dev/lsp-extensions.md#snippet-textedit
+    //
+    // This allows setting the cursor position/selection in TextEdits included
+    // in CodeActions, for example Flutter's "Wrap with widget" assist that
+    // should select the text "widget".
+
+    const content = '''
+import 'package:flutter/widgets.dart';
+build() {
+  return Container(
+    child: Row(
+      children: [^
+        Text('111'),
+        Text('222'),
+        Container(),
+      ],
+    ),
+  );
+}
+''';
+
+    // For testing, the snippet will be inserted literally into the text, as
+    // this requires some magic on the client. The expected text should
+    // therefore contain the snippets in the standard format.
+    const expectedContent = r'''
+import 'package:flutter/widgets.dart';
+build() {
+  return Container(
+    child: Row(
+      children: [
+        ${0:widget}(
+          children: [
+            Text('111'),
+            Text('222'),
+            Container(),
+          ],
+        ),
+      ],
+    ),
+  );
+}
+''';
+
+    setSnippetTextEditSupport();
+    var verifier = await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('refactor.flutter.wrap.generic'),
+      title: 'Wrap with widget...',
+    );
+
+    // Also ensure there was a single edit that was correctly marked
+    // as a SnippetTextEdit.
+    var textEdits =
+        extractTextDocumentEdits(verifier.edit.documentChanges!)
+            .expand((tde) => tde.edits)
+            .map(
+              (edit) => edit.map(
+                (e) => throw 'Expected SnippetTextEdit, got AnnotatedTextEdit',
+                (e) => e,
+                (e) => throw 'Expected SnippetTextEdit, got TextEdit',
+              ),
+            )
+            .toList();
+    expect(textEdits, hasLength(1));
+    expect(textEdits.first.insertTextFormat, equals(InsertTextFormat.Snippet));
+  }
+
+  Future<void> test_snippetTextEdits_unsupported() async {
+    // This tests experimental support for including Snippets in TextEdits
+    // is not active when the client capabilities do not advertise support for it.
+    // https://github.com/rust-analyzer/rust-analyzer/blob/b35559a2460e7f0b2b79a7029db0c5d4e0acdb44/docs/dev/lsp-extensions.md#snippet-textedit
+
+    const content = '''
+import 'package:flutter/widgets.dart';
+build() {
+  return Container(
+    child: Row(
+      children: [^
+        Text('111'),
+        Text('222'),
+        Container(),
+      ],
+    ),
+  );
+}
+''';
+
+    var assist = await expectCodeActionLiteral(
+      content,
+      kind: CodeActionKind('refactor.flutter.wrap.generic'),
+      title: 'Wrap with widget...',
+    );
+
+    // Extract just TextDocumentEdits, create/rename/delete are not relevant.
+    var edit = assist.edit!;
+    var textDocumentEdits = extractTextDocumentEdits(edit.documentChanges!);
+    var textEdits =
+        textDocumentEdits
+            .expand((tde) => tde.edits)
+            .map((edit) => edit.map((e) => e, (e) => e, (e) => e))
+            .toList();
+
+    // Ensure the edit does _not_ have a format of Snippet, nor does it include
+    // any $ characters that would indicate snippet text.
+    for (var edit in textEdits) {
+      expect(edit, isNot(TypeMatcher<SnippetTextEdit>()));
+      expect(edit.newText, isNot(contains(r'$')));
+    }
+  }
+
+  Future<void> test_sort() async {
+    setDocumentChangesSupport();
+    setSupportedCodeActionKinds([CodeActionKind.Refactor]);
+
+    var code = TestCode.parse('''
+import 'package:flutter/widgets.dart';
+
+build() => Contai^ner(child: Container());
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      position: code.position.position,
+    );
+    var codeActionTitles = codeActions.map((action) => action.title);
+
+    expect(
+      codeActionTitles,
+      containsAllInOrder([
+        // Check the ordering for two well-known assists that should always be
+        // sorted this way.
+        // https://github.com/Dart-Code/Dart-Code/issues/3646
+        'Wrap with widget...',
+        'Remove this widget',
+      ]),
+    );
+  }
+
+  Future<void> test_surround_editGroupsAndSelection() async {
+    const content = '''
+void f() {
+  [!print(0);!]
+}
+''';
+
+    const expectedContent = r'''
+void f() {
+  if (${1:condition}) {
+    print(0);
+  }$0
+}
+''';
+
+    setSnippetTextEditSupport();
+    var verifier = await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('refactor.surround.if'),
+      title: "Surround with 'if'",
+    );
+
+    // Also ensure there was a single edit that was correctly marked
+    // as a SnippetTextEdit.
+    var textEdits =
+        extractTextDocumentEdits(verifier.edit.documentChanges!)
+            .expand((tde) => tde.edits)
+            .map(
+              (edit) => edit.map(
+                (e) => throw 'Expected SnippetTextEdit, got AnnotatedTextEdit',
+                (e) => e,
+                (e) => throw 'Expected SnippetTextEdit, got TextEdit',
+              ),
+            )
+            .toList();
+    expect(textEdits, hasLength(1));
+    expect(textEdits.first.insertTextFormat, equals(InsertTextFormat.Snippet));
+  }
+}
+
+class _RawParams extends ToJsonable {
+  final String _json;
+
+  _RawParams(this._json);
+
+  @override
+  Object toJson() => jsonDecode(_json) as Object;
+}
diff --git a/pkg/analysis_server/test/shared/shared_code_actions_fixes_tests.dart b/pkg/analysis_server/test/shared/shared_code_actions_fixes_tests.dart
new file mode 100644
index 0000000..14c3a6c
--- /dev/null
+++ b/pkg/analysis_server/test/shared/shared_code_actions_fixes_tests.dart
@@ -0,0 +1,788 @@
+// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/src/lsp/extensions/code_action.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analyzer/src/dart/error/lint_codes.dart';
+import 'package:analyzer/src/lint/linter.dart';
+import 'package:analyzer/src/lint/registry.dart';
+import 'package:analyzer/src/test_utilities/test_code_format.dart';
+import 'package:linter/src/rules.dart';
+import 'package:test/test.dart';
+
+import '../lsp/code_actions_mixin.dart';
+import '../lsp/request_helpers_mixin.dart';
+import '../lsp/server_abstract.dart';
+import '../utils/test_code_extensions.dart';
+import 'shared_test_interface.dart';
+
+/// Shared tests used by both LSP + Legacy server tests and/or integration.
+mixin SharedFixesCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  String get analysisOptionsPath =>
+      pathContext.join(projectFolderPath, 'analysis_options.yaml');
+
+  @override
+  void setUp() {
+    super.setUp();
+
+    // Fix tests are likely to have diagnostics that need fixing.
+    failTestOnErrorDiagnostic = false;
+
+    setApplyEditSupport();
+    setDocumentChangesSupport();
+    setSupportedCodeActionKinds([CodeActionKind.QuickFix]);
+
+    registerBuiltInFixGenerators();
+  }
+
+  Future<void> test_addImport_noPreference() async {
+    createFile(
+      pathContext.join(projectFolderPath, 'lib', 'class.dart'),
+      'class MyClass {}',
+    );
+
+    var code = TestCode.parse('''
+MyCla^ss? a;
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      position: code.position.position,
+    );
+    var codeActionTitles = codeActions.map((action) => action.title);
+
+    expect(
+      codeActionTitles,
+      // With no preference, server defaults to absolute.
+      containsAllInOrder([
+        "Import library 'package:test/class.dart'",
+        "Import library 'class.dart'",
+      ]),
+    );
+  }
+
+  Future<void> test_addImport_preferAbsolute() async {
+    _enableLints(['always_use_package_imports']);
+
+    createFile(
+      pathContext.join(projectFolderPath, 'lib', 'class.dart'),
+      'class MyClass {}',
+    );
+
+    var code = TestCode.parse('''
+MyCla^ss? a;
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      position: code.position.position,
+    );
+    var codeActionTitles = codeActions.map((action) => action.title);
+
+    expect(
+      codeActionTitles,
+      containsAllInOrder(["Import library 'package:test/class.dart'"]),
+    );
+  }
+
+  Future<void> test_addImport_preferRelative() async {
+    _enableLints(['prefer_relative_imports']);
+
+    createFile(
+      pathContext.join(projectFolderPath, 'lib', 'class.dart'),
+      'class MyClass {}',
+    );
+
+    var code = TestCode.parse('''
+MyCla^ss? a;
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      position: code.position.position,
+    );
+    var codeActionTitles = codeActions.map((action) => action.title);
+
+    expect(
+      codeActionTitles,
+      containsAllInOrder(["Import library 'class.dart'"]),
+    );
+  }
+
+  Future<void> test_analysisOptions() async {
+    registerLintRules();
+
+    // To ensure there's an associated code action, we manually deprecate an
+    // existing lint (`camel_case_types`) for the duration of this test.
+
+    // Fetch the "actual" lint so we can restore it after the test.
+    var camelCaseTypes = Registry.ruleRegistry.getRule('camel_case_types')!;
+
+    // Overwrite it.
+    Registry.ruleRegistry.registerLintRule(_DeprecatedCamelCaseTypes());
+
+    // Now we can assume it will have an action associated...
+
+    try {
+      const content = r'''
+linter:
+  rules:
+    - prefer_is_empty
+    - [!camel_case_types!]
+    - lines_longer_than_80_chars
+''';
+
+      const expectedContent = r'''
+linter:
+  rules:
+    - prefer_is_empty
+    - lines_longer_than_80_chars
+''';
+
+      await verifyCodeActionLiteralEdits(
+        filePath: analysisOptionsPath,
+        content,
+        expectedContent,
+        kind: CodeActionKind('quickfix.removeLint'),
+        title: "Remove 'camel_case_types'",
+      );
+    } finally {
+      // Restore the "real" `camel_case_types`.
+      Registry.ruleRegistry.registerLintRule(camelCaseTypes);
+    }
+  }
+
+  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
+    // This code should get a fix to remove the unused import.
+    const content = '''
+import 'dart:async';
+[!import!] 'dart:convert';
+
+Future foo;
+''';
+
+    const expectedContent = '''
+import 'dart:async';
+
+Future foo;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.remove.unusedImport'),
+      title: 'Remove unused import',
+    );
+  }
+
+  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
+    // This code should get a fix to remove the unused import.
+    const content = '''
+import 'dart:async';
+[!import!] 'dart:convert';
+
+Future foo;
+''';
+
+    const expectedContent = '''
+import 'dart:async';
+
+Future foo;
+''';
+
+    setDocumentChangesSupport(false);
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.remove.unusedImport'),
+      title: 'Remove unused import',
+    );
+  }
+
+  Future<void> test_createFile() async {
+    const content = '''
+import '[!createFile.dart!]';
+''';
+
+    const expectedContent = '''
+>>>>>>>>>> lib/createFile.dart created
+// TODO Implement this library.<<<<<<<<<<
+''';
+
+    setFileCreateSupport();
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.create.file'),
+      title: "Create file 'createFile.dart'",
+    );
+  }
+
+  Future<void> test_filtersCorrectly() async {
+    setSupportedCodeActionKinds([
+      CodeActionKind.QuickFix,
+      CodeActionKind.Refactor,
+    ]);
+
+    var code = TestCode.parse('''
+import 'dart:async';
+[!import!] 'dart:convert';
+
+Future foo;
+''');
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    ofKind(CodeActionKind kind) =>
+        getCodeActions(testFileUri, range: code.range.range, kinds: [kind]);
+
+    // The code above will return a 'quickfix.remove.unusedImport'.
+    expect(await ofKind(CodeActionKind.QuickFix), isNotEmpty);
+    expect(await ofKind(CodeActionKind('quickfix.remove')), isNotEmpty);
+    expect(await ofKind(CodeActionKind('quickfix.remove.foo')), isEmpty);
+    expect(await ofKind(CodeActionKind('quickfix.other')), isEmpty);
+    expect(await ofKind(CodeActionKind.Refactor), isEmpty);
+  }
+
+  Future<void> test_fixAll_logsExecution() async {
+    const content = '''
+void f(String a) {
+  [!print(a!!)!];
+  print(a!!);
+}
+''';
+
+    var action = await expectCodeActionLiteral(
+      content,
+      kind: CodeActionKind('quickfix.remove.nonNullAssertion.multi'),
+      title: "Remove '!'s in file",
+    );
+
+    await executeCommand(action.command!);
+    expectCommandLogged('dart.fix.remove.nonNullAssertion.multi');
+  }
+
+  Future<void> test_fixAll_notWhenNoBatchFix() async {
+    // Some fixes (for example 'create function foo') are not available in the
+    // batch processor, so should not generate fix-all-in-file fixes even if there
+    // are multiple instances.
+    var code = TestCode.parse('''
+var a = [!foo!]();
+var b = bar();
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var allFixes = await getCodeActions(testFileUri, range: code.range.range);
+
+    // Expect only the single-fix, there should be no apply-all.
+    expect(allFixes, hasLength(1));
+    var fixTitle = allFixes.first.map((f) => f.title, (f) => f.title);
+    expect(fixTitle, equals("Create function 'foo'"));
+  }
+
+  Future<void> test_fixAll_notWhenSingle() async {
+    const content = '''
+void f(String a) {
+  [!print(a!)!];
+}
+''';
+
+    await expectNoAction(
+      content,
+      kind: CodeActionKind('quickfix'),
+      title: "Remove '!'s in file",
+    );
+  }
+
+  /// Ensure the "fix all in file" action doesn't appear against an unfixable
+  /// item just because the diagnostic is also reported in a location that
+  /// is fixable.
+  ///
+  /// https://github.com/dart-lang/sdk/issues/53021
+  Future<void> test_fixAll_unfixable() async {
+    registerLintRules();
+    createFile(analysisOptionsPath, '''
+linter:
+  rules:
+    - non_constant_identifier_names
+    ''');
+
+    const content = '''
+/// This is unfixable because it's a top-level. It should not have a "fix all
+/// in file" action.
+var aaa_a^aa = '';
+
+void f() {
+  /// These are here to ensure there's > 1 instance of this diagnostic to
+  /// allow "fix all in file" to appear.
+  final bbb_bbb = 0;
+  final ccc_ccc = 0;
+}
+''';
+
+    await expectNoAction(
+      content,
+      kind: CodeActionKind('quickfix.rename.toCamelCase.multi'),
+      title: 'Rename to camel case everywhere in file',
+    );
+  }
+
+  Future<void> test_fixAll_whenMultiple() async {
+    const content = '''
+void f(String a) {
+  [!print(a!!)!];
+  print(a!!);
+}
+''';
+
+    const expectedContent = '''
+void f(String a) {
+  print(a);
+  print(a);
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.remove.nonNullAssertion.multi'),
+      title: "Remove '!'s in file",
+    );
+  }
+
+  Future<void> test_ignoreDiagnostic_afterOtherFixes() async {
+    var code = TestCode.parse('''
+void main() {
+  Uint8List inputBytes = Uin^t8List.fromList(List.filled(100000000, 0));
+}
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var position = code.position.position;
+    var range = Range(start: position, end: position);
+    var codeActions = await getCodeActions(testFileUri, range: range);
+    var codeActionKinds = codeActions.map(
+      (item) =>
+          item.map((literal) => literal.kind?.toString(), (command) => null),
+    );
+
+    expect(
+      codeActionKinds,
+      containsAllInOrder([
+        // Non-ignore fixes (order doesn't matter here, but this is what
+        // server produces).
+        'quickfix.create.class',
+        'quickfix.create.mixin',
+        'quickfix.create.localVariable',
+        'quickfix.remove.unusedLocalVariable',
+        // Ignore fixes last, with line sorted above file.
+        'quickfix.ignore.line',
+        'quickfix.ignore.file',
+      ]),
+    );
+  }
+
+  Future<void> test_ignoreDiagnosticForFile() async {
+    const content = '''
+// Header comment
+// Header comment
+// Header comment
+
+// This comment is attached to the below import
+import 'dart:async';
+[!import!] 'dart:convert';
+
+Future foo;
+''';
+
+    const expectedContent = '''
+// Header comment
+// Header comment
+// Header comment
+
+// ignore_for_file: unused_import
+
+// This comment is attached to the below import
+import 'dart:async';
+import 'dart:convert';
+
+Future foo;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.ignore.file'),
+      title: "Ignore 'unused_import' for the whole file",
+    );
+  }
+
+  Future<void> test_ignoreDiagnosticForLine() async {
+    const content = '''
+import 'dart:async';
+[!import!] 'dart:convert';
+
+Future foo;
+''';
+
+    const expectedContent = '''
+import 'dart:async';
+// ignore: unused_import
+import 'dart:convert';
+
+Future foo;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.ignore.line'),
+      title: "Ignore 'unused_import' for this line",
+    );
+  }
+
+  Future<void> test_logsExecution() async {
+    var code = TestCode.parse('''
+[!import!] 'dart:convert';
+''');
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      range: code.range.range,
+    );
+    var fixAction =
+        findCodeActionLiteral(
+          codeActions,
+          title: 'Remove unused import',
+          kind: CodeActionKind('quickfix.remove.unusedImport'),
+        )!;
+
+    await executeCommand(fixAction.command!);
+    expectCommandLogged('dart.fix.remove.unusedImport');
+  }
+
+  /// Repro for https://github.com/Dart-Code/Dart-Code/issues/4462.
+  ///
+  /// Original code only included a fix on its first error (which in this sample
+  /// is the opening brace) and not the whole range of the error.
+  Future<void> test_multilineError() async {
+    registerLintRules();
+    createFile(analysisOptionsPath, '''
+linter:
+  rules:
+    - prefer_expression_function_bodies
+    ''');
+
+    var code = TestCode.parse('''
+int foo() {
+  [!return!] 1;
+}
+    ''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      range: code.range.range,
+    );
+    var fixAction = findCodeActionLiteral(
+      codeActions,
+      title: 'Convert to expression body',
+      kind: CodeActionKind('quickfix.convert.toExpressionBody'),
+    );
+    expect(fixAction, isNotNull);
+  }
+
+  Future<void> test_noDuplicates_differentFix() async {
+    // For convenience, quick-fixes are usually returned for the entire line,
+    // though this can lead to duplicate entries (by title) when multiple
+    // diagnostics have their own fixes of the same type.
+    //
+    // Expect only the only one nearest to the start of the range to be returned.
+    var code = TestCode.parse('''
+void f() {
+  var a = [];
+  print(a!!);^
+}
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      position: code.position.position,
+    );
+    var removeNnaAction =
+        findCodeActionLiteral(
+          codeActions,
+          title: "Remove the '!'",
+          kind: CodeActionKind('quickfix.remove.nonNullAssertion'),
+        )!;
+
+    // Ensure the action is for the diagnostic on the second bang which was
+    // closest to the range requested.
+    var diagnostics = removeNnaAction.diagnostics;
+    var secondBangPos = positionFromOffset(code.code.indexOf('!);'), code.code);
+    expect(diagnostics, hasLength(1));
+    var diagStart = diagnostics!.first.range.start;
+    expect(diagStart, equals(secondBangPos));
+  }
+
+  Future<void> test_noDuplicates_sameFix() async {
+    var code = TestCode.parse('''
+var a = [Test, Test, Te[!!]st];
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      range: code.range.range,
+    );
+    var createClassAction =
+        findCodeActionLiteral(
+          codeActions,
+          title: "Create class 'Test'",
+          kind: CodeActionKind('quickfix.create.class'),
+        )!;
+
+    expect(createClassAction.diagnostics, hasLength(3));
+  }
+
+  Future<void> test_noDuplicates_withDocumentChangesSupport() async {
+    setApplyEditSupport();
+    setDocumentChangesSupport();
+    setSupportedCodeActionKinds([CodeActionKind.QuickFix]);
+
+    var code = TestCode.parse('''
+var a = [Test, Test, Te[!!]st];
+''');
+
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      testFileUri,
+      range: code.range.range,
+    );
+    var createClassActions =
+        findCodeActionLiteral(
+          codeActions,
+          title: "Create class 'Test'",
+          kind: CodeActionKind('quickfix.create.class'),
+        )!;
+
+    expect(createClassActions.diagnostics, hasLength(3));
+  }
+
+  Future<void> test_organizeImportsFix_namedOrganizeImports() async {
+    registerLintRules();
+    createFile(analysisOptionsPath, '''
+linter:
+  rules:
+    - directives_ordering
+    ''');
+
+    // This code should get a fix to sort the imports.
+    const content = '''
+import 'dart:io';
+[!import 'dart:async'!];
+
+Completer a;
+ProcessInfo b;
+''';
+
+    const expectedContent = '''
+import 'dart:async';
+import 'dart:io';
+
+Completer a;
+ProcessInfo b;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.organize.imports'),
+      title: 'Organize Imports',
+    );
+  }
+
+  Future<void> test_outsideRoot() async {
+    var otherFilePath = pathContext.normalize(
+      pathContext.join(projectFolderPath, '..', 'otherProject', 'foo.dart'),
+    );
+    var otherFileUri = pathContext.toUri(otherFilePath);
+    createFile(otherFilePath, 'bad code to create error');
+    await initializeServer();
+
+    var codeActions = await getCodeActions(
+      otherFileUri,
+      position: startOfDocPos,
+    );
+    expect(codeActions, isEmpty);
+  }
+
+  Future<void> test_pubspec() async {
+    const content = '^';
+
+    const expectedContent = r'''
+name: my_project
+''';
+
+    await verifyCodeActionLiteralEdits(
+      filePath: pubspecFilePath,
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.add.name'),
+      title: "Add 'name' key",
+    );
+  }
+
+  Future<void> test_snippets_createMethod_functionTypeNestedParameters() async {
+    const content = '''
+class A {
+  void a() => c^((cell) => cell.south);
+  void b() => c((cell) => cell.west);
+}
+''';
+
+    const expectedContent = r'''
+class A {
+  void a() => c((cell) => cell.south);
+  void b() => c((cell) => cell.west);
+
+  ${1:void} ${2:c}(${3:Function(dynamic cell)} ${4:param0}) {}
+}
+''';
+
+    setSnippetTextEditSupport();
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.create.method'),
+      title: "Create method 'c'",
+    );
+  }
+
+  /// Ensure braces aren't over-escaped in snippet choices.
+  /// https://github.com/dart-lang/sdk/issues/54403
+  Future<void> test_snippets_createMissingOverrides_recordBraces() async {
+    const content = '''
+abstract class A {
+  void m(Iterable<({int a, int b})> r);
+}
+
+class ^B extends A {}
+''';
+
+    const expectedContent = r'''
+abstract class A {
+  void m(Iterable<({int a, int b})> r);
+}
+
+class B extends A {
+  @override
+  void m(${1|Iterable<({int a\, int b})>,Object|} ${2:r}) {
+    // TODO: implement m$0
+  }
+}
+''';
+
+    setSnippetTextEditSupport();
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.create.missingOverrides'),
+      title: 'Create 1 missing override',
+    );
+  }
+
+  Future<void>
+  test_snippets_extractVariable_functionTypeNestedParameters() async {
+    const content = '''
+void f() {
+  useFunction(te^st);
+}
+
+useFunction(int g(a, b)) {}
+''';
+
+    const expectedContent = r'''
+void f() {
+  ${1:int Function(dynamic a, dynamic b)} ${2:test};
+  useFunction(test);
+}
+
+useFunction(int g(a, b)) {}
+''';
+
+    setSnippetTextEditSupport();
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      kind: CodeActionKind('quickfix.create.localVariable'),
+      title: "Create local variable 'test'",
+    );
+  }
+
+  void _enableLints(List<String> lintNames) {
+    registerLintRules();
+    var lintsYaml = lintNames.map((name) => '    - $name\n').join();
+    createFile(analysisOptionsPath, '''
+linter:
+  rules:
+$lintsYaml
+''');
+  }
+}
+
+/// A version of `camel_case_types` that is deprecated.
+class _DeprecatedCamelCaseTypes extends LintRule {
+  static const LintCode code = LintCode(
+    'camel_case_types',
+    "The type name '{0}' isn't an UpperCamelCase identifier.",
+    correctionMessage:
+        'Try changing the name to follow the UpperCamelCase style.',
+    hasPublishedDocs: true,
+  );
+
+  _DeprecatedCamelCaseTypes()
+    : super(
+        name: 'camel_case_types',
+        state: State.deprecated(),
+        description: '',
+      );
+
+  @override
+  LintCode get lintCode => code;
+}
diff --git a/pkg/analysis_server/test/shared/shared_code_actions_refactor_tests.dart b/pkg/analysis_server/test/shared/shared_code_actions_refactor_tests.dart
new file mode 100644
index 0000000..6317671
--- /dev/null
+++ b/pkg/analysis_server/test/shared/shared_code_actions_refactor_tests.dart
@@ -0,0 +1,962 @@
+// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/handlers/commands/perform_refactor.dart';
+import 'package:analyzer/src/test_utilities/test_code_format.dart';
+import 'package:test/test.dart';
+
+import '../lsp/code_actions_mixin.dart';
+import '../lsp/request_helpers_mixin.dart';
+import '../lsp/server_abstract.dart';
+import '../tool/lsp_spec/matchers.dart';
+import '../utils/test_code_extensions.dart';
+import 'shared_test_interface.dart';
+
+mixin SharedConvertGetterToMethodRefactorCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  final refactorTitle = 'Convert Getter to Method';
+
+  Future<void> test_refactor() async {
+    const content = '''
+int get ^test => 42;
+void f() {
+  var a = test;
+  var b = test;
+}
+''';
+    const expectedContent = '''
+int test() => 42;
+void f() {
+  var a = test();
+  var b = test();
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: refactorTitle,
+    );
+  }
+
+  Future<void> test_setter_notAvailable() async {
+    const content = '''
+set ^a(String value) {}
+''';
+
+    await expectNoAction(
+      content,
+      command: Commands.performRefactor,
+      title: refactorTitle,
+    );
+  }
+}
+
+mixin SharedConvertMethodToGetterRefactorCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  final refactorTitle = 'Convert Method to Getter';
+
+  Future<void> test_constructor_notAvailable() async {
+    const content = '''
+class A {
+  ^A();
+}
+''';
+
+    await expectNoAction(
+      content,
+      command: Commands.performRefactor,
+      title: refactorTitle,
+    );
+  }
+
+  Future<void> test_refactor() async {
+    const content = '''
+int ^test() => 42;
+void f() {
+  var a = test();
+  var b = test();
+}
+''';
+    const expectedContent = '''
+int get test => 42;
+void f() {
+  var a = test;
+  var b = test;
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: refactorTitle,
+    );
+  }
+}
+
+mixin SharedExtractMethodRefactorCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin,
+        LspProgressNotificationsMixin {
+  final extractMethodTitle = 'Extract Method';
+
+  Future<void> test_appliesCorrectEdits() async {
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+    const expectedContent = '''
+void f() {
+  print('Test!');
+  newMethod();
+}
+
+void newMethod() {
+  print('Test!');
+}
+''';
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+  }
+
+  Future<void> test_cancelsInProgress() async {
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+    const expectedContent = '''
+>>>>>>>>>> lib/test.dart
+void f() {
+  print('Test!');
+  newMethod();
+}
+
+void newMethod() {
+  print('Test!');
+}
+''';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+
+    // Respond to any applyEdit requests from the server with successful responses
+    // and capturing the last edit.
+    late WorkspaceEdit edit;
+    requestsFromServer.listen((request) {
+      if (request.method == Method.workspace_applyEdit) {
+        var params = ApplyWorkspaceEditParams.fromJson(
+          request.params as Map<String, Object?>,
+        );
+        edit = params.edit;
+        respondTo(request, ApplyWorkspaceEditResult(applied: true));
+      }
+    });
+
+    // Send two requests together.
+    var req1 = executeCommand(codeAction.command!);
+    var req2 = executeCommand(codeAction.command!);
+
+    // Expect the first will have cancelled the second.
+    await expectLater(
+      req1,
+      throwsA(
+        isResponseError(
+          ErrorCodes.RequestCancelled,
+          message:
+              'Another workspace/executeCommand request for a refactor was started',
+        ),
+      ),
+    );
+    await req2;
+
+    // Ensure applying the changes will give us the expected content.
+    verifyEdit(edit, expectedContent);
+  }
+
+  Future<void> test_contentModified() async {
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+      openTargetFile: true,
+    );
+
+    // Use a Completer to control when the refactor handler starts computing.
+    var completer = Completer<void>();
+    PerformRefactorCommandHandler.delayAfterResolveForTests = completer.future;
+    try {
+      // Send an edit request immediately after the refactor request.
+      var req1 = executeCommand(codeAction.command!);
+      var req2 = replaceFile(100, testFileUri, '// new test content');
+      completer.complete();
+
+      // Expect the first to fail because of the modified content.
+      await expectLater(
+        req1,
+        throwsA(isResponseError(ErrorCodes.ContentModified)),
+      );
+      await req2;
+    } finally {
+      // Ensure we never leave an incomplete future if anything above throws.
+      PerformRefactorCommandHandler.delayAfterResolveForTests = null;
+    }
+  }
+
+  Future<void> test_filtersCorrectly() async {
+    // Support everything (empty prefix matches all)
+    setSupportedCodeActionKinds([CodeActionKind.Empty]);
+
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+    var code = TestCode.parse(content);
+    createFile(testFilePath, code.code);
+    await initializeServer();
+
+    ofKind(CodeActionKind kind) =>
+        getCodeActions(testFileUri, range: code.range.range, kinds: [kind]);
+
+    // The code above will return a 'refactor.extract' (as well as some other
+    // refactors, but not rewrite).
+    expect(await ofKind(CodeActionKind.Refactor), isNotEmpty);
+    expect(await ofKind(CodeActionKind.RefactorExtract), isNotEmpty);
+    expect(await ofKind(CodeActionKind('refactor.extract.foo')), isEmpty);
+    expect(await ofKind(CodeActionKind.RefactorRewrite), isEmpty);
+  }
+
+  Future<void> test_generatesNames() async {
+    const content = '''
+Object? F() {
+  return Container([!Text('Test!')!]);
+}
+
+Object? Container(Object? text) => null;
+Object? Text(Object? text) => null;
+''';
+    const expectedContent = '''
+Object? F() {
+  return Container(text());
+}
+
+Object? text() => Text('Test!');
+
+Object? Container(Object? text) => null;
+Object? Text(Object? text) => null;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+  }
+
+  Future<void> test_invalidLocation() async {
+    const content = '''
+import 'dart:convert';
+^
+void f() {}
+''';
+
+    await expectNoAction(
+      content,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+  }
+
+  Future<void> test_invalidLocation_importPrefix() async {
+    const content = '''
+import 'dart:io' as io;
+
+i^o.File? a;
+''';
+
+    await expectNoAction(
+      content,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+  }
+
+  Future<void> test_logsAction() async {
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+
+    setDocumentChangesSupport(false);
+    var action = await expectCodeActionLiteral(
+      content,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+
+    await executeCommandForEdits(action.command!);
+    expectCommandLogged('dart.refactor.extract_method');
+  }
+
+  Future<void> test_progress_clientProvided() async {
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+    const expectedContent = '''
+void f() {
+  print('Test!');
+  newMethod();
+}
+
+void newMethod() {
+  print('Test!');
+}
+''';
+
+    // Expect begin/end progress updates without a create, since the
+    // token was supplied by us (the client).
+    expect(progressUpdates, emitsInOrder(['BEGIN', 'END']));
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+      commandWorkDoneToken: clientProvidedTestWorkDoneToken,
+    );
+  }
+
+  Future<void> test_progress_notSupported() async {
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+    const expectedContent = '''
+void f() {
+  print('Test!');
+  newMethod();
+}
+
+void newMethod() {
+  print('Test!');
+}
+''';
+
+    var didGetProgressNotifications = false;
+    progressUpdates.listen((_) => didGetProgressNotifications = true);
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+
+    expect(didGetProgressNotifications, isFalse);
+  }
+
+  Future<void> test_progress_serverGenerated() async {
+    const content = '''
+void f() {
+  print('Test!');
+  [!print('Test!');!]
+}
+''';
+    const expectedContent = '''
+void f() {
+  print('Test!');
+  newMethod();
+}
+
+void newMethod() {
+  print('Test!');
+}
+''';
+
+    // Expect create/begin/end progress updates, because in this case the server
+    // generates the token.
+    expect(progressUpdates, emitsInOrder(['CREATE', 'BEGIN', 'END']));
+
+    setWorkDoneProgressSupport();
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+  }
+
+  Future<void> test_validLocation_failsInitialValidation() async {
+    const content = '''
+f() {
+  var a = 0;
+  doFoo([!() => print(a)!]);
+  print(a);
+}
+
+void doFoo(void Function() a) => a();
+
+''';
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+    var command = codeAction.command!;
+
+    // Call the `refactor.validate` command with the same arguments.
+    // Clients that want validation behaviour will need to implement this
+    // themselves (via middleware).
+    var response = await executeCommand(
+      Command(
+        title: command.title,
+        command: Commands.validateRefactor,
+        arguments: command.arguments,
+      ),
+      decoder: ValidateRefactorResult.fromJson,
+    );
+
+    expect(response.valid, isFalse);
+    expect(
+      response.message,
+      contains('Cannot extract the closure as a method'),
+    );
+  }
+
+  Future<void> test_validLocation_passesInitialValidation() async {
+    const content = '''
+f() {
+  doFoo([!() => print(1)!]);
+}
+
+void doFoo(void Function() a) => a();
+
+''';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.performRefactor,
+      title: extractMethodTitle,
+    );
+    var command = codeAction.command!;
+
+    // Call the `Commands.validateRefactor` command with the same arguments.
+    // Clients that want validation behaviour will need to implement this
+    // themselves (via middleware).
+    var response = await executeCommand(
+      Command(
+        title: command.title,
+        command: Commands.validateRefactor,
+        arguments: command.arguments,
+      ),
+      decoder: ValidateRefactorResult.fromJson,
+    );
+
+    expect(response.valid, isTrue);
+    expect(response.message, isNull);
+  }
+}
+
+mixin SharedExtractVariableRefactorCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  final convertMethodToGetterTitle = 'Convert Method to Getter';
+  final extractVariableTitle = 'Extract Local Variable';
+  final inlineMethodTitle = 'Inline Method';
+
+  Future<void> test_appliesCorrectEdits() async {
+    const content = '''
+void f() {
+  foo([!1 + 2!]);
+}
+
+void foo(int arg) {}
+''';
+    const expectedContent = '''
+void f() {
+  var arg = 1 + 2;
+  foo(arg);
+}
+
+void foo(int arg) {}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractVariableTitle,
+    );
+  }
+
+  Future<void> test_doesNotCreateNameConflicts() async {
+    const content = '''
+void f() {
+  var arg = "test";
+  foo([!1 + 2!]);
+}
+
+void foo(int arg) {}
+''';
+    const expectedContent = '''
+void f() {
+  var arg = "test";
+  var arg2 = 1 + 2;
+  foo(arg2);
+}
+
+void foo(int arg) {}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractVariableTitle,
+    );
+  }
+
+  Future<void> test_inlineMethod_function_startOfParameterList() async {
+    const content = '''
+test^(a, b) {
+  print(a);
+  print(b);
+}
+void f() {
+  test(1, 2);
+}
+''';
+    const expectedContent = '''
+void f() {
+  print(1);
+  print(2);
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: inlineMethodTitle,
+    );
+  }
+
+  Future<void> test_inlineMethod_function_startOfTypeParameterList() async {
+    const content = '''
+test^<T>(T a, T b) {
+  print(a);
+  print(b);
+}
+void f() {
+  test(1, 2);
+}
+''';
+    const expectedContent = '''
+void f() {
+  print(1);
+  print(2);
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: inlineMethodTitle,
+    );
+  }
+
+  Future<void> test_inlineMethod_method_startOfParameterList() async {
+    const content = '''
+class A {
+  test^(a, b) {
+    print(a);
+    print(b);
+  }
+  void f() {
+    test(1, 2);
+  }
+}
+''';
+    const expectedContent = '''
+class A {
+  void f() {
+    print(1);
+    print(2);
+  }
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: inlineMethodTitle,
+    );
+  }
+
+  Future<void> test_inlineMethod_method_startOfTypeParameterList() async {
+    const content = '''
+class A {
+  test^<T>(T a, T b) {
+    print(a);
+    print(b);
+  }
+  void f() {
+    test(1, 2);
+  }
+}
+''';
+    const expectedContent = '''
+class A {
+  void f() {
+    print(1);
+    print(2);
+  }
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: inlineMethodTitle,
+    );
+  }
+
+  Future<void> test_methodToGetter_function_startOfParameterList() async {
+    const content = '''
+int test^() => 42;
+''';
+    const expectedContent = '''
+int get test => 42;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: convertMethodToGetterTitle,
+    );
+  }
+
+  Future<void> test_methodToGetter_function_startOfTypeParameterList() async {
+    const content = '''
+int test^<T>() => 42;
+''';
+    const expectedContent = '''
+int get test<T> => 42;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: convertMethodToGetterTitle,
+    );
+  }
+
+  Future<void> test_methodToGetter_method_startOfParameterList() async {
+    const content = '''
+class A {
+  int test^() => 42;
+}
+''';
+    const expectedContent = '''
+class A {
+  int get test => 42;
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: convertMethodToGetterTitle,
+    );
+  }
+
+  Future<void> test_methodToGetter_method_startOfTypeParameterList() async {
+    const content = '''
+class A {
+  int test^<T>() => 42;
+}
+''';
+    const expectedContent = '''
+class A {
+  int get test<T> => 42;
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: convertMethodToGetterTitle,
+    );
+  }
+}
+
+mixin SharedExtractWidgetRefactorCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  final extractWidgetTitle = 'Extract Widget';
+
+  String get expectedNewWidgetConstructorDeclaration => '''
+const NewWidget({
+    super.key,
+  });
+''';
+
+  Future<void> test_appliesCorrectEdits() async {
+    const content = '''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return new Row(
+      children: <Widget>[
+        new [!Column!](
+          children: <Widget>[
+            new Text('AAA'),
+            new Text('BBB'),
+          ],
+        ),
+        new Text('CCC'),
+        new Text('DDD'),
+      ],
+    );
+  }
+}
+''';
+    var expectedContent = '''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return new Row(
+      children: <Widget>[
+        NewWidget(),
+        new Text('CCC'),
+        new Text('DDD'),
+      ],
+    );
+  }
+}
+
+class NewWidget extends StatelessWidget {
+  $expectedNewWidgetConstructorDeclaration
+  @override
+  Widget build(BuildContext context) {
+    return new Column(
+      children: <Widget>[
+        new Text('AAA'),
+        new Text('BBB'),
+      ],
+    );
+  }
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: extractWidgetTitle,
+      openTargetFile: true,
+    );
+  }
+
+  Future<void> test_invalidLocation() async {
+    const content = '''
+import 'dart:convert';
+^
+void f() {}
+''';
+
+    await expectNoAction(
+      content,
+      command: Commands.performRefactor,
+      title: extractWidgetTitle,
+    );
+  }
+}
+
+mixin SharedInlineLocalVariableRefactorCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  final inlineVariableTitle = 'Inline Local Variable';
+
+  Future<void> test_appliesCorrectEdits() async {
+    const content = '''
+void f() {
+  var a^ = 1;
+  print(a);
+  print(a);
+  print(a);
+}
+''';
+    const expectedContent = '''
+void f() {
+  print(1);
+  print(1);
+  print(1);
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: inlineVariableTitle,
+      openTargetFile: true,
+    );
+  }
+}
+
+mixin SharedInlineMethodRefactorCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  final inlineMethodTitle = 'Inline Method';
+
+  Future<void> test_inlineAtCallSite() async {
+    const content = '''
+void foo1() {
+  ba^r();
+}
+
+void foo2() {
+  bar();
+}
+
+void bar() {
+  print('test');
+}
+''';
+    const expectedContent = '''
+void foo1() {
+  print('test');
+}
+
+void foo2() {
+  bar();
+}
+
+void bar() {
+  print('test');
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: inlineMethodTitle,
+    );
+  }
+
+  Future<void> test_inlineAtMethod() async {
+    const content = '''
+void foo1() {
+  bar();
+}
+
+void foo2() {
+  bar();
+}
+
+void ba^r() {
+  print('test');
+}
+''';
+    const expectedContent = '''
+void foo1() {
+  print('test');
+}
+
+void foo2() {
+  print('test');
+}
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.performRefactor,
+      title: inlineMethodTitle,
+    );
+  }
+}
diff --git a/pkg/analysis_server/test/shared/shared_code_actions_source_tests.dart b/pkg/analysis_server/test/shared/shared_code_actions_source_tests.dart
new file mode 100644
index 0000000..4427655
--- /dev/null
+++ b/pkg/analysis_server/test/shared/shared_code_actions_source_tests.dart
@@ -0,0 +1,335 @@
+// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:test/test.dart';
+
+import '../lsp/code_actions_mixin.dart';
+import '../lsp/request_helpers_mixin.dart';
+import '../lsp/server_abstract.dart';
+import '../tool/lsp_spec/matchers.dart';
+import 'shared_test_interface.dart';
+
+/// Shared tests used by both LSP + Legacy server tests and/or integration.
+mixin SharedOrganizeImportsSourceCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
+    const content = '''
+import 'dart:math';
+import 'dart:async';
+import 'dart:convert';
+
+Completer? foo;
+int minified(int x, int y) => min(x, y);
+''';
+    const expectedContent = '''
+import 'dart:async';
+import 'dart:math';
+
+Completer? foo;
+int minified(int x, int y) => min(x, y);
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.organizeImports,
+    );
+  }
+
+  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
+    const content = '''
+import 'dart:math';
+import 'dart:async';
+import 'dart:convert';
+
+Completer? foo;
+int minified(int x, int y) => min(x, y);
+''';
+    const expectedContent = '''
+import 'dart:async';
+import 'dart:math';
+
+Completer? foo;
+int minified(int x, int y) => min(x, y);
+''';
+
+    setDocumentChangesSupport(false);
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.organizeImports,
+    );
+  }
+
+  Future<void> test_availableAsCodeActionLiteral() async {
+    const content = '';
+
+    await expectCodeActionLiteral(content, command: Commands.organizeImports);
+  }
+
+  Future<void> test_availableAsCommand() async {
+    createFile(testFilePath, '');
+    setSupportedCodeActionKinds(null); // no codeActionLiteralSupport
+    await initializeServer();
+
+    var actions = await getCodeActions(testFileUri);
+    var action = findCommand(actions, Commands.organizeImports)!;
+    action.map(
+      (codeActionLiteral) => throw 'Expected command, got codeActionLiteral',
+      (command) {},
+    );
+  }
+
+  Future<void> test_fileHasErrors_failsSilentlyForAutomatic() async {
+    failTestOnErrorDiagnostic = false;
+    var content = 'invalid dart code';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.organizeImports,
+      triggerKind: CodeActionTriggerKind.Automatic,
+    );
+    var command = codeAction.command!;
+
+    // Expect a valid null result.
+    var response = await executeCommand(command);
+    expect(response, isNull);
+  }
+
+  Future<void> test_fileHasErrors_failsWithErrorForManual() async {
+    failTestOnErrorDiagnostic = false;
+    var content = 'invalid dart code';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.organizeImports,
+    );
+    var command = codeAction.command!;
+
+    // Ensure the request returned an error (error responses are thrown by
+    // the test helper to make consuming success results simpler).
+    await expectLater(
+      executeCommand(command),
+      throwsA(isResponseError(ServerErrorCodes.FileHasErrors)),
+    );
+  }
+
+  Future<void> test_filtersCorrectly() async {
+    createFile(testFilePath, '');
+    await initializeServer();
+
+    ofKind(CodeActionKind kind) => getCodeActions(testFileUri, kinds: [kind]);
+
+    expect(await ofKind(CodeActionKind.Source), hasLength(3));
+    expect(await ofKind(CodeActionKind.SourceOrganizeImports), hasLength(1));
+    expect(await ofKind(DartCodeActionKind.SortMembers), hasLength(1));
+    expect(await ofKind(DartCodeActionKind.FixAll), hasLength(1));
+    expect(await ofKind(CodeActionKind('source.foo')), isEmpty);
+    expect(await ofKind(CodeActionKind.Refactor), isEmpty);
+  }
+
+  Future<void> test_noEdits() async {
+    const content = '''
+import 'dart:async';
+import 'dart:math';
+
+Completer? foo;
+int minified(int x, int y) => min(x, y);
+''';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.organizeImports,
+    );
+    var command = codeAction.command!;
+
+    // Execute the command and it should return without needing us to process
+    // a workspace/applyEdit command because there were no edits.
+    var commandResponse = await executeCommand(command);
+    // Successful edits return an empty success() response.
+    expect(commandResponse, isNull);
+  }
+
+  Future<void> test_unavailableWhenNotRequested() async {
+    var content = '';
+
+    setSupportedCodeActionKinds([CodeActionKind.Refactor]); // not Source
+    await expectNoAction(content, command: Commands.organizeImports);
+  }
+
+  Future<void> test_unavailableWithoutApplyEditSupport() async {
+    var content = '';
+
+    setApplyEditSupport(false);
+    await expectNoAction(content, command: Commands.organizeImports);
+  }
+}
+
+/// Shared tests used by both LSP + Legacy server tests and/or integration.
+mixin SharedSortMembersSourceCodeActionsTests
+    on
+        SharedTestInterface,
+        CodeActionsTestMixin,
+        LspRequestHelpersMixin,
+        LspEditHelpersMixin,
+        LspVerifyEditHelpersMixin,
+        ClientCapabilitiesHelperMixin {
+  Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
+    const content = '''
+String? b;
+String? a;
+''';
+    const expectedContent = '''
+String? a;
+String? b;
+''';
+
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.sortMembers,
+    );
+  }
+
+  Future<void> test_appliesCorrectEdits_withoutDocumentChangesSupport() async {
+    const content = '''
+String? b;
+String? a;
+''';
+    const expectedContent = '''
+String? a;
+String? b;
+''';
+
+    setDocumentChangesSupport(false);
+    await verifyCodeActionLiteralEdits(
+      content,
+      expectedContent,
+      command: Commands.sortMembers,
+    );
+  }
+
+  Future<void> test_availableAsCodeActionLiteral() async {
+    const content = '';
+
+    await expectCodeActionLiteral(content, command: Commands.sortMembers);
+  }
+
+  Future<void> test_availableAsCommand() async {
+    createFile(testFilePath, '');
+    setSupportedCodeActionKinds(null); // no codeActionLiteralSupport
+    await initializeServer();
+
+    var actions = await getCodeActions(testFileUri);
+    var action = findCommand(actions, Commands.sortMembers)!;
+    action.map(
+      (codeActionLiteral) => throw 'Expected command, got codeActionLiteral',
+      (command) {},
+    );
+  }
+
+  Future<void> test_failsIfClientDoesntApplyEdits() async {
+    const content = '''
+String? b;
+String? a;
+''';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.sortMembers,
+    );
+    var command = codeAction.command!;
+
+    var commandResponse = handleExpectedRequest<
+      Object?,
+      ApplyWorkspaceEditParams,
+      ApplyWorkspaceEditResult
+    >(
+      Method.workspace_applyEdit,
+      ApplyWorkspaceEditParams.fromJson,
+      () => executeCommand(command),
+      // Claim that we failed tpo apply the edits. This is what the client
+      // would do if the edits provided were for an old version of the
+      // document.
+      handler:
+          (edit) => ApplyWorkspaceEditResult(
+            applied: false,
+            failureReason: 'Document changed',
+          ),
+    );
+
+    // Ensure the request returned an error (error responses are thrown by
+    // the test helper to make consuming success results simpler).
+    await expectLater(
+      commandResponse,
+      throwsA(isResponseError(ServerErrorCodes.ClientFailedToApplyEdit)),
+    );
+  }
+
+  Future<void> test_fileHasErrors_failsSilentlyForAutomatic() async {
+    failTestOnErrorDiagnostic = false;
+    var content = 'invalid dart code';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.sortMembers,
+      triggerKind: CodeActionTriggerKind.Automatic,
+    );
+    var command = codeAction.command!;
+
+    // Expect a valid null result.
+    var response = await executeCommand(command);
+    expect(response, isNull);
+  }
+
+  Future<void> test_fileHasErrors_failsWithErrorForManual() async {
+    failTestOnErrorDiagnostic = false;
+    var content = 'invalid dart code';
+
+    var codeAction = await expectCodeActionLiteral(
+      content,
+      command: Commands.sortMembers,
+    );
+    var command = codeAction.command!;
+
+    // Ensure the request returned an error (error responses are thrown by
+    // the test helper to make consuming success results simpler).
+    await expectLater(
+      executeCommand(command),
+      throwsA(isResponseError(ServerErrorCodes.FileHasErrors)),
+    );
+  }
+
+  Future<void> test_nonDartFile() async {
+    await expectNoAction(
+      filePath: pubspecFilePath,
+      simplePubspecContent,
+      command: Commands.sortMembers,
+    );
+  }
+
+  Future<void> test_unavailableWhenNotRequested() async {
+    var content = '';
+
+    setSupportedCodeActionKinds([CodeActionKind.Refactor]); // not Source
+    await expectNoAction(content, command: Commands.sortMembers);
+  }
+
+  Future<void> test_unavailableWithoutApplyEditSupport() async {
+    var content = '';
+
+    setApplyEditSupport(false);
+    await expectNoAction(content, command: Commands.sortMembers);
+  }
+}