diff --git a/lib/core/global_keys.dart b/lib/core/global_keys.dart
index e447d685467c50c75bcc576c8d6ef96023f48219..c2eed85c28254b22d1fe1045ce9780f2afe5d99f 100644
--- a/lib/core/global_keys.dart
+++ b/lib/core/global_keys.dart
@@ -6,4 +6,5 @@ class GlobalKeys {
   static GlobalKey<State<BottomNavigationBar>> rootBottomNavigationBarKey = GlobalKey();
 
   static String navigationBarCurrentIndexKey = "navigation_bar_current_index";
+  static String currentMergeRequestWebUrlKey = "current_merge_request_web_url";
 }
diff --git a/lib/core/user_provider.dart b/lib/core/user_provider.dart
index 27553e52eedc427d0ef594ed6e2725b0d81cd6c8..01a6d33a9bce8427812ee82d00b851683a631f97 100644
--- a/lib/core/user_provider.dart
+++ b/lib/core/user_provider.dart
@@ -3,6 +3,7 @@ import 'dart:convert';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:jihu_gitlab_app/core/domain/token.dart';
+import 'package:jihu_gitlab_app/core/global_keys.dart';
 import 'package:jihu_gitlab_app/core/id.dart';
 import 'package:jihu_gitlab_app/core/local_storage.dart';
 import 'package:jihu_gitlab_app/core/log_helper.dart';
