From 933f56854ead41ee5034caeeb20207904dc80ea0 Mon Sep 17 00:00:00 2001 From: yaoweiprc <6896642+yaoweiprc@users.noreply.github.com> Date: Tue, 28 Apr 2026 17:44:54 +0800 Subject: [PATCH] Git server for smoke test [INS-2258] (#9816) * Git server for smoke test * Try to solve flaky test * feat: remove unused Git hook samples and add Credentials tab functionality - Deleted various sample Git hook scripts from the git-server fixture, including post-update, pre-applypatch, pre-commit, pre-merge-commit, pre-push, pre-rebase, pre-receive, prepare-commit-msg, push-to-checkout, sendemail-validate, and update hooks. - Introduced a new PreferencesCredentialsTab class to manage Git credentials within the Insomnia Preferences. - Updated the PreferencesPage to include the new Credentials tab for Git credentials management. - Enhanced the ProjectPage with a method to create a Git Sync project, including branch creation and switching. - Added comprehensive tests for Git Sync functionality, including creating branches, committing changes, and merging branches. - Updated UI components to support new features, including data-testid attributes for better testability. Co-authored-by: Copilot * feat: update path import and add Git sync tests * revert package.json * Update package.json * feat: add new dependencies for Git HTTP mock server and related utilities * refactor: remove commented-out code in addAccessTokenGitCredential function * fix: update export tests to use toHaveLength for file count assertions --------- Co-authored-by: Copilot --- .vscode/settings.json | 3 +- package-lock.json | 452 ++++++++++++++++++ .../fixtures/git-repo/git-server.git/HEAD | 1 + .../fixtures/git-repo/git-server.git/config | 6 + .../git-repo/git-server.git/description | 1 + .../git-repo/git-server.git/info/exclude | 6 + .../33/57649e085f0f653c60993fc34b0d380c4c2991 | Bin 0 -> 53 bytes .../5a/d28e22767f979da2c198dc6c1003b25964e3da | Bin 0 -> 20 bytes .../73/a07b09e3e790de0277df5ac98e0ad62ecf83d4 | 3 + .../git-repo/git-server.git/refs/heads/master | 1 + packages/insomnia-smoke-test/package.json | 1 + .../insomnia-smoke-test/playwright.config.ts | 5 +- .../pages/preferences/credentials-tab.ts | 38 ++ .../playwright/pages/preferences/index.ts | 9 +- .../playwright/pages/project/index.ts | 27 ++ packages/insomnia-smoke-test/server/index.ts | 10 + .../tests/smoke/disable-git-sync.test.ts | 101 ++++ .../tests/smoke/export.test.ts | 7 +- .../tests/smoke/git-sync.test.ts | 171 ++++--- .../modals/git-project-branches-modal.tsx | 2 + .../ui/components/modals/project-modal.tsx | 1 + .../ui/components/settings/credentials.tsx | 2 +- 22 files changed, 749 insertions(+), 98 deletions(-) create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/HEAD create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/config create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/description create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/info/exclude create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/objects/33/57649e085f0f653c60993fc34b0d380c4c2991 create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/objects/73/a07b09e3e790de0277df5ac98e0ad62ecf83d4 create mode 100644 packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/refs/heads/master create mode 100644 packages/insomnia-smoke-test/playwright/pages/preferences/credentials-tab.ts create mode 100644 packages/insomnia-smoke-test/tests/smoke/disable-git-sync.test.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 914fc1596c..184ba76b1b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -43,5 +43,6 @@ ], "[cpp]": { "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" - } + }, + "editor.formatOnPaste": true } diff --git a/package-lock.json b/package-lock.json index 3afadc5170..b0557507e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11591,6 +11591,29 @@ "dev": true, "license": "MIT" }, + "node_modules/apache-crypt": { + "version": "1.2.6", + "resolved": "https://registry.npmmirror.com/apache-crypt/-/apache-crypt-1.2.6.tgz", + "integrity": "sha512-072WetlM4blL8PREJVeY+WHiUh1R5VNt2HfceGS8aKqttPHcmqE5pkKuXPz/ULmJOFkc8Hw3kfKl6vy7Qka6DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "unix-crypt-td-js": "^1.1.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/apache-md5": { + "version": "1.1.8", + "resolved": "https://registry.npmmirror.com/apache-md5/-/apache-md5-1.1.8.tgz", + "integrity": "sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/apiconnect-wsdl": { "version": "2.0.36", "resolved": "https://registry.npmjs.org/apiconnect-wsdl/-/apiconnect-wsdl-2.0.36.tgz", @@ -11918,6 +11941,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -12021,6 +12067,16 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmmirror.com/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -12241,6 +12297,13 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmmirror.com/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/bignumber.js": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", @@ -13692,6 +13755,16 @@ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, + "node_modules/crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha512-GsVpkFPlycH7/fRR7Dhcmnoii54gV1nz7y4CWyeFS14N+JVBBhY+r8amRHE4BwSYal7BPTDp8isvAlCxyFt3Hg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/css-in-js-utils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", @@ -13803,6 +13876,16 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/daemonize-process": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/daemonize-process/-/daemonize-process-1.0.9.tgz", + "integrity": "sha512-YoB+AmcgHIBDVeyfVWSCV90FNk799zX8Uvn7RJTDCD8Y0EMNbSfIKLG961VgchJme2GHmqpXUuV8Rxe2j2L+bw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4" + } + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -14508,6 +14591,19 @@ "node": "*" } }, + "node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/dmg-builder": { "version": "26.8.1", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.8.1.tgz", @@ -16936,6 +17032,31 @@ "micromatch": "^4.0.2" } }, + "node_modules/fixturez": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/fixturez/-/fixturez-1.1.0.tgz", + "integrity": "sha512-c4q9eZsAmCzj9gkrEO/YwIRlrHWt/TXQiX9jR9WeLFOqeeV6EyzdiiV28CpSzF6Ip+gyYrSv5UeOHqyzfcNTVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-extra": "^5.0.0", + "globby": "^7.1.1", + "signal-exit": "^3.0.2", + "tempy": "^0.2.1" + } + }, + "node_modules/fixturez/node_modules/fs-extra": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-5.0.0.tgz", + "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -17375,6 +17496,108 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/git-http-mock-server": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/git-http-mock-server/-/git-http-mock-server-2.0.0.tgz", + "integrity": "sha512-LOCls7jjuzwfKmUbcFsqj2yIEqExBzv0rA1tL7j1ULhRLAax4U1Bd/rbU9ebtri1ldzgcPD1VAyuhS1pvDC2pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-auth": "^2.0.0", + "buffer-equal-constant-time": "^1.0.1", + "chalk": "^2.4.1", + "daemonize-process": "^1.0.9", + "fixturez": "^1.1.0", + "htpasswd-js": "^1.0.2", + "micro-cors": "^0.1.1", + "minimisted": "^2.0.0", + "ssh-keygen": "^0.4.2", + "ssh2": "^0.6.1", + "tree-kill": "^1.2.0" + }, + "bin": { + "git-http-mock-server": "http-daemon.js", + "git-ssh-mock-server": "ssh-daemon.js" + } + }, + "node_modules/git-http-mock-server/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-http-mock-server/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-http-mock-server/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/git-http-mock-server/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/git-http-mock-server/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/git-http-mock-server/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/git-http-mock-server/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -17485,6 +17708,51 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/globby/-/globby-7.1.1.tgz", + "integrity": "sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true, + "license": "MIT" + }, + "node_modules/globby/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gonzales-pe": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", @@ -18033,6 +18301,32 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/htpasswd-js": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/htpasswd-js/-/htpasswd-js-1.0.2.tgz", + "integrity": "sha512-KON5L4YKYXk647tmVclKgmHHG5nApjy9K+WiRoScnoWhS63lMoTca1ommUW2XQ3FDW8TtNDIQA7J0WYXICbMAA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "apache-crypt": "^1.2.1", + "apache-md5": "^1.1.2", + "bcryptjs": "^2.4.3", + "fs-extra": "^4.0.2", + "xerror": "^1.1.2" + } + }, + "node_modules/htpasswd-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "node_modules/http-assert": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", @@ -20959,6 +21253,16 @@ "node": ">= 0.6" } }, + "node_modules/micro-cors": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/micro-cors/-/micro-cors-0.1.1.tgz", + "integrity": "sha512-6WqIahA5sbQR1Gjexp1VuWGFDKbZZleJb/gy1khNGk18a6iN1FdTcr3Q8twaxkV5H94RjxIBjirYbWCehpMBFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -23354,6 +23658,29 @@ "dev": true, "license": "MIT" }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -25979,6 +26306,60 @@ "license": "BSD-3-Clause", "optional": true }, + "node_modules/ssh-keygen": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/ssh-keygen/-/ssh-keygen-0.4.2.tgz", + "integrity": "sha512-SlEWW3cCtz87jwtCTfxo+tR+SQd4jJXWaBI/D9JVd74b2/N9ZvrWcd9lMFwFv0iMYb4aVAeMderH4AK5ZyW+Nw==", + "dev": true, + "dependencies": { + "underscore": "1.4.x" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/ssh-keygen/node_modules/underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmmirror.com/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==", + "dev": true + }, + "node_modules/ssh2": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/ssh2/-/ssh2-0.6.2.tgz", + "integrity": "sha512-DJ+dOhXEEsmNpcQTI0x69FS++JH6qqL/ltEHf01pI1SSLMAcmD+hL4jRwvHjPwynPsmSUbHJ/WIZYzROfqZWjA==", + "dev": true, + "dependencies": { + "ssh2-streams": "~0.2.0" + }, + "engines": { + "node": ">=4.5.0" + } + }, + "node_modules/ssh2-streams": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/ssh2-streams/-/ssh2-streams-0.2.1.tgz", + "integrity": "sha512-3zCOsmunh1JWgPshfhKmBCL3lUtHPoh+a/cyQ49Ft0Q0aF7xgN06b76L+oKtFi0fgO57FLjFztb1GlJcEZ4a3Q==", + "dev": true, + "dependencies": { + "asn1": "~0.2.0", + "semver": "^5.1.0", + "streamsearch": "~0.1.2" + }, + "engines": { + "node": ">=4.5.0" + } + }, + "node_modules/ssh2-streams/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/ssri": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz", @@ -26228,6 +26609,15 @@ "any-promise": "^1.1.0" } }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -26835,6 +27225,16 @@ "node": ">=6.0.0" } }, + "node_modules/temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/temp-file": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", @@ -26898,6 +27298,20 @@ "rimraf": "bin.js" } }, + "node_modules/tempy": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/tempy/-/tempy-0.2.1.tgz", + "integrity": "sha512-LB83o9bfZGrntdqPuRdanIVCPReam9SOZKW0fOy5I9X3A854GGWi0tjCqoXEk84XIEYBc/x9Hq3EFop/H5wJaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "temp-dir": "^1.0.0", + "unique-string": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/throttle-debounce": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz", @@ -27121,6 +27535,16 @@ "node": ">=18" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", @@ -27527,6 +27951,19 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha512-ODgiYu03y5g76A1I9Gt0/chLCzQjvzDy7DsZGsLOE/1MrF6wriEskSncj1+/C58Xk/kPZDppSctDybCwOSaGAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -27537,6 +27974,13 @@ "node": ">= 4.0.0" } }, + "node_modules/unix-crypt-td-js": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz", + "integrity": "sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -28852,6 +29296,13 @@ } } }, + "node_modules/xerror": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/xerror/-/xerror-1.1.3.tgz", + "integrity": "sha512-2l5hmDymDUIuKT53v/nYxofTMUDQuu5P/Y3qHOjQiih6QUHBCgWpbpL3I8BoE5TVfUVTMmUQ0jdUAimTGc9UIg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -29435,6 +29886,7 @@ "esbuild-runner": "2.2.2", "express": "^4.21.2", "express-basic-auth": "^1.2.1", + "git-http-mock-server": "^2.0.0", "graphql": "^16.10.0", "graphql-http": "^1.22.4", "http-errors": "^2.0.0", diff --git a/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/HEAD b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/HEAD new file mode 100644 index 0000000000..cb089cd89a --- /dev/null +++ b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/config b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/config new file mode 100644 index 0000000000..64280b806c --- /dev/null +++ b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = true + symlinks = false + ignorecase = true diff --git a/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/description b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/description new file mode 100644 index 0000000000..498b267a8c --- /dev/null +++ b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/info/exclude b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/info/exclude new file mode 100644 index 0000000000..a5196d1be8 --- /dev/null +++ b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/objects/33/57649e085f0f653c60993fc34b0d380c4c2991 b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/objects/33/57649e085f0f653c60993fc34b0d380c4c2991 new file mode 100644 index 0000000000000000000000000000000000000000..78c4d86d1a520fa0bb21890968c065128eccf3f8 GIT binary patch literal 53 zcmb>}iuOv4#ExB8mWPDd*S=fSZ2ayChe3XqPh|}^ JgL9jp0RRDg6cYdd literal 0 HcmV?d00001 diff --git a/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da new file mode 100644 index 0000000000000000000000000000000000000000..a49384ff604c8486178beafbf3cf566283daef9a GIT binary patch literal 20 bcmb_zZT-bS`؍0RB`$gv&u)t^+E& +}ߴl;]_Gf]ߓGĶ`N=?hD, \ No newline at end of file diff --git a/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/refs/heads/master b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/refs/heads/master new file mode 100644 index 0000000000..1c22a98738 --- /dev/null +++ b/packages/insomnia-smoke-test/fixtures/git-repo/git-server.git/refs/heads/master @@ -0,0 +1 @@ +73a07b09e3e790de0277df5ac98e0ad62ecf83d4 diff --git a/packages/insomnia-smoke-test/package.json b/packages/insomnia-smoke-test/package.json index 303c651514..00c79d8825 100644 --- a/packages/insomnia-smoke-test/package.json +++ b/packages/insomnia-smoke-test/package.json @@ -30,6 +30,7 @@ "esbuild-runner": "2.2.2", "express": "^4.21.2", "express-basic-auth": "^1.2.1", + "git-http-mock-server": "^2.0.0", "graphql": "^16.10.0", "graphql-http": "^1.22.4", "http-errors": "^2.0.0", diff --git a/packages/insomnia-smoke-test/playwright.config.ts b/packages/insomnia-smoke-test/playwright.config.ts index 36f49be05f..907d01ba00 100644 --- a/packages/insomnia-smoke-test/playwright.config.ts +++ b/packages/insomnia-smoke-test/playwright.config.ts @@ -1,4 +1,7 @@ +import os from 'node:os'; + import type { PlaywrightTestConfig } from '@playwright/test'; +const isWindows = os.platform() === 'win32'; const config: PlaywrightTestConfig = { projects: [ { @@ -35,7 +38,7 @@ const config: PlaywrightTestConfig = { }, }, reporter: process.env.CI ? [['github'], ['line']] : [['list']], - timeout: process.env.CI ? 60 * 1000 : 20 * 1000, + timeout: process.env.CI || isWindows ? 60 * 1000 : 20 * 1000, forbidOnly: !!process.env.CI, outputDir: 'traces', testDir: 'tests', diff --git a/packages/insomnia-smoke-test/playwright/pages/preferences/credentials-tab.ts b/packages/insomnia-smoke-test/playwright/pages/preferences/credentials-tab.ts new file mode 100644 index 0000000000..17f20b6d03 --- /dev/null +++ b/packages/insomnia-smoke-test/playwright/pages/preferences/credentials-tab.ts @@ -0,0 +1,38 @@ +import type { ElectronApplication, Locator, Page } from '@playwright/test'; + +import { BasePage } from '../base-page'; + +/** + * Component for the **Credentials tab** within Insomnia Preferences. + * + * Handles credential management functionality: + * - Add, edit, and remove credentials + */ +export class PreferencesCredentialsTab extends BasePage { + constructor( + readonly page: Page, + readonly app: ElectronApplication, + ) { + super(page); + } + + get root(): Locator { + return this.page.getByTestId('credentials-settings-tab'); + } + + async addAccessTokenGitCredential() { + await this.page.getByRole('button', { name: 'Create Git Credential' }).click(); + await this.page.getByText('Access Token').click(); + await this.page.getByRole('textbox', { name: 'Author Email' }).click(); + await this.page.getByRole('textbox', { name: 'Author Email' }).fill('a@b.com'); + await this.page.getByRole('textbox', { name: 'Author Name' }).click(); + await this.page.getByRole('textbox', { name: 'Author Name' }).fill('author'); + await this.page.getByRole('textbox', { name: 'Username' }).click(); + await this.page.getByRole('textbox', { name: 'Username' }).fill('username'); + await this.page.getByRole('textbox', { name: 'Git Access Token' }).click(); + await this.page.getByRole('textbox', { name: 'Git Access Token' }).fill('accesstoken'); + await this.page.getByRole('textbox', { name: 'Repository base URL' }).click(); + await this.page.getByRole('textbox', { name: 'Repository base URL' }).fill('http://localhost:4010/git/'); + await this.page.getByRole('button', { name: 'Save Credential' }).click(); + } +} diff --git a/packages/insomnia-smoke-test/playwright/pages/preferences/index.ts b/packages/insomnia-smoke-test/playwright/pages/preferences/index.ts index 995f2f5cfa..d58096b7ad 100644 --- a/packages/insomnia-smoke-test/playwright/pages/preferences/index.ts +++ b/packages/insomnia-smoke-test/playwright/pages/preferences/index.ts @@ -1,25 +1,30 @@ import type { ElectronApplication, Locator, Page } from '@playwright/test'; +import { PreferencesCredentialsTab } from './credentials-tab'; import { PreferencesDataTab } from './data-tab'; -type PreferencesTab = 'Data' | 'General' | 'Themes' | 'Plugins' | 'Other'; +type PreferencesTab = 'Data' | 'General' | 'Themes' | 'Credentials' | 'Plugins' | 'Other'; /** * Page Object for **Insomnia Preferences** modal. * * Composes preference tabs: * - Data tab (import/export) + * - Credentials tab (Git credentials management) * - Other tabs (themes, plugins, etc.) can be added as needed */ export class PreferencesPage { /** Data tab (import/export functionality). */ readonly dataTab: PreferencesDataTab; + /** Credentials tab (Git credentials management). */ + readonly credentialsTab: PreferencesCredentialsTab; constructor( readonly page: Page, readonly app: ElectronApplication, ) { this.dataTab = new PreferencesDataTab(page, app); + this.credentialsTab = new PreferencesCredentialsTab(page, app); } /** The root preferences dialog. */ @@ -43,7 +48,7 @@ export class PreferencesPage { * Closes the preferences modal. */ async closePreferences(): Promise { - await this.page.locator('.app').press('Escape'); + await this.page.getByRole('button', { name: 'Modal Close Button' }).click(); await this.root.waitFor({ state: 'hidden' }); } } diff --git a/packages/insomnia-smoke-test/playwright/pages/project/index.ts b/packages/insomnia-smoke-test/playwright/pages/project/index.ts index b174339a0e..df1d6e81d5 100644 --- a/packages/insomnia-smoke-test/playwright/pages/project/index.ts +++ b/packages/insomnia-smoke-test/playwright/pages/project/index.ts @@ -80,6 +80,33 @@ export class ProjectPage extends BasePage { await this.page.getByRole('button', { name: 'Create', exact: true }).click(); } + async createGitSyncProject(name = 'My Git Project'): Promise { + await this.page.getByRole('button', { name: 'Create new Project' }).click(); + await this.page.getByRole('textbox', { name: 'Project name' }).click(); + await this.page.getByRole('textbox', { name: 'Project name' }).press('ControlOrMeta+a'); + await this.page.getByRole('textbox', { name: 'Project name' }).fill(name); + await this.page.getByText('Git Sync').click(); + await this.page.getByRole('button', { name: 'Access Token author Git' }).click(); + await this.page.getByRole('option', { name: 'Custom Git Credential' }).click(); + await this.page.getByRole('textbox', { name: 'Repository URL' }).click(); + await this.page.getByRole('textbox', { name: 'Repository URL' }).fill('git-server.git'); + await this.page.getByRole('button', { name: 'Show suggestions Branch' }).click(); + await this.page.getByRole('option', { name: 'master' }).click(); + await this.page.getByRole('button', { name: 'Scan for files' }).click(); + await this.page.getByRole('button', { name: 'Create Blank Project' }).click(); + const projectModalCloseButton = this.page.locator('[data-test-id="project-modal-close-button"]'); + await projectModalCloseButton.waitFor({ state: 'visible', timeout: 5000 }).catch(() => {}); + if (await projectModalCloseButton.isVisible()) { + await projectModalCloseButton.click(); + } + await this.page.getByRole('button', { name: 'Personal workspace' }).click(); + await this.page.getByRole('option', { name: /Magic/ }).locator('span').click(); + await this.page.getByRole('button', { name: /Magic/ }).click(); + await this.page.getByRole('option', { name: 'Personal workspace' }).locator('span').click(); + await this.page.getByText('Git Project').waitFor({ state: 'visible', timeout: 10_000 }); + await this.page.getByText('Git Project').click(); + } + // =========================================================================== // Import Operations // =========================================================================== diff --git a/packages/insomnia-smoke-test/server/index.ts b/packages/insomnia-smoke-test/server/index.ts index 0f29bad42b..649160830d 100644 --- a/packages/insomnia-smoke-test/server/index.ts +++ b/packages/insomnia-smoke-test/server/index.ts @@ -6,6 +6,7 @@ import nodePath from 'node:path'; import * as bodyParser from 'body-parser'; import cookieParser from 'cookie-parser'; import express from 'express'; +import gitMiddleware from 'git-http-mock-server/middleware'; import { createHandler } from 'graphql-http/lib/use/http'; import { basicAuthRouter } from './basic-auth'; @@ -152,6 +153,15 @@ app.get('/v1/oauth/azure/config', (_req, res) => { }); }); +app.use( + '/git', + gitMiddleware({ + root: nodePath.join(__dirname, '../fixtures/git-repo'), + glob: '*', + route: '/', + }), +); + startWebSocketServer( app.listen(port, '::', () => { console.log(`Listening at http://localhost:${port}`); diff --git a/packages/insomnia-smoke-test/tests/smoke/disable-git-sync.test.ts b/packages/insomnia-smoke-test/tests/smoke/disable-git-sync.test.ts new file mode 100644 index 0000000000..4f476cbe31 --- /dev/null +++ b/packages/insomnia-smoke-test/tests/smoke/disable-git-sync.test.ts @@ -0,0 +1,101 @@ +import { expect } from '@playwright/test'; + +import { test } from '../../playwright/test'; + +const mockCredentials = { + email: 'insomnia-test@konghq.com', + gitUsername: 'insomnia-test', + username: 'insomnia', + token: '12345', + baseUrl: 'https://fakeurl.com/', +}; + +test.describe('Git Sync', () => { + test.describe('with git sync feature flag disabled', () => { + test.beforeEach(async ({ request }) => { + // Disable git sync feature flag for organization + await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/features', { + data: { + features: { + gitSync: { + enabled: false, + }, + konnectSync: { + enabled: true, + }, + }, + }, + }); + }); + + test.afterEach(async ({ request }) => { + // Re-enable git sync feature flag for organization + await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/features', { + data: { + features: { + gitSync: { + enabled: true, + }, + konnectSync: { + enabled: true, + }, + }, + }, + }); + }); + + test('should disable git sync usage', async ({ page }) => { + await page.getByTestId('settings-button').click(); + await page.getByRole('tab', { name: 'Credentials' }).click(); + await page.getByRole('button', { name: 'Create Git Credential' }).click(); + await page.getByText('Access Token').click(); + await page.getByRole('textbox', { name: 'Author Email' }).fill(mockCredentials.email); + await page.getByRole('textbox', { name: 'Author Name' }).fill(mockCredentials.gitUsername); + await page.getByRole('textbox', { name: 'Username', exact: true }).fill(mockCredentials.username); + await page.getByRole('textbox', { name: 'Git Access Token' }).fill(mockCredentials.token); + await page.getByRole('textbox', { name: 'Repository base URL' }).fill(mockCredentials.baseUrl); + await page.getByRole('button', { name: 'Save Credential' }).click(); + await page.getByRole('button', { name: 'Modal Close Button' }).click(); + await page.getByRole('button', { name: 'Create new Project' }).click(); + await page.getByLabel('Project Type Item: git').click(); + await expect.soft(page.getByLabel('Git Sync Feature Disabled Banner')).toBeVisible(); + + await expect.soft(page.getByLabel('Git Setup Form')).toBeHidden(); + await expect.soft(page.getByRole('button', { name: 'Scan for files' })).toBeDisabled(); + }); + }); + + test.describe('with git storage rule disabled', () => { + test.beforeEach(async ({ request }) => { + // Set storage rule to disable git sync + await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/storage-rule', { + data: { + enableCloudSync: true, + enableGitSync: false, + enableLocalVault: true, + isOverridden: false, + }, + }); + }); + + test.afterEach(async ({ request }) => { + // reset the storage rule after test + await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/storage-rule', { + data: { + enableCloudSync: true, + enableGitSync: true, + enableLocalVault: true, + isOverridden: false, + }, + }); + }); + + test('disable git sync selection', async ({ page }) => { + await page.getByRole('button', { name: 'Create new Project' }).click(); + const banner = page.getByLabel('Project Storage Restriction Banner'); + await expect.soft(banner).toBeVisible(); + await expect.soft(banner).not.toHaveText('Git Sync'); + await expect.soft(page.getByLabel('Project Type: git')).toBeDisabled(); + }); + }); +}); diff --git a/packages/insomnia-smoke-test/tests/smoke/export.test.ts b/packages/insomnia-smoke-test/tests/smoke/export.test.ts index fb0cd9f4d9..563801382d 100644 --- a/packages/insomnia-smoke-test/tests/smoke/export.test.ts +++ b/packages/insomnia-smoke-test/tests/smoke/export.test.ts @@ -33,9 +33,8 @@ test.describe('Export', () => { await insomnia.preferencesPage.switchToPreferenceTab('Data'); await insomnia.preferencesPage.dataTab.exportProjectData(tempDir, 'yaml'); await waitForExportFiles(tempDir, 2); - await insomnia.preferencesPage.closePreferences(); const exportedFiles = getExportedFiles(tempDir); - expect.soft(exportedFiles.length).toBe(2); + expect.soft(exportedFiles).toHaveLength(2); const fixtureMap: Record = { 'Collection-A': FIXTURE_FILES[0], 'Collection-B': FIXTURE_FILES[1], @@ -78,7 +77,7 @@ test.describe('Export', () => { await insomnia.preferencesPage.dataTab.exportAllData(tempDir); await insomnia.preferencesPage.closePreferences(); const exportedFiles = getExportedFiles(tempDir).filter((file: string) => !file.includes('scratchpad')); - expect.soft(exportedFiles.length).toBe(2); + expect.soft(exportedFiles).toHaveLength(2); const fixtureMap: Record = { 'Collection-A': FIXTURE_FILES[0], 'Collection-B': FIXTURE_FILES[1], @@ -123,8 +122,6 @@ test.describe('Export', () => { await insomnia.preferencesPage.dataTab.exportProjectData(exportFilePath, 'har'); await waitForExportFiles(tempDir, 1); - await insomnia.preferencesPage.closePreferences(); - const exportedContent = readExportedFile(exportFilePath); const har = JSON.parse(exportedContent); diff --git a/packages/insomnia-smoke-test/tests/smoke/git-sync.test.ts b/packages/insomnia-smoke-test/tests/smoke/git-sync.test.ts index 4f476cbe31..c604c4ab8d 100644 --- a/packages/insomnia-smoke-test/tests/smoke/git-sync.test.ts +++ b/packages/insomnia-smoke-test/tests/smoke/git-sync.test.ts @@ -1,101 +1,96 @@ import { expect } from '@playwright/test'; +import type { InsomniaApp } from '../../playwright/pages'; import { test } from '../../playwright/test'; -const mockCredentials = { - email: 'insomnia-test@konghq.com', - gitUsername: 'insomnia-test', - username: 'insomnia', - token: '12345', - baseUrl: 'https://fakeurl.com/', -}; - test.describe('Git Sync', () => { - test.describe('with git sync feature flag disabled', () => { - test.beforeEach(async ({ request }) => { - // Disable git sync feature flag for organization - await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/features', { - data: { - features: { - gitSync: { - enabled: false, - }, - konnectSync: { - enabled: true, - }, - }, - }, - }); - }); + test.slow(); - test.afterEach(async ({ request }) => { - // Re-enable git sync feature flag for organization - await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/features', { - data: { - features: { - gitSync: { - enabled: true, - }, - konnectSync: { - enabled: true, - }, - }, - }, - }); - }); + test('Create new branch and switch to it', async ({ insomnia, page }) => { + await addAccessTokenGitCredential(insomnia); + await insomnia.projectPage.createGitSyncProject(); - test('should disable git sync usage', async ({ page }) => { - await page.getByTestId('settings-button').click(); - await page.getByRole('tab', { name: 'Credentials' }).click(); - await page.getByRole('button', { name: 'Create Git Credential' }).click(); - await page.getByText('Access Token').click(); - await page.getByRole('textbox', { name: 'Author Email' }).fill(mockCredentials.email); - await page.getByRole('textbox', { name: 'Author Name' }).fill(mockCredentials.gitUsername); - await page.getByRole('textbox', { name: 'Username', exact: true }).fill(mockCredentials.username); - await page.getByRole('textbox', { name: 'Git Access Token' }).fill(mockCredentials.token); - await page.getByRole('textbox', { name: 'Repository base URL' }).fill(mockCredentials.baseUrl); - await page.getByRole('button', { name: 'Save Credential' }).click(); - await page.getByRole('button', { name: 'Modal Close Button' }).click(); - await page.getByRole('button', { name: 'Create new Project' }).click(); - await page.getByLabel('Project Type Item: git').click(); - await expect.soft(page.getByLabel('Git Sync Feature Disabled Banner')).toBeVisible(); - - await expect.soft(page.getByLabel('Git Setup Form')).toBeHidden(); - await expect.soft(page.getByRole('button', { name: 'Scan for files' })).toBeDisabled(); - }); + await page.getByTestId('git-dropdown').click(); + await page.getByRole('menuitemradio', { name: 'Branches' }).click(); + await page.getByRole('textbox', { name: 'New branch name:' }).click(); + await page.getByRole('textbox', { name: 'New branch name:' }).fill('branch1'); + await page.getByRole('button', { name: 'Create', exact: true }).click(); + await expect.soft(page.getByText('branch1 *')).toBeVisible(); }); - test.describe('with git storage rule disabled', () => { - test.beforeEach(async ({ request }) => { - // Set storage rule to disable git sync - await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/storage-rule', { - data: { - enableCloudSync: true, - enableGitSync: false, - enableLocalVault: true, - isOverridden: false, - }, - }); - }); + test('Commit and check history', async ({ insomnia, page }) => { + await addAccessTokenGitCredential(insomnia); + await insomnia.projectPage.createGitSyncProject(); - test.afterEach(async ({ request }) => { - // reset the storage rule after test - await request.post('http://127.0.0.1:4010/v1/test-utils/organizations/storage-rule', { - data: { - enableCloudSync: true, - enableGitSync: true, - enableLocalVault: true, - isOverridden: false, - }, - }); - }); + await page.getByRole('button', { name: 'New request collection' }).click(); + await page.getByRole('textbox', { name: 'Name', exact: true }).click(); + await page.getByRole('textbox', { name: 'Name', exact: true }).press('ControlOrMeta+a'); + await page.getByRole('textbox', { name: 'Name', exact: true }).fill('Collection 1'); + await page.getByRole('textbox', { name: 'File name my_collection' }).click(); + await page.getByRole('textbox', { name: 'File name my_collection' }).press('ControlOrMeta+a'); + await page.getByRole('textbox', { name: 'File name my_collection' }).fill('collection_1'); + await page.getByRole('button', { name: 'Create', exact: true }).click(); + await page.getByTestId('git-dropdown').click(); + await expect.soft(page.getByRole('menuitemradio', { name: 'Commit' })).toBeVisible(); + await page.getByRole('menuitemradio', { name: 'Commit' }).click(); + await expect.soft(page.getByLabel('Unstaged changes').locator('span')).toContainText('collection_1.yaml'); - test('disable git sync selection', async ({ page }) => { - await page.getByRole('button', { name: 'Create new Project' }).click(); - const banner = page.getByLabel('Project Storage Restriction Banner'); - await expect.soft(banner).toBeVisible(); - await expect.soft(banner).not.toHaveText('Git Sync'); - await expect.soft(page.getByLabel('Project Type: git')).toBeDisabled(); - }); + await page.locator('button[name="Stage all changes"]').click(); + await page.getByRole('textbox', { name: 'Message' }).click(); + await page.getByRole('textbox', { name: 'Message' }).fill('1'); + await page.getByRole('button', { name: 'Commit', exact: true }).click(); + await page.getByTestId('git-dropdown').click(); + await page.getByText('History').click(); + await expect.soft(page.getByLabel('1', { exact: true }).getByRole('rowheader')).toContainText('1'); + }); + + test('Merge branch and verify changes on the other branch has been merged into current branch', async ({ + insomnia, + page, + }) => { + await addAccessTokenGitCredential(insomnia); + await insomnia.projectPage.createGitSyncProject(); + + await page.getByTestId('git-dropdown').click(); + await page.getByRole('menuitemradio', { name: 'Branches' }).click(); + await page.getByRole('textbox', { name: 'New branch name:' }).click(); + await page.getByRole('textbox', { name: 'New branch name:' }).fill('branch1'); + await page.getByRole('button', { name: 'Create', exact: true }).click(); + await expect.soft(page.getByText('branch1 *')).toBeVisible(); + await page.getByTestId('close-git-project-branches-modal').click(); + await page.getByTestId('git-project-branches-modal-overlay').waitFor({ state: 'hidden' }); + await page.getByRole('button', { name: 'New request collection' }).click(); + await page.getByRole('textbox', { name: 'Name', exact: true }).click(); + await page.getByRole('textbox', { name: 'Name', exact: true }).press('ControlOrMeta+a'); + await page.getByRole('textbox', { name: 'Name', exact: true }).fill('collection 1'); + await page.getByRole('textbox', { name: 'File name my_collection' }).click(); + await page.getByRole('textbox', { name: 'File name my_collection' }).press('ControlOrMeta+a'); + await page.getByRole('textbox', { name: 'File name my_collection' }).fill('collection_1'); + await page.getByRole('button', { name: 'Create', exact: true }).click(); + await page.getByTestId('project').click(); + await page.getByTestId('git-dropdown').click(); + await page.getByRole('menuitemradio', { name: 'Commit' }).click(); + await page.locator('button[name="Stage all changes"]').click(); + await page.getByRole('textbox', { name: 'Message' }).click(); + await page.getByRole('textbox', { name: 'Message' }).fill('commit 1'); + await page.getByRole('button', { name: 'Commit', exact: true }).click(); + await page.getByTestId('git-dropdown').click(); + await page.getByRole('menuitemradio', { name: 'master' }).click(); + await page.locator('html').click(); + await page.getByTestId('git-dropdown').click(); + await page.getByRole('menuitemradio', { name: 'Branches' }).click(); + await page.getByLabel('branch1').getByRole('button', { name: 'Merge' }).click(); + await page.getByRole('button', { name: ' Confirm' }).click(); + await page.getByTestId('close-git-project-branches-modal').click(); + await page.getByTestId('git-project-branches-modal-overlay').waitFor({ state: 'hidden' }); + await expect.soft(page.getByText('collection 1')).toBeVisible(); }); }); + +async function addAccessTokenGitCredential(insomnia: InsomniaApp) { + await insomnia.statusbar.openPreferences(); + await insomnia.preferencesPage.switchToPreferenceTab('Credentials'); + await insomnia.preferencesPage.credentialsTab.addAccessTokenGitCredential(); + await expect.soft(insomnia.page.getByRole('row', { name: 'Custom Git Credential' })).toBeVisible(); + await insomnia.preferencesPage.closePreferences(); +} diff --git a/packages/insomnia/src/ui/components/modals/git-project-branches-modal.tsx b/packages/insomnia/src/ui/components/modals/git-project-branches-modal.tsx index 7f5385c357..50a1ae5b3d 100644 --- a/packages/insomnia/src/ui/components/modals/git-project-branches-modal.tsx +++ b/packages/insomnia/src/ui/components/modals/git-project-branches-modal.tsx @@ -311,6 +311,7 @@ export const GitProjectBranchesModal: FC = ({ currentBranch, branches, on }} isDismissable className="fixed top-0 left-0 z-10 flex h-(--visual-viewport-height) w-full items-center justify-center bg-black/30" + data-testid="git-project-branches-modal-overlay" > { @@ -328,6 +329,7 @@ export const GitProjectBranchesModal: FC = ({ currentBranch, branches, on diff --git a/packages/insomnia/src/ui/components/modals/project-modal.tsx b/packages/insomnia/src/ui/components/modals/project-modal.tsx index c00f1238d4..93adddbbe1 100644 --- a/packages/insomnia/src/ui/components/modals/project-modal.tsx +++ b/packages/insomnia/src/ui/components/modals/project-modal.tsx @@ -64,6 +64,7 @@ export const ProjectModal = ({