@@ -169,6 +170,8 @@ class UserProvider extends ChangeNotifier {
   static int? get userId => _users.isEmpty ? null : _users[0].id;
 
   static bool get isLoggedOutByUser => _isLoggedOutByUser;
+
+  static Future<String> get mergeRequestWebUrl async => await LocalStorage.get(GlobalKeys.currentMergeRequestWebUrlKey, '');
 }
 
 class UserInfo {
diff --git a/lib/modules/mr/merge_request_page.dart b/lib/modules/mr/merge_request_page.dart
index a0dcb8442642762688f983d41e744f510126fc6f..4fb04a0a5c0f99a89de6673a2d5fdf4fe3f21c28 100644
--- a/lib/modules/mr/merge_request_page.dart
+++ b/lib/modules/mr/merge_request_page.dart
@@ -1,6 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_svg/flutter_svg.dart';
+import 'package:jihu_gitlab_app/core/global_keys.dart';
 import 'package:jihu_gitlab_app/core/load_state.dart';
+import 'package:jihu_gitlab_app/core/local_storage.dart';
 import 'package:jihu_gitlab_app/core/settings/settings_provider.dart';
 import 'package:jihu_gitlab_app/core/string_extension.dart';
 import 'package:jihu_gitlab_app/core/user_provider.dart';
@@ -38,19 +40,31 @@ class _MergeRequestPageState extends State<MergeRequestPage> {
 
   @override
   Widget build(BuildContext context) {
+    _saveWebUrl();
     return Consumer<UserProvider>(
       builder: (context, _, child) => _buildScaffold(),
     );
   }
 
+  Future<void> _saveWebUrl() async {
+    if (_model.mr != null && (await UserProvider.mergeRequestWebUrl).isEmpty) {
+      LocalStorage.save(GlobalKeys.currentMergeRequestWebUrlKey, _model.mr!.webUrl);
+    }
+  }
+
   Widget _buildScaffold() {
-    return Scaffold(
-      appBar: CommonAppBar(
-        showLeading: true,
-        title: Text(_model.pageTitle),
-      ),
-      body: SafeArea(child: _buildBody()),
-    );
+    return WillPopScope(
+        child: Scaffold(
+          appBar: CommonAppBar(
+            showLeading: true,
+            title: Text(_model.pageTitle),
+          ),
+          body: SafeArea(child: _buildBody()),
+        ),
+        onWillPop: () {
+          LocalStorage.remove(GlobalKeys.currentMergeRequestWebUrlKey);
+          return Future(() => true);
+        });
   }
 
   Widget _buildBody() {
diff --git a/lib/modules/mr/models/graphql_request_body.dart b/lib/modules/mr/models/graphql_request_body.dart
index 2f58d847424c794c281e9a8cddb83c69a7707269..d14b3c177923f4006ef8a30d3e3aa79e9c136020 100644
--- a/lib/modules/mr/models/graphql_request_body.dart
+++ b/lib/modules/mr/models/graphql_request_body.dart
@@ -3,7 +3,7 @@ Map<String, dynamic> getMergeRequestDetailsGraphQLRequestBody(String fullPath, i
     "operationName": "getMergeRequest",
     "variables": {"fullPath": fullPath, "mrIid": '$mrIid'},
     "query":
-        "query getMergeRequest(\$fullPath: ID!, \$mrIid: String!) {  project(fullPath: \$fullPath) {    id    name    nameWithNamespace    path    fullPath    webUrl    allowMergeOnSkippedPipeline    onlyAllowMergeIfAllStatusChecksPassed    onlyAllowMergeIfAllDiscussionsAreResolved    onlyAllowMergeIfPipelineSucceeds    removeSourceBranchAfterMerge    mergeRequest(iid: \$mrIid) {      id      iid      state      title      description      draft      createdAt      rebaseInProgress      allowCollaboration      approved      approvalsLeft      approvalsRequired      approvalState {        approvalRulesOverwritten        rules {          id          name          type          approvalsRequired          eligibleApprovers {            ...UserCoreFragment          }        }      }      approvedBy {        nodes {          ...UserCoreFragment        }      }      assignees {        nodes {          id          name        }      }      commitCount      commits {        nodes {          id          shortId          sha          title          description        }      }      author {        id        name        username        avatarUrl      }      autoMergeEnabled      autoMergeStrategy      availableAutoMergeStrategies      conflicts      mergeError      mergeOngoing      detailedMergeStatus      mergeStatusEnum      mergeUser {        ...UserCoreFragment      }      mergeWhenPipelineSucceeds      mergeable      mergeableDiscussionsState      mergedAt      rebaseCommitSha      rebaseInProgress      shouldBeRebased      shouldRemoveSourceBranch      sourceBranch      sourceBranchExists      sourceBranchProtected      targetBranch      targetBranchExists      squash      squashOnMerge      defaultMergeCommitMessage      defaultSquashCommitMessage      headPipeline {        id        iid        active        cancelable        complete        coverage        status        ref        detailedStatus {          icon          label        }        codeQualityReportSummary {          count        }        codeQualityReports {          nodes {            line            path            description            severity          }        }        jobs {          nodes {            id            name            active            status            allowFailure            duration            startedAt            finishedAt            stage {              id              name              status              jobs {                nodes {                  id                  name                  status                  allowFailure                }              }            }          }        }        warnings        warningMessages {          content        }        createdAt        finishedAt        committedAt        startedAt      }      userPermissions {        adminMergeRequest        canMerge        pushToSourceBranch        readMergeRequest        removeSourceBranch      }    }  }}fragment UserCoreFragment on UserCore {  id  username  name  state  avatarUrl  webUrl  publicEmail  commitEmail}"
+        "query getMergeRequest(\$fullPath: ID!, \$mrIid: String!) {  project(fullPath: \$fullPath) {    id    name    nameWithNamespace    path    fullPath    webUrl    allowMergeOnSkippedPipeline    onlyAllowMergeIfAllStatusChecksPassed    onlyAllowMergeIfAllDiscussionsAreResolved    onlyAllowMergeIfPipelineSucceeds    removeSourceBranchAfterMerge    mergeRequest(iid: \$mrIid) {      id      iid      state      title      description    webUrl   draft      createdAt      rebaseInProgress      allowCollaboration      approved      approvalsLeft      approvalsRequired      approvalState {        approvalRulesOverwritten        rules {          id          name          type          approvalsRequired          eligibleApprovers {            ...UserCoreFragment          }        }      }      approvedBy {        nodes {          ...UserCoreFragment        }      }      assignees {        nodes {          id          name        }      }      commitCount      commits {        nodes {          id          shortId          sha          title          description        }      }      author {        id        name        username        avatarUrl      }      autoMergeEnabled      autoMergeStrategy      availableAutoMergeStrategies      conflicts      mergeError      mergeOngoing      detailedMergeStatus      mergeStatusEnum      mergeUser {        ...UserCoreFragment      }      mergeWhenPipelineSucceeds      mergeable      mergeableDiscussionsState      mergedAt      rebaseCommitSha      rebaseInProgress      shouldBeRebased      shouldRemoveSourceBranch      sourceBranch      sourceBranchExists      sourceBranchProtected      targetBranch      targetBranchExists      squash      squashOnMerge      defaultMergeCommitMessage      defaultSquashCommitMessage      headPipeline {        id        iid        active        cancelable        complete        coverage        status        ref        detailedStatus {          icon          label        }        codeQualityReportSummary {          count        }        codeQualityReports {          nodes {            line            path            description            severity          }        }        jobs {          nodes {            id            name            active            status            allowFailure            duration            startedAt            finishedAt            stage {              id              name              status              jobs {                nodes {                  id                  name                  status                  allowFailure                }              }            }          }        }        warnings        warningMessages {          content        }        createdAt        finishedAt        committedAt        startedAt      }      userPermissions {        adminMergeRequest        canMerge        pushToSourceBranch        readMergeRequest        removeSourceBranch      }    }  }}fragment UserCoreFragment on UserCore {  id  username  name  state  avatarUrl  webUrl  publicEmail  commitEmail}"
   };
 }
 
diff --git a/lib/modules/mr/models/merge_request.dart b/lib/modules/mr/models/merge_request.dart
index 8e58807fb2e0814488472bd780f97aca065b5d21..ffe9f3d63ad6ddcc5ba01cb467152e4fa106530d 100644
--- a/lib/modules/mr/models/merge_request.dart
+++ b/lib/modules/mr/models/merge_request.dart
@@ -36,6 +36,7 @@ class MergeRequest {
   final bool mergeable;
   final bool shouldBeRebased;
   final String? mergeError;
+  final String webUrl;
 
   MergeRequest._(
       this.iid,
@@ -62,38 +63,41 @@ class MergeRequest {
       this._approvalRules,
       this.mergeable,
       this.shouldBeRebased,
-      this.mergeError);
+      this.mergeError,
+      this.webUrl);
 
   factory MergeRequest.fromJson(Map<String, dynamic> json) {
     var mergeRequest = json['mergeRequest'] ?? {};
     var headPipeline = mergeRequest['headPipeline'] ?? {};
     List<dynamic> rules = mergeRequest['approvalState']?['rules'] ?? [];
     return MergeRequest._(
-        int.parse(mergeRequest['iid'] ?? ''),
-        Id.fromGid(json['id'] ?? '/0').id,
-        json['fullPath'] ?? '',
-        json['name'] ?? '',
-        mergeRequest['sourceBranch'] ?? '',
-        mergeRequest['targetBranch'] ?? '',
-        MergeRequestState.valueOf(mergeRequest['state'] ?? ''),
-        mergeRequest['title'] ?? '',
-        mergeRequest['description'] ?? '',
-        Assignee.fromGraphQLJson(mergeRequest['author'] ?? {}),
-        mergeRequest['headPipeline'] == null ? null : Pipeline.fromJson(headPipeline),
-        Time.init(mergeRequest['createdAt'] ?? ''),
-        mergeRequest['rebaseInProgress'] ?? false,
-        DetailMergeStatus.valueOf(mergeRequest['detailedMergeStatus'] ?? DetailMergeStatus.unchecked.name),
-        mergeRequest['userPermissions']?['canMerge'] ?? false,
-        mergeRequest['conflicts'] ?? false,
-        mergeRequest['commitCount'] ?? 0,
-        mergeRequest['draft'] ?? false,
-        Commits.fromJson(mergeRequest['commits']['nodes']),
-        mergeRequest['headPipeline'] == null ? null : CodeQualityReport.fromJson(headPipeline),
-        Jobs.fromJson(headPipeline['jobs']?['nodes'] ?? []),
-        rules.map((e) => ApprovalRule.fromGraphQLJson(e)).toList(),
-        mergeRequest['mergeable'] ?? false,
-        mergeRequest['shouldBeRebased'] ?? false,
-        mergeRequest['mergeError']);
+      int.parse(mergeRequest['iid'] ?? ''),
+      Id.fromGid(json['id'] ?? '/0').id,
+      json['fullPath'] ?? '',
+      json['name'] ?? '',
+      mergeRequest['sourceBranch'] ?? '',
+      mergeRequest['targetBranch'] ?? '',
+      MergeRequestState.valueOf(mergeRequest['state'] ?? ''),
+      mergeRequest['title'] ?? '',
+      mergeRequest['description'] ?? '',
+      Assignee.fromGraphQLJson(mergeRequest['author'] ?? {}),
+      mergeRequest['headPipeline'] == null ? null : Pipeline.fromJson(headPipeline),
+      Time.init(mergeRequest['createdAt'] ?? ''),
+      mergeRequest['rebaseInProgress'] ?? false,
+      DetailMergeStatus.valueOf(mergeRequest['detailedMergeStatus'] ?? DetailMergeStatus.unchecked.name),
+      mergeRequest['userPermissions']?['canMerge'] ?? false,
+      mergeRequest['conflicts'] ?? false,
+      mergeRequest['commitCount'] ?? 0,
+      mergeRequest['draft'] ?? false,
+      Commits.fromJson(mergeRequest['commits']['nodes']),
+      mergeRequest['headPipeline'] == null ? null : CodeQualityReport.fromJson(headPipeline),
+      Jobs.fromJson(headPipeline['jobs']?['nodes'] ?? []),
+      rules.map((e) => ApprovalRule.fromGraphQLJson(e)).toList(),
+      mergeRequest['mergeable'] ?? false,
+      mergeRequest['shouldBeRebased'] ?? false,
+      mergeRequest['mergeError'],
+      mergeRequest['webUrl'] ?? '',
+    );
   }
 
   List<ApprovalRule> get approvalRules => _approvalRules.where((e) => e.ruleType != 'ANY_APPROVER').toList();
diff --git a/lib/modules/mr/models/merge_request_model.dart b/lib/modules/mr/models/merge_request_model.dart
index 43152341051bc2ea4b28e80cbb13eb149fc72a7a..80837e5c8392bad326a7dbb31600de9fa7a88698 100644
--- a/lib/modules/mr/models/merge_request_model.dart
+++ b/lib/modules/mr/models/merge_request_model.dart
@@ -38,8 +38,7 @@ class MergeRequestModel {
   Future<void> _getBasicMr(void Function()? setState) {
     return _makeRefresh(() async {
       var resp = await HttpClient.instance().post('/api/graphql', getMergeRequestDetailsGraphQLRequestBody(projectFullPath, mergeRequestIid));
-      var result = MergeRequest.fromJson(resp.body()['data']['project']);
-      mr = result;
+      mr = MergeRequest.fromJson(resp.body()['data']['project']);
     }, setState);
   }
 
diff --git a/lib/modules/root/root_page.dart b/lib/modules/root/root_page.dart
index b9b3a876826d164e9c7b6c6423f4e3454a03e654..3e75e8d902f9a4d3d799e356400510d8a7a0a05c 100644
--- a/lib/modules/root/root_page.dart
+++ b/lib/modules/root/root_page.dart
@@ -8,6 +8,7 @@ import 'package:jihu_gitlab_app/core/layout/adaptive.dart';
 import 'package:jihu_gitlab_app/core/local_storage.dart';
 import 'package:jihu_gitlab_app/core/plugins/install_apk_plugin.dart';
 import 'package:jihu_gitlab_app/core/user_provider.dart';
+import 'package:jihu_gitlab_app/core/widgets/paste_type_url_navigation.dart';
 import 'package:jihu_gitlab_app/l10n/jihu_localizations.dart';
 import 'package:jihu_gitlab_app/modules/privacy_policy/privacy_policy_page.dart';
 import 'package:provider/provider.dart';
@@ -48,6 +49,17 @@ class _RootPageState extends State<RootPage> {
     if (!agreedPrivacyPolicy) {
       Future.delayed(Duration.zero, _showPrivacyPolicyDialog);
     }
+    parseMergeRequest();
+  }
+
+  Future<void> parseMergeRequest() async {
+    var url = await UserProvider.mergeRequestWebUrl;
+    if (url.isEmpty) {
+      return;
+    }
+    Future.delayed(Duration.zero, () {
+      PasteTypeUrlNavigationModel().parseAndToward(url, context);
+    });
   }
 
   @override
diff --git a/test/integration_tests/helper/core.dart b/test/integration_tests/helper/core.dart
index e67f7a2f201b428a68058b55224c05ce23aa26f4..64d3971878e4333f88448fd3a201edd85d3ae4d4 100644
--- a/test/integration_tests/helper/core.dart
+++ b/test/integration_tests/helper/core.dart
@@ -1,3 +1,28 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:jihu_gitlab_app/core/net/http_client.dart';
+import 'package:jihu_gitlab_app/core/net/response.dart';
+import 'package:jihu_gitlab_app/core/user_provider.dart';
+import 'package:mockito/mockito.dart';
+
 import '../../core/net/http_request_test.mocks.dart';
+import '../../mocker/tester.dart';
+import '../../test_data/user.dart';
 
 final client = MockHttpClient();
+
+void saasLogin({VoidCallback? onMock}) {
+  expect(UserProvider.authorized, isFalse);
+  UserProvider().resetToken(Tester.token());
+  UserProvider().reset(Tester.user());
+  UserProvider().notifyChanged();
+  expect(UserProvider.authorized, isTrue);
+
+  when(client.get<Map<String, dynamic>>("/api/v4/user")).thenAnswer((_) => Future(() => Response.of<Map<String, dynamic>>(userInfo)));
+  when(client.get<List<dynamic>>("/api/v4/todos?page=1&per_page=20&state=pending")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
+  when(client.get<List<dynamic>>("/api/v4/todos?page=1&per_page=20&state=done")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
+  when(client.get<List<dynamic>>("/api/v4/groups?top_level_only=true&page=1&per_page=50")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
+  when(client.get<List<dynamic>>("/api/v4/users/9527/starred_projects?page=1&per_page=50")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
+  onMock?.call();
+  HttpClient.setInstance(client);
+}
diff --git a/test/integration_tests/helper/mobile_test_helper/root.dart b/test/integration_tests/helper/mobile_test_helper/root.dart
index dbe3b2541257bb277637f4f54c7ea6cd512c7cca..83fead680dae0906d6fd9b7f14e986d85d70aa0d 100644
--- a/test/integration_tests/helper/mobile_test_helper/root.dart
+++ b/test/integration_tests/helper/mobile_test_helper/root.dart
@@ -1,19 +1,12 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:jihu_gitlab_app/core/global_keys.dart';
-import 'package:jihu_gitlab_app/core/net/http_client.dart';
-import 'package:jihu_gitlab_app/core/net/response.dart';
-
-import 'package:jihu_gitlab_app/core/user_provider.dart';
 import 'package:jihu_gitlab_app/core/widgets/unauthorized_view.dart';
 import 'package:jihu_gitlab_app/main.dart';
 import 'package:jihu_gitlab_app/modules/modules.dart';
 import 'package:jihu_gitlab_app/modules/root/mobile_root_page.dart';
-import 'package:mockito/mockito.dart';
 
-import '../../../mocker/tester.dart';
 import '../../../test_binding_setter.dart';
-import '../../../test_data/user.dart';
 import '../core.dart';
 
 Future<void> launchMobileAppForTest(WidgetTester tester) async {
@@ -37,19 +30,7 @@ Future<void> navigateToTargetMobilePage(WidgetTester tester, int targetPageIndex
 Future<void> mobileLoginWithSaaSForPage(WidgetTester tester, index, pageType, {VoidCallback? onMock}) async {
   await navigateToTargetMobilePage(tester, JiHuPageType.todo.index, ToDosPage);
   expect(find.byType(UnauthorizedView), findsWidgets);
-  expect(UserProvider.authorized, isFalse);
-  UserProvider().resetToken(Tester.token());
-  UserProvider().reset(Tester.user());
-  UserProvider().notifyChanged();
-  expect(UserProvider.authorized, isTrue);
-
-  when(client.get<Map<String, dynamic>>("/api/v4/user")).thenAnswer((_) => Future(() => Response.of<Map<String, dynamic>>(userInfo)));
-  when(client.get<List<dynamic>>("/api/v4/todos?page=1&per_page=20&state=pending")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  when(client.get<List<dynamic>>("/api/v4/todos?page=1&per_page=20&state=done")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  when(client.get<List<dynamic>>("/api/v4/groups?top_level_only=true&page=1&per_page=50")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  when(client.get<List<dynamic>>("/api/v4/users/9527/starred_projects?page=1&per_page=50")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  onMock?.call();
-  HttpClient.setInstance(client);
+  saasLogin(onMock: onMock);
 
   await navigateToTargetMobilePage(tester, JiHuPageType.faq.index, FaqPage);
   await navigateToTargetMobilePage(tester, JiHuPageType.todo.index, ToDosPage);
diff --git a/test/integration_tests/helper/tablet_test_helper/root.dart b/test/integration_tests/helper/tablet_test_helper/root.dart
index 8f6e506e499a562d3222e69b7ce899f54937264f..896976b0d68662047d4b67d5ed28e6c3b3470155 100644
--- a/test/integration_tests/helper/tablet_test_helper/root.dart
+++ b/test/integration_tests/helper/tablet_test_helper/root.dart
@@ -1,20 +1,13 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:jihu_gitlab_app/core/global_keys.dart';
-import 'package:jihu_gitlab_app/core/net/http_client.dart';
-import 'package:jihu_gitlab_app/core/net/response.dart';
-
-import 'package:jihu_gitlab_app/core/user_provider.dart';
 import 'package:jihu_gitlab_app/core/widgets/unauthorized_view.dart';
 import 'package:jihu_gitlab_app/l10n/jihu_localizations.dart';
 import 'package:jihu_gitlab_app/main.dart';
 import 'package:jihu_gitlab_app/modules/modules.dart';
 import 'package:jihu_gitlab_app/modules/root/desktop_root_page.dart';
-import 'package:mockito/mockito.dart';
 
-import '../../../mocker/tester.dart';
 import '../../../test_binding_setter.dart';
-import '../../../test_data/user.dart';
 import '../core.dart';
 
 Future<void> launchTabletAppForTest(WidgetTester tester) async {
@@ -38,19 +31,7 @@ Future<void> tabletLoginWithSaaSForPage(WidgetTester tester, index, pageType, {V
   await navigateToTargetTabletPage(tester, JiHuPageType.todo.index, ToDosPage);
 
   expect(find.byType(UnauthorizedView), findsWidgets);
-  expect(UserProvider.authorized, isFalse);
-  UserProvider().resetToken(Tester.token());
-  UserProvider().reset(Tester.user());
-  UserProvider().notifyChanged();
-  expect(UserProvider.authorized, isTrue);
-
-  when(client.get<Map<String, dynamic>>("/api/v4/user")).thenAnswer((_) => Future(() => Response.of<Map<String, dynamic>>(userInfo)));
-  when(client.get<List<dynamic>>("/api/v4/todos?page=1&per_page=20&state=pending")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  when(client.get<List<dynamic>>("/api/v4/todos?page=1&per_page=20&state=done")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  when(client.get<List<dynamic>>("/api/v4/groups?top_level_only=true&page=1&per_page=50")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  when(client.get<List<dynamic>>("/api/v4/users/9527/starred_projects?page=1&per_page=50")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>([])));
-  onMock?.call();
-  HttpClient.setInstance(client);
+  saasLogin(onMock: onMock);
 
   await navigateToTargetTabletPage(tester, JiHuPageType.faq.index, FaqPage);
   await navigateToTargetTabletPage(tester, JiHuPageType.todo.index, ToDosPage);
diff --git a/test/integration_tests/modules/merge_request/reopen_merge_request_details_test.dart b/test/integration_tests/modules/merge_request/reopen_merge_request_details_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e6d166367614a2e57cfa40c4f3b1434a12abeef7
--- /dev/null
+++ b/test/integration_tests/modules/merge_request/reopen_merge_request_details_test.dart
@@ -0,0 +1,97 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:jihu_gitlab_app/core/dependency_injector.dart';
+import 'package:jihu_gitlab_app/core/global_keys.dart';
+import 'package:jihu_gitlab_app/core/local_storage.dart';
+import 'package:jihu_gitlab_app/core/net/http_client.dart';
+import 'package:jihu_gitlab_app/core/net/response.dart';
+import 'package:jihu_gitlab_app/core/user_provider.dart';
+import 'package:jihu_gitlab_app/core/widgets/photo_picker.dart';
+import 'package:jihu_gitlab_app/modules/modules.dart';
+import 'package:jihu_gitlab_app/modules/mr/merge_request_page.dart';
+import 'package:jihu_gitlab_app/modules/mr/models/graphql_request_body.dart';
+import 'package:mockito/mockito.dart';
+
+import '../../../test_data/issue.dart';
+import '../../../test_data/merge_request.dart';
+import '../../../test_data/to_dos.dart';
+import '../../helper/core.dart';
+import '../../helper/mobile_test_helper/root.dart';
+import '../../helper/tablet_test_helper/root.dart';
+
+void main() {
+  setUp(() async {
+    WidgetsFlutterBinding.ensureInitialized();
+    setupLocator();
+
+    when(client.post<dynamic>("/api/graphql", getIssuesEEGraphQLRequestBody(true, 'ultimate-plan/jihu-gitlab-app/faq', '', 20, null)))
+        .thenAnswer((_) => Future(() => Response.of(faqIssuesGraphQLResponseData)));
+    HttpClient.setInstance(client);
+  });
+
+  testWidgets('Should launch with mobile and save webUrl of Merge Request after enter in Merge Request Page and clear when exit', (WidgetTester tester) async {
+    await launchMobileAppForTest(tester);
+    await mobileLoginWithSaaSForPage(tester, JiHuPageType.todo.index, ToDosPage, onMock: onToDoRequestMock);
+    await pageContentTest(tester);
+  });
+
+  testWidgets('Should app launch with tablet and save webUrl of Merge Request after enter in Merge Request Page and clear when exit', (WidgetTester tester) async {
+    await launchTabletAppForTest(tester);
+    await tabletLoginWithSaaSForPage(tester, JiHuPageType.todo.index, ToDosPage, onMock: onToDoRequestMock);
+    await pageContentTest(tester);
+  });
+
+  tearDown(() async {
+    UserProvider().fullReset();
+
+    locator.unregister<SubgroupListModel>();
+    locator.unregister<ProjectsGroupsModel>();
+    locator.unregister<ProjectsStarredModel>();
+    locator.unregister<IssueDetailsModel>();
+    locator.unregister<PhotoPicker>();
+  });
+}
+
+Future<void> pageContentTest(WidgetTester tester) async {
+  expect(find.text('pending test name'), findsOneWidget);
+  expect(find.text('merge request item'), findsOneWidget);
+  await tester.tap(find.text('merge request item'));
+  await tester.pumpAndSettle();
+  expect(find.byType(ToDosPage), findsNothing);
+  expect(find.byType(MergeRequestPage), findsOneWidget);
+
+  var webUrl = await LocalStorage.get(GlobalKeys.currentMergeRequestWebUrlKey, '');
+  expect(webUrl, isNotEmpty);
+  expect(webUrl, 'https://jihulab.com/ultimate-plan/jihu-gitlab-app/jihu-gitlab-app/-/merge_requests/84');
+
+  await tester.tap(find.byType(BackButton));
+  await tester.pumpAndSettle();
+  webUrl = await LocalStorage.get(GlobalKeys.currentMergeRequestWebUrlKey, '');
+  expect(find.byType(ToDosPage), findsOneWidget);
+  expect(find.byType(MergeRequestPage), findsNothing);
+  expect(webUrl, isEmpty);
+}
+
+void onToDoRequestMock() {
+  when(client.get<List<dynamic>>("/api/v4/todos?page=1&per_page=20&state=pending")).thenAnswer((_) => Future(() => Response.of<List<dynamic>>(todoPendingResponseData)));
+  when(client.get<Map<String, dynamic>>("/api/v4/projects/59893/merge_requests/84/approvals")).thenAnswer((_) => Future(() => Response.of<Map<String, dynamic>>(approvalResponse)));
+  when(client.get('/api/v4/projects/59893')).thenAnswer((_) => Future(() => Response.of<Map>({"path_with_namespace": "ultimate-plan/jihu-gitlab-app/jihu-gitlab-app"})));
+  when(client.post<Map<String, dynamic>>('/api/graphql', getMergeRequestDetailsGraphQLRequestBody('ultimate-plan/jihu-gitlab-app/jihu-gitlab-app', 84)))
+      .thenAnswer((_) => Future(() => Response.of<Map<String, dynamic>>(mrGraphQLDraftResponse)));
+  when(client.post('/api/graphql', {
+    "variables": {"fullPath": 'ultimate-plan/jihu-gitlab-app/jihu-gitlab-app'},
+    "query": """
+        query (\$fullPath: ID!) {
+          project(fullPath: \$fullPath) {
+            id
+            name
+            fullPath
+          }
+        }
+      """,
+  })).thenAnswer((_) => Future(() => Response.of<Map<String, dynamic>>({
+        "data": {
+          "project": {"id": "gid://gitlab/Project/59893", "name": "merge request item", "fullPath": "ultimate-plan/jihu-gitlab-app/jihu-gitlab-app"}
+        }
+      })));
+}
diff --git a/test/test_data/merge_request.dart b/test/test_data/merge_request.dart
index 7ba8aa5cd1ea34189ea9240e21880326f81819d0..65e98b276e5bfaf1f31766362f711e7066cd96ef 100644
--- a/test/test_data/merge_request.dart
+++ b/test/test_data/merge_request.dart
@@ -382,6 +382,7 @@ Map<String, dynamic> mrGraphQLDraftResponse = {
         "state": "opened",
         "title": "Draft: Resolve \"Feature: 开发人员查看 Merge blocked\"",
         "description": "Closes #47",
+        "webUrl": "https://jihulab.com/ultimate-plan/jihu-gitlab-app/jihu-gitlab-app/-/merge_requests/84",
         "draft": true,
         "createdAt": "2023-02-14T15:34:08+08:00",
         "rebaseInProgress": false,